/*                                                                            *
 *   This file is part of the ESO X-shooter Pipeline                          *
 *   Copyright (C) 2006 European Southern Observatory                         *
 *                                                                            *
 *   This library 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 2 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, write to the Free Software              *
 *   Foundation, 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA     *
 *                                                                            */

/*
 * $Author: amodigli $
 * $Date: 2013-01-31 08:05:57 $
 * $Revision: 1.20 $
 */
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

/*--------------------------------------------------------------------------*/
/**
 * @defgroup unit_tests Unit Tests
 *
 */
/**
 * @defgroup test_xsh_compute_noise  Test Compute Noisy Pixels
 * @ingroup unit_tests

 */
/*--------------------------------------------------------------------------*/
/**@{*/

/*---------------------------------------------------------------------------
                                Includes
 ---------------------------------------------------------------------------*/


#include <xsh_data_pre.h>
#include <xsh_error.h>
#include <xsh_msg.h>
#include <xsh_data_instrument.h>
#include <xsh_badpixelmap.h>
#include <xsh_dfs.h>
#include <xsh_pfits.h>
#include <tests.h>
#include <cpl.h>
#include <math.h>
#include <getopt.h>
/*---------------------------------------------------------------------------
                            Defines
 ---------------------------------------------------------------------------*/
#define MODULE_ID "XSH_COMPUTE_NOISE_MAP"
/*---------------------------------------------------------------------------
                         Functions prototypes
 ---------------------------------------------------------------------------*/
cpl_frameset * add_noisy_pixels( cpl_frameset *set, 
  xsh_instrument* instrument);
int verify_noisy( cpl_frame * frame, xsh_instrument* instrument);
/*--------------------------------------------------------------------------*/
/**
  @brief    Unit test of XSH_SUBTRACT
  @return   0 iff success

  Test the Data Reduction Library function XSH_SUBTRACT
 */
/*--------------------------------------------------------------------------*/

cpl_frameset * add_noisy_pixels( cpl_frameset *set,
				 xsh_instrument* instrument )
{
  /* Add a noisy pixel somewhere in the frame.
     for a given pixel, take the avvg value of the frames
     and add or subtract 1/2 of the value.
     Should make a noisy pixel !
  */
  cpl_frameset * newset = NULL ;
  int ix = 10, iy = 10 ;
  int i = 0 ;
  cpl_frame *current ;
  float avg = 0., noise ;

  cpl_frame_group group   ;
  /* Get the values at position ix,iy
     Calculate average
     Add noise
  */
  current = cpl_frameset_get_first( set ) ;
  assure( current != NULL, cpl_error_get_code(),
	  "Cant get current" ) ;

  group = cpl_frame_get_group( current ) ;

  do {
    xsh_pre * pre ;
    int rej ;
    float val ;

    pre = xsh_pre_load( current, instrument ) ;
    assure( pre != NULL, cpl_error_get_code(),
	    "Cant pre load" ) ;
    xsh_instrument_set_recipe_id( instrument, "xsh_mdark" ) ;

    val = cpl_image_get( pre->data, ix, iy, &rej ) ;
    xsh_msg( "Current value (%d): %f", i, val ) ;
    avg += val ;
    xsh_pre_free( &pre ) ;
    i++ ;
  } while( (current = cpl_frameset_get_next( set )) != NULL ) ;
  avg /= (float)i ;
  xsh_msg( "   avg: %f", avg ) ;

  noise = avg/2. ;

  current = cpl_frameset_get_first( set ) ;
  newset = cpl_frameset_new();
  assure( newset != NULL, cpl_error_get_code(),
	  "Cant create new framesey" ) ;
  i = 0 ;
  do {
    xsh_pre * pre ;
    char fname[128] ;
    char tag[128] ;
    cpl_frame * noisy = NULL ;

    pre = xsh_pre_load( current, instrument ) ;
    cpl_image_set( pre->data, ix, iy, noise ) ;
    xsh_msg( "  --> new value (%d): %f", i, noise ) ;
    sprintf( fname, "noisy_%d.fits", i ) ;
    sprintf( tag, "noisy_%d", i ) ;
    xsh_msg( "Save frame %s", fname ) ;
    noisy = xsh_pre_save( pre, fname, tag,1 ) ;
    assure( noisy != NULL, cpl_error_get_code(),
	    "Cant save %s", fname ) ;
    cpl_frame_set_filename( noisy, fname);
    cpl_frame_set_group( noisy, group);
    cpl_frame_set_tag( noisy, tag);
    noise *= 2. ;
    xsh_pre_free( &pre ) ;
    i++ ;
    //xsh_msg( "newset: %x - noisy: %x", newset, noisy ) ;
    check_msg( cpl_frameset_insert( newset, noisy ),
	       "Cant insert noisy frame into newset" ) ;
  } while( (current = cpl_frameset_get_next( set ) ) != NULL ) ;

 cleanup:
  return newset ;
}

