#!/usr/bin/perl -w

# script to print out information about the current status of a burntool run.
use DBI;
use Getopt::Std;

getopts('AhfcPv:',\%opt);
if (exists($opt{h})) {
    print STDERR "Usage: examine_burntool_pcontrol.pl [-f] <pcontrol.pro>\n";
    print STDERR "         -f          Read all burntool entries, even those commented out.\n";
    print STDERR "         -c          Print out the needed mysql statement to do a convert. DOES NOT EXECUTE THIS!\n";
    print STDERR "         -v <val>    Use this value as the target burntool_state in convert statements.\n";
    print STDERR "         -P          Print out the ipp_apply_burntool.pl commands, even if fully updated.\n";
    print STDERR "         -A          Print out the ipp_apply_burntool.pl commands, for every exposure not fully updated.\n";
    print STDERR "\n";
    print STDERR "         Reads in the pcontrol.pro file you're using to run burntool, and uses the\n";
    print STDERR "         date ranges included there to query the database to tell you the current\n";
    print STDERR "         status of the processing.  On the OTA grid:\n";
    print STDERR "                  _             Blank chip\n";
    print STDERR "                  O             Null/zero value for burntool_state. No burntool attempted (yet).\n";
    print STDERR "                  P             -1 value for burntool_state. Burntool is running.\n";
    print STDERR "                  E             -2 value for burntool_state. Error! (modified raw pixels)\n";
    print STDERR "                  X             -3 value for burntool_state. Burntool segfaulted on this chip.\n";
    print STDERR "                  B             Current version value for burntool_state. Burntool succeeded.\n";
    print STDERR "                  b             Old version value for burntool_state. Burntool needs to be rerun.\n";
    print STDERR "                  ?             No matching rawImfile entry found in database.\n";
    exit(1);
}
$| = 1;
# Determine what the value of "BURNTOOL.STATE.GOOD" currently is:
$burntoolStateGood = 999;
open(LAZY,"ppConfigDump -camera GPC1 -dump-camera - |") || die "Can't run ppConfigDump\n";
while(<LAZY>) {
    chomp;
    if ($_ =~ /BURNTOOL.STATE.GOOD/) {
	@line = split /\s+/;
	$burntoolStateGood = $line[2];
    }
}
close(LAZY);
unless( $burntoolStateGood == 999) {
    print STDERR "GOOD == $burntoolStateGood\n";
}
$convert_bt_state = -1.0 * $burntoolStateGood;

# Read a class_id and burntool_state pair, and set the correct cell of the (sorry, global) character array vector
sub class_to_vector {
    my $class = shift;
    my $burntool_state = shift;
    my $char = '_';
    if (abs($burntool_state) == $burntoolStateGood) {
	$char = '[32;01mB[m';
	$burncount++;
    }
    elsif ($burntool_state == -1) {   # processing
	$char = '[01;33mP[m';
    }
    elsif ($burntool_state == 0) {    # has not been processed yet
	$char = '[31mO[m';
    }
    elsif ($burntool_state == -2) {   # modified pixel data
	$char = '[35;01;44;05mE[m';
    }
    elsif ($burntool_state == -3) {   # previous burntool segfaulted.
	$char = '[34mX[m';
    }
    else {                            # old version
	$char = '[32mb[m';
    }
    
    my @cv = split //, $class;

    my $id = $cv[2] * 8 + $cv[3];
    if (($id == 0)||($id == 7)||($id == 63)||($id == 56)) {
	die "impossible chip";
    }
    $vector[$id] = $char;
}
# Engauge autoflush, in case the database server is acting up.
$| = 1;

