#
#
# 66_ECMDDevice.pm
# written by Dr. Boris Neubert 2011-01-15
# e-mail: omega at online dot de
#
##############################################
# $Id$
package main;

use strict;
use warnings;
use Time::HiRes qw(gettimeofday);

sub ECMDDevice_Get($@);
sub ECMDDevice_Set($@);
sub ECMDDevice_Define($$);

my %gets= (
);

my %sets= (
);

###################################
sub
ECMDDevice_Initialize($)
{
  my ($hash) = @_;

  $hash->{GetFn}     = "ECMDDevice_Get";
  $hash->{SetFn}     = "ECMDDevice_Set";
  $hash->{DefFn}     = "ECMDDevice_Define";

  $hash->{AttrList}  = "loglevel 0,1,2,3,4,5";
}

###################################
sub
ECMDDevice_AnalyzeCommand($)
{
        my ($ecmd)= @_;
        Log 5, "ECMDDevice: Analyze command >$ecmd<";
        return AnalyzePerlCommand(undef, $ecmd);
}

#############################
sub
ECMDDevice_GetDeviceParams($)
{
        my ($hash)= @_;
        my $classname= $hash->{fhem}{classname};
        my $IOhash= $hash->{IODev};
        if(defined($IOhash->{fhem}{classDefs}{$classname}{params})) {
                my $params= $IOhash->{fhem}{classDefs}{$classname}{params};
                return split("[ \t]+", $params);
        }
        return;
}

sub
ECMDDevice_DeviceParams2Specials($)
{
        my ($hash)= @_;
        my %specials= (
                "%NAME" => $hash->{NAME},
                "%TYPE" => $hash->{TYPE}
        );
        my @deviceparams= ECMDDevice_GetDeviceParams($hash);
        foreach my $param (@deviceparams) {
                $specials{"%".$param}= $hash->{fhem}{params}{$param};
        }
        return %specials;
}

###################################
sub
ECMDDevice_Changed($$$)
{
        my ($hash, $cmd, $value)= @_;


        readingsBeginUpdate($hash);
        readingsUpdate($hash, $cmd, $value);
        readingsEndUpdate($hash, 1);

        $hash->{STATE} = "$cmd $value";

        my $name= $hash->{NAME};
        Log GetLogLevel($name, 4), "ECMDDevice $name $cmd: $value";

        return $hash->{STATE};

}

###################################
sub
ECMDDevice_PostProc($$$)
{
  my ($hash, $postproc, $value)= @_;

  # the following lines are commented out because we do not want specials to be evaluated
  # this is mainly due to the unwanted substitution of single semicolons by double semicolons
  #my %specials= ECMDDevice_DeviceParams2Specials($hash);
  #my $command= EvalSpecials($postproc, %specials);
  # we pass the command verbatim instead
  # my $command= $postproc;

  if($postproc) {
        my %specials= ECMDDevice_DeviceParams2Specials($hash);
        my $command= EvalSpecials($postproc, %specials);
	$_= $value;
	Log 5, "Postprocessing $value with perl command $command.";
	$value= AnalyzePerlCommand(undef, $command);
  }
  return $value;
}


###################################

