#!/usr/bin/perl

use IO::Handle; autoflush STDOUT 1; 

sub CPOUTPUT {
    return if $pid = open(STDOUT, "|-");
    die "cannot fork: $!" unless defined $pid;
    open (LOG,">process_lev1_data.log") || die;
    use IO::Handle;
    autoflush STDOUT 1;
    autoflush LOG 1;
    while (<STDIN>) {
        print;
        print LOG $_;
    }
    close(LOG);
    exit 0;
}

CPOUTPUT;

@gov = split (/\//,$0); pop @gov; $BINDIR = join ('/',@gov);
$getpar   = "$BINDIR/getpar";
if ($ENV{'FITSFILTER'}) {
  $fcopy = $ENV{'FITSFILTER'}
} else {
  $fcopy    = "$BINDIR/fitsfilter";
}
$fdelhdu  = "fdelhdu";
$fappend  = "fappend";
$fstruct  = "fstruct";
$badpixf  = "$ENV{'CH'}/bin/badpixfilter";
$makeacisbg = "$ENV{'CH'}/bin/make_acisbg";

# Read common PERL subs
require "$BINDIR/perlutil.pl";

# Initialize internal variables ($UNDEF etc)
&ini_vars;

@PARS = &fixpars (@ARGV); # this is needed to escape arguments with parens etc

chop (
($evtfile,$outfile,$gtifile,$do_cti,$do_tgain,$do_gain,$vf_clean,$clean_afterglow,
 $badpixfilter,$grade_set,
 $flt_grade_set,$ccd_set,$tmpdir,
 $do_aspect,$aspfile,
 $bg_file,$input_bg_file,
 $destreak, $bg_only
 ) =
`$getpar inputevtfile,evtfile,gtifile,do_cti,do_tgain,do_gain,vf_clean,clean_afterglow,badpixfilter,grade_set,flt_grade_set,ccd_set,tmpdir,do_aspect,aspfile,bg_file,input_bg_file,destreak,bg_only @PARS`
);

chop (
    ($do_cti_t,$mtlfile,$do_subpix) = `$getpar do_cti_t,mtlfile,do_subpix @PARS`
    );

chop (
      ($readout_bg_file,$readout_bg_only) =
      `$getpar readout_bg_file,readout_bg_only @PARS`
     );

foreach $var ($evtfile,$outfile,$gtifile,$do_cti,$do_tgain,$do_gain,$vf_clean,
	      $clean_afterglow,$badpixfilter,
	      $grade_set,$flt_grade_set,$tmpdir,$ccd_set,$do_aspect,
	      $bg_file,$input_bg_file,$readout_bg_file
	     ) {
  if ($var eq $UNDEF) { $var=""; }
}
foreach $var ($do_cti,$do_tgain,$do_gain,$do_cti_t,$do_subpix,
	      $vf_clean,$clean_afterglow,$do_aspect,$destreak) {
  if ($var =~ /^y/i) { $var=1; } else { $var=0;}
}

if ( $tmpdir ) {$tmpname = "$tmpdir/gov$$.fits";} else {$tmpname="gov$$.fits";}


# save EVT file name because it will be reset by DOBG and DOREADOUTBG ######
$outfile_evt = $outfile;

print "BGONLY: ",$bg_only,"\n";
if ($bg_only eq "yes") {
  goto DOBG;
}

print "READOUT BG ONLY: ",$readout_bg_only,"\n";
if ($readout_bg_only eq "yes") {
  goto DOREADOUTBG;
}

&clean_initial;

$doingbg = 0;
$aspect_applied = 0;
if ($do_cti) { &do_cti_correction }
if ($do_tgain) {
  if ( ! $do_cti ) { &rm_tgain_correction; }
  &do_tgain;
}

if ($do_gain && !$do_cti && !$do_tgain ) { &do_gain; }

if ($do_aspect && !$aspect_applied ) { &do_aspect; }

&copy_gti_file;



###### BG ######

DOBG:
if ( $bg_file ) {

 $evtfile=$bg_file;
 $outfile=$bg_file;
 $doingbg = 1;

 if ( $input_bg_file ) {
   @cl=("cp",$input_bg_file,$bg_file);
   print join(' ','=== ',@cl,'...',"\n");
   system(@cl) && die;
   print "=== OK\n";
 }

 $aspect_applied=1;
 &clean_initial;
 #if ($do_tgain) { &do_tgain }
 #if ($do_gain && !$do_cti && !$do_tgain ) { &do_gain; }
 &do_gain;

 open (PAR,"> make_acisbg.par") || die;
 print PAR "
evtfile=$outfile_evt
bg_file=$bg_file
aspfile=$aspfile
";
 if ($gtifile) {
   print PAR "gtifile=$gtifile\n";
 } else {
   print PAR "gtifile=$outfile","[gti]\n"
 }
 close PAR;
 print "=== MAKEACISBG: \n";
 system ($makeacisbg) && die;
 print "=== OK\n";

}

##### READOUT BG ######  Modified code from the make_readout_bg by M.Markevitch
DOREADOUTBG:
if ( $readout_bg_file ) {

 $evtfile=$readout_bg_file;
 $outfile=$readout_bg_file;
 $doingbg = 0;
 $doingreadoutbg = 1;

# Randomize chipy:
 @cl=($fcopy,$outfile_evt."[events][col chipy=(int)(2+1022*random()); *]","!$outfile");
 print join(' ','=== ',@cl,'...',"\n");
 system(@cl) && die;
 print "=== OK\n";

# reprocess
 $do_aspect=1;
 $aspect_applied=0;

 if ( $badpixfilter ) {
   &do_badpix;
 }
 if ($do_cti) { &do_cti_correction }
 if ($do_aspect && !$aspect_applied ) { &do_aspect; }
 if ($do_tgain) {
   if ( ! $do_cti ) { &rm_tgain_correction; }
   &do_tgain;
 }

# fake gti extension
 chomp($tstart = `printkey $outfile+0 TSTART`);
 chomp($expos = `gtiexp $gtifile+1`);
 $ontime=$expos*3.2/0.041;
 $tstop=$tstart+$ontime;

 open (GTIDATA,"> govgti$$") || die;
 print GTIDATA "$tstart $tstop\n";
 close (GTIDATA);
 system ("gtifits","govgti$$","govgti$$.fits");
 &copy_gti_file ("govgti$$.fits");
 unlink ("govgti$$","govgti$$.fits");

}


exit(0);

###########################################################################
sub do_destreak {
  chop (
	($destreak_max,$destreak_filter,$destreak_mask,$destreak_ccd_id) =
 `$getpar destreak_max,destreak_filter,destreak_mask,destreak_ccd_id @PARS`
       );

  foreach $var ($destreak_max,$destreak_mask,$destreak_ccd_id) {
    if ($var eq $UNDEF) {
      $var = "DEFAULT";
    }
  }

  @cl=();
  push @cl,"destreak";
  push @cl,$outfile;
  push @cl,$tmpname;
#  push @cl,"verbose=3";
  if ($destreak_max ne "DEFAULT") {
    push @cl,"max=$destreak_max";
  }
  if ($destreak_filter ne "DEFAULT") {
    push @cl,"filter=$destreak_filter";
  }
  if ($destreak_mask ne "DEFAULT") {
    push @cl,"mask=$destreak_mask";
  }
  if ($destreak_ccd_id ne "DEFAULT") {
    push @cl,"ccd_id=$destreak_ccd_id";
  }

  print join(' ','=== DESTREAK: ',@cl,'...',"\n");
  system(@cl) && die;
  print "=== OK\n";
  unlink ($outfile);
  print ("$fcopy $tmpname'[events][status==bxxxxxxxxxxxxxxxx0xxxxxxxxxxxxxxx]' $outfile\n");
  system ("$fcopy $tmpname'[events][status==bxxxxxxxxxxxxxxxx0xxxxxxxxxxxxxxx]' $outfile") && die;
  rename ($tmpname,$outfile);


}

###########################################################################
sub rm_tgain_correction {
chop (
($gainfile,$gradefile) = `$getpar GAINFILE,GRADEFILE @PARS`
);

@cl = ();
push @cl,"acis_process_events";
push @cl,"infile=$outfile";
push @cl,"outfile=$tmpname"; push @cl,"clobber+";
push @cl,"stop=none";
push @cl,"acaofffile=NONE";

if ($gainfile ne $UNDEF) {push @cl,"gainfile=$gainfile";}
if ($gradefile ne $UNDEF) {push @cl,"gradefile=$gradefile";}
push @cl,"apply_cti=no";
push @cl,"doevtgrade=yes";
push @cl,"apply_tgain=no";
push @cl,"calculate_pi=yes";

print join (' ','=== ',@cl,":\n");
system (@cl) && die;
print "===OK\n";

print ("mv $tmpname $outfile\n");
rename ($tmpname,$outfile);

}

###########################################################################
sub do_cti_correction {
chop (
($gainfile,$gradefile,$ctifile) = `$getpar GAINFILE,GRADEFILE,CTIFILE @PARS`
);

@cl = ();
push @cl,"acis_process_events";
push @cl,"infile=$outfile";
push @cl,"outfile=$tmpname"; push @cl,"clobber+";
if (($do_aspect || $do_subpix) && ! $aspect_applied) {
  $aspect_applied = 1;
  push @cl,"acaofffile=$aspfile";
} else {
  push @cl,"stop=none";
  push @cl,"acaofffile=NONE";
}
if ($gainfile ne $UNDEF) {push @cl,"gainfile=$gainfile";}
if ($ctifile  ne $UNDEF) {push @cl,"ctifile=$ctifile";}
if ($gradefile ne $UNDEF) {push @cl,"gradefile=$gradefile";}
push @cl,"apply_cti=yes";
push @cl,"doevtgrade=yes";
push @cl,"apply_tgain=no";
push @cl,"calculate_pi=yes";
if ($do_cti_t) {push @cl,"mtlfile=$mtlfile";} else {push @cl,"mtlfile=NONE";}
if ($do_subpix) {push @cl,"pix_adj=EDSER";} else {push @cl,"pix_adj=NONE";}

print join (' ','=== ',@cl,":\n");
system (@cl) && die;
print "===OK\n";

if ( $grade_set || $flt_grade_set ) {
  print "=== re-apply grade selection:\n";
  $filter=""; $firstgrade=1;
  if ( $grade_set ) {
    foreach $grade ( split (',',$grade_set ) ) {
      if ( ! $firstgrade ) { $filter=$filter."||"; }
      $filter=$filter."grade==$grade";
      $firstgrade=0;
    }
  }
  if ( $flt_grade_set ) {
    foreach $grade ( split (',',$grade_set ) ) {
      if ( ! $firstgrade ) { $filter=$filter."||"; }
      $filter=$filter."fltgrade==$grade";
      $firstgrade=0;
    }
  }
  @cl=($fcopy,$tmpname."[events][$filter]","!$outfile");
  print join(' ',@cl,"\n"); system (@cl) && die; print "=== OK\n";
  unlink ($tmpname);
} else {
  print ("mv $tmpname $outfile\n");
  rename ($tmpname,$outfile);
}

}

###########################################################################
sub do_gain {
chop (
($gainfile) = `$getpar GAINFILE @PARS`
);

@cl = ();
# push @cl,"acis_process_events";
# push @cl,"infile=$outfile";
# push @cl,"outfile=$tmpname"; push @cl,"clobber+";
# if ($do_aspect && ! $aspect_applied) {
#   $aspect_applied = 1;
#   push @cl,"acaofffile=$aspfile";
# } else {
#   push @cl,"stop=none";
#   push @cl,"acaofffile=NONE";
# }
# if ($gainfile ne $UNDEF) {push @cl,"gainfile=$gainfile";}
# push @cl,"apply_cti=no";
# push @cl,"doevtgrade=no";
# push @cl,"calculate_pi=yes";

push @cl,"apply_gain";
push @cl,"$outfile";
push @cl,"-gain";
push @cl,"$gainfile";

print join (' ','=== ',@cl," ...\n");
system (@cl) && die;
print "OK\n";
# print ("mv $tmpname $outfile\n");
# rename ($tmpname,$outfile);
}

###########################################################################
sub do_tgain {
chop (
($gainfile,$do_au_gain) = `$getpar GAINFILE,do_Au_gain @PARS`
);

#$corr_tgain_dir = "$ENV{'CH'}/corr_tgain";

($corr_tgain_dir)=`$getpar ^TGAIN_DIR @PARS`; chop $corr_tgain_dir;
if ( $corr_tgain_dir eq $UNDEF ) {
  if ( $ENV{'TGAIN_DIR'} ) {
    $corr_tgain_dir = $ENV{'TGAIN_DIR'};
  } else { # default
    $corr_tgain_dir = "$ENV{'CH'}/CAL/tgain";
  }
}

chop (
@tgaindates = `ls $corr_tgain_dir | grep corrgain | grep \.fits | grep -v \.v | awk -F. '{print $1}' | sort -r | uniq `
);
foreach $tgaindate ( @tgaindates ) {
  $tgaindate =~ s/\..*//;
  $tgaindate =~ s/[^\d-]//g;
}


($info1,$info2) = `printkey $evtfile\[events\] date-obs,date-end`;
chop $info1; chop $info2;
($date_start) = split (' ',$info1); $date_start =~ s/T.*//;
($date_end) = split (' ',$info2); $date_end =~ s/T.*//;
$mjd_start = &sla_cldj (split('-',$date_start));
$mjd_end   = &sla_cldj (split('-',$date_end));
($yy,$mm,$dd) = &sla_djcl(0.5*($mjd_start+$mjd_end));
$mm=sprintf("%2.2d",$mm);$dd=sprintf("%2.2d",$dd);
$date = join('-',$yy,$mm,$dd);

$epoch=$tgaindate[0];
foreach $tgaindate ( @tgaindates ) {
  if ( $date ge $tgaindate ) {
    $epoch = $tgaindate;
    last;
  }
}
$tgain="corrgain$epoch";
print join(' ',$outfile,$date_start,$date_end,$date,"corrgain$epoch","\n");

print "=== TGAIN correction: \n";
@cl = ("apply_gain",$outfile,
       "-tgain","$corr_tgain_dir/$tgain",
       "-gain",$gainfile,
       "do_cti=$do_cti");
print join (' ',@cl," ...\n");
system (@cl) && die;

if ($do_au_gain eq "yes") {
    print " ... compute Au line based gain adjustments\n";
    system ("augain evtfile=$outfile > $tmpdir/augain.par.$$") && die;
    push (@cl,"\@$tmpdir/augain.par.$$");
    print " ... apply those adustments\n";
    print join (' ',@cl," ...\n");
    system (@cl) && die;
    unlink ("$tmpdir/augain.par.$$");
}

print "=== OK\n";

# print "=== TGAIN correction: \n";
# @cl = ("$corr_tgain_dir/corr_tgain",$outfile,"-tgain",
#        "$corr_tgain_dir/$tgain");
# print join (' ',@cl," ...\n");
# system (@cl) && die;
# print "=== OK\n";
# 
# 
# @cl=();
# push @cl,"acis_process_events";
# push @cl,"infile=$outfile";
# push @cl,"outfile=$tmpname"; push @cl,"clobber+";
# if ($do_aspect && ! $aspect_applied) {
#   $aspect_applied = 1;
#   push @cl,"acaofffile=$aspfile";
# } else {
#   push @cl,"stop=none";
#   push @cl,"acaofffile=NONE";
# }
# if ($gainfile ne $UNDEF) {push @cl,"gainfile=$gainfile";}
# push @cl,"apply_cti=no";
# push @cl,"doevtgrade=no";
# push @cl,"calculate_pi=yes";
# 
# print "=== Recompute ENERGY & PI: \n";
# print join (' ',@cl," ...\n");
# system (@cl) && die;
# print "=== OK\n";
# 
# if ($doingbg) { # COPY GTI
#   my ($igti, $ngti);
#   print "=== replace GTI extensions in the output file ...\n";
#   $ngti = `$fstruct $tmpname | grep "BINTABLE GTI" | wc`;
#   ($ngti) = split (' ',$ngti);
#   foreach $igti ( 1 .. $ngti ) {
#     system ("$fdelhdu",$tmpname."[gti]","NO","YES") && die;
#   }
#   system ("$fappend",$outfile."[gti]",$tmpname) && die;
#   print "=== OK\n";
# }
# 
# print ("mv $tmpname $outfile\n");
# rename ($tmpname,$outfile);
}

###########################################################################
sub do_aspect {

@cl = ();
push @cl,"acis_process_events";
push @cl,"infile=$outfile";
push @cl,"outfile=$tmpname"; push @cl,"clobber+";
push @cl,"acaofffile=$aspfile";
if ($do_subpix) {push @cl,"pix_adj=EDSER";} else {push @cl,"pix_adj=NONE";}

push @cl,"gainfile=none";
push @cl,"ctifile=none";
push @cl,"gradefile=none";
push @cl,"apply_cti=no";
push @cl,"apply_tgain=no";
push @cl,"doevtgrade=no";
push @cl,"calculate_pi=no";

print "=== APPLY ASPECT: \n"; print join (' ',@cl," ...\n");
system (@cl) && die;
print "=== OK\n";

print ("mv $tmpname $outfile\n");
rename ($tmpname,$outfile);

}



###########################################################################
sub clean_initial {
#
# We want to make as much cleaning as possible at this first step
#

  my ($first)=1;

  if ( $gtifile || $clean_afterglow || $ccd_set || ( !$do_cti && ($grade_set || $flt_grade_set)) ) {
    $filter = "[events][";

    if ($gtifile && !$doingbg) {
      if (!$first) { $filter=$filter."&&"; }
      $filter=$filter."gtifilter( \"$gtifile\" )";
      $first=0;
    }

    if ( $clean_afterglow && ! $doingbg ) {
      # explicitly run acis_detect_afterglow;
      print "=== ","acis_detect_afterglow ... \n";
      system ("acis_detect_afterglow","infile=$evtfile","outfile=$tmpname",
	      "logfile=stdout","pha_rules=LTEQ","fltgrade_rules=NONE",
	      "maxchain=16","verbose=0","clobber=no") && die;
      print "=== OK\n";
      rename ($tmpname,$outfile);
    } else {
      if ( ! $doingbg ) {
	system ("cp",$evtfile,$outfile) && die;
      }
    }

    $statusfilt = "bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
    $z="0";
    if ($clean_afterglow) {
      $statusfilt =~ s/(.............)....(................)/$1$z$z$z$z$2/;
#### bxxxxxxxxxxxx0000xxxxxxxxxxxxxxxx
    }
    if ($doingbg && $vf_clean) {
      $statusfilt =~ s/(.........).(.......................)/$1$z$2/;
    }
    if ( ! ( $statusfilt =~ /^bx+$/) ) {
      if (!$first) { $filter=$filter."&&"; }
      $filter=$filter."status==$statusfilt";
      $first=0;
    }

    if ($ccd_set) {
      my ($ccd,$firstccd); $firstccd=1;
      if (!$first) { $filter=$filter."&&"; }
      $filter=$filter."(";
      foreach $ccd ( split (',',$ccd_set ) ) {
	if ( ! $firstccd ) { $filter=$filter."||"; }
	$filter=$filter."ccd_id==$ccd";
	$firstccd=0;
      }
      $filter=$filter.")";
      $first=0;
    }

    if ( (!$do_cti||$doingbg) && ($grade_set || $flt_grade_set)) {
      if ($grade_set) {
	my ($grade,$firstgrade); $firstgrade=1;
	if (!$first) { $filter=$filter."&&"; }
	$filter=$filter."(";
	foreach $grade ( split (',',$grade_set ) ) {
	  if ( ! $firstgrade ) { $filter=$filter."||"; }
	  $filter=$filter."grade==$grade";
	  $firstgrade=0;
	}
	$filter=$filter.")";
	$first=0;
      }
      if ($flt_grade_set) {
	my ($grade,$firstgrade); $firstgrade=1;
	if (!$first) { $filter=$filter."&&"; }
	$filter=$filter."(";
	foreach $grade ( split (',',$flt_grade_set ) ) {
	  if ( ! $firstgrade ) { $filter=$filter."||"; }
	  $filter=$filter."fltgrade==$grade";
	  $firstgrade=0;
	}
	$filter=$filter.")";
	$first=0;
      }
    }

    $filter = $filter."]";

    print "=== ",$fcopy," ",$outfile.$filter," !",$tmpname," ...\n";
    system ($fcopy,$outfile.$filter,"!$tmpname") && die;
    print "=== OK\n";
    print "=== mv $tmpname $outfile ...\n";
    rename ($tmpname,$outfile);
    print "=== OK\n";
  }

  if ( $badpixfilter ) {
    &do_badpix;
  }

  if ( (! $doingbg) && $destreak ) {
    &do_destreak;
  }

  if ( $vf_clean && ! $doingbg ) {
    print "=== clean55 -g $outfile ...\n";
    if (system ("clean55","-g",$outfile)) {
      print " VF cleaning failed (NOT VF MODE?)\n";
      $vf_clean = 0;
    } else {
      system ($fcopy,$outfile."[events][grade!=255]","!$tmpname") && die;
      rename ($tmpname,$outfile);
      print "=== OK\n"
    }
  }


}

sub do_badpix {
  print join(' ','=== ',
	     $badpixf,"evtfile=$outfile","badpixfilter=$badpixfilter",
	     "o=!$tmpname ...\n");
  system ($badpixf,"evtfile=$outfile","badpixfilter=$badpixfilter",
	  "o=!$tmpname") && die;
  print ("\n   mv $tmpname $outfile ...\n");
  rename ($tmpname,$outfile);
  print "=== OK\n"
}

sub copy_gti_file {
  my ($igti, $ngti);
  my ($gti_file);
  if ( $#_ >= 0 ) {
    $gti_file = $_[0];
  } else {
    $gti_file = $gtifile;
  }
  if ($gti_file) {
    print "=== replace GTI extensions in the output file ...\n";
    $ngti = `$fstruct $outfile | grep "BINTABLE GTI " | wc`;
    ($ngti) = split (' ',$ngti);
    if ( $ngti > 0 ) {
      foreach $igti ( 1 .. $ngti ) {
	system ("$fdelhdu",$outfile."[gti]","NO","YES") && die;
      }
    }
    system ("$fappend",$gti_file."[gti]",$outfile) && die;
    print "=== OK\n";
  }
}

#####################################################################
sub ini_vars {
  $UNDEF = "undefined";
}

############################################################################
sub sla_mod {
 my ($x,$y) = @_;
 return $x-int($x/$y)*$y;
}
sub sla_nint {
  my $x = $_[0];
  my $n = int($x);
  if ( $x > 0 ) {
    if ( $x-$n > 0.5) {
      return $n+1;
    }
    else {
      return $n;
    }
  }
  else {
    if ( $n-$x > 0.5) {
      return $n-1;
    }
    else {
      return $n;
    }
  }
}
sub sla_cldj {
  my ($IY, $IM, $ID) = @_;
  my ($DJM);

  my @MTAB = (0,31,28,31,30,31,30,31,31,30,31,30,31);

  if ($IY<-4699) {
    return -1e10;
  }

# Validate month
  if ($IM>=1&&$IM<=12) {
#     Allow for leap year
    if (sla_mod($IY,4)==0) {
      $MTAB[2]=29;
    } else {
      $MTAB[2]=28;
    }
    if (sla_mod($IY,100)==0&&sla_mod($IY,400)!=0) {
      $MTAB[2]=28;
    }

#   Validate day
    if ($ID<1||ID>$MTAB[$IM]) {
      return -3e10;
    }

    use integer;
    #   Modified Julian Date
    $DJM = (1461*($IY-(12-$IM)/10+4712))/4
      +(306*sla_mod($IM+9,12)+5)/10
	-(3*(($IY-(12-$IM)/10+4900)/100))/4
	  +$ID-2399904;
    return $DJM
  } else {
    return -2e10;
  }
}

sub sla_djcl {
  my ($DJM) = @_;
  my ($IY, $IM, $ID, $FD);
  my ($F,$D,$N4,$ND10);
  if ($DJM<=-2395522||$DJM>=1e9) {
    return (-1e10,-1,-1,-1);
  }

  #  Separate day and fraction
  $F=sla_mod(DJM,1.0);
  if ($F<0.0) { $F+=1.0;}
  $D=sla_nint($DJM-$F);

  #  Express day in Gregorian calendar
  $JD=sla_nint($D)+2400001;

  use integer;
  $N4=4*($JD+((6*((4*$JD-17918)/146097))/4+1)/2-37);
  $ND10=10*(sla_mod($N4-237,1461)/4)+5;
  $IY=$N4/1461-4712;
  $IM=sla_mod($ND10/306+2,12)+1;
  $ID=sla_mod($ND10,306)/10+1;
  $FD=$F;
  return ($IY, $IM, $ID, $FD);
}
