#!/usr/bin/perl
use FileHandle;

$az_patch = 6144;	#default patch azimuth patch size
$af_snr = 6;		#autofocus minimum SNR
$af_azoff = 0;		#number of lines offset from the start of the range compressed data
$af_ovr = 2;		#autofocus offset estimation over-sampling factor
$af_dr = 1024;		#af range sample increment
$af_daz = 4096;		#af azimuth line increment
$MSP_HOME = $ENV{'MSP_HOME'};

if (($#ARGV + 1) < 8){die <<EOS ;}
*** $0
*** Copyright 2014, Gamma Remote Sensing, v2.6 19-Jun-2014 clw ***
*** RADARSAT processing from CEOS format raw data with the MSP ***

usage: $0 <proc_list> <raw_dir> <rc_dir> <SLC_dir> <MLI_dir> <rlks> <azlks> <SLC_format> [az_patch][autof_snr] [autof_azoff]
    proc_list	(input) processing list (8 columns): 
    		  1. scene_identifier  
		  2. offset in echoes to start of processed data (enter - for default)
		  3. number of echoes to process (enter - for default)
		  4. range offset in samples (enter - for default)
		  5. number of range samples to process (enter - for default)
		  6. doppler centroid
		  7. doppler slope
		  8. fraction of the bandwidth to process
    raw_dir	directory containing raw data files 
    rc_dir	directory to contain range compressed data (rc data is deleted)
    SLC_dir	directory to contain SLC data 
    MLI_dir	directory to contain multilook intensity (MLI) files derived from SLC data
    rlks	range looks for MLI image
    azlks	azimuth looks for MLI image
    SLC_format	output SLC image format (0:FCOMPLEX  1:SCOMPLEX) 
    az_patch    azimuth patch size (default: $az_patch)
    autof_snr   minimum SNR threshold for autofocus, 0.0 for no autofocus (nominal = $autof_snr)
    autof_azoff offset lines to determine where to evaluate autofocus (default = 0)
    
    NOTE: current directory is denoted by .
    
EOS

open(SLIST, "<$ARGV[0]") or die "ERROR $0: processing list does not exist: $ARGV[0]\n\n";
print "processing list: $ARGV[0]\n"; 

$raw_dir = $ARGV[1];
$rc_dir  = $ARGV[2];
$slc_dir = $ARGV[3];
$mli_dir = $ARGV[4];
$rlks    = $ARGV[5];
$azlks   = $ARGV[6];
$slc_format = $ARGV[7];

-d $raw_dir or die "ERROR $0: raw data directory does not exist: $raw_dir\n";
-d $rc_dir or die "ERROR $0: directory for temp storage of range compressed data does not exist: $rc_dir\n";

unless (-d $slc_dir) {
  print "creating SLC directory: $slc_dir\n";
  $exit = system("mkdir $slc_dir");
  $exit == 0 or die "ERROR $0: non-zero exit status: mkdir $slc_dir\n"
}
unless(-d $mli_dir) {
  print "creating mli directory: $mli_dir\n";
  $exit = system("mkdir $mli_dir");
  $exit == 0 or die "ERROR $0: non-zero exit status: mkdir $slc_dir\n"
}
 
print "input raw data directory: $raw_dir\n";
print "directory for temp storage of range compressed data: $rc_dir\n";
print "output SLC data directory: $slc_dir\n";
print "output MLI data directory: $mli_dir\n";

($slc_format == 0 || $slc_format == 1) or die "ERROR $0: invalid slc format value: $ARGV[4]\n";
if($slc_format == 0){print "SLC image data format: FCOMPLEX\n";}
else {print "slc image data format: SCOMPLEX\n";}

$rlks =~ /\d+$/ && $rlks > 0 or die "ERROR $0: invalid number of range looks: $rlks\n";
$azlks =~ /\d+$/ && $azlks > 0 or die "ERROR $0: invalid number of azimuth looks: $azlks\n";
print "mli range looks: $rlks  azimuth looks: $azlks\n";

if ($#ARGV >= 8){
   $ARGV[8] =~ /\d+$/ or die "ERROR $0: invalid entry for azimuth patch size: $ARGV[8]\n";
   $az_patch = $ARGV[8];   
}
print "azimuth patch size (lines): $az_patch\n";

if ($#ARGV >= 9){
  $af_snr = $ARGV[9]; 
  $af_snr >= 0.0 or die "ERROR $0: invalid entry for autofocus minimum SNR threshold: $autof_snr)\n";
}    
print "autofocus SNR threshold: $autof_snr\n";

if ($#ARGV >= 10){
  $af_azoff = $ARGV[10]; 
  $af_azoff >= 0 or die "ERROR $0: invalid azimuth line offset for auto focus: $af_azoff)\n";
  print "azimuth line offset for autofocus: $af_azoff\n";
}
    
LINE: while (<SLIST>) {		#read lines of processing list file
  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, sensor parameter file, and other parameters
  $#fields + 1 >= 5 or die "ERROR $0: wrong number of columns in proc_list, check file: $_\n";	#check if enough entries

  $id = $fields[0];
  $log = $slc_dir."/".$id."_MSP.log";		#concatenate strings with . 
  $time = localtime;
  print "\n*** scene id: $id  processing log file: $log  start time: $time ***\n";
  open(LOG,">$log") or die "ERROR $0: cannot open log file: $log\n";
  LOG->autoflush;
  print LOG "$0 @ARGV\n\n";			#save command line that was used
  
  print LOG "*** scene id: $id  processing log file: $log  start time: $time ***\n";  
  $proc_par = "$raw_dir"."\/p$id.slc.par";	#create processing parameter file name
  -f $proc_par or die "ERROR $0: MSP processing parameter file does not exist: $proc_par\n";

  $sensor = "$raw_dir/RSAT_".$fields[0].".par";
  -f $sensor or die "ERROR $0: MSP sensor parameter file does not exist: $sensor\n";

  print "MSP processing parameter file: $proc_par\n";
  print "MSP sensor parameter file: $sensor\n";
  print LOG "MSP processing parameter file: $proc_par\n";
  print LOG "MSP sensor parameter file: $sensor\n";
  print LOG "azimuth patch size (lines): $az_patch\n";
  print LOG "autofocus SNR threshold: $af_snr\n";
   
  @ant_pattern = extract_param($sensor,"antenna_pattern_filename:");	#check if antenna pattern exists

  unless(-e $ant_pattern[1]) {
    $antp = $MSP_HOME."/sensors/".$ant_pattern[1];
    print "antenna pattern filename: ",$antp,"\n";
    $exit = system("cp $antp .");
    $exit == 0 or die <<EOS ;

    ERROR: non-zero exit status: "cp $antp ."
    The default location for the Radarsat antenna pattern files is \$MSP_HOME/sensors

EOS
  }
  
  print "antenna pattern file: $ant_pattern[1]\n\n";
  print LOG "antenna pattern file: $ant_pattern[1]\n\n";
  
  $raw = "$raw_dir/$id.fix";   	#check if raw data file exists
  -e $raw or die "ERROR $0: RSAT raw data file does not exist: $raw\n";
  $azsp = "$id.azsp";
  $rspec = "$id.rspec";
  $rc = "$rc_dir/$id.rc";
  $slc = "$slc_dir/$id.slc";
  $mli = "$mli_dir/$id.mli";
  $proc_mli_par = "p$id.mli.par";
  $isp_slc_par = "$slc_dir/$id.slc.par";
  $isp_mli_par = "$mli_dir/$id.mli.par";
  $slc_type = 0;	#sigma0
  $k_beta = 2.12;	#Kaiser window beta (1.0 = -20 db sidelobes, 2.12 = -30 dB sidelobes)

  @sensor_name = extract_param($sensor,"sensor_name:");
  @date = extract_param($proc_par, "date:");
  $year = $date[1];
  print LOG "SAR sensor name:   $sensor_name[1]   year of acquisition: $year\n";
  $cal_fact = -17.0;

  if($slc_format == 1){$cal_fact += 60.0;}
  print LOG "calibration factor (dB): $cal_fact\n";
  print LOG "minimum autofocus SNR: $autof_snr\n";
  print LOG "azimuth Kaiser window beta: $k_beta\n";
  print LOG "raw data file:         $raw\n";
  print LOG "range spectrum file:   $rspec\n";
  print LOG "azimuth spectrum file: $azsp\n";
  print LOG "SLC output image:      $slc\n";
  print LOG "MSP MLI proc file:     $proc_mli_par\n";
  print LOG "MLI output image:      $mli\n\n";
  close LOG;		

# column entries must be valid numbers or -
  
  $fields[1] =~ /\d+$|-$/ or die "ERROR $0: invalid offset to first echo to process: $fields[1]\n";
  $fields[2] =~ /\d+$|-$/ or die "ERROR $0: invalid number of lines to process: $fields[2]\n";
  $fields[3] =~ /\d+$|-$/ or die "ERROR $0: invalid range sample offset:$fields[3]\n";
  $fields[4] =~ /\d+$|-$/ or die "ERROR $0: invalid number of range samples: $fields[4]\n";

  $fields[1] =~ /-/ or execute("set_value $proc_par $proc_par offset_to_first_echo_to_process $fields[1]",$log);  
  $fields[2] =~ /-/ or execute("set_value $proc_par $proc_par echoes_to_process $fields[2]",$log);
  $fields[3] =~ /-/ or execute("set_value $proc_par $proc_par range_offset $fields[3]",$log);
  $fields[4] =~ /-/ or execute("set_value $proc_par $proc_par raw_range_samples $fields[4]",$log);
  @dop = extract_param($proc_par,"doppler_polynomial:");

  if( $fields[5] ne "-"){$dop[1] = sprintf "%10.3f", $fields[5];}   #update doppler parameters
  if( $fields[6] ne "-"){$dop[2] = sprintf "%12.5e", $fields[6];}
  if($fields[7] ne "-"){
    ($fields[7] >= 0.2 && $fields[7] <= 1.0) or die "ERROR $0: invalid azimuth processing bandwidth fraction: $fields[7]\n";
    execute("set_value $proc_par $proc_par azimuth_bandwidth_fraction $fields[7]",$log);
  }   
 
  execute("set_value $proc_par $proc_par doppler_polynomial \"$dop[1] $dop[2]  0.0  0.0\" ",$log);
   
#  execute("rspec_IQ $sensor $proc_par $raw $rspec",$log);

  execute("pre_rc_RSAT $sensor $proc_par $raw $rc",$log);
  execute("az_proc $sensor $proc_par $rc $slc $az_patch $slc_format $cal_fact $slc_type $k_beta",$log);
  eval{
    execute("af $sensor $proc_par $slc - - $af_dr $af_daz $af_snr 1 0 0 - 1 $af_ovr",$log);
  } or do {
    goto MULTI;
  }; 
  
  execute("az_proc $sensor $proc_par $rc $slc $az_patch $slc_format $cal_fact $slc_type $k_beta",$log);
  eval{
    execute("af $sensor $proc_par $slc - - $af_dr $af_daz $af_snr 1 0 0 - 1 $af_ovr",$log);
   } or do {
    goto MULTI;
  };
  
MULTI:
  execute("multi_SLC $proc_par $proc_mli_par $slc $mli $rlks $azlks",$log);
  @width = extract_param($proc_mli_par, "range_pixels:");       #width of MLI image
  execute("raspwr $mli $width[1] 1 0 1 1 1 $mli.bmp",$log);
  execute("par_MSP $sensor $proc_par $isp_slc_par",$log);	#create ISP image parameter files 
  execute("par_MSP $sensor $proc_mli_par $isp_mli_par",$log);

  open(LOG,">>${log}") or die "ERROR $0: cannot open log file: $log\n\n";
  $time = localtime;
  if (-e $rc) {
    unlink $rc;
  }
  print "\nprocessing end: $time\n\n";
  print LOG "\nprocessing end: $time\n\n";
  close LOG;
} 
exit 0;

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

sub extract_param{
  my ($infile,$keyword) = @_;
  open(PAR_IN,$infile) || die "ERROR $0: 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 "ERROR $0: keyword $keyword not found in file: $infile\n";
}

