/*                                                                           *
 *   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-03-18 15:15:17 $
 * $Revision: 1.33 $
 * $Name: not supported by cvs2svn $
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <math.h>

/*---------------------------------------------------------------------------*/
/**
 * @defgroup xsh_data_linetilt Line Tilt
 * @ingroup data_handling
 */
/*---------------------------------------------------------------------------*/

/**@{*/


/*-----------------------------------------------------------------------------
                                 Includes
 ----------------------------------------------------------------------------*/
#include <xsh_data_instrument.h>
#include <xsh_data_arclist.h>
#include <xsh_data_linetilt.h>
#include <xsh_utils.h>
#include <xsh_error.h>
#include <xsh_msg.h>
#include <xsh_pfits.h>
#include <xsh_dfs.h>
#include <cpl.h>
#include <xsh_utils_table.h>


#define XSH_MAX_SHIFT_Y 10.
/*----------------------------------------------------------------------------
                                 Function implementation
 ----------------------------------------------------------------------------*/

xsh_linetilt_list * xsh_linetilt_list_new( int size,
					   cpl_propertylist * header )
{
  xsh_linetilt_list * result = NULL ;

  XSH_ASSURE_NOT_NULL( header ) ;

  /* Create an empty list */
  check( result = cpl_malloc( sizeof( xsh_linetilt_list ) ) ) ;
  memset( result, 0, sizeof( xsh_linetilt_list ) ) ;

  check( result->list = cpl_malloc( sizeof( xsh_linetilt * ) * size ) ) ;
  memset( result->list, 0, sizeof( xsh_linetilt * )*size ) ;
  result->full_size = size ;
  result->header = header ;

 cleanup:
  return result ;
}
/**
  @brief free memory associated to a arclist
  @param list the arclist to free
 */
/*---------------------------------------------------------------------------*/
void xsh_linetilt_list_free( xsh_linetilt_list ** list)
{
  int i;
 
  if (list && *list) {
    if ((*list)->list) {
      for (i=0; i< (*list)->size; i++) {
        xsh_linetilt * tilt = (*list)->list[i];
        xsh_linetilt_free( &tilt );
      }
      cpl_free((*list)->list);
      xsh_free_propertylist(&((*list)->header));
    }
    cpl_free(*list);
    *list = NULL;
  }
}
/*---------------------------------------------------------------------------*/
/**
  @brief free memory associated to a linetilt
  @param tilt the linetilt to free
 */
/*---------------------------------------------------------------------------*/
void xsh_linetilt_free( xsh_linetilt ** tilt)
{
  if (tilt && (*tilt) ){
    if ((*tilt)->name != NULL) {
      cpl_free(( *tilt)->name );
    }
    cpl_free( *tilt );
    *tilt = NULL;
  }
}

xsh_linetilt * xsh_linetilt_new( void )
{
  xsh_linetilt * result = NULL ;

  XSH_CALLOC( result, xsh_linetilt, 1) ;

  cleanup:
    return result ;
}

/** 
 * Add a new entry to a linetilt list.
 * 
 * @param list Linetilt Liste 
 * @param line Pointer to the linetilt to add
 * @param idx Index where to add the linetilt
 */
void xsh_linetilt_list_add( xsh_linetilt_list * list,
			    xsh_linetilt * line, int idx )
{
  XSH_ASSURE_NOT_NULL( list ) ;
  XSH_ASSURE_NOT_NULL( line ) ;
  list->list[idx] = line ;
  list->size++ ;
 cleanup:
  return ;
}
/*---------------------------------------------------------------------------*/
/**
  @brief save a (ks clip clean) linetilt list to a frame
  @param list the linetilt list structure to save
  @param instr Pointer to instrument description structure
  @param filename the name of the save file on disk
  @param tag    the pro catg of the save file on disk
  @param kappa  kappa value of ks clip
  @param niter  niter value of ks clip
  @return a newly allocated frame

 */
