#!/usr/bin/perl
use FileHandle;
use File::Basename;

$npoly = 3;	#offset polynomial terms
$rlks = 1;
$azlks = 1;
$rpos1 = "-";
$azpos1 = "-";
$cflag = "1";	#copy initial offsets into the offset polynomial when running init_offset
$thres0 = 7.0;	#threshold for accepting initial offset
$phflg = 1;	#phase flag 0: no phase offset correction, 1: phase offset correction applied 

if (($#ARGV + 1) < 5){die <<EOS ;}
*** $0
*** Copyright 2012, Gamma Remote Sensing, v4.5 15-Nov-2012 clw ***
*** Concatenate pairs of sequential SLC frames to create a stack of larger images ***

usage: $0 <SLC_tab1> <SLC_tab2> <cslc_dir> <CSLC_tab> <mode> [phflg] [rpos] [azpos] [npoly]

    SLC_tab1  (input) two column list of SLCs and SLC parameter files for the early frame
    SLC_tab2  (input) two column list of SLCs and SLC parameter files of the frames to concatenate to the frames in SLC_tab1
    cslc_dir  directory to receive the concatenated SLCs and ISP image parameter files
    CSLC_tab  (output) RCSLC_tab file for the concatenated SLC files
    mode      processing mode:
                0: create offset parameter files
                1: estimate initial range and azimuth offsets using orbit state vectors
                2: measure initial range and azimuth offsets using SLC images (optional)
                3: estimate range and azimuth offset models using correlation of image intensities (optional)
                4: concatenate SLC images using measured offset model 
    phflg     phase offset correction flag:
                0: no phase offset correction for SLC-2 
                1: apply phase offset correction to SLC-2 (default)
    rpos      center of patch in range (samples) (enter - for default: image center)
    azpos     center of patch in azimuth (lines) (enter - for default: 1024 lines before end of SLC-1)
    npoly     number of terms in the polynomial fit (1,3,4,6 default: $npoly)
EOS

print "\nSLC_cat_all Copyright 2012, Gamma Remote Sensing, v4.5 14-Nov-2012 clw\n";
print "*** Concatenate pairs of sequential SLC frames to create a stack of larger images ***\n\n";
open(SLC_TAB1, "<$ARGV[0]") or die "\nERROR $0: table of SLC-1 images and parameter files does not exist: $ARGV[0]\n\n";
print "SLC_tab1 table of SLC-1 images and parameter files: $ARGV[0]\n";

open(SLC_TAB2, "<$ARGV[1]") or die "\nERROR $0: table of SLC-2 images and parameter files does not exist: $ARGV[1]\n\n";
print "SLC_tab2 table of SLC-2 images and parameter files: $ARGV[1]\n";

$cslc_dir = $ARGV[2];
$cslc_tab = $ARGV[3];
$mode = $ARGV[4];

if($#ARGV >= 5){$phflg = $ARGV[5];}
if($#ARGV >= 6){$rpos1 = $ARGV[6];}
if($#ARGV >= 7){$azpos1 = $ARGV[7];}
if($#ARGV >= 8){$npoly = $ARGV[8];}

($mode == 0 || $mode == 1 || $mode == 2 || $mode == 3 || $mode == 4) or die "\ERROR $0: invalid mode for script: $mode\n\n";
($npoly == 1 || $npoly == 3 || $npoly == 4 || $npoly == 6) or die "\ERROR $0: invalid value for npoly value: $npoly\n\n";
($phflg == 0 || $phflg == 1) or die "\ERROR $0: invalid value for phflg: $phflg\n\n";

unless (-d $cslc_dir){
  print "creating concatenated SLC directory: $cslc_dir\n";
  $exit = system("mkdir $cslc_dir");
  $exit == 0 or die "ERROR $0: non-zero exit status: mkdir $cslc_dir\n";
}

$log = "$cslc_dir/SLC_cat_all"."_$mode".".log";
open(LOG,">$log") or die "ERROR $0: cannot open log file: $log\n";
$time = localtime;
print LOG "$0 @ARGV\n\n";
print LOG "*** $0 processing start: $time ***\n";
print "*** $0 processing start: $time ***\n";
print "log file: $log\n";

print LOG "concatenated SLC data directory:$cslc_dir\n";
print LOG "output CSLC_tab file:         $cslc_tab\n";
print "concatenated cslc data directory: $cslc_dir\n";
print "output CSLC_tab file: $cslc_tab\n";
print "processing mode: $mode\n";
print "offset estimation location range: $rpos1    azimuth: $azpos1\n";
if ($phflg == 1){
  print "NOTE: applying phase offset correction to SLC-2\n";
}

if ($mode == 0 || $mode == 1 || $mode == 2){
  LINE: while (<SLC_TAB1>) {	#read lines of processing list file
    $time = localtime;
    chomp $_;			#remove new line from record
    next LINE if /^$/; 		#skip blank lines in processing list
    next LINE if /^#/; 		#skip comments in processing list
    @fields = split;		#extract the scene identifier and other parameters on the line if present
    $slc1 = $fields[0];
    $slc1_par = $fields[1];
    my ($s1, $dir1, $ext1) = fileparse($slc1, qr/\.[^.]*/); #extension is the last bit after the last period

    -e $slc1 or die "ERROR $0: slc1 image file does not exist: $slc1\n";
    -e $slc1_par or die "ERROR $0: ISP image parameter file does not exist for slc1: $slc1_par\n";

    @width1 = extract_param($slc1_par,"range_samples:");
    @lines1 = extract_param($slc1_par,"azimuth_lines:");

    if($rpos1 eq "-"){
      $rpos = $width1[1]/2;
    }
    else {
      $rpos = $rpos1;
    }

    if($azpos1 eq "-"){
      $azpos =  $lines1[1] - 1024;
    }
    else {
       $azpos = $azpos1;
    }

    $slc2_tab = readline *SLC_TAB2;
    @fields = split(/\s+/, $slc2_tab);
    $slc2 = $fields[0];
    $slc2_par = $fields[1];
    -e $slc2 or die "ERROR $0: SLC-2 not exist: $slc2\n";
    -e $slc2_par or die "ERROR $0:SLC2_par does not exist: $slc2_par\n";

    my ($s2, $dir2, $ext2) = fileparse($slc2, qr/\.[^.]*/); #extension is the last bit after the last period
    @width2 = extract_param($slc2_par,"range_samples:");
    @lines2 = extract_param($slc2_par,"azimuth_lines:");

    print "\n*** SLC-1: $slc1   SLC-2: $slc2   start time: $time ***";
    $id = $s1."_".$s2;
    $off = "$cslc_dir/$id.off";
    $log = "$cslc_dir/".$id."_resamp.log";
    $nr_patches = 64;
    $naz_patches = int($lines1[1]/250);
    print "number of patches range: $nr_patches  azimuth: $naz_patches\n";
    print LOG "*** SLC-1: $slc1  SLC-2: $slc2   start time: $time ***\n";
    print LOG "concatenated SLC data directory: $cslc_dir\n";
    print LOG "output CSLC_tab file: $cslc_tab\n";
    print LOG "SLC-1 range samples: $width1[1]  azimuth lines: $lines1[1]\n";
    print LOG "SLC-2 range samples: $width2[1]  azimuth lines: $lines2[1]\n";
    print LOG "offset estimation position range: $rpos  azimuth: $azpos\n";
    print LOG "number of patches range: $nr_patches  azimuth: $naz_patches\n";
    close LOG;

    print "\n";
    if ($mode == 0){
      $exit = system("rm -f $off");
      $exit == 0 or die "ERROR $0: non-zero exit status: rm -f $off\n";
      open(OFFINP, ">create_offset.in") or die "ERROR $0: cannot create file with inputs to create_offset: create_offset.in\n\n";
      print OFFINP "offset parameters\n0 0\n$nr_patches $naz_patches\n128 128\n7.0\n0\n".$width1[1]."\n";
      close OFFINP;
      execute("create_offset $slc1_par $slc2_par $off < create_offset.in",$log);
      print "\n";
    }

    if ($mode == 1){
      printf "orbit-derived initial range and azimuth offsets:\n";
      open(LOG,">>$log") or die "ERROR $0: cannot open log file: $log\n";
      print LOG "MODE 1: initial offset position  range: $rpos  azimuth: $azpos\n";
      close LOG;
      execute("init_offset_orbit $slc1_par $slc2_par $off $rpos $azpos",$log);
      @rpoly1 = extract_param($off ,"range_offset_polynomial:");
      @azpoly1 = extract_param($off ,"azimuth_offset_polynomial:");
      print "\n@rpoly1\n";
      print "@azpoly1\n";
    }

    if ($mode == 2){
      print "SLC-derived initial range and azimuth offsets:\n";
      open(LOG,">>$log") or die "ERROR $0: cannot open log file: $log\n";
      print LOG "MODE 2: initial offset looks  range: $rlks  azimuth: $azlks\n";
      print LOG "MODE 2: initial offset position  range: $rpos  azimuth: $azpos\n";
      print LOG "MODE 2: initial offset SNR threshold; $thres0  copy offset flag: $cflag\n";
      close LOG;
      execute("init_offset $slc1 $slc2 $slc1_par $slc2_par $off $rlks $azlks $rpos $azpos - - $thres0 512 512 $cflag",$log);

      if ($cflag == 0){
        @roff1 = extract_param($off ,"initial_range_offset:");
        @azoff1 = extract_param($off ,"initial_azimuth_offset:");
        print "initial range offset:   $roff1[1]\n";
        print "initial azimuth offset: $azoff1[1]\n";
      }
      else{
        @rpoly1 = extract_param($off ,"range_offset_polynomial:");
        @azpoly1 = extract_param($off ,"azimuth_offset_polynomial:");
        print "\n@rpoly1\n";
        print "@azpoly1\n";
      }
    }
  }
  $time = localtime;
  print "\n*** $0 COMPLETED: $time ***\n";
  open(LOG,">>$log") or die "ERROR $0: cannot open log file: $log\n";
  print LOG "\n*** $0 COMPLETED: $time***\n";
  close LOG;
  exit 0;
}

$time = localtime;
seek SLC_TAB1, 0, 0;		#rewind the files
seek SLC_TAB2, 0, 0;

LINE: while (<SLC_TAB1>) {	#read lines of processing list file
  $time = localtime;
  chomp $_;			#remove new line from record
  next LINE if /^$/; 		#skip blank lines in processing list
  next LINE if /^#/; 		#skip comments in processing list
  @fields = split;		#extract the scene identifier and other parameters on the line if present

  $slc1 = $fields[0];
  $slc1_par = $fields[1];
  my ($s1, $dir1, $ext1) = fileparse($slc1, qr/\.[^.]*/); #extension is the last bit after the last period

  -e $slc1 or die "ERROR $0: slc1 image file does not exist: $slc1\n";
  -e $slc1_par or die "ERROR $0: ISP image parameter file does not exist for slc1: $slc1_par\n";

  @width1 = extract_param($slc1_par,"range_samples:");
  @lines1 = extract_param($slc1_par,"azimuth_lines:");
  $cslc = "$cslc_dir/$s1".".slc";
  $cslc_par = "$cslc_dir/$s1".".slc.par";
  print "concatenated SLC:                $cslc\n";
  print "concatenated SLC parameter file: $cslc_par \n";

  $slc2_tab = readline *SLC_TAB2;
  @fields = split(/\s+/, $slc2_tab);
  $slc2 = $fields[0];
  $slc2_par = $fields[1];

  -e $slc2_par or die "ERROR $0: ISP image parameter file does not exist for slc1: $slc2_par\n";
  -e $slc2 or die "ERROR $0: slc1 image file does not exist: $slc2\n";
   my ($s2, $dir2, $ext2) = fileparse($slc2, qr/\.[^.]*/); #extension is the last bit after the last period
  @width2 = extract_param($slc2_par,"range_samples:");
  @lines2 = extract_param($slc2_par,"azimuth_lines:");

  print "\n*** SLC-1: $slc1   SLC-2: $slc2   start time: $time ***\n";
  $id = $s1."_".$s2;
  $off = "$cslc_dir/$id.off";
  $log = "$cslc_dir/".$id."_resamp.log";

  open(LOG,">>$log") or die "ERROR $0: cannot open log file: $log\n";
  print LOG "\n*** SLC-1: $slc1  SLC-2: $slc2   start time: $time ***\n";
  print LOG "concatenated SLC data directory: $cslc_dir\n";
  print LOG "output CSLC_tab file: $cslc_tab\n";
  print LOG "SLC-1 range samples: $width1[1]  azimuth lines: $lines1[1]\n";
  print LOG "SLC-2 range samples: $width2[1]  azimuth lines: $lines2[1]\n";
  close LOG;

  $offs = "$cslc_dir/$id.offs";			#binary offsets
  $coffs = "$cslc_dir/$id.coffs";		#culled offsets
  $snr = "$cslc_dir/$id.snr";

  if($mode == 3){
    execute("offset_pwr $slc1 $slc2 $slc1_par $slc2_par $off $offs $snr",$log);
    execute("offset_fit $offs $snr $off $coffs - - $npoly",$log);

    @rpoly1 =  extract_param($off,"range_offset_polynomial:");
    @azpoly1 = extract_param($off,"azimuth_offset_polynomial:");
    print "\n@rpoly1\n";
    print "@azpoly1\n\n";
    if ((abs($rpoly1[1]) < .001) && (abs($rpoly1[2]) < 1.e-7) && (abs($rpoly1[3]) < 1.e-7)){
      print "NOTE: range offsets are below .001 pixel, setting range offset polynomial coefficients to 0.0\n";
      $sv1 = "0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00";
      execute("set_value $off $off \"range_offset_polynomial\"  \"$sv1\"",$log); 
    }   
  }

  if($mode == 4){
    execute("SLC_cat $slc1 $slc2 $slc1_par $slc2_par $off $cslc $cslc_par 1 0 $phflg ",$log);
  }

  $time = localtime;
  open(LOG,">>${log}") or die "\nERROR $0: cannot open existing log file: $log\n";
  print LOG "*** ref. SLC: $ref_slc   SLC-2: $slc2  END: $time ***\n";
  close LOG;
  print "*** ref. SLC: $ref_slc   SLC-2: $slc2  END: $time ***\n";
}

# create output CSLC_tab file
if ($mode == 4){
  execute("mk_tab $cslc_dir slc slc.par $cslc_tab",$log);
}

$time = localtime;
print "*** $0 MODE: $mode COMPLETED: $time ***\n";
open(LOG,">>${log}") or die "\nERROR $0: cannot open existing log file: $log\n";
print LOG "*** $0 MODE: $mode COMPLETED: $time***\n";
close LOG;
exit 0;

sub execute{
  my ($command, $log) = @_;
  if (-e $log){open(LOG,">>$log") or die "\nERROR $0: cannot open log file: $log\n";}
  else {open(LOG,">$log") or die "\nERROR $0: cannot open log file: $log\n";}
  print "$command\n";
  print LOG ("\n${command}\n");
  $exit = system("$command 1>> $log");
  close LOG;
  $exit == 0 or die "ERROR $0: non-zero exit status: $command\n"
}

sub extract_param{
  my ($infile,$keyword) = @_;
  open(PAR_IN,$infile) || die "\nERROR extract_param: cannot open parameter file: $infile\n";
  while(<PAR_IN>){
    chomp;
    @tokens = split;
    if($tokens[0] eq $keyword){close PAR_IN; return @tokens;}

  }
  close PAR_IN;
  die "\nERROR $0: keyword $keyword not found in file: $infile\n";
}

