/*                                                                           *
 *   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-12-08 18:43:31 $
 * $Revision: 1.22 $
*/

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

/*---------------------------------------------------------------------------*/
/**
 * @defgroup xsh_create_order_table Order Table creation
 * @ingroup drl_functions
 *
 * Functions used to compute and create a guess order table from the
 * residual map (recipe xsh_predict)
 */

#include <xsh_drl.h>
#include <xsh_pfits.h>
#include <xsh_utils.h>
#include <xsh_data_order.h>
#include <xsh_data_arclist.h>
#include <xsh_error.h>
#include <xsh_utils.h>
#include <xsh_msg.h>
#include <xsh_data_pre.h>
#include <xsh_data_order.h>
#include <xsh_data_resid_tab.h>
#include <cpl.h>


static int
data_order_compare (const void *one, const void *two)
{
  xsh_sort_data* a = NULL;
  xsh_sort_data* b = NULL;
  double* da =  NULL, *db = NULL;

  a = (xsh_sort_data *) one;
  b = (xsh_sort_data *) two;

  da = (double*)(a->data);
  db = (double*)(b->data);

  if ((*da) <= (*db))
    return -1;
  else
    return 1;
}



cpl_frame* xsh_create_order_table(  cpl_frame *in_frame,
				    cpl_frame* spectralformat_frame,
				     cpl_frame *resid_frame,
				     cpl_frame *arclines,
				     xsh_detect_arclines_param *da,
				     xsh_clipping_param *dac,
				     xsh_instrument *instrument)
{
  xsh_pre *pre = NULL;
  cpl_frame *result = NULL ;
  xsh_resid_tab *resid_tab = NULL ;
  xsh_order_list *list = NULL ;
  xsh_arclist *arclist = NULL;
  cpl_propertylist *header = NULL ;
  double *vlambda = NULL;
  // double *thpre_x = NULL, *thpre_y = NULL;
  double  *xgauss = NULL, *ygauss = NULL, *vorder = NULL ;
  double *pos_x = NULL, *pos_y = NULL ;
  int size, i, nlinecat;
  //int nlineclean;
  int *sort = NULL;
  const char *model_date = NULL;
  const char *tag = NULL;
  char fname[256];
  xsh_spectralformat_list *spectralformat_list = NULL;
  cpl_table* spc_fmt_tab=NULL;
  FILE* debug_out = NULL;

  xsh_msg("Creating the Order Table");
  XSH_ASSURE_NOT_NULL( in_frame);
  XSH_ASSURE_NOT_NULL( resid_frame);
  XSH_ASSURE_NOT_NULL( arclines);
  XSH_ASSURE_NOT_NULL( da);
  XSH_ASSURE_NOT_NULL( dac);
  XSH_ASSURE_NOT_NULL( instrument);
  XSH_ASSURE_NOT_NULL( spectralformat_frame);

  check( pre = xsh_pre_load( in_frame, instrument));
  check( resid_tab = xsh_resid_tab_load( resid_frame));
  check( arclist = xsh_arclist_load( arclines));
 check( spectralformat_list = xsh_spectralformat_list_load( 
   spectralformat_frame, instrument));
  check( nlinecat = xsh_arclist_get_size( arclist));
  //check( nlineclean = xsh_arclist_get_size( arclist));
  check( model_date = xsh_pfits_get_date( resid_tab->header));

  /* Extract from resid table lambda, x, y, dx, dy */
  check( size = xsh_resid_tab_get_size( resid_tab));
  xsh_msg_dbg_high ( "   Resid Table Size: %d", size);

  check( vlambda = xsh_resid_tab_get_lambda_data( resid_tab ) ) ;
  check( vorder = xsh_resid_tab_get_order_data( resid_tab ) ) ;
  //check( thpre_x = xsh_resid_tab_get_thpre_x_data( resid_tab ) ) ;
  //check( thpre_y = xsh_resid_tab_get_thpre_y_data( resid_tab ) ) ;
  check( xgauss = xsh_resid_tab_get_xgauss_data( resid_tab ) ) ;
  check( ygauss = xsh_resid_tab_get_ygauss_data( resid_tab ) ) ;

  /* Calculate pos_x & pos_y from theoretical and diff */
  XSH_CALLOC( pos_x, double, size);
  XSH_CALLOC( pos_y, double, size);
  for( i = 0 ; i<size ; i++ ) {
    *(pos_x+i) = *(xgauss+i) ;
    *(pos_y+i) = *(ygauss+i) ;
  }

  check( sort = xsh_sort( vorder, size, sizeof(double), 
			  data_order_compare));
  check(xsh_reindex( vorder, sort, size));
  check(xsh_reindex( pos_x, sort, size));
  check(xsh_reindex( pos_y, sort, size));
  check(xsh_reindex( vlambda, sort, size));

  /* init */
  check(list = xsh_order_list_create( instrument));
  xsh_msg_dbg_medium("Number of orders expected : %d",list->size);

  xsh_order_list_fit(list, size, vorder, pos_x, pos_y, da->ordertab_deg_y);
  xsh_msg("size=%d",size);

  /* update starty and endy */
  for( i=0; i < list->size; i++){
    list->list[i].starty = 1;
    list->list[i].endy = pre->ny;
  }
  spc_fmt_tab=cpl_table_load(cpl_frame_get_filename(spectralformat_frame),1,0);
  if(cpl_table_has_column(spc_fmt_tab,XSH_SPECTRALFORMAT_TABLE_COLNAME_XMIN)) {
    for( i=0; i < list->size; i++){
      list->list[i].starty = spectralformat_list->list[i].ymin;
      list->list[i].endy =   spectralformat_list->list[i].ymax;
    }
  }
  xsh_free_table(&spc_fmt_tab);
  xsh_spectralformat_list_free(&spectralformat_list);
  xsh_msg( "  Save the produced order table" ) ;

  if ( cpl_error_get_code() == CPL_ERROR_NONE){
    /* save guess order table */
    check(header = xsh_order_list_get_header(list));
    check(xsh_pfits_set_qc_nlinecat(header,nlinecat));
    xsh_msg("create order tab. nlinecat=%d",nlinecat);
    check(xsh_pfits_set_qc_nlinefound(header,size));
/*    check(xsh_pfits_set_qc_nlinecat_clean(header,nlineclean));*/
    check(xsh_pfits_set_qc(header, (void*)model_date,
			   XSH_QC_MODEL_FMTCHK_DATE, instrument));

    tag=XSH_GET_TAG_FROM_ARM( XSH_ORDER_TAB_GUESS,instrument);
    sprintf(fname,"%s%s",tag,".fits");
    check(result =  xsh_order_list_save(list,instrument,fname,tag,pre->ny));
    //xsh_add_temporary_file( fname ) ;

  
    /* REGDEBUG */
    if (xsh_debug_level_get() >= XSH_DEBUG_LEVEL_MEDIUM) {
      int dy,dor;

      debug_out = fopen("predict_cen_points.log","w");
      for(dy=0;dy< size; dy++){
	fprintf(debug_out,"%f %f\n",pos_x[dy],pos_y[dy]);
      }

      fclose(debug_out);
      debug_out = fopen("predict_cen.log","w");

      for(dor = 0; dor < list->size; dor++){
	for(dy=0;dy<pre->ny;dy++){
	  float dx = 0;

	  check( dx = cpl_polynomial_eval_1d(list->list[dor].cenpoly,dy,NULL));
	  fprintf(debug_out,"%f %d\n",dx,dy);
	}
      }
      fclose(debug_out);
    }
    /* ENDREGDEBUG */
  }
  else{
    if (da->mode_iterative){
      cpl_error_reset();
      xsh_msg("********** Not enough orders to produce ORDER_TABLE");
    }
  }

 cleanup:
  if(debug_out!=NULL) {
    fclose(debug_out);
  }
  xsh_pre_free( &pre);
  xsh_resid_tab_free( &resid_tab);
  xsh_arclist_free( &arclist);
  xsh_order_list_free( &list);
  xsh_spectralformat_list_free(&spectralformat_list);
  XSH_FREE( pos_x);
  XSH_FREE( pos_y);
  XSH_FREE( sort);
  xsh_spectralformat_list_free(&spectralformat_list);
  return result ;
}

/**@}*/
