#!/usr/bin/perl -T
# $Id: ajax_multi.cgi,v 1.8 2021/02/05 06:49:31 sqko Exp $
use strict;
use warnings;
use CGI qw(:standard :netscape);
use RFC::Main;
use RFC::RFCCGI qw(:cgi :html);
use RFC::Header;
use File::stat;
use File::Copy;
use File::Touch;
use Cwd;
use SocketClient;
use SemaforeFile;
use Math::Complex qw(cplx Im Re);
use ElchemeaConfig;
use LWP::UserAgent;
use Sys::Hostname qw(hostname);
my $ssl = 0;
$ssl = 1 if (CGI::https());
my $pngdir = '/home/http/html/multiplot/';
unless (param('ajax') && param('action'))
{
    print header();
    print "Oops, no parameters!\n";
    exit;
}
my $ac = param('action');

my @lt = (1,3,4,7,8,2,5,10,12,13,16,17,11,14,19,21,22,25,26,20,23,28,29,30,31);
my @pt = (1,3,4,7,8,2,5,10,12,13,16,17,11,14,19,21,22,25,26,20,23,28,29,30,31);

if ($ac eq 'save')
{
    my $files = param('filenames');
    if ($files)
    {
        $files =~ /([\w\,\.\-\:\+\/\s]+)/;
        $files = $1;
    }
    my $sessionid = get_CGI_value_clean('session');
    my @list = split(/,/,$files);
    unless (@list)
    {
	print header();
	print start_html();
	print center(h1("No files selected!"));
	print end_html();
        exit;
    }
    my $fn = 'Multiplot_'.time.'.emp';
    my $semfile = SemaforeFile->new('/tmp/'.$fn);
    $semfile->writeline('');
    my $file = ElchemeaConfig->new($semfile);
    my $style = param('style');
    $style = 'lines' unless ($style);
    my $mode = param('mode');
    $mode = 'All' unless ($mode);
    my $xmin = get_CGI_value_clean('xmin');
    my $xmax = get_CGI_value_clean('xmax');
    my $ymin = get_CGI_value_clean('ymin');
    my $ymax = get_CGI_value_clean('ymax');
    my $y2min = get_CGI_value_clean('y2min');
    my $y2max = get_CGI_value_clean('y2max');
    my $color = lc(get_CGI_value_clean('color'));
    $color = 'color' unless $color;
    my $key = lc(get_CGI_value_clean('key'));
    my $title = lc(get_CGI_value_clean('title'));
    my $comm = param('comm');
    $file->change_config_value('plot','style',$style);
    $file->change_config_value('plot','mode',$mode);
    $file->change_config_value('plot','xmin',$xmin);
    $file->change_config_value('plot','xmax',$xmax);
    $file->change_config_value('plot','ymin',$ymin);
    $file->change_config_value('plot','ymax',$ymax);
    $file->change_config_value('plot','y2min',$y2min);
    $file->change_config_value('plot','y2max',$y2max);
    $file->change_config_value('plot','color',$color);
    $file->change_config_value('plot','key',$key);
    $file->change_config_value('plot','title',$title);
    my $x = 0;
    foreach my $line (split(/\n/,$comm))
    {
	$file->change_config_value('Comments',$x++,$line);
    }
    $file->change_config_value('Comments','lines',$x);
    my @filenames = ();
    my $filenr = 0;
    foreach my $item (@list)
    {
	$filenr++;
        my ($fl,$label) = split(/:/,$item);
	next unless $fl;
	my $f = SemaforeFile->new('/tmp/'.$fl);
	$fl =~ s/^$sessionid//;
	$fl =~ s/^_//;
	$fl =~ s/\.data$//;
	$label =~ s/^$sessionid//;
	$label =~ s/^_//;
	$label =~ s/\.data$//;
	my @lines = $f->readlines();
	$x = 0;
	foreach my $line (@lines)
	{
	    $file->change_config_value('File_'.$filenr,$x++,$line);
	}
	$file->change_config_value('File_'.$filenr,'lines',$x);
	$file->change_config_value('File_'.$filenr,'name',$fl);
	push @filenames,$fl;
    }
    $file->change_config_value('plot','files',$filenr);
    print "Content-type:application/x-download\n";
    print "Content-Disposition:attachment;filename=$fn\n\n";
    print join("\n",$file->readlines());
    unlink $semfile->filename if ($semfile->exist);
    exit;
}

print header();