sub
ECMDDevice_Get($@)
{
        my ($hash, @a)= @_;

        my $name= $hash->{NAME};
        my $type= $hash->{TYPE};
        return "get $name needs at least one argument" if(int(@a) < 2);
        my $cmdname= $a[1];

        my $IOhash= $hash->{IODev};
        my $classname= $hash->{fhem}{classname};
        if(!defined($IOhash->{fhem}{classDefs}{$classname}{gets}{$cmdname})) {
                return "$name error: unknown command $cmdname";
        }

        my $ecmd= $IOhash->{fhem}{classDefs}{$classname}{gets}{$cmdname}{cmd};
        my $params= $IOhash->{fhem}{classDefs}{$classname}{gets}{$cmdname}{params};
        my $postproc= $IOhash->{fhem}{classDefs}{$classname}{gets}{$cmdname}{postproc};

        my %specials= ECMDDevice_DeviceParams2Specials($hash);
        # add specials for command
        if($params) {
                shift @a; shift @a;
                my @params= split('[\s]+', $params);
                return "Wrong number of parameters." if($#a != $#params);

                my $i= 0;
                foreach my $param (@params) {
                        Log 5, "Parameter %". $param . " is " . $a[$i];
                        $specials{"%".$param}= $a[$i++];
                }
        }
        $ecmd= EvalSpecials($ecmd, %specials);

        my $r = ECMDDevice_AnalyzeCommand($ecmd);

        my $v= IOWrite($hash, $r);

	$v= ECMDDevice_PostProc($hash, $postproc, $v);

        return ECMDDevice_Changed($hash, $cmdname, $v);
}


#############################
sub
ECMDDevice_Set($@)
{
        my ($hash, @a)= @_;

        my $name= $hash->{NAME};
        my $type= $hash->{TYPE};
        return "set $name needs at least one argument" if(int(@a) < 2);
        my $cmdname= $a[1];

        my $IOhash= $hash->{IODev};
        my $classname= $hash->{fhem}{classname};
        if(!defined($IOhash->{fhem}{classDefs}{$classname}{sets}{$cmdname})) {
		my $sets= $IOhash->{fhem}{classDefs}{$classname}{sets};
                return "Unknown argument ?, choose one of " . join(' ', keys %$sets);
        }

        my $ecmd= $IOhash->{fhem}{classDefs}{$classname}{sets}{$cmdname}{cmd};
        my $params= $IOhash->{fhem}{classDefs}{$classname}{sets}{$cmdname}{params};
        my $postproc= $IOhash->{fhem}{classDefs}{$classname}{sets}{$cmdname}{postproc};

        my %specials= ECMDDevice_DeviceParams2Specials($hash);
        # add specials for command
        if($params) {
                shift @a; shift @a;
                my @params= split('[\s]+', $params);
                return "Wrong number of parameters." if($#a != $#params);

                my $i= 0;
                foreach my $param (@params) {
                        $specials{"%".$param}= $a[$i++];
                }
        }
        $ecmd= EvalSpecials($ecmd, %specials);

        my $r = ECMDDevice_AnalyzeCommand($ecmd);

        my $v= IOWrite($hash, $r);

	$v= ECMDDevice_PostProc($hash, $postproc, $v);

#        $v= join(" ", @a) if($params);

        return ECMDDevice_Changed($hash, $cmdname, $v);

}


#############################

sub
ECMDDevice_Define($$)
{
        my ($hash, $def) = @_;
        my @a = split("[ \t]+", $def);

        return "Usage: define <name> ECMDDevice <classname> [...]"    if(int(@a) < 3);
        my $name= $a[0];
        my $classname= $a[2];

        AssignIoPort($hash);

        my $IOhash= $hash->{IODev};
        if(!defined($IOhash->{fhem}{classDefs}{$classname}{filename})) {
                my $err= "$name error: unknown class $classname.";
                Log 1, $err;
                return $err;
        }

        $hash->{fhem}{classname}= $classname;

        my @prms= ECMDDevice_GetDeviceParams($hash);
        my $numparams= 0;
        $numparams= $#prms+1 if(defined($prms[0]));
        #Log 5, "ECMDDevice $classname requires $numparams parameter(s): ". join(" ", @prms);

        # keep only the parameters
        shift @a; shift @a; shift @a;

        # verify identical number of parameters
        if($numparams != $#a+1) {
                my $err= "$name error: wrong number of parameters";
                Log 1, $err;
                return $err;
        }

        # set parameters
        for(my $i= 0; $i< $numparams; $i++) {
                $hash->{fhem}{params}{$prms[$i]}= $a[$i];
        }
        return undef;
}

1;
