/*                                                                            *
 *   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: 2012-04-26 14:10:08 $
 * $Revision: 1.10 $
 * $Name: not supported by cvs2svn $
 */
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

/*--------------------------------------------------------------------------*/
/**
 * @defgroup test_xsh_subtract_dark Test Subtract Dark
 * @ingroup unit_tests
 *
 */
/*--------------------------------------------------------------------------*/
/**@{*/

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


#include <xsh_data_pre.h>
#include <xsh_error.h>
#include <xsh_msg.h>
#include <xsh_data_instrument.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_SUBTRACT_DARK"

enum {
DEBUG_OPT, HELP_OPT
};

static struct option long_options[] = {
  {"debug", required_argument, 0, DEBUG_OPT},
  {"help", 0, 0, HELP_OPT},
  {0, 0, 0, 0}
};

static void Help( void )
{
  puts( "Unitary test of xsh_subtract_dark");
  puts( "Usage: test_xsh_subtract_dark [options] <input_files>");

  puts( "Options" ) ;
  puts( " --debug=<n>        : Level of debug LOW | MEDIUM | HIGH [MEDIUM]" );
  puts( " --help             : What you see" ) ;
  puts( "\nInput Files" ) ;
  puts( "The input files argument MUST be in this order:" ) ;
  puts( " 1. Science frame in PRE format" ) ;
  puts( " 2. SOF [MASTER_DARK]");
  TESTS_CLEAN_WORKSPACE(MODULE_ID);
  TEST_END();
  exit(0);
}

static void HandleOptions( int argc, char **argv)
{
  int opt ;
  int option_index = 0;
  while (( opt = getopt_long (argc, argv, "debug:help",
    long_options, &option_index)) != EOF ){

    switch ( opt ) {
    case DEBUG_OPT:
      if ( strcmp( optarg, "LOW")==0){
        xsh_debug_level_set( XSH_DEBUG_LEVEL_LOW);
      }
      else if ( strcmp( optarg, "HIGH")==0){
        xsh_debug_level_set( XSH_DEBUG_LEVEL_HIGH);
      }
      break;
    case HELP_OPT:
      Help();
      break;
    default:
      break;
    }
  }
  return;
}
/*---------------------------------------------------------------------------
                         Functions prototypes
 ---------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------*/
/**
  @brief    Unit test of XSH_SUBTRACT
  @return   0 iff success

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

int main(int argc, char** argv)
{
  xsh_instrument * instrument = NULL ;
  cpl_frameset* set = NULL;
  cpl_frame* frame = NULL;
  cpl_frame* dark = NULL;
  char* sci_name = NULL;
  char* sof_name = NULL;
  cpl_frame* temp = NULL;
  int i = 0;
  xsh_pre* pre1 = NULL;
  xsh_pre* pre2 = NULL;
  xsh_pre* pre3 = NULL;
  float *data1 = NULL,*errs1 = NULL;
  int * qual1 = NULL;
  float *data2 = NULL,*errs2 = NULL;
  int * qual2 = NULL;
  float *data3 = NULL,*errs3 = NULL;
  int * qual3 = NULL;
  int ret=0;
  const int decode_bp=2147483647;
  /* Initialize libraries */
  TESTS_INIT_WORKSPACE(MODULE_ID);
  TESTS_INIT(MODULE_ID);
  cpl_msg_set_level( CPL_MSG_DEBUG);
  xsh_debug_level_set( XSH_DEBUG_LEVEL_MEDIUM);

  HandleOptions( argc, argv);

  if ( (argc-optind) >= 2 ) {
    sci_name = argv[optind];
    sof_name = argv[optind+1];

    /* Create frameset from sof */
    check( set = sof_to_frameset( sof_name));

    /* Validate frame set */
    check( instrument = xsh_dfs_set_groups( set));
    check( dark = xsh_find_master_dark( set, instrument));
    TESTS_XSH_FRAME_CREATE( frame, "OBJECT_SLIT_STARE_arm", sci_name);
  }
  else{
    xsh_msg("-------------------------------------------");
    xsh_msg("Execute default test : do --help for option");
    xsh_msg("-------------------------------------------");
    /* Create valid instrument */
    instrument = xsh_instrument_new() ;
    xsh_instrument_set_mode( instrument, XSH_MODE_IFU ) ;
    xsh_instrument_set_arm( instrument, XSH_ARM_UVB ) ;
    xsh_instrument_set_lamp( instrument, XSH_LAMP_QTH ) ;

    /* Create two frames in frameset */
    set = cpl_frameset_new();
    for(i=0;i<2;i++){
      char framename[256];

      sprintf(framename,"frame%d.fits",i);
      frame = xsh_test_create_frame(framename,10,10,
        XSH_LINEARITY_UVB,CPL_FRAME_GROUP_RAW, instrument);
      cpl_frameset_insert(set,frame);
    }

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

    /* TEST2 : test the subtract_dark function */

    check( frame = cpl_frame_duplicate(cpl_frameset_get_frame(set,0)));
    check( dark = cpl_frameset_get_frame(set,1));
  }

  xsh_msg("SCI            : %s",
    cpl_frame_get_filename( frame));
  XSH_ASSURE_NOT_NULL( dark);
  xsh_msg("DARK           : %s",
    cpl_frame_get_filename( dark));
  xsh_instrument_set_decode_bp( instrument, decode_bp ) ;
  check( temp = xsh_subtract_dark(frame,dark, "tmp_sub.fits", instrument));

  check(pre1 = xsh_pre_load(temp,instrument));
  check(pre2 = xsh_pre_load(frame,instrument));
  check(pre3 = xsh_pre_load(dark,instrument));

  data1 = cpl_image_get_data_float(pre1->data);
  data2 = cpl_image_get_data_float(pre2->data);
  data3 = cpl_image_get_data_float(pre3->data);
  errs1 = cpl_image_get_data_float(pre1->errs);
  errs2 = cpl_image_get_data_float(pre2->errs);
  errs3 = cpl_image_get_data_float(pre3->errs);
  qual1 = cpl_image_get_data_int(pre1->qual);
  qual2 = cpl_image_get_data_int(pre2->qual);
  qual3 = cpl_image_get_data_int(pre3->qual);

  /* verify data, errs and qual */
  xsh_msg("exptime %f",pre2->exptime);
  for(i=0;i<100;i++){
    assure(data1[i] -(data2[i] -data3[i]*pre2->exptime) < XSH_FLOAT_PRECISION,
      CPL_ERROR_ILLEGAL_OUTPUT,"Wrong data part");
    assure(errs1[i] - (sqrt(errs2[i]*errs2[i]+errs3[i]*errs3[i]*pre2->exptime*
      pre2->exptime)) <
      XSH_FLOAT_PRECISION,CPL_ERROR_ILLEGAL_OUTPUT,"Wrong errs part");
    assure(qual1[i] == (qual2[i] + qual3[i]),CPL_ERROR_ILLEGAL_OUTPUT,
      "Wrong qual part");
  }
  xsh_msg("subtract dark ok");

  cleanup:
    xsh_free_frame( &frame); 
    xsh_pre_free(&pre1);
    xsh_pre_free(&pre2);
    xsh_pre_free(&pre3);
    xsh_instrument_free(&instrument);
    xsh_free_frameset(&set);
    xsh_free_frame(&temp);

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

/**@}*/