/*---------------------------------------------------------------------------*/
cpl_frame* xsh_linetilt_list_save(xsh_linetilt_list * list,
				  xsh_instrument * instr,
				  const char* filename, 
                                  const char* tag, 
                                  const double kappa, 
                                  const int niter)
{
  cpl_table* table = NULL;
  cpl_table* ext = NULL;
  cpl_frame * result = NULL ;
  int i=0;
  //int j=0;
  //double med=0;
  //double rms=0;
  //double* pres=0;
  //int nrow=0;
  XSH_ASSURE_NOT_NULL(list);
  XSH_ASSURE_NOT_NULL(filename);
  
  /* create a table */
  check( table = cpl_table_new( XSH_LINETILT_TABLE_NB_COL));

  /* create column names */
  check(
    cpl_table_new_column(table,XSH_LINETILT_TABLE_COLNAME_WAVELENGTH,
      CPL_TYPE_FLOAT));
  check(
    cpl_table_set_column_unit ( table, XSH_LINETILT_TABLE_COLNAME_WAVELENGTH,
      XSH_LINETILT_TABLE_UNIT_WAVELENGTH));

  check(
    cpl_table_new_column(table,XSH_LINETILT_TABLE_COLNAME_NAME,
     CPL_TYPE_STRING));
  check(
    cpl_table_set_column_unit ( table, XSH_LINETILT_TABLE_COLNAME_NAME,
      XSH_LINETILT_TABLE_UNIT_NAME));

  check(
    cpl_table_new_column(table,XSH_LINETILT_TABLE_COLNAME_ORDER,
     CPL_TYPE_INT));
  check(
    cpl_table_set_column_unit ( table, XSH_LINETILT_TABLE_COLNAME_ORDER,
      XSH_LINETILT_TABLE_UNIT_ORDER));

  check(
    cpl_table_new_column(table,XSH_LINETILT_TABLE_COLNAME_FLUX,
     CPL_TYPE_DOUBLE));
  check(
    cpl_table_set_column_unit ( table, XSH_LINETILT_TABLE_COLNAME_FLUX,
      XSH_LINETILT_TABLE_UNIT_FLUX));

  check(
    cpl_table_new_column(table,XSH_LINETILT_TABLE_COLNAME_INTENSITY,
     CPL_TYPE_DOUBLE));
  check(
    cpl_table_set_column_unit ( table, XSH_LINETILT_TABLE_COLNAME_INTENSITY,
      XSH_LINETILT_TABLE_UNIT_INTENSITY));

  check(
    cpl_table_new_column(table,XSH_LINETILT_TABLE_COLNAME_CENPOSX,
     CPL_TYPE_DOUBLE));
  check(
    cpl_table_set_column_unit ( table, XSH_LINETILT_TABLE_COLNAME_CENPOSX,
      XSH_LINETILT_TABLE_UNIT_CENPOSX));

  check(
    cpl_table_new_column(table,XSH_LINETILT_TABLE_COLNAME_CENPOSY,
     CPL_TYPE_DOUBLE));
  check(
    cpl_table_set_column_unit ( table, XSH_LINETILT_TABLE_COLNAME_CENPOSY,
      XSH_LINETILT_TABLE_UNIT_CENPOSY));


  check(
    cpl_table_new_column(table,XSH_LINETILT_TABLE_COLNAME_GAUSSY,
     CPL_TYPE_DOUBLE));
  check(
    cpl_table_set_column_unit ( table, XSH_LINETILT_TABLE_COLNAME_GAUSSY,
      XSH_LINETILT_TABLE_UNIT_GAUSSY));

  check(
    cpl_table_new_column(table,XSH_LINETILT_TABLE_COLNAME_TILTY,
     CPL_TYPE_DOUBLE));
  check(
    cpl_table_set_column_unit ( table, XSH_LINETILT_TABLE_COLNAME_TILTY,
      XSH_LINETILT_TABLE_UNIT_TILTY));

  check(
    cpl_table_new_column(table,XSH_LINETILT_TABLE_COLNAME_FWHM,
     CPL_TYPE_DOUBLE));
  check(
    cpl_table_set_column_unit ( table, XSH_LINETILT_TABLE_COLNAME_FWHM,
      XSH_LINETILT_TABLE_UNIT_FWHM));

  check(
    cpl_table_new_column(table,XSH_LINETILT_TABLE_COLNAME_SHIFTY,
     CPL_TYPE_DOUBLE));
  check(
    cpl_table_set_column_unit ( table, XSH_LINETILT_TABLE_COLNAME_SHIFTY,
      XSH_LINETILT_TABLE_UNIT_SHIFTY));

  check(
    cpl_table_new_column(table,XSH_LINETILT_TABLE_COLNAME_TILT,
     CPL_TYPE_DOUBLE));
  check(
    cpl_table_set_column_unit ( table, XSH_LINETILT_TABLE_COLNAME_TILT,
      XSH_LINETILT_TABLE_UNIT_TILT));

  check(
    cpl_table_new_column(table,XSH_LINETILT_TABLE_COLNAME_CHISQ,
     CPL_TYPE_DOUBLE));
  check(
    cpl_table_set_column_unit ( table, XSH_LINETILT_TABLE_COLNAME_CHISQ,
      XSH_LINETILT_TABLE_UNIT_CHISQ));

    check(
	  cpl_table_new_column(table,XSH_LINETILT_TABLE_COLNAME_SPECRES,
			       CPL_TYPE_DOUBLE));
    check(
	  cpl_table_set_column_unit ( table, XSH_LINETILT_TABLE_COLNAME_SPECRES,
				      XSH_LINETILT_TABLE_UNIT_SPECRES));
    check(
	  cpl_table_new_column(table,XSH_LINETILT_TABLE_COLNAME_FLAG,
			       CPL_TYPE_INT));
    check(
	  cpl_table_set_column_unit ( table, XSH_LINETILT_TABLE_COLNAME_FLAG,
				      XSH_LINETILT_TABLE_UNIT_FLAG));




  check(cpl_table_set_size(table,list->size));

  /* insert data */
  for(i=0;i<list->size;i++){
      check(cpl_table_set_float(table,XSH_LINETILT_TABLE_COLNAME_WAVELENGTH,
        i,list->list[i]->wavelength));
      check(cpl_table_set_string(table,XSH_LINETILT_TABLE_COLNAME_NAME,
        i,list->list[i]->name));
      check(cpl_table_set_int(table,XSH_LINETILT_TABLE_COLNAME_ORDER,
        i,list->list[i]->order));
      check(cpl_table_set_double(table,XSH_LINETILT_TABLE_COLNAME_FLUX,
        i,list->list[i]->area));
      check(cpl_table_set_double(table,XSH_LINETILT_TABLE_COLNAME_INTENSITY,
        i,list->list[i]->intensity));
      check(cpl_table_set_double(table,XSH_LINETILT_TABLE_COLNAME_CENPOSX,
        i,list->list[i]->cenposx));
      check(cpl_table_set_double(table,XSH_LINETILT_TABLE_COLNAME_CENPOSY,
        i,list->list[i]->pre_pos_y));
      check(cpl_table_set_double(table,XSH_LINETILT_TABLE_COLNAME_GAUSSY,
        i,list->list[i]->cenposy));
      check(cpl_table_set_double(table,XSH_LINETILT_TABLE_COLNAME_TILTY,
        i,list->list[i]->tilt_y));
      check(cpl_table_set_double(table,XSH_LINETILT_TABLE_COLNAME_FWHM,
        i,list->list[i]->deltay));
      check(cpl_table_set_double(table,XSH_LINETILT_TABLE_COLNAME_SHIFTY,
        i,list->list[i]->shift_y));
      check(cpl_table_set_double(table,XSH_LINETILT_TABLE_COLNAME_TILT,
        i,list->list[i]->tilt));
      check(cpl_table_set_double(table,XSH_LINETILT_TABLE_COLNAME_CHISQ,
        i,list->list[i]->chisq));
 
	check(cpl_table_set_double(table,XSH_LINETILT_TABLE_COLNAME_SPECRES,
				   i,list->list[i]->specres));
	
        if( fabs(list->list[i]->shift_y)> XSH_MAX_SHIFT_Y ) {
	  list->list[i]->flag=3;
	  check(cpl_table_set_int(table,XSH_LINETILT_TABLE_COLNAME_FLAG,
	        i,3));
 
	}
	
        if(list->list[i]->flag>0) {
  	  cpl_table_set_invalid(table,XSH_LINETILT_TABLE_COLNAME_SHIFTY, i);
  	  cpl_table_set_invalid(table,XSH_LINETILT_TABLE_COLNAME_FWHM, i);
	  cpl_table_set_invalid(table,XSH_LINETILT_TABLE_COLNAME_INTENSITY, i);
	}
	check(cpl_table_set_int(table,XSH_LINETILT_TABLE_COLNAME_FLAG,
				i,list->list[i]->flag));
   }


  int k=0;
  double  yshift_std=0;
  double  yshift_avg=0;
  double* pshift=NULL;
  pshift=cpl_table_get_data_double(table,XSH_LINETILT_TABLE_COLNAME_SHIFTY);
  //PIPPO
  for(k=0;k<niter;k++) {
    yshift_std=cpl_table_get_column_stdev(table,XSH_LINETILT_TABLE_COLNAME_SHIFTY);
    yshift_avg=cpl_table_get_column_mean(table,XSH_LINETILT_TABLE_COLNAME_SHIFTY);
    for(i=0;i<list->size;i++){
      if( fabs(pshift[i]-yshift_avg) > kappa*yshift_std ) {
	list->list[i]->flag=4;
	cpl_table_set_invalid(table,XSH_LINETILT_TABLE_COLNAME_SHIFTY, i);
	cpl_table_set_invalid(table,XSH_LINETILT_TABLE_COLNAME_FWHM, i);
	cpl_table_set_invalid(table,XSH_LINETILT_TABLE_COLNAME_INTENSITY, i);
  check(cpl_table_set_int(table,XSH_LINETILT_TABLE_COLNAME_FLAG,
          i,4));
      }
    }
  }
  double avg;
  double med;
  double std;
  double wavg;
  double wstd;
  double iavg;

  avg = cpl_table_get_column_mean(table,XSH_LINETILT_TABLE_COLNAME_SHIFTY );
  med = cpl_table_get_column_median(table,XSH_LINETILT_TABLE_COLNAME_SHIFTY );
  std = cpl_table_get_column_stdev(table,XSH_LINETILT_TABLE_COLNAME_SHIFTY );

  wstd = cpl_table_get_column_stdev(table, XSH_LINETILT_TABLE_COLNAME_FWHM);
  wavg = cpl_table_get_column_mean(table, XSH_LINETILT_TABLE_COLNAME_FWHM);

  iavg = cpl_table_get_column_mean(table, XSH_LINETILT_TABLE_COLNAME_INTENSITY);

  xsh_pfits_set_qc( list->header, &avg, QC_WAVECAL_DIFFYAVG,instr );
  xsh_pfits_set_qc( list->header, &med, QC_WAVECAL_DIFFYMED,instr );
  xsh_pfits_set_qc( list->header, &std, QC_WAVECAL_DIFFYSTD,instr );
  xsh_pfits_set_qc( list->header, &iavg, QC_WAVECAL_NLININT,instr );
  xsh_pfits_set_qc( list->header, &wavg, QC_WAVECAL_FWHMAVG,instr );
  xsh_pfits_set_qc( list->header, &wstd, QC_WAVECAL_FWHMRMS,instr );

  /* create fits file */
  check( xsh_pfits_set_pcatg(list->header,tag));
  check(cpl_table_save(table, list->header, NULL, filename, CPL_IO_DEFAULT));

  /* Create the frame */
  check(result=xsh_frame_product(filename,
				 XSH_GET_TAG_FROM_MODE( XSH_TILT_TAB, instr),
				 CPL_FRAME_TYPE_TABLE,
				 CPL_FRAME_GROUP_PRODUCT,
				 CPL_FRAME_LEVEL_TEMPORARY));
  xsh_add_temporary_file( filename ) ;

  cleanup:
  xsh_free_table(&ext);
    XSH_TABLE_FREE( table);
    return result ;
}