# Set up the class->host hash
%host  = ('XY01' => 'ipp014', 'XY02' => 'ipp014', 'XY03' => 'ipp038', 'XY04' => 'ipp038', 
	  'XY05' => 'ipp023', 'XY06' => 'ipp023', 
	  'XY10' => 'ipp039', 'XY11' => 'ipp039', 'XY12' => 'ipp024', 'XY13' => 'ipp024', 
	  'XY14' => 'ipp040', 'XY15' => 'ipp040', 'XY16' => 'ipp026', 'XY17' => 'ipp026', 
	  'XY20' => 'ipp041', 'XY21' => 'ipp041', 'XY22' => 'ipp042', 'XY23' => 'ipp042', 
	  'XY24' => 'ipp043', 'XY25' => 'ipp043', 'XY26' => 'ipp028', 'XY27' => 'ipp028', 
	  'XY30' => 'ipp044', 'XY31' => 'ipp044', 'XY32' => 'ipp029', 'XY33' => 'ipp029', 
	  'XY34' => 'ipp045', 'XY35' => 'ipp045', 'XY36' => 'ipp030', 'XY37' => 'ipp030', 
	  'XY40' => 'ipp046', 'XY41' => 'ipp046', 'XY42' => 'ipp031', 'XY43' => 'ipp031', 
	  'XY44' => 'ipp047', 'XY45' => 'ipp047', 'XY46' => 'ipp032', 'XY47' => 'ipp032', 
	  'XY50' => 'ipp048', 'XY51' => 'ipp048', 'XY52' => 'ipp033', 'XY53' => 'ipp033', 
	  'XY54' => 'ipp049', 'XY55' => 'ipp049', 'XY56' => 'ipp034', 'XY57' => 'ipp034', 
	  'XY60' => 'ipp050', 'XY61' => 'ipp050', 'XY62' => 'ipp035', 'XY63' => 'ipp035', 
	  'XY64' => 'ipp051', 'XY65' => 'ipp051', 'XY66' => 'ipp036', 'XY67' => 'ipp036', 
	  'XY71' => 'ipp052', 'XY72' => 'ipp052', 'XY73' => 'ipp015', 'XY74' => 'ipp015', 
	  'XY75' => 'ipp053', 'XY76' => 'ipp053');

# Load the pcontrol.pro file, and create arrays of the dates included
$file = shift(@ARGV);
if (!defined($file)) {
    system("$0 -h");
    exit(1);
}
else {
    @date_min = ();
    @date_max = ();
    open(F,$file);
    while(<F>) {
       chomp;
       if (exists($opt{f})) {
	   $_ =~ s/^\s*?#//;
       }
       $_ =~ s/^\s+//;

       if ($_ =~ /^burntool /) {
	   ($burncount,$start,$end) = split /\s+/; #lazy variable reuse
           push @date_min, $start;
           push @date_max, $end;

       }
    }
    close(F);
}

# Set up the database
use constant DB_SOCKET => '/var/run/mysqld/mysqld.sock';
$dbname = 'gpc1';
$dbserver = 'ippdb01';
$dbuser = 'ipp';
$dbpass = 'ipp';
$db = DBI->connect("DBI:mysql:database=${dbname};host=${dbserver};" .
                   "mysql_socket=" . DB_SOCKET(),
                   ${dbuser},${dbpass}, 
		   { RaiseError => 1, AutoCommit => 1}
		   ) or die "Unable to connect to database $DBI::errstr\n";



