#!/usr/bin/perl
#$Id: json_rig_ui.cgi,v 1.41 2023/11/23 09:54:28 sqko Exp $
use strict;
use warnings;
use CGI qw(:standard :netscape);
use RFC::Main;
use RFC::Rig;
use RFC::RFCCGI qw(:cgi);
use RFC::Header;
use Data::Dumper;
use JSON qw(decode_json to_json);
my $cache_delay = 30;
my $ref = &RFC::RFCCGI::get_user_data_ref();
my $uid = $$ref{'uid'};
unless (param)
{
    print header(-access_control_allow_origin => '*',-content_type=>'text/plain',-charset=>'utf-8');
    print <<END;


Oops.. no parameters, displaying interface definitions!


END
    exit;
}

my $maxdelay = get_cv('main','maximum_time_delay_for_current_values');
$maxdelay = 60 unless $maxdelay;

print header(-access_control_allow_origin => '*');
my $ac = param('action');
unless ($ac)
{
    my %h = ('status'=>"No action specified!");
    print to_json(\%h);
    exit;
}

my $r = param('rig');
unless ($r)
{
    my %h = ('status'=>"No rig specified!");
    print to_json(\%h);
    exit;
}
my $rig = RFC::Rig->new($r);


unless ($$ref{'uid'})
{
    my %h = ('status'=>"User not authenticated!");
    print to_json(\%h);
    exit;
}

if ($ac eq 'get_latest_proglog')
{
    my $str = $rig->get_sessionlog;
    my @list = split(/\n/,$str);
    my @res = @list[-5..-1];
    print to_json(\@res);
    exit;    
}

if ($ac eq 'get_latest_userlog')
{
    my $str = $rig->get_userlog;
    my @list = split(/\n/,$str);
    my @res = @list[-5..-1];
    print to_json(\@res);
    exit;    
}

if ($ac eq 'get_latest_errorlog')
{
    my $str = $rig->get_errorlog;
    my @list = split(/\n/,$str);
    my @res = @list[-5..-1];
    print to_json(\@res);
    exit;    
}

if ($ac eq 'get_info')
{
    my $str = $rig->info;
    my @list = split(/\n/,$str);
    print to_json(\@list);
    exit;    
}


if ($ac eq 'get_logs')
{
    my %logs = ('status' => 'OK');
    my $str = $rig->get_sessionlog;
    my @list = split(/\n+/,$str);
    my @plog = @list[-10..-1];
    $logs{'proglog'} =  [@plog];
    $str = $rig->get_errorlog;
    @list = split(/\n+/,$str);
    my @elog = ($list[-1]);
    $logs{'errorlog'} =  [@elog];
    $str = $rig->get_userlog;
    @list = split(/\n+/,$str);
    my @ulog = ($list[-1]);
    $logs{'userlog'} =  [@ulog];
    $str = $rig->info;
    @list = split(/\n/,$str);
    $logs{'info'} =  [@list];
    print to_json(\%logs);
    exit;    
}


if ($ac eq 'get_value')
{
    unless ($$ref{'auth'} || $$ref{'allow'})
    {
	my %h = ();
	print to_json(\%h);
	exit;	
    }
    my $class = param('class');
    my $name = param('name');
    my $dev = $rig->get_device($class,$name);
    unless ($dev)
    {
	print "Device '$name' of class '$class' does not exist!\n";
	exit;
    } 
    my $val = CGI_client($r,'get_data_cache',$class,$name,$cache_delay);
    unless (defined($val) && $val =~/\d/ && $val != -1)
    {
	$val = $dev->read();
	CGI_client($r,'set_data_cache',$class,$name,$val);
    }
    my %h = (
	'class' => $class,
	'name' => $name,
	'value' => $val,
	'readonly' => $dev->readonly(),
	);
    print to_json(\%h);
    exit;
}


if ($ac eq 'userlog')
{
    unless (($$ref{'auth'} || $$ref{'allow'}) && param('json_data'))
    {
	my %h = ();
	print to_json(\%h);
	exit;	
    }	
    my $r = decode_json(param('json_data'));
    my %logs = ('status' => 'OK');
    my $str = $rig->get_sessionlog;
    my @list = split(/\n+/,$str);
    my @plog = @list[-10..-1];
    $logs{'proglog'} =  [@plog];
    $str = $rig->get_errorlog;
    @list = split(/\n+/,$str);
    my @elog = ($list[-1]);
    $logs{'errorlog'} =  [@elog];
    $rig->userlog($$r{'log'},$$ref{'name'});
    $str = $rig->get_userlog;
    @list = split(/\n+/,$str);
    my @ulog = ($list[-1]);
    $logs{'userlog'} =  [@ulog];
    my $time = localtime();
    my $user = $$ref{'name'};
    my $logstr = $time.', User '.$user.' added: '.$$r{'log'}."\n";
    $str = $rig->info($logstr);
    @list = split(/\n/,$str);
    $logs{'info'} =  [@list];
    print to_json(\%logs);
    exit;    
}

