#!/usr/bin/perl

$version = 'makeluciflat.ver020.pl';

if ($#ARGV < 0) { 
  printf "USAGE:  makeflat.pl script \n";
  exit(-1);
  }

# This is a script which will parse an imaging or spectroscopic script
# to produce a script for making a corresponding flat in the same mode
# Based on count rates in the Lucifer manual it attempts to automatically
# assign lamps and integration times.  The usage is simply
#          makeluciflat.pl script.type
# it will output a script called script.flat.cal, if it cannot estimate
# the appropriate DIT and LAMPs it fills in the values with UNKNOWN and
# warns the user -- in this case the outfile is script.flat.cal.needsfixes 
# 
# initial version written by CS Kochanek at OSU
# ver010 -- December 9, 2012
# ver020 -- January  2, 2013 -- modified to have 200 grating in zJ/HK modes
#
# Questions/Anomolies
#    * lucichk.pl -- rejects imaging flats (mirror in) - in practice no one seems to do them, which is not surprising
#    * there is in entry in the imaging flat for Archive/2012/Nov/LBTB_j2240luci for DIT that says "luci will calculate"

$countwant = 10000; # this is the recommended flat count level in the Luci manual
$countmax  = 20000; # this is the maximum count level allowed before filling in DIT/LAMPs with UNKNOWN
$nflatdo   =     5; # default number of flat exposures to make

$script0 = $ARGV[0];
chomp($script0);

if (  ($script0 =~ /acq/) || ($script0 =~ /flat/) || ($script0 =~ /cal/) || ($script0 =~ /dark/) ) {
  printf "$script0 seems to be an acquisition, flat or other calibration script\n";
  printf "because is contains acq, flat or cal -- if this is not true, please use \n";
  printf "standard naming conventions that allow easy recognition of script types\n";
  exit(-1);
  }

# strip off any trailing .spec etc, add .flat.cal
$script =  $script0;
$script =~ s/\.[a-zA-Z0-9]*$/\.flat\.cal/;

printf "\nProducing a flat for script $script0 - output will be $script \n\n";
printf "INFORMATION: defaults to O2DCR read mode and NORMAL save mode\n";
printf "             with $nflatdo exposures designed to yield $countwant counts each \n";
printf "             based on count rates reported in the Lucifer manual\n\n";

# yes, perl can do this, but date provides a nice format with no further work
open(GETTIME,"date |");
$date = <GETTIME>;
chomp($date);
close(GETTIME);

$PI       = 'UNKNOWN';
$propid   = 'UNKNOWN';
$camera   = 'UNKNOWN';
$specfilt = 'UNKNOWN';
$specgrat = 'UNKNOWN';
$speclcen = 'UNKNOWN';
$specmask = 'UNKNOWN';
$maskpos  = 'UNKNOWN';
$roemode  = 'UNKNOWN';

# clear the data base of count rates
@halo1 = (); @halo2 = (); @halo3 = (); @halo12 = (); 
#table of imaging flat count rates (ADU/s) for N3.75 camera
                          $halo3{'z'}       = 1450;
                          $halo3{'j'}       = 5500;
                          $halo3{'h'}       = 7100;
                          $halo3{'ks'}      = 3500;
                          $halo3{'k'}       = 4550;
                          $halo3{'j_low'}   = 2150;
                          $halo3{'j_hig'}   = 2150;
                          $halo3{'y1'}      =  620;
                          $halo3{'y2'}      =  750;
$halo2{'oh_1060'} = 2700; $halo3{'oh_1060'} =  110;
$halo2{'oh 1190'} = 4450; $halo3{'oh 1190'} =  190;
$halo2{'hei'}     = 2150; $halo3{'hei'}     =  180;
$halo2{'p_gam'}   = 3600; $halo3{'p_gam'}   =  150;
$halo2{'p_beta'}  = 6200;
$halo2{'feii'}    =11000; $halo3{'feii'}    =  480;
$halo2{'h2'}      = 8800; $halo3{'h2'}      =  350;
$halo2{'br_gam'}  = 8300; $halo3{'br_gam'}  = 3200;
#table of spectroscopic flat count rates for N3.75 camera and the 1 arcsec slit
#  for N1.8 the counts are (basically) 4 times higher
#  drops roughly as slit width
$halo12{'grating210z'}     =  180;   
$halo12{'grating210j'}     =  450;
$halo1{'grating210h'}      =  650;
$halo12{'grating210k'}     =  550;
$halo2{'grating200h'}      =  700;
$halo2{'grating200k'}      =  700;
$halo2{'grating200hkspec'} =  700;
$halo2{'grating200z'}      =  350;
$halo2{'grating200j'}      =  350;
$halo2{'grating200zjspec'} =  350;
$halo2{'grating150'}       =  280;
# these are the values listed for the spectrophotometric slit divided by the slit width of 10 arcsec
# but it is not clear how they apply for the other gratings - just going to turn off for now
#$halo2{'grating210z'}  =  180/10.0;   
#$halo2{'grating210j'}  =  450/10.0;
#$halo2{'grating210h'}   = 800/10.0;
#$halo2{'grating210k'}  =  550/10.0;