/**
 * @brief get the X central positions. The returned array must be
 * deallocated by the caller.
 *
 * @param list The tilt-list
 * @return return a created array of X positions
 */
/*---------------------------------------------------------------------------*/
double * xsh_linetilt_list_get_posx( xsh_linetilt_list * list)
{
  double* res = NULL, *p ;
  int i, size ;

  XSH_ASSURE_NOT_NULL( list );
  size = list->size ;
  check( res = cpl_malloc( list->size * sizeof(double) ) ) ;
  for( p = res, i = 0 ; i<size ; i++, p++ )
    *p = list->list[i]->cenposx ;

  cleanup:
    return res;
}

/**
 * @brief get the Y central positions. The returned array must be
 * deallocated by the caller.
 *
 * @param list The tilt-list
 * @return return a created array of Y positions
 */
/*---------------------------------------------------------------------------*/
double * xsh_linetilt_list_get_posy( xsh_linetilt_list * list)
{
  double* res = NULL, *p ;
  int i, size ;

  XSH_ASSURE_NOT_NULL( list );
  size = list->size ;
  check( res = cpl_malloc( list->size * sizeof(double) ) ) ;
  for( p = res, i = 0 ; i<size ; i++, p++ )
    *p = list->list[i]->cenposy ;

  cleanup:
    return res;
}