static cpl_frame* create_frame(const char* name,int nx, int ny,
			       const char* tag, cpl_frame_group group,
			       xsh_instrument* instrument,
			       int norm )
{
  
  XSH_INSTRCONFIG * iconfig = NULL ;
  cpl_propertylist* header = NULL;
  cpl_image* data = NULL;
  cpl_frame *frame = NULL;

  iconfig = xsh_instrument_get_config( instrument ) ;
  header = cpl_propertylist_new();
  setHeader(header, iconfig, nx, ny, 1. );
  xsh_msg("name=%s",name);
  check(xsh_pfits_set_dit (header,1.));
  check(xsh_pfits_set_ndit (header,1));
  /* Special NIR */
  check_msg( cpl_propertylist_append_double( header, XSH_DET_PXSPACE,
					     iconfig->pxspace),
             "Cant append GAIN" ) ;

  data = cpl_image_new(nx,ny,XSH_PRE_DATA_TYPE);
  cpl_image_fill_gaussian(data,
			  nx / 3.0, ny / 3.0,     /* center */
			  norm,     /* norm */
			  nx, ny / 8.0); /* sigma */
  cpl_image_save(data,name,XSH_PRE_DATA_BPP,header,
		 CPL_IO_DEFAULT);

  /* Create test frame */
  frame = cpl_frame_new();
  cpl_frame_set_filename(frame,name);
  cpl_frame_set_group(frame,group);
  cpl_frame_set_tag(frame,tag);
  
 cleanup:
  xsh_free_propertylist(&header);
  xsh_free_image(&data);
  
  return frame;
}

int verify_noisy( cpl_frame * frame, xsh_instrument* instrument )
{
  /* One should find 1 noisy pixel in the Qual image of the frame */
  xsh_pre *pre = NULL ;
  int count = 0 ;

  pre = xsh_pre_load( frame, instrument ) ;
  assure( pre != NULL, cpl_error_get_code(),
	    "Cant pre load" ) ;
  /* Get the QC parameter */
  /* Check how many bad pixels in QUAL image */
  count = xsh_bpmap_count( pre->qual, pre->nx, pre->ny ) ;
  xsh_msg( "Number of bad pixels: %d (should be 1)", count ) ;
  xsh_pre_free( &pre ) ;

 cleanup:
  if ( count == 1 ) return 0;
  else return 1 ;
}

int main(void)
{
  xsh_instrument * instrument = NULL ;
  cpl_frameset* set = NULL;
  cpl_frameset *newset = NULL ;
  cpl_frame* medFrame = NULL;
  cpl_frame* Master = NULL;
  cpl_frame* frame = NULL;
#if defined(PICKUP_NOISE_HOT_PIXEL_MAP)
  cpl_frame * noise_map = NULL ;
#endif
  xsh_clipping_param crh_clipping ;
  xsh_clipping_param noise_clipping ;
  cpl_imagelist *Liste ;
  int i = 0;
  int nx = 100, ny = 100 ;	/**< Image size */
  int nframes = 3 ;		/**< Nb of dark frames */
  int norme = 48 ;
  xsh_stack_param stack_param = {"median",5.,5.};
  int decode_bp=QFLAG_OUTSIDE_DATA_RANGE;
  /* Initialize libraries */
  TESTS_INIT_WORKSPACE(MODULE_ID);
  TESTS_INIT(MODULE_ID);

  /* Create valid instrument */
  instrument = xsh_instrument_new() ;
  xsh_instrument_set_mode( instrument, XSH_MODE_IFU ) ;
  xsh_instrument_set_arm( instrument, XSH_ARM_NIR ) ;
  xsh_instrument_set_decode_bp( instrument, decode_bp ) ;
  /* Create three frames in frameset */
  set = cpl_frameset_new();

  for(i=0;i<nframes;i++){
    char framename[256];
    sprintf(framename,"frame%d.fits",i);
    frame = create_frame(framename, nx, ny,
			 XSH_DARK_NIR,CPL_FRAME_GROUP_RAW, instrument,
			 norme );
    cpl_frameset_insert(set,frame);
    norme += 2 ;
  }

  /* USE prepare function (no BpMap) */
  check(xsh_prepare(set, NULL, NULL,"PRE",instrument,0,CPL_FALSE));

  /* Add a few noisy pixels in the frames */
  newset = add_noisy_pixels( set, instrument ) ;

  /* Set the crh_clipping parameters (default values ) */
  crh_clipping.sigma = 5. ;
  crh_clipping.niter = 2 ;
  crh_clipping.frac = 0.7 ;

  /* Set the noise_clipping parameters (default values ) */
  noise_clipping.sigma = 5. ;
  noise_clipping.niter = 3 ;
  noise_clipping.frac = 0.7 ;
  noise_clipping.diff = 0.7 ;

  /* run remove_crh_multi (should not found any Cosmic !) */
  xsh_msg("param method=%s",stack_param.stack_method);
  check( medFrame = xsh_remove_crh_multiple( newset, "remove_crh.fits",
					     &stack_param,&crh_clipping,
                                             instrument,
					     &Liste,NULL,0 ) ) ;

  /* TEST1 : test the compute_noise_map function */
#if defined(PICKUP_NOISE_HOT_PIXEL_MAP)
  check( Master = xsh_compute_noise_map( Liste, medFrame, &noise_clipping,
					 instrument,&noise_map ) ) ;
#else
  check( Master = xsh_compute_noise_map( Liste, medFrame, &noise_clipping,
					 instrument) ) ;
#endif
  /* Verify ==> check that the QUAL of the master contains the correct
     number of noisy pixels
  */
  verify_noisy( Master, instrument ) ;

  xsh_msg("Compute Noise OK");

cleanup:
  xsh_instrument_free(&instrument);
  xsh_free_frameset(&set);
  xsh_free_frameset(&newset);
  xsh_free_frame(&medFrame);
  xsh_free_frame( &Master ) ;
  xsh_free_frame(&noise_map);
  xsh_free_imagelist(&Liste);
  xsh_free_temporary_files();

  TESTS_CLEAN_WORKSPACE(MODULE_ID);
  if (cpl_error_get_code() != CPL_ERROR_NONE) {
    xsh_error_dump(CPL_MSG_ERROR);
    return 1;
  } else {
    return 0;
  }
}

/**@}*/