#extract the partner information
printf "\n";
printf "EXTRACTING INFORMATION FROM TARGET SCRIPT $script0\n";
open(INFILE,"<$script0");
while(<INFILE>) {
  $line = $_;
  # delete any comments
  $line =~ s/\#.*//;
  $line =~ s/\r//g; # Clean Ctrl-Ms if present (sigh)
  $line =~ s/\s*$//g;  # delete all trailing spaces to a parameters
  $line =~ s/=\s*/=/g; # delete all leading spaces to a parameters
  # extract key words
  if ($line =~ /^\s*PI_NAME\s*=/i)            { $line =~ /^\s*PI_NAME\s*=\s*(.*)/;           $PI      = $1; chomp($PI);       printf "found PI_NAME $PI\n";}
  if ($line =~ /^\s*PROP_ID\s*=/i)            { $line =~ /^\s*PROP_ID\s*=\s*(.*)/;           $propid  = $1; chomp($propid);   printf "found PROP_ID $propid\n";}
  if ($line =~ /^\s*CAMERA\s*=/i)             { $line =~ /^\s*CAMERA\s*=\s*(N\d\.\d*)/;      $camera  = $1; chomp($camera);   printf "found CAMERA $camera\n";}
  if ($line =~ /^\s*FILTER\s*=/i)             { $line =~ /^\s*FILTER\s*=\s*([a-zA-Z0-9_]*)/; $specfilt= $1; chomp($specfilt); printf "found FILTER $specfilt\n";}
  if ($line =~ /^\s*GRATING_UNIT\s*=/i)       { $line =~ /^\s*GRATING_UNIT\s*=\s*(.*)/;      $specgrat= $1; chomp($specgrat); printf "found GRATING $specgrat\n";}
  if ($line =~ /^\s*CENTRAL_WAVELENGTH\s*=/i) { $line =~ /^\s*CENTRAL_WAVELENGTH\s*=\s*(.*)/;$speclcen= $1; chomp($speclcen); printf "found CENTRAL WAVE $speclcen\n";}
  if ($line =~ /^\s*MASK\s*=/i)               { $line =~ /^\s*MASK\s*=\s*(.*)/;              $specmask= $1; chomp($specmask); printf "found MASK $specmask\n";}
  if ($line =~ /^\s*MASK_POSITION\s*=/i)      { $line =~ /^\s*MASK_POSITION\s*=\s*(.*)/;     $maskpos = $1; chomp($maskpos);  printf "found MASK_POSITION $maskpos\n";}
  if ($line =~ /^\s*ROE_MODE\s*=/i)           { $line =~ /^\s*ROE_MODE\s*=\s*(.*)/;          $roemode = $1; chomp($roemode);  printf "found ROE_MODE $roemode\n";}
  }
close(INFILE);

if ($PI       =~ /UNKNOWN/) { printf "failed to find PI_NAME\n"; exit(-1); }
if ($camera   =~ /UNKNOWN/) { printf "failed to find CAMERA \n"; exit(-1); }
if ($specfilt =~ /UNKNOWN/) { printf "failed to find FILTER \n"; exit(-1); }
if ($specgrat =~ /UNKNOWN/) { printf "failed to find GRATING_UNIT \n"; exit(-1); }
if ($maskpos  =~ /UNKNOWN/) { printf "failed to find MASK_POSITION \n"; exit(-1); }
if ($roemode  =~ /UNKNOWN/) { printf "failed to find ROE_MODE \n"; exit(-1); }
if ( !($specgrat =~ /mirror/i) ) { 
  if ($speclcen =~ /UNKNOWN/) { printf "failed to find CENTRAL_WAVE \n"; exit(-1); }
  if ($specmask =~ /UNKNOWN/) { printf "failed to find MASK \n"; exit(-1); }
  }

printf "Appear to have found all the needed parameters, estimating count rate \n";