/**
 * @brief get the Y Delta. The returned array must be
 * deallocated by the caller.
 *
 * @param list The tilt-list
 * @return return a created array of Y delta
 */
/*---------------------------------------------------------------------------*/
double * xsh_linetilt_list_get_deltay( xsh_linetilt_list * list)
{
  double* res = NULL, *p ;
  int i, size ;

  XSH_ASSURE_NOT_NULL( list );
  size = list->size ;

  check( res = cpl_malloc( list->size * sizeof(double) ) ) ;
  for( p = res, i = 0 ; i<size ; i++, p++ )
    *p = list->list[i]->deltay ;


  cleanup:
    return res;
}

/**
 * @brief get the Y sigma. The returned array must be
 * deallocated by the caller.
 *
 * @param list The tilt-list
 * @return return a created array of Y sigma
 */
/*---------------------------------------------------------------------------*/
double * xsh_linetilt_list_get_sigma_y( xsh_linetilt_list * list)
{
  double* res = NULL, *p ;
  int i, size ;

  XSH_ASSURE_NOT_NULL( list );
  size = list->size ;

  check( res = cpl_malloc( list->size * sizeof(double) ) ) ;
  for( p = res, i = 0 ; i<size ; i++, p++ )
    *p = list->list[i]->chisq ;


  cleanup:
    return res;
}

