#! /cdf/scratch/cdfopr/cdfcalib/products/bin/perl

#############
#
#  CalibRequester.pl
#
#    Does calibration for runs which
#      - have pass 10A defined
#      - have calibration files available [ see "CalibValidFiles.pl" ]
#      - have not had calibrations done already [ pending approval or already rejected ]
#
#


use strict;
use lib '/cdf/scratch/cdfopr/danielw/CommonLibs/';
require "db_queries.pl";
require "CalibValidFiles.pl";
require "CalibStatus.pl";

$ENV{'ORACLE_HOME'} = '/home/cdfsoft/products/oracle_client/v9_2_0_1a/Linux+2';
$ENV{'TNS_ADMIN'} = '/home/cdfsoft/dist/oracle_tnsnames';

use DBI;

# comment to DB
my $dbh = DBI->connect('dbi:Oracle:cdfonprd','cdf_reader','reader') 
    or die "Error connecting $DBI::errstr\n";

# arbitrary
my $firstrun = 217993;
#my $lastrun = 218050;
my $lastrun = 218625;

# some definitions -> put these in a common header later
my $status_dir = "/cdf/home/danielw/public_html/Calibrations/Status";
my $status_html = "http://www-cdf.fnal.gov/~danielw/Calibrations/Status";

my $process_dir = "/cdf/scratch/cdfopr/danielw/Calibration/Processes/";
my @processes = ("tof","miniplug","pes-align","cal-em","hadtiming","emtiming");

# associate process with user
my %emails;
$emails{"pes-align"} = "danielw\@FNAL.GOV";
$emails{"cal-em"}    = "danielw\@FNAL.GOV";
$emails{"miniplug"} = "danielw\@FNAL.GOV";
$emails{"tof"} = "danielw\@FNAL.GOV";
$emails{"emtiming"} = "danielw\@FNAL.GOV";
$emails{"hadtiming"} = "danielw\@FNAL.GOV";

my @runsv;

&get_uncalibrated_runs($dbh,$firstrun,$lastrun,\@runsv);

sort @runsv;
my @runs = reverse @runsv;

my $stage = "Calib";

# get list of pending runs
my %pendingRuns = &getPendingRuns($stage);

# get list of rejected runs
my %rejectedRuns = &getRejectedRuns($stage);

my $run;

my @runchunk;
my $nruns;

my %cfiles;

foreach $run (@runs)
{
    my $rr = $rejectedRuns{$run};
    my $rp = $pendingRuns{$run};

    printf("Run $run need calibrating [ pending = $rp ] [ rejected = $rr ]\n");

    if (!$rr && !$rp)
    {
	my $proc;
	my %cfiles_run;
	my $calibavail = 1;
	my $missing ="";

	foreach $proc (@processes)
	{

	    # look for calib files
	    my @cfiles_run_proc = &getCalibFiles($proc,$run);

	    printf(" Files available for $proc in run $run:".(scalar @cfiles_run_proc)."\n");
	    if ((scalar @cfiles_run_proc) > 0)
	    {
		$cfiles_run{$proc} = [ @cfiles_run_proc ];
	    }
	    else
	    {
		$calibavail = 0;
		$missing = $missing." ".$proc;
	    }
	}
	
	if ($calibavail)
	{
	    $runchunk[$nruns++] = $run;
	    foreach $proc (@processes)
	    {
		my $cnew = $cfiles_run{$proc};
		my @cnewa = @$cnew;
		my $cold = $cfiles{$proc};
		if ($cold eq "")
		{
		    $cfiles{$proc} = [ @cnewa ];
		}
		else
		{
		    my @colda = @$cold;
		    $cfiles{$proc} = [ (@colda,@cnewa) ];
#		    printf(" New files are : @cnewa\nOld files are: @colda\n\n");

		}
	    }
	    printf(" All files available for calibration!\n");
	}
	else
	{
	    printf("Missing files for $missing\n");
	}
	    
	
    }
}

if ((scalar @runchunk) > 0)
{
    doCalibs(@runchunk);
    
    requestApproval(@runchunk);
}
else
{
    printf("No runs are ready to calibrate\n");
}

exit(0);