if ($ac eq 'set_device')
{
    my @list = ();
    unless ($$ref{'auth'} && param('json_data'))
    {
	print to_json(\@list);
	exit;	
    }
    my $data = RFC::Cache->new();
    my $rr = $r;
    my $r = decode_json(param('json_data'));
    $rig->lock_control();
    for my $i (keys %{$r})
    {
	eval {
	    my $class = $$r{$i}{'devclass'};
	    my $name = $$r{$i}{'devname'};
	    my $action = $$r{$i}{'command'};
	    my $arglist = $$r{$i}{'arguments'};
	    next unless ($class && $name && $action);
	    my @args = ();
	    @args = @{$arglist} if ($arglist);
	    push @args,$$ref{'name'} unless ($$r{$i}{'no_username_arg'});
	    my $dev = $rig->get_device($class,$name);
	    if ($class eq 'relay' && !$dev)
	    {
		$dev = $rig->get_device('water',$name);
		$action = 'setstatus';
	    }
	    next unless ($dev);	    
	    my $res = $dev->$action(@args);
	    my %h = (
		'class' => $class,
		'name' => $name,
		'result' => $res,
		'action' => $res,
		'readonly' => $dev->readonly(),
		);	
	    if ($class eq 'multiplex')
	    {
		$h{'gasses'} = [$dev->gasses()];
		$h{'value'} = $dev->gas_name();
	    }
	    if ($class eq 'relay')
	    {
		my $val = CGI_client($rr,'get_data_cache',$class,$name,$cache_delay);
		unless (defined($val) && $val =~/\d/ && $val != -1)
		{
		    $val = $dev->read();
		    CGI_client($rr,'set_data_cache',$class,$name,$val);
		}
		$h{'value'} = $val;
                if ($dev->type() eq 'Humidifier')
                {
                    $h{'value'} = $dev->readstatus();
                }
	    }
	    push @list,\%h;
	    if ($class eq 'gas')
	    {
		my $contr = $dev->controler();
		if ($contr)
		{
		    my $val = CGI_client($rr,'get_data_cache','MFC',$contr->name,$cache_delay);
		    unless (defined($val) && $val =~/\d/ && $val != -1)
		    {
			$val = $contr->read();
			CGI_client($rr,'set_data_cache','MFC',$contr->name,$val);
		    }
		    my %h2 = (
			'class' => 'MFC',
			'name' => $contr->name,
			'value' => $val,
			'gas' => $contr->selected_gas(),
			'readonly' => $contr->readonly,
			'setpoint' => $dev->setpoint(),
			);	
		    push @list,\%h2;
		}
	    }
	    if ($class eq 'multiplex')
	    {
		if ($dev->type eq 'Selector')
		{
		    my $val = CGI_client($rr,'get_data_cache','selector',$dev->name,$cache_delay);
		    unless (defined($val) && $val =~/\d/ && $val != -1)
		    {
			$val = $dev->read();
			CGI_client($rr,'set_data_cache','selector',$dev->name,$val);
		    }
 		    my %h2 = (
			'class' => 'Selector',
			'name' => $dev->name,
			'value' => $val,
			'readonly' => $dev->readonly(),
			'gas' => $dev->gas_name(),
			'setpoint' => $dev->setpoint(),
			);	
		    push @list,\%h2;	    
		}
		else
		{
		    foreach my $rdev ($dev->relays())
		    {
			my $val = CGI_client($rr,'get_data_cache','relay',$rdev->name,$cache_delay);
			unless (defined($val) && $val =~/\d/ && $val != -1)
			{
			    $val = $rdev->read();
			    CGI_client($rr,'set_data_cache','relay',$rdev->name,$val);
			}
			my %h2 = (
			    'class' => 'relay',
			    'name' => $rdev->name,
			    'value' => $val,
			    'readonly' => 0,
			    );	
			push @list,\%h2;
		    }
		    my $gas = $dev->gas_name();
		    my $cdev = $dev->controler();
		    my $gdev = $rig->get_device('gas',$gas);
		    my $val = CGI_client($rr,'get_data_cache','MFC',$cdev->name,$cache_delay);
		    unless (defined($val) && $val =~/\d/ && $val != -1)
		    {
			$val = $cdev->read();
			CGI_client($rr,'set_data_cache','MFC',$cdev->name,$val);
		    }
		    my %h2 = (
			'class' => 'MFC',
			'name' => $cdev->name,
			'value' => $val,
			'readonly' => $cdev->readonly(),
			'gas' => $gas,
			'setpoint' => $cdev->setpoint(),
			);	
		    push @list,\%h2;	    
		}
	    }
	};
	if ($@)
	{
	    $rig->errorlog($@);
	}
    }
    $rig->unlock_control();
    ## Fetch gas list for control ##
    my @gasses = $rig->list_devices_control('gas');
    my @multi = $rig->list_devices_control('multiplex');
    my %mgasses = ();
    my %glist = ();
    foreach (@gasses)
    {
	$glist{$_} = 1;
    }
    foreach my $n (@multi)
    {
        my $d = $rig->get_device('multiplex',$n);
        next unless ($d);
	my @g =$d->gasses();
	foreach my $gas (@g)
        {
            $glist{$gas} = 0 unless ($gas eq $d->gas_name());
	}
        $mgasses{$n} = [@g];
    }
    @gasses = ();
    foreach my $gas (sort keys %glist)
    {
	push @gasses,$gas if ($glist{$gas});
    }
    my %h = (
	'class' => 'gas_list',
	'gasses' => [@gasses],
	);
    push @list,\%h;
    print to_json(\@list);
}