/**
 * @brief get the previous Y positions. The returned array must be
 * deallocated by the caller.
 *
 * @param list The tilt-list
 * @return return a created array of previous Y positions
 */
/*---------------------------------------------------------------------------*/
double * xsh_linetilt_list_get_pre_posy( xsh_linetilt_list * list)
{
  double* res = NULL, *p ;
  int i, size ;

  XSH_ASSURE_NOT_NULL( list );
  size = list->size ;

  check( res = cpl_malloc( list->size * sizeof(double) ) ) ;
  for( p = res, i = 0 ; i<size ; i++, p++ )
    *p = list->list[i]->pre_pos_y ;


  cleanup:
    return res;
}

/**
 * @brief get the orders . The returned array must be
 * deallocated by the caller.
 *
 * @param list The tilt-list
 * @return return a created array of orders
 */
/*---------------------------------------------------------------------------*/
double * xsh_linetilt_list_get_orders( xsh_linetilt_list * list)
{
  double* res = NULL, *p ;
  int i, size ;

  XSH_ASSURE_NOT_NULL( list );
  size = list->size ;
  check( res = cpl_malloc( list->size * sizeof(double) ) ) ;
  for( p = res, i = 0 ; i<size ; i++, p++ )
    *p = list->list[i]->order ;

  cleanup:
    return res;
}

/**
 * @brief get the wavelength . The returned array must be
 * deallocated by the caller.
 *
 * @param list The tilt-list
 * @return return a created array of orders
 */
/*---------------------------------------------------------------------------*/
double * xsh_linetilt_list_get_wavelengths( xsh_linetilt_list * list)
{
  double* res = NULL, *p ;
  int i, size ;

  XSH_ASSURE_NOT_NULL( list );
  size = list->size ;
  check( res = cpl_malloc( list->size * sizeof(double) ) ) ;
  for( p = res, i = 0 ; i<size ; i++, p++ )
    *p = list->list[i]->wavelength ;

  cleanup:
    return res;
}

/**
 * @brief get the slits . The returned array must be
 * deallocated by the caller.
 *
 * @param list The tilt-list
 * @return return a created array of orders
 */
/*---------------------------------------------------------------------------*/
double * xsh_linetilt_list_get_slits( xsh_linetilt_list * list)
{
  double* res = NULL, *p ;
  int i, size ;

  XSH_ASSURE_NOT_NULL( list );
  size = list->size ;
  check( res = cpl_malloc( list->size * sizeof(double) ) ) ;
  for( p = res, i = 0 ; i<size ; i++, p++ )
    *p = list->list[i]->slit ;

  cleanup:
    return res;
}

/**
 * @brief get the slit_index array . The returned array must be
 * deallocated by the caller.
 *
 * @param list The tilt-list
 * @return return a created array of slit indexes
 */
/*---------------------------------------------------------------------------*/
int * xsh_linetilt_list_get_slit_index(  xsh_linetilt_list * list)
{
  int * res = NULL, *p ;
  int i, size ;

  XSH_ASSURE_NOT_NULL( list );
  size = list->size ;
  check( res = cpl_malloc( list->size * sizeof(int) ) ) ;
  for( p = res, i = 0 ; i<size ; i++, p++ )
    *p = list->list[i]->slit_index ;

  cleanup:
    return res;
}

/** 
 * Returns a pointer to the propertylist. MUST not be deallocated directly
 * by the caller (use xsh_linetilt_free).
 * 
 * @param list Linetilt List
 * 
 * @return Pointer to the propertylist
 */
