#! /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 ]
#
#

# usage: process firstrun lastrun

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{'ORACLE_HOME'} = $ENV{'CDFSOFT2_DIR'}.'/../../../products/oracle_client/v9_2_0_1a/Linux+2';
#$ENV{'TNS_ADMIN'} = '/home/cdfsoft/dist/oracle_tnsnames';
$ENV{'TNS_ADMIN'} = $ENV{'CDFSOFT2_DIR'}.'/../../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 = $ARGV[1];#222427;
my $lastrun  = $ARGV[2];#228597;

#my $lastrun = 218050;
#my $lastrun = 218625;
#my $lastrun = 222426;

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

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

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

my @runsv;

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

my %cfiles_all_proc_run = &getAllCalibValidFiles();

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

my $nrunsinrange= scalar @runs;
printf("Found $nrunsinrange between $runs[0] and $runs[$nrunsinrange-1]\n");

my $stage = "Calib";

my $run;

my $nruns;

my @cfiles_proc_arr;

my $proc;
foreach $proc (@processes)
{
    # clear between processes
    @cfiles_proc_arr = ();

# get list of pending runs
    my %pendingRunsProc; # = &getPendingRunsProc($stage,$proc);
    
# get list of rejected runs
    my %rejectedRunsProc; # = &getRejectedRunsProc($stage,$proc);

    my $calibavail = 1;
    my $missing ="";
    foreach $run (@runs)
    {
	my $rr = $rejectedRunsProc{$run};
	my $rp = $pendingRunsProc{$run};
	
	printf("Run $run need calibrating [ $proc pending = $rp ] [ $proc rejected = $rr ]\n");

	if (!$rr && !$rp)
	{
	    # look for calib files
	    my $tag = $proc.".".$run;
	    my $c_p_r = $cfiles_all_proc_run{$tag};
	    if ($c_p_r ne "")
	    {
		my @cfiles_run_proc = @$c_p_r; 
		printf(" Files available for $proc in run $run:".(scalar @cfiles_run_proc)."\n");
#		printf("Files for $tag are @cfiles_run_proc\n\n"); 
		@cfiles_proc_arr = (@cfiles_proc_arr,@cfiles_run_proc);
#		printf(" Files are : @cfiles_proc_arr\n");
	    }
	    else
	    {
#		$calibavail = 0;
		$missing = $missing." ".$run;
		printf("!!! Missing $proc files for runs $missing\n");
	    }
	    
	}
    }

    if ($calibavail)
    {
	doCalibs($proc,@runs);
	
    }
    else
    {
	printf("Missing $proc calibration files for runs $missing\n");
    }

}

exit(0);

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

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

    my $cdir = "${status_dir}/${stage}_Pending/${minrun}_${maxrun}";
    printf("Making $cdir\n");
    `mkdir $cdir`;
    {
	printf("Proces ${proc}:".@cfiles_proc_arr." files available\n");
	my $pdir = $cdir."/$proc";
        printf("Making pdir $pdir\n");
	`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}";
	printf("Running: $cmd\n");

    }
}

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


    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);

    {
        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 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;
}



sub get_calibrated_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 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;
}
