/* $Id: xsh_model_anneal.c,v 1.20 2011-12-02 14:15:28 amodigli Exp $
 *
 * This file is part of the ESO X-shooter Pipeline                          
 * Copyright (C) 2006 European Southern Observatory 
 * 
 * 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 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, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/*
 * $Author: amodigli $
 * $Date: 2011-12-02 14:15:28 $
 * $Revision: 1.20 $
 * $Name: not supported by cvs2svn $
 */

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

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

#include <cpl.h>

#include <xsh_msg.h>
#include <xsh_error.h>

#include "xsh_model_anneal.h"
#include "xsh_model_kernel.h"
#include "xsh_model_arm_constants.h"
#include "xsh_model_io.h"
#include "xsh_model_metric.h"
#include "xsh_model_sa.h"

#define MAXIT 25000

/*----------------------------------------------------------------------------*/
/**
 * @defgroup xsh_model_anneal    Anneal computation function
 */
/*----------------------------------------------------------------------------*/

/**@{*/

/*----------------------------------------------------------------------------*/
/**
  @brief    The actual anneal computation takes place here
  @param    xsh_config_file model cfg filename
  @param    xsh_config_tag  model cfg pro catg
  @param    meas_coord_file masure coordination file
  @return   the new configuration table or NULL in error case
 */
/*----------------------------------------------------------------------------*/
cpl_table * xsh_model_anneal_reduce(
        const char  *   xsh_config_file,
        const char  *   xsh_config_tag,
        const char  *   meas_coord_file)
{
  cpl_table *   conf_tab = NULL;
  int ii;
  int morder,sizearraywavelengths, DS_size,adim;
  int morder_it;
  int morder_min, morder_max;
  struct xs_3 xs_model, *p_xs_3;
  ann_all_par all_par[300], *p_all_par;
  double abest[300];
  double amin[300];
  double amax[300];
  int aname[300];

  DOUBLE flux_tot;
  int tot;
  coord *msp_coord = NULL;
  DOUBLE ** ref_ind = NULL;
  DOUBLE *p_wlarray = NULL;


  p_xs_3=&xs_model;
  p_all_par=&all_par[0];
  sizearraywavelengths=countlines(meas_coord_file);
  XSH_CALLOC( msp_coord, coord, sizearraywavelengths+5);

  xsh_msg("%d \n",sizearraywavelengths);
  /*wavelength =  (DOUBLE *)cpl_malloc(sizearraywavelengths*sizeof(DOUBLE));*/
  xsh_msg("tag=%s",xsh_config_tag);
  adim=xsh_model_readfits(abest,
                          amin,
                          amax,
                          aname,
                          xsh_config_file,
                          xsh_config_tag,
                          p_xs_3,
                          p_all_par);

  xsh_msg("arm %d \n",p_xs_3->arm);

  ref_ind=xsh_alloc2Darray(8,7);

  if (p_xs_3->arm==0) {
    p_xs_3->BSIZE=UVB_BSIZE;
    p_xs_3->ASIZE=UVB_ASIZE;
    p_xs_3->chipxpix=UVB_chipxpix;
    p_xs_3->chipypix=UVB_chipypix;
    xsh_ref_ind_read(0,ref_ind,p_xs_3->temper);
    morder=UVB_morder;
    morder_it=5;
    morder_min=UVB_morder_min;
    morder_max=UVB_morder_max;
  }
  else if (p_xs_3->arm==1) {
    p_xs_3->BSIZE=VIS_BSIZE;
    p_xs_3->ASIZE=VIS_ASIZE;
    p_xs_3->chipypix=VIS_chipypix;
    p_xs_3->chipxpix=VIS_chipxpix;
    xsh_ref_ind_read(1,ref_ind,p_xs_3->temper);
    morder=VIS_morder;
    morder_it=7;
    morder_min=VIS_morder_min;
    morder_max=VIS_morder_max;
  }
  else if (p_xs_3->arm==2) {
    p_xs_3->ASIZE=NIR_ASIZE;
    p_xs_3->BSIZE=NIR_BSIZE;
    p_xs_3->chipxpix=NIR_chipxpix;
    p_xs_3->chipypix=NIR_chipypix;
    xsh_ref_ind_read(2,ref_ind,p_xs_3->t_ir_p2);
    morder=NIR_morder;
    morder_it=8;
    morder_min=NIR_morder_min;
    morder_max=NIR_morder_max;
  }
  else {
    printf("Arm not set. \n");
    return NULL;
  }

  xsh_showmatrix(p_xs_3->e_slit);
  /*We now need to update several matrices (that were set in the
    xsh_3_init routine outside of the current loop) for this prism angle */
  xsh_3_init(p_xs_3);

  /* Size of the data structure is simply the length of the coords file, since
     wavelengths matched in more than one order are lister each time (unlike
     the x-dispersion for stisanneal)*/
  DS_size = sizearraywavelengths;

  /* now allocate memory for the data structure*/
  p_wlarray=xsh_alloc1Darray(DS_size);

  get_meas_coordinates(sizearraywavelengths, msp_coord,(char*)meas_coord_file);
  flux_tot=0.0;
  tot=0;
  /* get total flux */
  for(ii=0;ii<sizearraywavelengths;ii++) {
    p_wlarray[ii]=msp_coord[ii].wave*1e-6;
    /* below is a quick hack to allow an offset in the
       co-ordinates eg 0.5 for pixel centres*/
/*     if (p_xs_3->arm==0) { */
/*       msp_coord[ii].x=2144.0-msp_coord[ii].x-0.0; */
/*       msp_coord[ii].y=3000.0-msp_coord[ii].y-0.0; */
/*     } */
    flux_tot+=msp_coord[ii].flux;
    tot+=1;
  }
  /* Normalise fluxes */
  for(ii=0;ii<sizearraywavelengths;ii++) {
    msp_coord[ii].flux=msp_coord[ii].flux*(double)(tot)/flux_tot;
  }
#ifdef DEBUG 
  printf ("Before anneal: \n");
  for (ii=0;ii<adim;ii++) {
    printf("%d %s %lf \n", aname[ii], (p_all_par+aname[ii])->name, abest[ii]);
  }

  xsh_showmatrix(p_xs_3->e_slit);
  /*Call the model kernel with the initial values*/
  int jj=0;

  for (jj=0;jj<DS_size;jj++) {
    p_xs_3->es_y_tot=p_xs_3->es_y+p_xs_3->slit[msp_coord[jj].slit_pos]*p_xs_3->slit_scale;
    morder=msp_coord[jj].order;
    xsh_3_init(p_xs_3);
    xsh_3_eval(p_wlarray[jj],morder,ref_ind,p_xs_3);
    xsh_3_detpix(p_xs_3);
    printf("check %d %lf %lf %d %d %lf %lf %lf %lf %d\n",
	   jj,p_wlarray[jj],p_xs_3->es_y_tot,p_xs_3->chippix[0],
	   msp_coord[jj].arm,p_xs_3->xpospix,p_xs_3->ypospix,
	   msp_coord[jj].x-p_xs_3->xpospix,msp_coord[jj].y-p_xs_3->ypospix,
	   msp_coord[jj].order);
  }
#endif
  /*Call the main anneal algorithm in crires_model_metric.c*/
  conf_tab = xsh_model_anneal_comp( p_all_par,
					adim,
					abest,
					amin,
					amax,
					aname,
					p_xs_3,
					DS_size,
					msp_coord,
					p_wlarray,
					ref_ind,
					MAXIT);
  cleanup:
    xsh_free2Darray(ref_ind,8);
    cpl_free(p_wlarray);
  return conf_tab ;
}
/**@}*/