if ($ac eq 'plot')
{
    my $n = param('name');
    my $p = param('pass');
    my $cred = '&name='.$n.'&pass='.$p;
    my $files = param('filenames');
    if ($files)
    {
	$files =~ /([\w\,\.\-\:\+\/\s\[\(\]\)\%]+)/;
	$files = $1;
    }
    my $sessionid = get_CGI_value_clean('session');
    my @list = split(/,/,$files);
    my $style = lc(param('style'));
    $style = 'lines' unless ($style);
    my $mode = param('mode');
    $mode = 'All' unless ($mode);
    my $xmin = get_CGI_value_clean('xmin');
    my $xmax = get_CGI_value_clean('xmax');
    my $ymin = get_CGI_value_clean('ymin');
    my $ymax = get_CGI_value_clean('ymax');
    my $y2min = get_CGI_value_clean('y2min');
    my $y2max = get_CGI_value_clean('y2max');
    my $title = get_CGI_value_clean('title');
    $title = '' unless defined($title);
    foreach ($xmin,$xmax,$ymin,$ymax,$y2min,$y2max)
    {
	$_ = '' unless defined($_);
    }
    unless (@list)
    {
	print "Warning: No files selected for plotting";
	exit;
    }
    my @fl = ();
    my $user = get_CGI_value_clean('user');
    my $ses = get_CGI_value_clean('usersession');
    if ($user && defined($ses) && $ses =~ /\d/)
    {
	foreach my $item (@list)
	{
	    my ($file,$label) = split(/:/,$item);
	    $file =~ /\d+\_(\d+)/;
	    my $fn = $user.$ses.$1.'.data';
	    my $o = SemaforeFile->new('/tmp/'.$fn);
	    if ($item =~ /^(\d+)test(\d+)\-(\d+)/)
	    {
		my $r = $1;
		my $t = $2;
		my $i = $3;
		my $s = hostname();
                my $ua = LWP::UserAgent->new();
                $ua->timeout(10);
                my $url = 'http://'.$s . '/cgi-bin/celltest/ajax_interface.cgi?action=iv_file&noajax=1&furnace='.$r.'&runnr='.$t .'&filenr='.$i.$cred;
                $url = 'https://'.$s . '/cgi-bin/celltest/ajax_interface.cgi?action=iv_file&noajax=1&furnace='.$r.'&runnr='.$t .'&filenr='.$i.$cred if ($ssl);
                my $request = new HTTP::Request('GET',$url);
                my $response = $ua->request($request);
		$o->writeline($response->content());
	    }
	    elsif ($item =~ /^\d+\_\d+\s/)
	    {
		$user =~ /(\d+)/;
		my $r = $1;;
		$ses =~ /(\d+)$/;
		my $t = $1;
		$item =~ /(\d+)\s/;
		my $i = $1;
		my $s = hostname();
                my $ua = LWP::UserAgent->new();
                $ua->timeout(10);
                my $url = 'http://'.$s . '/cgi-bin/celltest/ajax_interface.cgi?action=iv_file&noajax=1&furnace='.$r.'&runnr='.$t .'&filenr='.$i.$cred;
                $url = 'https://'.$s . '/cgi-bin/celltest/ajax_interface.cgi?action=iv_file&noajax=1&furnace='.$r.'&runnr='.$t .'&filenr='.$i.$cred if ($ssl);
                my $request = new HTTP::Request('GET',$url);
                my $response = $ua->request($request);
		$o->writeline($response->content());
	    }
	    else
	    {
		## Do nothing
	    }
	    push @fl,$o->filename();
	}
    }
    foreach my $item (@list)
    {
	my ($file,$label) = split(/:/,$item);
	$label =~ s/_/\\_/g;
	$item = substr($label,0,60);
    }
    my $pngfn = $pngdir.'multiplot_'.$$.'.png';
    my $psfn = $pngdir.'multiplot_'.$$.'.ps';
    my $gp = SemaforeFile->new('/tmp/multiplot_'.$$.'.gp');
    $gp->open_write;
    $gp->append('set zeroaxis lt -1');
    $gp->append("set out '$psfn'");
    my $color = lc(get_CGI_value_clean('color'));
    $color = 'color' unless $color;
    my $gsversion = `ghostscript -v`;
    if ($gsversion && $gsversion =~ /\s+([\d\.]+\s+)/)
    {
	$gsversion = $1;
    }
    else
    {
	$gsversion = 0;
    }
    if ($gsversion > 8.5)
    {
	$gp->append('set term postscript enhanced '.$color);
    }
    else
    {
	$gp->append('set term postscript enhanced portrait '.$color);
	$gp->append('set size 1,0.6');
    }
    my $key = lc(get_CGI_value_clean('key'));
    if ($key)
    {
	$key =~ s/^key\s//;
	$key .= ' reverse' if ($key =~ /left/);
	if ($key =~ /no key/i)
	{
	    $gp->append('set nokey');
	}
	else
	{
	    $gp->append('set key '.$key);
	}
    }
    my $x = 0;
    my $f = $fl[0];
    my $comm = param('comm');
    if ($comm && $comm =~ /([\w\s\n\r\t\.\[\]\-\+\,\"\'\.\:\(\)\^\=\/\*\{\}]+)/)
    {
	$comm = $1;
	$comm =~ s/[\r\n]+/\n/g;
    }
    else
    {
	$comm = '';
    }
    $gp->append("set title '$title'") if (length($title) > 0);
    $gp->append("set xlabel 'I (A/cm^2)'");
    $gp->append('f(x) = x');
    $gp->append("set xrange [$xmin:$xmax]");
    $gp->append("set yrange [$ymin:$ymax]");
    $gp->append("f(x) = x<0?1/0:x");
    my $lt = 0;
    my $pt = 0;
    my $str = undef;
    my $ylabel = '';
    if ($mode =~ /U vs I/)
    {
	$gp->append("set ylabel 'U (mV)'");
	$str = "plot '$f' u (\$2/\$1):3 lt ".$lt[$lt++].' pt '.$pt[$pt++]." w $style tit '$list[0]'";
	for ($x = 1; $x < @fl; $x++)
	{
	    $str .= ", '$fl[$x]' u (\$2/\$1):3 lt ".$lt[$lt++].' pt '.$pt[$pt++]." w $style tit '$list[$x]'";
	}
    }
    elsif ($mode =~ /P vs I/)
    {
	$gp->append("set ylabel 'P (W/cm^2)'");
	$str = "plot '$f' u (\$2/\$1):(f(\$7)) lt ".$lt[$lt++].' pt '.$pt[$pt++]." w $style tit '$list[0]'";
	for ($x = 1; $x < @fl; $x++)
	{
	    $str .= ", '$fl[$x]' u (\$2/\$1):(f(\$7)) lt ".$lt[$lt++].' pt '.$pt[$pt++]." w $style tit '$list[$x]'";
	}
    }
    elsif ($mode =~ /ASR vs I/)
    {
	$gp->append("set ylabel 'ASR ({/Symbol W} cm^2)'");
	$str = "plot '$f' u (\$2/\$1):(f(\$6)) lt ".$lt[$lt++].' pt '.$pt[$pt++]." w $style tit '$list[0]'";
	for ($x = 1; $x < @fl; $x++)
	{
	    $str .= ", '$fl[$x]' u (\$2/\$1):(f(\$6)) lt ".$lt[$lt++].' pt '.$pt[$pt++]." w $style tit '$list[$x]'";
	}
    }
    elsif ($mode =~ /Rsec vs I/)
    {
	$gp->append("set ylabel 'R_{sec} ({/Symbol W} cm^2)'");
	$str = "plot '$f' u (\$2/\$1):(f(\$5)) lt ".$lt[$lt++].' pt '.$pt[$pt++]." w $style tit '$list[0]'";
	for ($x = 1; $x < @fl; $x++)
	{
	    $str .= ", '$fl[$x]' u (\$2/\$1):(f(\$5)) lt ".$lt[$lt++].' pt '.$pt[$pt++]." w $style tit '$list[$x]'";
	}
    }
    else
    {
	$gp->append("set y2range [$y2min:$y2max]");
	$gp->append('set y2tics');
	$gp->append("set ylabel 'U (mV)'");
	$gp->append("set y2label 'R ({/Symbol W}cm^2), P (W/cm^2)'");
	$str = "plot '$f' u (\$2/\$1):3 lt ".$lt[$lt].' pt '.$pt[$pt]." w $style tit '$list[0]'";
	$str .= ",'' u (\$2/\$1):(f(\$5)) lt ".$lt[$lt].' pt '.$pt[$pt]." w $style axes x1y2 notitle";
	$str .= ",'' u (\$2/\$1):(f(\$6)) lt ".$lt[$lt].' pt '.$pt[$pt]." w $style axes x1y2 notitle";
	$str .= ",'' u (\$2/\$1):(f(\$6)) lt ".$lt[$lt].' pt '.$pt[$pt]." w $style axes x1y2 notitle";
	$str .= ",'' u (\$2/\$1):(f(\$7)) lt ".$lt[$lt].' pt '.$pt[$pt]." w $style axes x1y2 notitle";
	$pt++;
	$lt++;
	for ($x = 1; $x < @fl; $x++)
	{
	    $str .= ", '$fl[$x]' u (\$2/\$1):3 lt ".$lt[$lt].' pt '.$pt[$pt]." w $style tit '$list[$x]'";
	    $str .= ",'' u (\$2/\$1):(f(\$5)) lt ".$lt[$lt].' pt '.$pt[$pt]." w $style axes x1y2 notitle";
	    $str .= ",'' u (\$2/\$1):(f(\$6)) lt ".$lt[$lt].' pt '.$pt[$pt]." w $style axes x1y2 notitle";
	    $str .= ",'' u (\$2/\$1):(f(\$7)) lt ".$lt[$lt].' pt '.$pt[$pt]." w $style axes x1y2 notitle";
	    $pt++;
	    $lt++;
	}
    }
    my $ltype = get_CGI_value_clean('ltype');
    $ltype = lc($ltype) if ($ltype);
    $ltype = '' unless (defined($ltype));
    $gp->append("\n",$comm,"\n");
    $gp->append($str);	
    $gp->close;
    touch(@fl);
    eval {
	my $errfile = '/tmp/gp_error_'.$$;
        system('/usr/bin/gnuplot '.$gp->filename.' 2> '.$errfile);
	if (-e $errfile)
	{
	    open MYIN,'<',$errfile or die "Could not open file $errfile $!\n";
	    my @e = <MYIN>;
	    close MYIN;
	    unlink $errfile;
	    my $errstr = join("\n",@e);
	    die $errstr if ($errstr);
	}
	system('/usr/local/bin/celltest/ps2png '.$psfn.' '.$pngfn);
    };
    if ($@)
    {
        print "ERROR\n";
        print $@;
        unlink $gp->filename if ($gp->exist);
        exit;
    }
    print "OK\n";
    print 'multiplot_'.$$.'.png';
    unlink $gp->filename if ($gp->exist);
    ### Clean old files in pngdir ###
    opendir DIR,$pngdir or die "Could not open directory '$pngdir' $!\n";
    while (my $file = readdir(DIR))
    {
        next unless ($file =~ /\.png$|\.ps$/);
        my $fn = $pngdir.$file;
        my $sb = stat($fn);
        next unless ((time-300) > $sb->mtime);
        if ($fn =~ /([\w\.\/\-\,\:\(\)\[\]\s]+)/)
        {
            unlink $1 if -e ($1);
        }
    }
    ### Clean old data files in tmpdir (older than 1 hour) ###
    my $dir = '/tmp/';
    opendir DIR,$dir or die "Could not open directory '$dir' $!\n";
    while (my $file = readdir(DIR))
    {
        next unless ($file =~ /\.data$|\.gp$|\.emp$/);
        my $fn = $dir.$file;
        my $sb = stat($fn);
        next unless ((time-3600) > $sb->mtime);
        if ($fn =~ /([\w\.\/\-\,\:\(\)\[\]\s]+)/)
        {
            unlink $1 if -e ($1);
        }
    }
    exit;
}


if ($ac eq 'save_file')
{
    my $name = get_CGI_value_clean('filename');
    my $data = param('data');
    my $sessionid = get_CGI_value_clean('session');
    unless ($name && $data && $sessionid)
    {
	print "Error: mangled data detected, file not saved!";
	exit;
    }
    my $path = '/tmp/';
    my $f = SemaforeFile->new($path.$sessionid.'_'.$name.'.data');
    $data =~s/\,/\t/g;
    $f->writeline($data);
    my $fn = $f->filename();
    if ($fn =~ /\/([\w\.\-\+]+)$/)
    {
	print "OK\n";
	print "$1\n";
	print $name,"\n";
    }
    else
    {
	print "Oops: Filename not valid: $fn";
	unlink $fn if -e $fn;
    }
    exit;
}


sub get_mean(@)
{
    my $n = 0;
    my $sum = 0;
    while (@_)
    {
	my $val = shift;
	next unless (defined($val));
	$sum += $val;
	$n++;
    }
    return $sum/$n if ($n);
    return 0;
}