sub doCalibs()
{
    my @rlist = @_;
    printf("performing calibs for [ @rlist ]\n");
    my $proc;

    my $maxrun=$rlist[0];
    my $minrun=$rlist[ (scalar @rlist)-1 ];

    my $cdir = "${status_dir}/${stage}_Pending/${minrun}_${maxrun}";
    printf("Making $cdir\n");
    `mkdir $cdir`;
    foreach $proc (@processes)
    {
	my $cfiles_proc = $cfiles{$proc};
	my @cfiles_proc_arr = @$cfiles_proc;
	printf("Proces ${proc}:".@cfiles_proc_arr." files available\n");
	my $pdir = $cdir."/$proc";
	`mkdir $pdir`;

	printf("Writing to $pdir/runs.list\n");
	open(ROUT,">$pdir/runs.list");
	my $run;
	foreach $run (@rlist)
	{
	    print ROUT "$run\n";
	}
	close(ROUT);

	printf("Writing file list to ${pdir}/files.list\n");

	open(FLOUT,">${pdir}/files.list");
	my $cf;
	foreach $cf ( @cfiles_proc_arr)
	{
	    print FLOUT "$cf\n";
	}
	close(FLOUT);

	my $cmd = "cp ${pdir}/{runs,files}.list ${process_dir}/${proc}; cd ${process_dir}/${proc}; ./run.sh ./files.list";
	printf("Running: $cmd\n");
	my @cmdres = `$cmd | grep "ResultsFile" | awk '{print \$2}'`;
	printf("Result: @cmdres\n");
	my $rf;
	foreach $rf (@cmdres)
	{
	    chop($rf);
	    my $cmd2 = "mv ${process_dir}/${proc}/$rf ${pdir}";
	    printf("Moving result file $cmd2\n");
	    `$cmd2`;
	}

	# indicate the status
	open(SOUT,">${pdir}/status.txt");
	print SOUT "Ready";
	close (SOUT);

    }
}

sub requestApproval()
{
    my @rlist = @_;
    printf("requesting approval  for for [ @rlist ]\n");
    my $proc;

    my $maxrun=$rlist[0];
    my $minrun=$rlist[ (scalar @rlist)-1 ];

    my $cdir = "${status_html}/${stage}_Pending/${minrun}_${maxrun}";
    my $cdirl = "${status_dir}/${stage}_Pending/${minrun}_${maxrun}";
    
    printf("Writing to $cdirl/runs.list\n");
    open(ROUT,">$cdirl/runs.list");
    my $run;
    foreach $run (@rlist)
    {
	print ROUT "$run\n";
    }
    close(ROUT);

    foreach $proc (@processes)
    {
        my $pdir = $cdir."/$proc";
	my $message = "Please review the new calibrations for $proc covering runs ($minrun-$maxrun):\n$pdir\n";
	my $recip = $emails{$proc};
	open(MOUT,">.mail.${proc}.$$");
	print MOUT $message;
	close(MOUT);
	my $res = `mail -s \"Please review $proc calibrations ($minrun-$maxrun)" $recip < .mail.${proc}.$$`;
	`rm .mail.${proc}.$$`;
	printf("Sent \"$message\" to $recip with result $res\n");
	
    }
}


sub get_uncalibrated_runs
{
# Arguments: 1) database handle 2) start run 3 array to return runs
# fills hash with key = run and value = run terminate time

    my ( $dbh, $start_run, $end_run,$run) = @_;

  my $sql =
  "select rc.runnumber
  from runconfigurations rc, run_status rs, physicstables pt
  where rs.runcontrol_status != 0
    and rs.shiftcrew_status != 0
    and rc.b0integratedlivelumi > 10.0
    and rc.csl_neventsoutput > 1000
    and not pt.physicstablename like '%TEST%'
    and (pt.physicstablename like '%Phyiscs' or pt.physicstablename like '%PHYSICS%')
    and rc.runnumber in (select lorun from passcalibs where pass_index =
  ( select pass_index from passes where passname like '10A' and retired is null) )
    and rc.runnumber not in (select lorun from passcalibs where pass_index =
  ( select pass_index from passes where passname like '17' and retired is null) )
    and pt.runnumber = rc.runnumber
    and rs.runnumber = rc.runnumber
    and rc.runnumber > ?
    and rc.runnumber < ?
  order by rc.runnumber";

    my $sth = $dbh->prepare($sql);
    $sth->execute($start_run,$end_run);

    while (my $row = $sth->fetchrow) { push @$run, $row }

    return 1;
}
