/******************************************************************************

   This file is a part of the

             COMPLEX PSEUDO-RAW SAR IMAGE PROCESSING TOOLBOX

   Copyright (C) 2017 Rémy Abergel (Remy.Abergel AT parisdescartes.fr), Loïc
   Denis (Loic.Denis AT univ-st-etienne.fr), Saïd Ladjal (Said.Ladjal AT
   telecom-paristech.fr) and Florence Tupin (Florence.Tupin AT
   telecom-paristech.fr).

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.

******************************************************************************/

/*
   Compilation (using gcc):
   ========================

   gcc -O3 irregularsampling.c irregularsampling_kernel.c tools.c tiffread.c tiffwrite.c -lfftw3 -lm -ltiff -o irregularsampling


   Source file description:
   ========================

   This module contains a main function (with TIFF Input/Output support)
   associated to the irregular resampling scheme coming from the research papers

   [1] R. Abergel, S. Ladjal, F. Tupin and J.-M. Nicolas, ``A Complex Spectrum
       Based SAR Image Resampling Method with Restricted Target Sidelobes and
       Statistics Preservation'', in proceedings of the 2017 IEEE International
       Geoscience and Remote Sensing Symposium (IGARSS 2017).

   [2] R. Abergel, L. Denis, S. Ladjal and F. Tupin, ``Sub-pixellic Methods for
       Sidelobes Suppression and Strong Targets Extraction in Single Look
       Complex SAR Images'', preprint HAL-IMT, submitted in July 2017.

   Note: the work [2] corresponds to the revision of the manuscript entitled
   ``Sidelobes Suppression and Strong Targets Extraction in Single Look Complex
   SAR Images with Several Applications'' that we submitted in July 2017 (we
   changed the title according to one Reviewer's recommandation).

   The core functions of the algorithm are available in the source file
   'irregularsampling_kernel.c'.


   Documentation of the irregularsampling module:
   ==============================================

   See explanations in the source file 'irregularsampling_kernel.c', as well as
   in the plain-text file 'README.org' embedded at the root directory of this
   toolbox.

   Please refer to [1,2] for more details and explanations about the irregular
   resampling algorithm.

*/

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <fftw3.h>

#define ASSERT_ALLOC(cmd) if(NULL == (cmd)) { printf("Not enough memory\n"); exit(EXIT_FAILURE); }

extern void irregularsampling(fftw_complex*,fftw_complex*,fftw_complex*,int,int,int,int,char); // see source file 'irregularsampling_kernel.c'
extern int load_2pages_tiff_into_fftw_complex(fftw_complex**,int*,int*,char*,char); // see source file 'tiffread.c'
extern int save_2pages_striped_tiff_float_from_fftw_complex(char*,fftw_complex*,int,int,char); // see source file 'tiffwrite.c'


/* display_usage: display usage message in the user terminal */
static void display_usage()
{
  printf("\nIrregular resampling scheme for pseudo-raw SAR images.\n\n");
  printf("Usage: irregularsampling [-N N] [-K K] [-T T] [-v] [-vv] u0 v0\n\n");
  printf("   -N N    : (default = 20) number of tested translations\n");
  printf("   -K K    : (default = 25) locality parameter\n");
  printf("   -T T    : output local displacement field (stack of 2 TIFF Float images)\n");
  printf("   -v      : light verbose mode (display algorithm progression)\n");
  printf("   -vv     : heavy verbose mode (also display information about TIFF I/O)\n");
  printf("   u0      : input image (a stack of 2 TIFF images, see description below)\n");
  printf("   v0      : output image (a stack of 2 TIFF images, see description below)\n\n");
  printf("Description of the 2-pages TIFF I/O format :\n\n");
  printf("   Input (u0) is a complex-valued pseudo-raw images, it must be stored as a\n");
  printf("   stack of two images into a single TIFF file, such as the first (respectively\n");
  printf("   second) image of the stack represents the real (resp. imaginary) part of u0.\n\n");
  printf("   Output (v0) is the irregularly resampled image produced by this algorithm,\n");
  printf("   it is stored as a stack of two TIFF-float images using the same convention.\n\n");
  printf("   Optional output (T) is a stack of two TIFF-Float images, the first (resp. \n");
  printf("   second) image of the stack contains the horizontal (resp. vertical)\n");
  printf("   component of the displacement field.\n\n");
}