# Get the data for each date range we're running burntool over
for ($i = 0; $i <= $#date_min; $i++) {
    $dmin = $date_min[$i];
    $dmax = $date_max[$i];
    # Get the data.  The limit is there to keep the database happy.  I don't think you can observe that many
    # images on a single night.
    $sth = "SELECT exp_id,exp_name,obs_mode,dateobs,class_id,burntool_state,comment FROM rawImfile WHERE dateobs >= '${dmin}' AND dateobs <= '${dmax}' order by dateobs limit 600000";

    $data_ref = $db->selectall_arrayref( $sth );

    # Reset
    $cur_exp_id = -99;
    $burncount = 0;
    for ($j = 0; $j < 64; $j++) {
	$vector[$j] = '_';
    }

    # Print out query for clarity, and the header:
    print "#### $sth\n";
    if (exists($opt{c})) {
	if (exists($opt{v})) {
	    $no_sth = "UPDATE rawImfile SET burntool_state = $opt{v} WHERE dateobs >= '${dmin}' AND dateobs <= '${dmax}';";
	}
	else {
	    $no_sth = "UPDATE rawImfile SET burntool_state = $convert_bt_state WHERE dateobs >= '${dmin}' AND dateobs <= '${dmax}';";
	}
	print "#### $no_sth\n";
    }
    print "#                                                     0       1       2       3       4       5       6       7       \n";
    print "#exp_i exp_name       obs_mode dateobs             nB 0123456701234567012345670123456701234567012345670123456701234567 comment\n";
    
    # If the database returns no entries (because we have a mistake in pcontrol.pro perhaps), return a null entry.
    if ($#{ $data_ref } == -1) {
	$cur_exp_id = -99;
	$burncount = 0;
	for ($j = 0; $j < 64; $j++) {
	    $vector[$j] = '_';
	}
    }
    
    foreach $row_ref (@{ $data_ref }) {
	($exp_id,$exp_name, $obs_mode,$dateobs,$class_id,$burntool_state,$comment) = @{ $row_ref };

	# Correct for nulls in the database.
	if (!defined($obs_mode)) {
	    $obs_mode = 'NULL';
	}
	if (!defined($burntool_state)) {
	    $burntool_state = 0;
	}
	if (!defined($comment)) {
	    $comment = ' ';
	}
#	print "$exp_id $class_id $burntool_state\n";
	# If we're still working on the same exp_id, update the chip we got
	if ($exp_id == $cur_exp_id) {
	    class_to_vector($class_id,$burntool_state);
	}
	else {
	    # otherwise, print, reset, and update
	    $V = join '', @vector;
	    
	    if ($cur_exp_id != -99) {
		printf("%6d %11s %11s %19s %2d %64s %s\n",
		       $cur_exp_id,$cur_exp_name,$cur_obs_mode,$cur_dateobs,$burncount, $V,$cur_comment);

		if (($burncount != 60)&&(exists($opt{A}))) {
		    for ($j = 0; $j < 64; $j++) {
#	    printf("%d %s %d\n",$j, $vector[$j], ($vector[$j] !~ /B/));
			if (($vector[$j] !~ /B/)&&(exists($opt{A}))) {
			    if ($vector[$j] ne '_') {
				$id = sprintf("XY%d%d",int($j / 8),$j % 8);
				print "#### ssh ipp\@$host{$id} && ipp_apply_burntool.pl --class_id $id  --dateobs_begin $dmin --dateobs_end $dmax --dbname gpc1 --logfile burntool_logs/${id}.${dmin}.log\n";
			    }
			}
		    }
		}

		$burncount = 0;
		for ($j = 0; $j < 64; $j++) {
		    if (($j == 0)||($j == 7)||($j == 63)||($j == 56)) {
			$vector[$j] = '_';
		    }
		    else {
			$vector[$j] = '[36;40;01m?[m';
		    }
		}
	    }
	    ($cur_exp_id,$cur_exp_name,$cur_obs_mode,$cur_dateobs,$cur_comment) = ($exp_id,$exp_name,$obs_mode,$dateobs,$comment);
	    class_to_vector($class_id,$burntool_state);
	}
    }
    # Final entry needs a manual print to clear it out. Let's tack on a footer as well.
    printf("%6d %11s %11s %19s %2d %64s %s\n",
	   $cur_exp_id,$cur_exp_name,$cur_obs_mode,$cur_dateobs,$burncount, $V,$cur_comment);
    print "#                                                     0       1       2       3       4       5       6       7       \n";
    print "#exp_i exp_name       obs_mode dateobs             nB 0123456701234567012345670123456701234567012345670123456701234567 comment\n";
    print"\n";

    # If we didn't find that all 60 chips had succesful burntools run, print out the ipp_apply_burntool.pl command we would need to fix this:
    if (($burncount != 60)||(exists($opt{P}))) {
	for ($j = 0; $j < 64; $j++) {
#	    printf("%d %s %d\n",$j, $vector[$j], ($vector[$j] !~ /B/));
	    if (($vector[$j] !~ /B/)||(exists($opt{P}))) {
		if ($vector[$j] ne '_') {
		    $id = sprintf("XY%d%d",int($j / 8),$j % 8);
		    print "#### ssh ipp\@$host{$id} && ipp_apply_burntool.pl --class_id $id  --dateobs_begin $dmin --dateobs_end $dmax --dbname gpc1 --logfile burntool_logs/${id}.${dmin}.log\n";
		}
	    }
	}
    }
    print "\n\n";	
}