# for an imaging flat try only halo2/halo3 since no halo1 entries
if ($specgrat =~ /mirror/i) { 
  $count2 = -1;
  $count3 = -1;
  $key  = $specfilt; $key =~ tr/A-Z/a-z/;
  if (exists($halo2{$key})) { $count2 = $halo2{$key}; if ($camera =~ /1\.8/) { $count2 /= 4;} $dit2 = $countwant/$count2; $dit2 = 1 + int($dit2);}
  if (exists($halo3{$key})) { $count3 = $halo3{$key}; if ($camera =~ /1\.8/) { $count3 /= 4;} $dit3 = $countwant/$count3; $dit3 = 1 + int($dit3);}
  TIMELOGIC1: {
    # no lamp/filter combination found
    if ( ($count2 < 0) && ($count3 < 0) ) { 
      printf "found no count rate estimate for an imaging flat using filter $specfilt\n";  
      printf "generating flat script but user will have to fill in DIT and LAMP \n";
      $dit  = 'UNKNOWN';
      $lamp = 'UNKNOWN';
      $cest = 'UNKNOWN';
      $count= 'UNKNOWN';
      last TIMELOGIC1;
      }
    # only halo2
    if ( ($count2 > 0) && ($count3 < 0) ) {
      $dit  = $dit2;  $dit  = ($dit < 4) ? 4 : $dit;
      $lamp = 'halo2';
      $count= $count2;
      $cest = $dit*$count2;
      last TIMELOGIC1;
      }
    # only halo3
    if ( ($count2 < 0) && ($count3 > 0) ) {
      $dit  = $dit3; $dit  = ($dit < 4) ? 4 : $dit;
      $lamp = 'halo3';
      $count= $count3;
      $cest = $dit*$count3;
      last TIMELOGIC1;
      }
     # both with halo2 being faster than halo3 but not less than dit=4, or halo3 is faster but has dit<4 
    if ( (($dit2 < $dit3) && ($dit2 >= 4)) || ($dit3 < 4) ) { 
      $dit  = $dit2;
      $lamp = 'halo2';
      $count= $count2;
      $cest = $dit*$count2;
      last TIMELOGIC1;
      }
     # both with halo3 being faster than halo2 but not less than dit=4, or halo2 is faster but has dit<4 
    if ( (($dit3 < $dit2) && ($dit3 >= 4)) || ($dit2 < 4) ) { 
      $dit  = $dit3;
      $lamp = 'halo3';
      $count= $count3;
      $cest = $dit*$count3;
      last TIMELOGIC1;
      }
    # missing case -- what to do if both give more than $countwant counts with dit<4 - should not happen
    printf "case with count2 = $count2 count3 = $count3 / dit2 = $dit2 dit3 = $dit3 is not considered quitting\n";
    exit(-1);
    }
# for a spectroscopic flat only halo1, halo2 and halo1+halo2, except for 3-slit
} else {
  $key  = 'UNKNOWN';
  $dit  = 'UNKNOWN';
  $lamp = 'UNKNOWN';
  $count= -1;
  if ($specgrat =~ /210/) { $key = 'grating210' . $specfilt; }
  if ($specgrat =~ /200/) { $key = 'grating200' . $specfilt; printf "SET KEY $key\n";}
  if ($specgrat =~ /150/) { $key = 'grating150'; }
  $key =~ tr/A-Z/a-z/;
  if (exists($halo1{$key})) {
    $lamp = 'halo1';
    $count= $halo1{$key}
    }
  if (exists($halo2{$key})) {
    $lamp = 'halo2';
    $count= $halo2{$key}
    }
  if (exists($halo12{$key})) {
    #Olga claims that there is no halo1+halo2 -- only one lamp on at a time
    #and that since halo1 is brighter this should really just be halo1
    #$lamp = 'halo12';
    $lamp = 'halo1';
    $count= $halo12{$key};
    }
  if ($lamp =~ /UNKNOWN/) {
    printf "\nWARNING: found no count rate estimate for an spectrosopic flat using grating $specgrat and filter $specfilt\n";  
    printf "         generating flat script with DIT=UNKNOWN and LAMP=UNKNOWN\n\n";
  } else {
    if ($camera =~ /1\.8/) { $count *= 4;}  
    $slitwidth = 'UNKNOWN';
    if ( $specmask =~ /995623/i) { $slitwidth =10.00; $count *= $slitwidth; }  # spectrophotometric slit
    if ( $specmask =~ /990018/i) { $slitwidth = 2.00; $count *= $slitwidth; }  
    if ( $specmask =~ /990021/i) { $slitwidth = 1.50; $count *= $slitwidth; } 
    if ( $specmask =~ /990034/i) { $slitwidth = 1.00; $count *= $slitwidth; }
    if ( $specmask =~ /990029/i) { $slitwidth = 0.75; $count *= $slitwidth; }
    if ( $specmask =~ /990032/i) { $slitwidth = 0.50; $count *= $slitwidth; }
    if ( $specmask =~ /990065/i) { $slitwidth = 0.25; $count *= $slitwidth; }
    if ($slitwidth =~ /UNKNOWN/) {
      printf "\nSlitwidth for mask $specmask is unknown -- please enter the slit width -- format like 1.0\n ";
      while ($slitwidth =~ /UNKNOWN/) {
        printf "Slitwidth?\n";
        $line = <STDIN>;
        chomp($line);
        if ( ($line =~ /\d+\.*\d*/) || ($line =~ /\d*\.\d+/)  ) {
          $slitwidth = $line;
          $count    *= $slitwidth;
          }
        }
      }
    printf "\nUsing slitwidth $slitwidth arcsec for slit $specmask\n\n";
    $dit = $countwant/$count; $dit = 1 + int($dit); $dit = ($dit > 4) ? $dit  : 4;
    $cest= $count*$dit;
    if ($cest > $countmax) {
      $dit  = 'UNKNOWN';
      $lamp = 'UNKNOWN';
      printf "\nWARNING: probably because you are using a very wide slit, you are getting excessive (>$countmax) counts of $cest\n";
      printf "         for the minimum DIT=4.  This can probably be solved by using a different lamp combination, but\n";
      printf "         incomplete tables prevent this script from doing it automatically.  Generating script with \n";
      printf "         DIT = UNKNOWN and LAMP = UNKNOWN\n\n";
      }
    }
  }