/* main function, including a simple hand-made parser */
int main(int argc, char **argv)
{

  char *filename_u0 = NULL,*filename_v0 = NULL,*filename_T = NULL,*Nvalue = NULL,*Kvalue = NULL,vflag,vvflag,verbose;
  fftw_complex *u0 = NULL, *v0 = NULL, *T = NULL;
  int Ntransl,K,i,err,nx,ny;
  vvflag = vflag = 0;

  /******************************************/
  /*            arguments parser            */
  /******************************************/

  /* main parser */
  for(i=1;i<argc;i++) {
    if (strcmp(argv[i],"-v") == 0) vflag = 1;
    else if (strcmp(argv[i],"-vv") == 0) vvflag = 1;
    else if (strcmp(argv[i],"-N") == 0) {
      if(i==argc-1) { display_usage(); printf("Error: option -N requires an argument\n\n"); return EXIT_FAILURE; }
      else {
	Nvalue = argv[i+1]; err = sscanf(Nvalue,"%d",&Ntransl); i++;
	if(err != 1) { display_usage(); printf("Error: could not retrieve properly the argument of option -N\n\n"); return EXIT_FAILURE; }
      }
    }
    else if (strcmp(argv[i],"-K") == 0) {
      if(i==argc-1) { display_usage(); printf("Error: option -K requires an argument\n\n"); return EXIT_FAILURE; }
      else {
	Kvalue = argv[i+1]; err = sscanf(Kvalue,"%d",&K); i++;
	if(err != 1) { display_usage(); printf("Error: could not retrieve properly the argument of option -K\n\n"); return EXIT_FAILURE; }
      }
    }
    else if (strcmp(argv[i],"-T") == 0) {
      if(i==argc-1) { display_usage(); printf("Error: option -T requires an argument\n\n"); return EXIT_FAILURE; }
      else { filename_T = argv[i+1]; i++; }
    }
    else if (NULL == filename_u0) filename_u0 = argv[i];
    else if (NULL == filename_v0) filename_v0 = argv[i];
    else { display_usage(); printf("Error: could not retrieve properly input arguments.\n\n"); return EXIT_FAILURE; }
  }

  /* set default values */
  if(NULL == Nvalue) Ntransl = 20;
  if(NULL == Kvalue) K = 25;

  /* check consistency */
  if ((NULL == filename_u0) || (NULL == filename_v0)) {
    display_usage();
    if (NULL == filename_u0) printf("Error: input 'u0' is missing\n\n");
    else if(NULL == filename_v0) printf("Error: output 'v0' is missing\n\n");
    return EXIT_FAILURE;
  }

  /* deal with verbose mode */
  verbose = vflag || vvflag;
  if(verbose) {
    printf("\nInput parameters\n");
    printf("================\n");
    printf("number of tested translations: N = %d\n",Ntransl);
    printf("locality parameter: K = %d\n\n",K);
  }

  /************************************************************/
  /* Open TIFF Image & get its graylevels in double precision */
  /************************************************************/
  if(verbose) {
    printf("Load input image and allocate memory\n");
    printf("====================================\n");
  }

  if(EXIT_FAILURE == load_2pages_tiff_into_fftw_complex(&u0,&nx,&ny,filename_u0,vvflag)) {
    if(!vvflag) printf("An error occured (try option -vv to get more information)\n");
    if(verbose) printf("Free memory and exit the program.\n\n");
   return EXIT_FAILURE;
  }

  if(vflag && !vvflag) printf("done\n\n");
  if(!vflag && vvflag) printf("\n");


  /*********************/
  /* Memory allocation */
  /*********************/
  ASSERT_ALLOC(v0 = (fftw_complex*) fftw_malloc (nx*ny*sizeof(fftw_complex)));
  if(filename_T) ASSERT_ALLOC(T = (fftw_complex*) fftw_malloc (nx*ny*sizeof(fftw_complex)));


  /***********************************/
  /* KERNEL: process the input image */
  /***********************************/
  if(verbose) {
    printf("Start the irregular resampling procedure\n");
    printf("========================================\n");
  }
  irregularsampling(v0,T,u0,nx,ny,Ntransl,K,verbose);

  /********************************/
  /* Write output as a TIFF Image */
  /********************************/
  if(verbose) {
    printf("Save output(s) as Stack(s) of two TIFF images\n");
    printf("=============================================\n");
  }
  if(EXIT_FAILURE == save_2pages_striped_tiff_float_from_fftw_complex(filename_v0,v0,nx,ny,vvflag)) {
    if(!vvflag) printf("An error occured (try option -vv to get more information)\n");
    if(vflag || vvflag) printf("Free memory and exit the program.\n\n");
    free(u0);
    if(T) free(T);
    return EXIT_FAILURE;
  }
  if(T && EXIT_FAILURE == save_2pages_striped_tiff_float_from_fftw_complex(filename_T,T,nx,ny,vvflag)) {
    if(!vvflag) printf("An error occured (try option -vv to get more information)\n");
    if(vflag || vvflag) printf("Free memory and exit the program.\n\n");
    free(u0);
    free(T);
    return EXIT_FAILURE;
  }

  /***************/
  /* free memory */
  /***************/
  fftw_free(u0);
  fftw_free(v0);
  if(NULL != T) fftw_free(T);
  if(vflag && !vvflag) printf("done\n\n");
  if(!vflag && vvflag) printf("\n");

  return EXIT_SUCCESS;
}