cpl_propertylist * xsh_linetilt_list_get_header( xsh_linetilt_list * list)
{
  cpl_propertylist * res = NULL ;

  XSH_ASSURE_NOT_NULL( list );

  res = list->header ;

  cleanup:
    return res;
}

/** 
 * Check if a given wavelength/order pair is already in the list.
 * 
 * @param list Linetilt list
 * @param lambda Wavelength
 * @param order Order
 * 
 * @return 0 if the wavelength/order is already in the list, 1 otherwise
 */
int xsh_linetilt_is_duplicate( xsh_linetilt_list * list, float lambda,
			       int order )
{
  int i, res = 0 ;
  XSH_ASSURE_NOT_NULL( list );

  for( i = 0 ; i<list->size ; i++ ) {
    if ( list->list[i]->wavelength == lambda && 
	 list->list[i]->order == order ) {
      res = 1 ;
      break ;
    }
  }

 cleanup:
  return res ;
}

#if 0
static int xsh_arclist_lambda_compare(const void* one, const void* two){
  xsh_arcline** a = NULL;
  xsh_arcline** b = NULL;
  float la, lb;

  a = (xsh_arcline**) one;
  b = (xsh_arcline**) two;
  
  la = (*a)->wavelength;
  lb = (*b)->wavelength;
 
  if (la <= lb)
    return -1;
  else
    return 1; 


}


/*---------------------------------------------------------------------------*/
/**

 * @brief sort arcline list by increasing lambda
 * 
 * @param list pointer to arcline_list
 */
/*---------------------------------------------------------------------------*/
void xsh_arclist_lambda_sort(xsh_arclist* list){
  qsort(list->list,list->size,sizeof(xsh_arcline*),
    xsh_arclist_lambda_compare);
}

/*---------------------------------------------------------------------------*/
/** 
 * @brief get size of arcline list
 * 
 * @param list pointer to arcline_list
 * @return the size
 */
/*---------------------------------------------------------------------------*/
int xsh_arclist_get_size(xsh_arclist* list){
  int i=0;

  XSH_ASSURE_NOT_NULL(list);
  i = list->size;

  cleanup:
    return i;
}


/*---------------------------------------------------------------------------*/
/** 
 * @brief get nb lines rejected in arcline list
 *  
 * @param list pointer to arcline_list
 * @return the number of rejected lines
 */
/*---------------------------------------------------------------------------*/
int xsh_arclist_get_nbrejected(xsh_arclist* list){
  int i=0;

  XSH_ASSURE_NOT_NULL(list);
  i = list->nbrejected;

  cleanup:
    return i;
}

/*---------------------------------------------------------------------------*/
/** 
 * @brief get wavelength of a line in the arcline list
 *  
 * @param list pointer to arcline_list
 * @param index index in the list
 * @return the wavelength of the arcline
 */
/*---------------------------------------------------------------------------*/
float xsh_arclist_get_wavelength(xsh_arclist* list, int index)
{
  float f = 0.0;

  XSH_ASSURE_NOT_NULL(list);
  XSH_ASSURE_NOT_ILLEGAL(index >= 0 && index < list->size);
  f = list->list[index]->wavelength;

  cleanup:
    return f;
}

/*---------------------------------------------------------------------------*/
/** 
 * @brief reject a line from the list
 *  
 * @param list pointer to arcline_list
 * @param index index of the line to reject
 */
/*---------------------------------------------------------------------------*/
void xsh_arclist_reject(xsh_arclist* list, int index)
{
  XSH_ASSURE_NOT_NULL(list);
  XSH_ASSURE_NOT_ILLEGAL(index >= 0 && index < list->size);
  
  list->rejected[index] = 1;
  list->nbrejected++;

  cleanup:
    return;

}

/*---------------------------------------------------------------------------*/
/**
 * @brief restore a line from the list
 *
 * @param list pointer to arcline_list
 * @param index index of the line to reject
 */
/*---------------------------------------------------------------------------*/
void xsh_arclist_restore(xsh_arclist* list, int index)
{
  XSH_ASSURE_NOT_NULL(list);
  XSH_ASSURE_NOT_ILLEGAL(index >= 0 && index < list->size);

  list->rejected[index] = 0;
  list->nbrejected--;

  cleanup:
    return;

}
/*---------------------------------------------------------------------------*/
/** 
 * @brief give if a line is rejected
 *  
 * @param list pointer to arcline_list
 * @param 1 if the line is rejected else 0
 */
/*---------------------------------------------------------------------------*/
int xsh_arclist_is_rejected(xsh_arclist* list, int index)
{
  int res = 0;

  XSH_ASSURE_NOT_NULL(list);
  XSH_ASSURE_NOT_ILLEGAL(index >= 0 && index < list->size);

  res = list->rejected[index];
  cleanup:
    return res;
}

