//////////////////////////////////////
// Cunren Liang, NASA JPL/Caltech
// Copyright 2017
//////////////////////////////////////


// program for mosaicking multiple consecutive subswaths
// Cunren Liang, 03-JUN-2015
// JPL/Caltech

//////////////////////////////////////////////////////////////////
//update history
//12-APR-2016, CL. output data of both adjacent subswaths as BIL
//                 file, instead of output the difference.
//////////////////////////////////////////////////////////////////


#include "resamp.h"

//int main(int argc, char *argv[]){
int mosaicsubswath(char *outputfile, int nrgout, int nazout, int delta, int diffflag, int n, char **inputfile, int *nrgin, int *nrgoff, int *nazoff, float *phc, int *oflag){

  FILE **infp;
  FILE *outfp;
  
  fcomplex **in;
  fcomplex *out, out1, out2;
  //fcomplex *leftoverlap;
  //fcomplex *rightoverlap;
  fcomplex tmp;
  int cnt;
  
  //int n;
  //int *nrgin;
  int *nazin;
  //int *nrgoff;
  //int *nazoff;
  //int *oflag;
  //int nrgout;
  //int nazout;
  int nrginmax;

  int los, loe, low; //start, end and width of left overlap area
  int ros, roe, row; //start, end and width of right overlap area
  int cnw; //width of center area

  int paroff;
  int parcyc;

  char diffname[256][256];
  FILE **difffp;
  fcomplex **diff;
  fcomplex **diff2;
  //int diffflag;
  //diffflag = 0;

  int ns;
  float r;

  int i, j, k, l;

  //int delta; //edge to be removed of the overlap area (number of samples)
  //delta = 20;


  // if(argc < 5){
  //   fprintf(stderr, "\nUsage: %s outputfile nrgout nazout delta diffflag n [inputfile0] [nrgin0] [nrgoff0] [nazoff0] [oflag0] (repeat...)\n\n", argv[0]);
  //   fprintf(stderr, "  for each frame\n");
  //   fprintf(stderr, "  range offset is relative to the first sample of last subswath\n");
  //   fprintf(stderr, "  azimuth offset is relative to the uppermost line\n\n");
  //   exit(1);
  // }


  //read mandatory parameters
  outfp    = openfile(outputfile, "wb");
  //nrgout   = atoi(argv[2]);
  //nazout   = atoi(argv[3]);
  //delta    = atoi(argv[4]);
  //diffflag = atoi(argv[5]);
  //n        = atoi(argv[6]);


  //allocate memory
  infp   = array1d_FILE(n);
  //nrgin  = array1d_int(n);
  nazin  = array1d_int(n);
  //nrgoff = array1d_int(n); //nrgoff must be <= 0
  //nazoff = array1d_int(n); //nazoff must be <= 0
  //oflag  = array1d_int(n);

  difffp = array1d_FILE(n - 1);

  //read optional parameters
  paroff = 6;
  parcyc = 5;
  for(i = 0; i < n; i++){
    infp[i] = openfile(inputfile[i], "rb");
    //nrgin[i] = atoi(argv[paroff + parcyc*i + 2]);
    //nrgoff[i] = atoi(argv[paroff + parcyc*i + 3]);
    //nazoff[i] = atoi(argv[paroff + parcyc*i + 4]);
    //oflag[i] = atoi(argv[paroff + parcyc*i + 5]);
    nazin[i] = file_length(infp[i], nrgin[i], sizeof(fcomplex));
    if(nrgoff[i] > 0){
      fprintf(stderr,"Error: positive range offset: %d\n\n", nrgoff[i]);
      exit(1);
    }
    if(nazoff[i] > 0){
      fprintf(stderr,"Error: positive azimuth offset: %d\n\n", nazoff[i]);
      exit(1);
    }
    if(nazout < nazin[i] - nazoff[i]){
      fprintf(stderr,"Error: ouput length < nazin[%d] - nazoff[%d], %d, %d\n\n", i, i, nazout, nazin[i] - nazoff[i]);
      exit(1);
    }
  }

  //find max width
  nrginmax = nrgin[0];
  for(i = 0; i < n; i++)
    if(nrgin[i] > nrginmax)
      nrginmax = nrgin[i];

  in   = array2d_fcomplex(n, nrginmax);
  out  = array1d_fcomplex(nrgout);
  //out1 = array1d_fcomplex(nrginmax);
  //out2 = array1d_fcomplex(nrginmax);
  diff = array2d_fcomplex(n-1, nrginmax);
  diff2 = array2d_fcomplex(n-1, nrginmax);

  if(diffflag == 0)
    for(i = 0; i < n - 1; i++){
      sprintf(diffname[i], "%d-%d.int", i, i+1);
      difffp[i] = openfile(diffname[i], "wb");
    }


  for(i = 0; i < nazout; i++){

    if((i + 1) % 1000 == 0)
      fprintf(stderr,"processing line: %6d of %6d\r", i + 1, nazout);
    if(i + 1 == nazout)
      fprintf(stderr,"processing line: %6d of %6d\n\n", i + 1, nazout);

    //prepare for writing data
    for(j = 0; j < nrgout; j++){
      out[j].re = 0.0;
      out[j].im = 0.0;
    }

    //prepare for reading data
    for(j = 0; j < n; j++){
      for(k = 0; k < nrginmax; k++){
        in[j][k].re = 0.0;
        in[j][k].im = 0.0;
      }
    }

    for(j = 0; j < n; j++){
      if(i + nazoff[j] >= 0 && i + nazoff[j] <= nazin[j] - 1)
        readdata((fcomplex *)in[j], nrgin[j] * sizeof(fcomplex), infp[j]);
      
      if(phc[j]!=0.0){
        tmp.re = cos(phc[j]);
        tmp.im = sin(phc[j]);
        for(k = 0; k < nrgin[j]; k++)
          in[j][k] = cmul(in[j][k], tmp);
      }
    }


    cnt = 0;
    for(j = 0; j < n; j++){

      //we follow the following convention: line and column number start with 0.
      //left overlap area of subswath j
      if(j != 0){
        los = - nrgoff[j];
        loe = nrgin[j-1] - 1;
        low = loe - los + 1;
        if(low < delta * 2){
          fprintf(stderr,"Error: not enough overlap area between subswath: %d and %d\n\n", j-1, j);
          exit(1);
        }
      }
      else{
        los = 0;
        loe = 0;
        low = 0;
      }

      //right overlap area of subswath j
      if(j != n - 1){
        ros = - nrgoff[j+1];
        roe = nrgin[j] - 1;
        row = roe - ros + 1;
        if(row < delta * 2){
          fprintf(stderr,"Error: not enough overlap area between subswath: %d and %d\n\n", j, j+1);
          exit(1);
        }
      }
      else{
        ros = 0;
        roe = 0;
        row = 0;
      }

      //center non-overlap area of subswath j
      //should add a check here?
      cnw = nrgin[j] - low - row;

      //deal with center non-overlap area.
      //this only excludes the right overlap area for the first subswath
      //this only excludes the left overlap area for the last subswath
      for(k = 0; k < cnw; k++){
        out[cnt + k].re = in[j][low + k].re;
        out[cnt + k].im = in[j][low + k].im;
      }
      cnt += cnw;

      //deal with right overlap area of subswath j, which is also the left overlap area
      //of subswath j + 1 (next subswath)
      
      //for last subswath, just skip
      if(j == n - 1){
        break;
      }


      for(k = 0; k < nrginmax; k++){
        diff[j][k].re = 0.0;
        diff[j][k].im = 0.0;
        diff2[j][k].re = 0.0;
        diff2[j][k].im = 0.0;
      }

      for(k = 0; k < row; k++){

        
        out1.re = in[j][low + cnw + k].re;
        out1.im = in[j][low + cnw + k].im;
        out2.re = in[j+1][k].re;
        out2.im = in[j+1][k].im;

        //left edge of overlap area
        //use current subswath: subswath j
        if(k < delta){
          out[cnt + k].re = out1.re;
          out[cnt + k].im = out1.im;
        }
        else if(k >= delta && k < row - delta){

          //output difference of overlap area
          //diffflag 0: subswath j phase - subswath j+1 phase
          if(diffflag == 0){
            if(out1.re != 0.0 && out1.im != 0.0 && out2.re != 0.0 && out2.im != 0.0){
              //diff[j][k - delta] = cmul(out1, cconj(out2));
              diff[j][k - delta] = out1;
              diff2[j][k - delta] = out2;
            }
          }
          //diffflag 1: subswath j - subswath j+1
          //else if(diffflag == 1){
          //  if(out1.re != 0.0 && out1.im != 0.0 && out2.re != 0.0 && out2.im != 0.0){
          //    diff[j][k - delta].re = out1.re - out2.re;
          //    diff[j][k - delta].im = out1.im - out2.im;
          //  }
          //}
          else{
            ;
          }

          //mosaic overlap area
          //case 0: mosaic at the center of overlap area
          if(oflag[j] == 0){
            if(k < row / 2){
              //avoid holes, Cunren Liang, Dec. 18, 2015.
              if(out1.re != 0.0 && out1.im != 0.0){
                out[cnt + k].re = out1.re;
                out[cnt + k].im = out1.im;
              }
              else{
                out[cnt + k].re = out2.re;
                out[cnt + k].im = out2.im;                
              }
            }
            else{
              //avoid holes, Cunren Liang, Dec. 18, 2015.
              if(out2.re != 0.0 && out2.im != 0.0){
                out[cnt + k].re = out2.re;
                out[cnt + k].im = out2.im;
              }
              else{
                out[cnt + k].re = out1.re;
                out[cnt + k].im = out1.im;                
              }
            }
          }
          //case 1: mosaic at the right egde of overlap area
          else if(oflag[j] == 1){
            out[cnt + k].re = out1.re;
            out[cnt + k].im = out1.im;
          }
          //case 2: mosaic at the left edge of overlap area
          else if(oflag[j] == 2){
            out[cnt + k].re = out2.re;
            out[cnt + k].im = out2.im;
          }
          //case 3: add overlap area
          else if(oflag[j] == 3){
            out[cnt + k].re = out1.re + out2.re;
            out[cnt + k].im = out1.im + out2.im;

            if(out1.re != 0.0 && out1.im != 0.0 && out2.re != 0.0 && out2.im != 0.0){
              out[cnt + k].re /= 2.0;
              out[cnt + k].im /= 2.0;
            }

          }
          //case 4: add by weight determined by distance to overlap center
          //perform overlapp area smoothing using a method discribed in:
          //C. Liang, Q. Zeng, J. Jia, J. Jiao, and X. Cui, ScanSAR interferometric processing
          //using existing standard InSAR software for measuring large scale land deformation
          //Computers & Geosciences, 2013.
          else{
            l = k - delta + 1; // l start with 1
            ns = row - 2 * delta;
            
            if(out1.re != 0.0 && out1.im != 0.0 && out2.re != 0.0 && out2.im != 0.0){
              r = sqrt((out1.re * out1.re + out1.im * out1.im) / (out2.re * out2.re + out2.im * out2.im));
              out[cnt + k].re = ((ns - l + 0.5) * out1.re + r * (l - 0.5) * out2.re) / ns;
              out[cnt + k].im = ((ns - l + 0.5) * out1.im + r * (l - 0.5) * out2.im) / ns;
            }
            else{
              out[cnt + k].re = out1.re + out2.re;
              out[cnt + k].im = out1.im + out2.im;
            }
          }
          //cnt += row - 2 * delta;
        }
        //right edge of overlap area
        //use next subswath: subswath j+1
        //else if(k >= row - delta){
        else{
          out[cnt + k].re = out2.re;
          out[cnt + k].im = out2.im;
        }
        //cnt += 1;
      }
      cnt += row;

      if(diffflag == 0){
        writedata((fcomplex *)diff[j], (row - 2 * delta) * sizeof(fcomplex), difffp[j]);
        writedata((fcomplex *)diff2[j], (row - 2 * delta) * sizeof(fcomplex), difffp[j]);
      }

    } //loop of j, subswath
    writedata((fcomplex *)out, nrgout * sizeof(fcomplex), outfp);
  } //loop of i, output line

  for(i = 0; i < n; i++)
    fclose(infp[i]);
  fclose(outfp);

  if(diffflag == 0)
    for(i = 0; i < n - 1; i++)
      fclose(difffp[i]);

  free_array1d_FILE(infp);
  free_array1d_FILE(difffp);

  free_array2d_fcomplex(in);
  free_array1d_fcomplex(out);

  //free_array1d_int(nrgin);
  free_array1d_int(nazin);
  //free_array1d_int(nrgoff); //nrgoff must be <= 0
  //free_array1d_int(nazoff); //nazoff must be <= 0
  //free_array1d_int(oflag);

  free_array2d_fcomplex(diff);
  free_array2d_fcomplex(diff2);

  return 0;

}