printf "Expected count rate for filter $specfilt lamp $lamp camera $camera grating $specgrat is $count (ADU/s)\n";
printf "  Will use time DIT=$dit to get total counts $cest in one exposure -- defaulting to making $nflatdo flat exposures\n";

if ( !($dit =~ /UNKNOWN/) && !($lamp =~ /UNKNOWN/)) { 
  open(OUTFLAT ,">$script");
} else {
  printf "WARNING: Some pararameters are unknown so writing to $script.needsfixes\n";
  printf "         Look for parameter values of UNKNOWN\n";
  open(OUTFLAT ,">$script.needsfixes");
  }
printf OUTFLAT "\n#generated from $script0 on $date by $version\n\n";

# the ARCHIVE BLOCK
printf OUTFLAT  "[START_ARCHIVE_INFORMATION]\n";
printf OUTFLAT  "    PARTNER                 = LBTB,INAF,AZ,OSURC,LBTO\n";
printf OUTFLAT  "    PI_NAME                 = $PI\n";
printf OUTFLAT  "    PROP_ID                 = CALIBRATION\n";
printf OUTFLAT  "    [END_ARCHIVE_INFORMATION]\n\n";

# INSTRUMENT SET UP
printf OUTFLAT "[START_INSTRUMENT_SETUP]\n";
printf OUTFLAT "    CAMERA                  =$camera \n";
printf OUTFLAT "    FILTER                  =$specfilt\n";
printf OUTFLAT "    GRATING_UNIT            =$specgrat\n";       
if ( !($specgrat =~ /mirror/i) ) { 
  printf OUTFLAT "    CENTRAL_WAVELENGTH      =$speclcen\n";       
  printf OUTFLAT "    MASK                    =$specmask\n";
  }
printf OUTFLAT "    MASK_POSITION           =$maskpos \n"; 
printf OUTFLAT "    FLEXURE_COMP            =on  \n";
printf OUTFLAT "    [END_INSTRUMENT_SETUP] \n\n";

# READOUT
printf OUTFLAT "#DIT computed assuming a slitwidth of $slitwidth arcsec\n";
printf OUTFLAT "#   estimated countrate per exposure is $cest\n";
printf OUTFLAT "[START_READOUT_SETUP]\n";
printf OUTFLAT "    DIT               =$dit \n";            
printf OUTFLAT "    NDIT              =1   \n";
printf OUTFLAT "    NEXPO             =$nflatdo   \n";
printf OUTFLAT "    ROE_MODE          = o2dcr  \n";  # there is no reason not to use this mode     
printf OUTFLAT "    SAVE_MODE         = normal \n";      
printf OUTFLAT "    [END_READOUT_SETUP]\n\n";

# OBSERVING
printf OUTFLAT "[START_OBSERVING_SETUP]\n";
if ($lamp =~ /halo.*1/) { printf OUTFLAT "    LAMP = HALO1\n"; }
if ($lamp =~ /halo.*2/) { printf OUTFLAT "    LAMP = HALO2\n"; }
if ($lamp =~ /halo.*3/) { printf OUTFLAT "    LAMP = HALO3\n"; }
if ($lamp =~ /UNKNOWN/) { printf OUTFLAT "    LAMP = UNKNOWN\n"; }
printf OUTFLAT "    [END_OBSERVING_SETUP]\n\n";