/*---------------------------------------------------------------------------*/
/**
  @brief get header of the table
  @param list the arclist
  @return the header associated to the table
 */
/*---------------------------------------------------------------------------*/
cpl_propertylist* xsh_arclist_get_header(xsh_arclist* list)
{
  cpl_propertylist * res = NULL;

  XSH_ASSURE_NOT_NULL(list);
  res = list->header;
  cleanup:
    return res;
}

/*---------------------------------------------------------------------------*/
/** 
 * @brief Dump main info about an arcline_list
 * 
 * @param list pointer to arcline_list
 */
/*---------------------------------------------------------------------------*/
void xsh_dump_arclist( xsh_arclist* list)
{
  int i = 0;

  XSH_ASSURE_NOT_NULL(list);

  xsh_msg( "ARCLINE_LIST Dump %d lines",list->size);  

  for(i=0; i< list->size; i++) {
    const char* name = list->list[i]->name;
    const char* comment = list->list[i]->comment;
    if (name == NULL) name ="";
    if (comment == NULL) comment ="";
    xsh_msg("  Wavelength %f name %s flux %d comment %s",
      list->list[i]->wavelength, name,
      list->list[i]->flux, comment);
  }
  xsh_msg( "END ARCLINE_LIST");

  cleanup:
    return;
}

/*---------------------------------------------------------------------------*/
/**
  @brief load an arcline list frame in arclist structure
  @param frame the table frame ARCLINE_LIST
  @return the arclist allocated structure

 */
/*---------------------------------------------------------------------------*/
xsh_arclist* xsh_arclist_load(cpl_frame* frame){
  cpl_table* table = NULL; 
  const char* tablename = NULL;
  xsh_arclist* result = NULL;
  int i = 0;

  /* verify input */
  XSH_ASSURE_NOT_NULL(frame);

  /* get table filename */
  check( tablename = cpl_frame_get_filename(frame));

  XSH_TABLE_LOAD( table, tablename);

  /* allocate memory */
  XSH_CALLOC(result,xsh_arclist,1);
   
  /* init structure */
  check(result->size = cpl_table_get_nrow(table));
  XSH_CALLOC(result->list, xsh_arcline*, result->size);
  XSH_CALLOC(result->rejected, int, result->size);
  result->nbrejected = 0;

  check(result->header = cpl_propertylist_load(tablename, 0));

  /* load table data */
  for(i=0;i<result->size;i++){
    const char* name ="";
    const char* comment ="";
    xsh_arcline* arc = (xsh_arcline*)cpl_malloc(sizeof(xsh_arcline));

    check(xsh_get_table_value(table, XSH_ARCLIST_TABLE_COLNAME_WAVELENGTH,
      CPL_TYPE_FLOAT, i, &(arc->wavelength)));
    check(xsh_get_table_value(table, XSH_ARCLIST_TABLE_COLNAME_NAME,
      CPL_TYPE_STRING, i, &name));
    check(xsh_get_table_value(table, XSH_ARCLIST_TABLE_COLNAME_FLUX,
      CPL_TYPE_INT, i, &(arc->flux)));
    check(xsh_get_table_value(table, XSH_ARCLIST_TABLE_COLNAME_COMMENT,
      CPL_TYPE_STRING, i, &comment));
    if (name != NULL) {
      arc->name = xsh_stringdup(name);
    }
    else {
      arc->name = NULL;
    }
    if (comment != NULL) {
      arc->comment = xsh_stringdup(comment);
    }
    else {
      arc->comment = NULL;
    }
    result->list[i] = arc;
  }

  cleanup:
    if (cpl_error_get_code () != CPL_ERROR_NONE) {
      xsh_error_msg("can't load frame %s",cpl_frame_get_filename(frame));
      xsh_arclist_free(&result);
    }
    XSH_TABLE_FREE( table);
    return result;  
}

/*---------------------------------------------------------------------------*/
/**
  @brief free memory associated to a arcline
  @param list the arcline to free
 */
/*---------------------------------------------------------------------------*/
void xsh_arcline_free(xsh_arcline** arc)
{
  if (arc && (*arc)){
    if ((*arc)->name != NULL) {
      cpl_free((*arc)->name);
    }
    if ((*arc)->comment != NULL) {
      cpl_free((*arc)->comment);
    }
    cpl_free(*arc);
    *arc = NULL;
  }
}