if ($ac eq 'get_data_list')
{
    my @list = ();
    ## Fdetch gas list for control ##
    my @gasses = $rig->list_devices_control('gas');
    my @multi = $rig->list_devices_control('multiplex');
    my %mgasses = ();
    my %glist = ();
    foreach (@gasses)
    {
	$glist{$_} = 1;
    }
    foreach my $n (@multi)
    {
        my $d = $rig->get_device('multiplex',$n);
        next unless ($d);
	my @g =$d->gasses();
	foreach my $gas (@g)
        {
            $glist{$gas} = 0 unless ($gas eq $d->gas_name());
	}
        $mgasses{$n} = [@g];
    }
    @gasses = ();
    foreach my $gas (sort keys %glist)
    {
	push @gasses,$gas if ($glist{$gas});
    }
    my %h = (
	'class' => 'gas_list',
	'gasses' => [@gasses],
	);
    push @list,\%h;
    ### Get rest 
    unless (($$ref{'auth'} || $$ref{'allow'}) && param('json_data'))
    {
	print to_json(\@list);
	exit;	
    }
    my $data = RFC::Cache->new();
    my $rr = $r;
    my $r = decode_json(param('json_data'));
    for my $i (keys %{$r})
    {
	my $class = $$r{$i}{'devclass'};
	my $name = $$r{$i}{'devname'};
	next unless ($class && $name);
	my $dev = $rig->get_device($class,$name);
	if ($class eq 'relay' && !$dev)
	{
	    $dev = $rig->get_device('water',$name);
	}
	next unless ($dev);
	eval {
	    if ($class eq 'tempcontrol')
	    {
		my $val = CGI_client($rr,'get_data_cache',$class,$name,$cache_delay);
		unless (defined($val) && $val =~/\d/ && $val != -1)
		{
		    $val = $dev->get_atemp();
		    CGI_client($rr,'set_data_cache',$class,$name,$val);
		}
		my $set = $dev->get_temp();
		my $ramp = $dev->get_ramp();
		my %h = (
		    'class' => $class,
		    'name' => $name,
		    'value' => $val,
		    'setpoint' => $set,
		    'ramprate' => $ramp,
		    'readonly' => $dev->readonly(),
		    );
		push @list,\%h;	    
	    }
	    elsif ($class eq 'MFC')
	    {
		my $val = CGI_client($rr,'get_data_cache',$class,$name,$cache_delay);
		unless (defined($val) && $val =~/\d/ && $val != -1)
		{
		    $val = $dev->read($data);
		    CGI_client($rr,'set_data_cache',$class,$name,$val);
		}
		my $set = $dev->setpoint();
		my %h = (
		    'class' => $class,
		    'name' => $name,
		    'value' => $val,
		    'setpoint' => $set,
		    'readonly' => $dev->readonly(),
		    'gas' => $dev->selected_gas($data),
		    );
		push @list,\%h;
	    }
	    elsif ($class eq 'gas')
	    {
		my $val = CGI_client($rr,'get_data_cache',$class,$name,$cache_delay);
		unless (defined($val) && $val =~/\d/ && $val != -1)
		{
		    $val = $dev->read($data);
		    CGI_client($rr,'set_data_cache',$class,$name,$val);
		}
		my $set = $dev->setpoint();
		my %h = (
		    'class' => $class,
		    'name' => $name,
		    'value' => $val,
		    'setpoint' => $set,
		    'readonly' => $dev->readonly(),
		    );
		push @list,\%h;
	    }
	    elsif ($class eq 'PSU')
	    {
		my $val = CGI_client($rr,'get_data_cache',$class,$name,$cache_delay);
		unless (defined($val) && $val =~/\d/ && $val != -1)
		{
		    $val = $dev->read($data);
		    CGI_client($rr,'set_data_cache',$class,$name,$val);
		}
		my %h = (
		    'class' => $class,
		    'name' => $name,
		    'value' => $val,
		    'setpoint' => $dev->get_I(),
		    'U' => $dev->measure_U(),
		    'setpoint_U' => $dev->get_U(),
		    'readonly' => $dev->readonly(),
		);
		push @list,\%h;
		
	    }
	    elsif ($class eq 'multiplex')
	    {
		if ($dev->type eq 'Selector')
		{
		    my $val = CGI_client($rr,'get_data_cache','selector',$dev->name,$cache_delay);
		    unless (defined($val) && $val =~/\d/ && $val != -1)
		    {
			$val = $dev->read();
			CGI_client($rr,'set_data_cache','selector',$dev->name,$val);
		    }
		    my @gasses = $dev->gasses();
 		    my %h2 = (
			'class' => $class,
			'name' => $dev->name,
			'value' => $val,
			'readonly' => $dev->readonly(),
			'gas' => $val,
			'gasses' =>  [@gasses],
			'selected_gas' => $val,
			'setpoint' => $val,
			);	
		    push @list,\%h2;	    
		}
		else
		{
		    my $val = CGI_client($rr,'get_data_cache',$class,$name,$cache_delay);
		    unless (defined($val) && $val =~/\d/ && $val != -1)
		    {
			$val = $dev->gas_name($data);
			CGI_client($rr,'set_data_cache',$class,$name,$val);
		    }
		    my $contr = $dev->controler;
		    my $flow = 0;
		    if ($contr)
		    {
			$flow = $contr->read();
			$contr = $contr->name();
		    }
		    my @gasses = $dev->gasses();
		    my %h = (
			'class' => $class,
			'name' => $name,
			'value' => $val,
			'mfc' => $contr,
			'flow' => $flow,
			'gasses' => [@gasses],
			);
		    push @list,\%h;
		}
	    }
	    elsif ($class eq 'Analog')
	    {
		my $val = CGI_client($rr,'get_data_cache',$class,$name,$cache_delay);
		unless (defined($val) && $val =~/\d/ && $val != -1)
		{
		    $val = $dev->read($data);
		    CGI_client($rr,'set_data_cache',$class,$name,$val);
		}
		my $set = $dev->setpoint();
		my $mode = $dev->mode();
		if ($mode =~ /V/i)
		{
		    my %h = (
			'class' => $class,
			'name' => $name,
			'U' => $val,
			'setpoint_U' => $set,
			'readonly' => $dev->readonly(),
			'mode' => $mode,
			);
		    push @list,\%h;	    
		}
		else
		{
		    my %h = (
			'class' => $class,
			'name' => $name,
			'value' => $val,
			'setpoint' => $set,
			'readonly' => $dev->readonly(),
			'mode' => $mode,
			);
		    push @list,\%h;
		}
	    }
	    else
	    {
		my $val = -32768;
		eval {
		    $val = CGI_client($rr,'get_data_cache',$class,$name,$cache_delay);
		    unless (defined($val) && $val =~/\d/ && $val != -1)
		    {
			$val = $dev->read($data);
			CGI_client($rr,'set_data_cache',$class,$name,$val);
		    }
		    $val = $dev->read_cache($maxdelay,$data);
		    if ($class eq 'relay' && $dev->type() eq 'Humidifier')
		    {
			$val = $dev->readstatus();
		    }
		};
		if ($@)
		{
#		    &errorlog($@);
		}
		my %h = (
		    'class' => $class,
		    'name' => $name,
		    'value' => $val,
		    'readonly' => $dev->readonly(),
		    );
		
		push @list,\%h;
	    } 
	};
	if ($@)
	{
#	    &errorlog($@);
	}
    } 
    print to_json(\@list);
}