/*The number of measured co-ordinates must equal the number of wavelengths in meas_coord_file (and they should also correspond)*/
void get_meas_coordinates(int sizearraywavelengths,
                          coord* meas_coord,
                          char* datname)
{
  int feat_cnt=0;

  FILE* measfile;
  measfile=fopen(datname,"r");
  /*  FILE * matchfile=fopen("match.dat","r");*/
  if(measfile ==NULL ){
    printf("Cannot open the measured coords file\n");
    abort();}

  while(fscanf(measfile, "%64d %64lf %64lf %64d %64lf %64d %64lf %64d\n",
               &meas_coord[feat_cnt].counter,
               &meas_coord[feat_cnt].y,
               &meas_coord[feat_cnt].x,
               &meas_coord[feat_cnt].arm,
               &meas_coord[feat_cnt].flux,
               &meas_coord[feat_cnt].slit_pos,
               &meas_coord[feat_cnt].wave,
               &meas_coord[feat_cnt].order) != EOF ){
    feat_cnt+=1;
  }
  fclose(measfile);
  if (feat_cnt != sizearraywavelengths) {
    printf("Number of spectral features is not equal to the number of wavelengths and slit posn's supplied! \n %d != %d \n",feat_cnt, sizearraywavelengths);
    abort();}
}

/*count lines of the calibration files in order to dimension the array's size.*/ 
int countlines (const char * filename)
  {

  /* count  lines  ignore Comments (lines start with a %)*/
  char oneline[200];
  char *c;
  char firstchar[]="";
  char comment[]="%";
  FILE * myfile;
  int linecounter=0;
  if((myfile=fopen((char*)filename,"r"))==NULL){
    printf("Cannot open file %s for reading.\n",filename);
    abort();
  }

  do
   {
      c = fgets(oneline, 200, myfile);  /* get one line from the file */
      if (c != NULL)
      {
       strncpy(firstchar,oneline,1);
       if(strncmp(firstchar,comment,1))
         /*if is not a comment increment linecounter*/
          linecounter++;
      }

   }
   while (c != NULL);               /* repeat until NULL          */
   fclose(myfile);
   return linecounter;
  }