/*---------------------------------------------------------------------------*/
/**
  @brief free memory associated to a arclist
  @param list the arclist to free
 */
/*---------------------------------------------------------------------------*/
void xsh_arclist_free(xsh_arclist** list)
{
  int i;
 
  if (list && *list) {
    if ((*list)->list) {
      for (i=0; i< (*list)->size; i++) {
        xsh_arcline* arc = (*list)->list[i];
        xsh_arcline_free(&arc);
      }
      cpl_free((*list)->list);
      xsh_free_propertylist(&((*list)->header));
    }
    XSH_FREE((*list)->rejected);
    cpl_free(*list);
    *list = NULL;
  }
}

void xsh_arclist_clean(xsh_arclist* list)
{
  int i, j;

  XSH_ASSURE_NOT_NULL(list);

  j = 0;
  for(i=0;i<list->size;i++)
  {
    if(xsh_arclist_is_rejected(list,i)){
      xsh_arcline_free(&list->list[i]);
    }
    else{
      j++;
      list->list[j-1] = list->list[i];
      list->rejected[j] = 0;
    }
  }
  list->size = j;
  list->nbrejected = 0;
  
  cleanup:
    return; 
}
/*---------------------------------------------------------------------------*/
/**
  @brief save a arclist to a frame
  @param list the arclist structure to save
  @param filename the name of the save file on disk
  @param tag the frame tag 
  @return a newly allocated frame

 */
/*---------------------------------------------------------------------------*/
cpl_frame* 
xsh_arclist_save(xsh_arclist* list,const char* filename,const char* tag)
{
  cpl_table* table = NULL;
  cpl_frame * result = NULL ;
  int i=0;

  XSH_ASSURE_NOT_NULL(list);
  XSH_ASSURE_NOT_NULL(filename);
  
  /* create a table */
  check(table = cpl_table_new(XSH_ARCLIST_TABLE_NB_COL));

  /* create column names */
  check(
    cpl_table_new_column(table,XSH_ARCLIST_TABLE_COLNAME_WAVELENGTH,
      CPL_TYPE_FLOAT));
  check(
    cpl_table_set_column_unit ( table, XSH_ARCLIST_TABLE_COLNAME_WAVELENGTH,
      XSH_ARCLIST_TABLE_UNIT_WAVELENGTH));
  check(
    cpl_table_new_column(table,XSH_ARCLIST_TABLE_COLNAME_NAME,
     CPL_TYPE_STRING));
  check(
    cpl_table_set_column_unit ( table, XSH_ARCLIST_TABLE_COLNAME_NAME,
      XSH_ARCLIST_TABLE_UNIT_NAME));

  check(
    cpl_table_new_column(table,XSH_ARCLIST_TABLE_COLNAME_FLUX,
     CPL_TYPE_INT));
  check(
    cpl_table_set_column_unit ( table, XSH_ARCLIST_TABLE_COLNAME_FLUX,
      XSH_ARCLIST_TABLE_UNIT_FLUX));

  check(
    cpl_table_new_column(table,XSH_ARCLIST_TABLE_COLNAME_COMMENT,
     CPL_TYPE_STRING));
  check(
    cpl_table_set_column_unit ( table, XSH_ARCLIST_TABLE_COLNAME_COMMENT,
      XSH_ARCLIST_TABLE_UNIT_COMMENT));

  check(cpl_table_set_size(table,list->size));

  /* insert data */
  for(i=0;i<list->size;i++){
      check(cpl_table_set_float(table,XSH_ARCLIST_TABLE_COLNAME_WAVELENGTH,
        i,list->list[i]->wavelength));
      check(cpl_table_set_string(table,XSH_ARCLIST_TABLE_COLNAME_NAME,
        i,list->list[i]->name));
      check(cpl_table_set_int(table,XSH_ARCLIST_TABLE_COLNAME_FLUX,
        i,list->list[i]->flux));
      check(cpl_table_set_string(table,XSH_ARCLIST_TABLE_COLNAME_COMMENT,
        i,list->list[i]->comment));
  }

  /* create fits file */
  check(cpl_table_save(table, list->header, NULL, filename, CPL_IO_DEFAULT));

  /* Create the frame */
  check(result=xsh_frame_product(filename,
				 tag,
				 CPL_FRAME_TYPE_TABLE,
				 CPL_FRAME_GROUP_PRODUCT,
				 CPL_FRAME_LEVEL_TEMPORARY));


  cleanup:
    XSH_TABLE_FREE( table);
    return result ;
}
#endif

/**@}*/
