/*                                                                           *
 *   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-16 14:07:08 $
 * $Revision: 1.106 $
 * $Name: not supported by cvs2svn $
 */

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

/*---------------------------------------------------------------------------*/
/**
 * @defgroup detect_order    Order Detection (xsh_detect_order_edge)
 * @ingroup drl_functions
 *
 */
/*---------------------------------------------------------------------------*/
/**@{*/

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

#include <math.h>
#include <xsh_drl.h>
#include <xsh_utils_wrappers.h>
#include <xsh_data_order.h>
#include <xsh_error.h>
#include <xsh_utils.h>
#include <xsh_utils_image.h>
#include <xsh_msg.h>
#include <xsh_data_pre.h>
#include <cpl.h>

/*---------------------------------------------------------------------------
                            Typedefs
  ---------------------------------------------------------------------------*/
#define HALF_SLIC_WINDOW 5

/*---------------------------------------------------------------------------
                            Functions prototypes
  ---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------
                              Implementation
  ---------------------------------------------------------------------------*/


/**
  @brief Measure flat edges (and eventually IFU slices) on master bias
         using Scharr X filter
  @param frame input (master) frame (must have good S/N)
  @param list  input order list
  @param instrument instrument setting
  @param method  method used
*/

static cpl_table*
xsh_compute_flat_edges(cpl_frame* frame,
                       xsh_order_list* list,
                       xsh_instrument* instrument,
                       const char* method)
{

  cpl_image* mflat=NULL;
  const char* name=NULL;
  const char* name_o=NULL;
  char name_t[256];
  cpl_image* filter_x=NULL;
  cpl_propertylist* plist=NULL;

  cpl_table* tbl=NULL;
  cpl_table* res=NULL;

  cpl_vector* vsliclo=NULL;
  cpl_vector* vslicup=NULL;
  cpl_vector* vedgelo=NULL;
  cpl_vector* vedgeup=NULL;
  cpl_vector* vypos=NULL;

  int* porder=NULL;
  int* pabsorder=NULL;

  double* pcenterx=NULL;
  double* pcentery=NULL;


  double* pedgelo=NULL;
  double* pedgeup=NULL;
  double* psliceup=NULL;
  double* pslicelo=NULL;
  double* psliceup_resx=NULL;
  double* pslicelo_resx=NULL;

  double* pedgeup_resx=NULL;
  double* pedgelo_resx=NULL;


  double* pedgelof=NULL;
  double* pedgeupf=NULL;
  double* psliceupf=NULL;
  double* pslicelof=NULL;
  double* psliceupthresf=NULL;
  double* pslicelothresf=NULL;

  double* ypos=NULL;


  double* edgelo=NULL;
  double* edgeup=NULL;
  double* sliclo=NULL;
  double* slicup=NULL;

  double max=0;
  int img_starty=0;
  int img_endy=0;
  int i=0;
  int is_ifu=0;
  int sx=0;
  int sy=0;
  int rad=6;
  int y=0;
  int llx=0;
  int urx=0;
  int nrows=0;
  int k=0;
  int num=0;
  int nsel=0;

  cpl_polynomial* sliclopoly=NULL;
  cpl_polynomial* slicuppoly=NULL;
  cpl_polynomial* edgelopoly=NULL;
  cpl_polynomial* edgeuppoly=NULL;
  //cpl_image* sbias=NULL;

  check(name=cpl_frame_get_filename(frame));
  check(mflat=cpl_image_load(name,CPL_TYPE_FLOAT,0,0));
  /* one may smooth the image to remove bad columns 
  check(sbias=xsh_image_smooth_median_x(mflat,2));
  check(cpl_image_save(sbias,"smooth.fits",CPL_BPP_IEEE_FLOAT,
  		       NULL,CPL_IO_DEFAULT));
  */

  check(sx=cpl_image_get_size_x(mflat));
  check(sy=cpl_image_get_size_y(mflat));

  if(strcmp(method,"sobel") == 0) {
     check(filter_x=xsh_sobel_lx(mflat));
  } else {
     check(filter_x=xsh_scharr_x(mflat));
  }
  
  //xsh_free_image(&sbias);

  check(max=cpl_image_get_max(filter_x));
  check(cpl_image_divide_scalar(filter_x,max));
  check(cpl_image_abs(filter_x));

  if(xsh_debug_level_get() >= XSH_DEBUG_LEVEL_MEDIUM) {
     if(strcmp(method,"sobel") == 0) {
        check(cpl_image_save(filter_x,"sobel_lx_n.fits",CPL_BPP_IEEE_FLOAT,
                             NULL,CPL_IO_DEFAULT));
     } else {
        check(cpl_image_save(filter_x,"scharr_x_n.fits",CPL_BPP_IEEE_FLOAT,
                             NULL,CPL_IO_DEFAULT));
     }
  }

  nrows=sy*list->size;
  check(tbl=cpl_table_new(nrows));
  check(cpl_table_new_column(tbl,"ORDER",CPL_TYPE_INT));
  check(cpl_table_new_column(tbl,"ABSORDER",CPL_TYPE_INT));

  check(cpl_table_new_column(tbl,"CENTERX",CPL_TYPE_DOUBLE));
  check(cpl_table_new_column(tbl,"CENTERY",CPL_TYPE_DOUBLE));
  check(cpl_table_new_column(tbl,"EDGELOX",CPL_TYPE_DOUBLE));
  check(cpl_table_new_column(tbl,"EDGEUPX",CPL_TYPE_DOUBLE));

  check(cpl_table_fill_column_window_int(tbl,"ORDER",0,nrows,-1));
  check(cpl_table_fill_column_window_int(tbl,"ABSORDER",0,nrows,-1));

  check(cpl_table_fill_column_window_double(tbl,"CENTERX",0,nrows,-1));
  check(cpl_table_fill_column_window_double(tbl,"CENTERY",0,nrows,-1));
  check(cpl_table_fill_column_window_double(tbl,"EDGELOX",0,nrows,-1));
  check(cpl_table_fill_column_window_double(tbl,"EDGEUPX",0,nrows,-1));


  check(porder=cpl_table_get_data_int(tbl,"ORDER"));
  check(pabsorder=cpl_table_get_data_int(tbl,"ABSORDER"));

  check(pcenterx=cpl_table_get_data_double(tbl,"CENTERX"));
  check(pcentery=cpl_table_get_data_double(tbl,"CENTERY"));
  check(pedgelo=cpl_table_get_data_double(tbl,"EDGELOX"));
  check(pedgeup=cpl_table_get_data_double(tbl,"EDGEUPX"));


  is_ifu = xsh_instrument_get_mode( instrument ) == XSH_MODE_IFU ;
  if ( is_ifu){
    xsh_msg( "Detect Order Edges in IFU mode");
    check(cpl_table_new_column(tbl,"SLICELOX",CPL_TYPE_DOUBLE));
    check(cpl_table_new_column(tbl,"SLICEUPX",CPL_TYPE_DOUBLE));
    check(cpl_table_new_column(tbl,"SLICELOTHRESFX",CPL_TYPE_DOUBLE));
    check(cpl_table_new_column(tbl,"SLICEUPTHRESFX",CPL_TYPE_DOUBLE));

    check(pslicelothresf=cpl_table_get_data_double(tbl,"SLICELOTHRESFX"));
    check(psliceupthresf=cpl_table_get_data_double(tbl,"SLICEUPTHRESFX"));
    check(cpl_table_fill_column_window_double(tbl,"SLICELOTHRESFX",0,nrows,-1));
    check(cpl_table_fill_column_window_double(tbl,"SLICEUPTHRESFX",0,nrows,-1));

    check(pslicelo=cpl_table_get_data_double(tbl,"SLICELOX"));
    check(psliceup=cpl_table_get_data_double(tbl,"SLICEUPX"));
    check(cpl_table_fill_column_window_double(tbl,"SLICELOX",0,nrows,-1));
    check(cpl_table_fill_column_window_double(tbl,"SLICEUPX",0,nrows,-1));

  }
  else {
    xsh_msg( "Detect Order Edges in SLIT mode");
  }
 
  /* find centroids using previous constrained solutions */
  for(i=0; i< list->size; i++){
    porder[k]=list->list[i].order;
    pabsorder[k]=list->list[i].absorder;

    img_starty = list->list[i].starty/list->bin_y;
    img_endy=list->list[i].endy/list->bin_y;

       /* 
          -999 can occur only in QC mode and is used as flag to skip 
          edge detection on a given order. This was explicitly asked by QC.
          Normal user mode should never have this behaviour.
       */
    if((list->list[i].starty == -999) || 
       (list->list[i].endy==-999)){
      xsh_msg("PROBLEMS tracing order %d",list->list[i].absorder);
       method="fixed";
       break;
    }

    xsh_msg_dbg_medium("start=%d end=%d",img_starty,img_endy);
    for(y=img_starty; y<img_endy; y++){
      double xl = 0, xu = 0,  xc=0, xsl=0, xsu=0;
      cpl_size px, py;
      int yb=y*list->bin_y;

      check( xu = xsh_order_list_eval_int( list, list->list[i].edguppoly, y));
      check( xl = xsh_order_list_eval_int( list, list->list[i].edglopoly, y));

      llx=(int)xl-rad;
      urx=(int)xl+rad;
      if((llx>0) && (urx< sx)) {
        //check(pedgelo[k]=cpl_image_get_centroid_x_window(filter_x,llx,y,urx,y));
        check( cpl_image_get_maxpos_window( filter_x, llx, y, urx, y, &px, &py));
        pedgelo[k] = px; 
        pedgelo[k]*=list->bin_x;
	porder[k]=list->list[i].order;
	pabsorder[k]=list->list[i].absorder;
      }
      /* xsh_msg("y=%d xl=%g llx=%d lly=%d max=%g",y,xl,llx,urx,pedgelo[i]); */
      llx=(int)xu-rad;
      urx=(int)xu+rad;

      if((llx>0) && (urx< sx)) {
        //check(pedgeup[k]=cpl_image_get_centroid_x_window(filter_x,llx,y,urx,y));
        check( cpl_image_get_maxpos_window( filter_x, llx,y,urx,y, &px, &py));
        pedgeup[k] = px;
        pedgeup[k]*=list->bin_x;
	porder[k]=list->list[i].order;
	pabsorder[k]=list->list[i].absorder;
      }
      /* xsh_msg("y=%d xu=%g llx=%d lly=%d max=%g",y,xu,llx,urx,pedgeup[i]); */
 
      check( xc = xsh_order_list_eval( list, list->list[i].cenpoly, y));
      pcenterx[k]=xc*list->bin_y;
      pcentery[k]=yb;

      /* xsh_msg("xu=%f xl=%f xc=%f y=%d i=%d\n",xl, xu, xc, y, i); */
      if ( is_ifu) {
        if ( list->list[i].sliclopoly != NULL ) {
            check(xsl=cpl_polynomial_eval_1d(list->list[i].sliclopoly,yb,NULL));

            xsl /= list->bin_x;
            pslicelothresf[k] = xsl; 
	    llx=(int)xsl-rad;
	    urx=(int)xsl+rad;

	    if((llx>0) && (urx)< sx) {
	      /*check(pslicelo[k]=cpl_image_get_centroid_x_window(filter_x,
							 llx,y,urx,y));*/
              check( cpl_image_get_maxpos_window( filter_x, llx, y, urx, y, &px, &py));
              pslicelo[k]=px;
              pslicelo[k]*=list->bin_x;
	      porder[k]=list->list[i].order;
	      pabsorder[k]=list->list[i].absorder;
	    }
	}

        if ( list->list[i].slicuppoly != NULL ) {
            check(xsu=cpl_polynomial_eval_1d(list->list[i].slicuppoly,yb,NULL));
            xsu /= list->bin_x;
            psliceupthresf[k] = xsu;
	    llx=(int)xsu-rad;
	    urx=(int)xsu+rad;

	    if((llx>0) && (urx)< sx) {
	      /*check(psliceup[k]=cpl_image_get_centroid_x_window(filter_x,
							 llx,y,urx,y));*/
              check( cpl_image_get_maxpos_window( filter_x, llx, y, urx, y, &px, &py));
              psliceup[k]=px;
              psliceup[k]*=list->bin_x;
	      porder[k]=list->list[i].order;
	      pabsorder[k]=list->list[i].absorder;
	    }
	}


      } /* end check ifu */

      k++;
    } /* end loop over y */

  } /* end loop over orders */

  //check(cpl_table_save(res,plist,NULL,"pippo.fits",CPL_IO_DEFAULT));
  check(num=cpl_table_and_selected_int(tbl,"ORDER",CPL_GREATER_THAN,-1));
  check(res=cpl_table_extract_selected(tbl));
  //check(cpl_table_save(res,plist,NULL,"pippo.fits",CPL_IO_DEFAULT));
  
  xsh_free_table(&tbl);
  cpl_table_select_all(res);

  /* fit the edge column values */
  check(cpl_table_new_column(res,"EDGELOFX",CPL_TYPE_DOUBLE));
  check(cpl_table_new_column(res,"EDGEUPFX",CPL_TYPE_DOUBLE));
  check(cpl_table_fill_column_window_double(res,"EDGELOFX",0,num,-1));
  check(cpl_table_fill_column_window_double(res,"EDGEUPFX",0,num,-1));

  check(cpl_table_new_column(res,"EDGELO_RESX",CPL_TYPE_DOUBLE));
  check(cpl_table_new_column(res,"EDGEUP_RESX",CPL_TYPE_DOUBLE));
  check(cpl_table_fill_column_window_double(res,"EDGELO_RESX",0,num,-1));
  check(cpl_table_fill_column_window_double(res,"EDGEUP_RESX",0,num,-1));

  check(pedgelof=cpl_table_get_data_double(res,"EDGELOFX"));
  check(pedgeupf=cpl_table_get_data_double(res,"EDGEUPFX"));
  check(pedgelo_resx=cpl_table_get_data_double(res,"EDGELO_RESX"));
  check(pedgeup_resx=cpl_table_get_data_double(res,"EDGEUP_RESX"));

  if ( is_ifu ) {
    check(cpl_table_new_column(res,"SLICELOFX",CPL_TYPE_DOUBLE));
    check(cpl_table_new_column(res,"SLICEUPFX",CPL_TYPE_DOUBLE));

    check(cpl_table_fill_column_window_double(res,"SLICELOFX",0,num,-1));
    check(cpl_table_fill_column_window_double(res,"SLICEUPFX",0,num,-1));
    check(pslicelof=cpl_table_get_data_double(res,"SLICELOFX"));
    check(psliceupf=cpl_table_get_data_double(res,"SLICEUPFX"));

    check(cpl_table_new_column(res,"SLICELO_RESX",CPL_TYPE_DOUBLE));
    check(cpl_table_new_column(res,"SLICEUP_RESX",CPL_TYPE_DOUBLE));
    check(cpl_table_fill_column_window_double(res,"SLICELO_RESX",0,num,-1));
    check(cpl_table_fill_column_window_double(res,"SLICEUP_RESX",0,num,-1));
    check(pslicelo_resx=cpl_table_get_data_double(res,"SLICELO_RESX"));
    check(psliceup_resx=cpl_table_get_data_double(res,"SLICEUP_RESX"));


  }

  k=0;
  for(i=0; i< list->size; i++){

       /* 
          -999 can occur only in QC mode and is used as flag to skip 
          edge detection on a given order. This was explicitly asked by QC.
          Normal user mode should never have this behaviour.
       */
    if((list->list[i].starty == -999) || 
       (list->list[i].endy==-999)){
      xsh_msg("PROBLEMS");
       method="fixed";
       break;
    }

    check(nsel=cpl_table_and_selected_int(res,"ABSORDER",CPL_EQUAL_TO,
					  list->list[i].absorder));
    if(nsel>0) {
      check(tbl=cpl_table_extract_selected(res));

      check(ypos=cpl_table_get_data_double(tbl,"CENTERY"));
      check(vypos = cpl_vector_wrap( nsel, ypos ));

      /* begin commented region */
      check(edgelo=cpl_table_get_data_double(tbl,"EDGELOX"));
      check(edgeup=cpl_table_get_data_double(tbl,"EDGEUPX"));

      check(vedgelo = cpl_vector_wrap( nsel, edgelo ));
      check(vedgeup = cpl_vector_wrap( nsel, edgeup ));

      check( xsh_free_polynomial( &edgelopoly));
      check(edgelopoly=xsh_polynomial_fit_1d_create( vypos, vedgelo,
						     list->list[i].pol_degree, 
						     NULL));

      check( xsh_free_polynomial( &edgeuppoly));
      check(edgeuppoly=xsh_polynomial_fit_1d_create( vypos, vedgeup,
						     list->list[i].pol_degree, 
						     NULL));



     
      //Overwrite flat edges polynomial coefficients values
      check( xsh_free_polynomial( &list->list[i].edglopoly));
      check(list->list[i].edglopoly=xsh_polynomial_fit_1d_create( vypos, vedgelo,
						     list->list[i].pol_degree, 
						     NULL));

      check( xsh_free_polynomial( &list->list[i].edguppoly));
      check(list->list[i].edguppoly=xsh_polynomial_fit_1d_create( vypos, vedgeup,
						     list->list[i].pol_degree, 
						     NULL));

      

      for(y=0; y< nsel; y++){
	check( pedgelof[k+y] = cpl_polynomial_eval_1d(edgelopoly,ypos[y],NULL));
	check( pedgeupf[k+y] = cpl_polynomial_eval_1d(edgeuppoly,ypos[y],NULL));

	  pedgelo_resx[k+y] =  pedgelof[k+y] -  edgelo[y];	  
          pedgeup_resx[k+y] =  pedgeupf[k+y] -  edgeup[y];
        //xsh_msg_debug("edge: lo=%g up=%g",pedgelof[k+y],pedgeupf[k+y]);
      }
      check( cpl_vector_unwrap(vedgeup )) ;
      check( cpl_vector_unwrap(vedgelo )) ;
      /* end commented region */

      if ( is_ifu ) {
	check(sliclo=cpl_table_get_data_double(tbl,"SLICELOX"));
	check(slicup=cpl_table_get_data_double(tbl,"SLICEUPX"));
	check( vslicup = cpl_vector_wrap( nsel, slicup )) ;
	check( vsliclo = cpl_vector_wrap( nsel, sliclo )) ;

	check( xsh_free_polynomial( &sliclopoly));
	check(sliclopoly=xsh_polynomial_fit_1d_create( vypos, vsliclo,
						       list->list[i].pol_degree, 
						       NULL));

	check( xsh_free_polynomial( &slicuppoly));
	check(slicuppoly=xsh_polynomial_fit_1d_create( vypos, vslicup,
						       list->list[i].pol_degree, 
						       NULL));



	//Overwrite IFU slices edges polynomial coefficients values	
	check( xsh_free_polynomial( &list->list[i].sliclopoly));
	check(list->list[i].sliclopoly=xsh_polynomial_fit_1d_create( vypos, vsliclo,
						       list->list[i].pol_degree, 
						       NULL));

	check( xsh_free_polynomial( &list->list[i].slicuppoly));
	check(list->list[i].slicuppoly=xsh_polynomial_fit_1d_create( vypos, vslicup,
						       list->list[i].pol_degree, 
						       NULL));

	

	for(y=0; y< nsel; y++){
	  check( pslicelof[k+y] = cpl_polynomial_eval_1d(sliclopoly,ypos[y],NULL));
	  check( psliceupf[k+y] = cpl_polynomial_eval_1d(slicuppoly,ypos[y],NULL));
	  pslicelo_resx[k+y] =  pslicelof[k+y] -  sliclo[y];	  
          psliceup_resx[k+y] =  psliceupf[k+y] -  slicup[y];
	}
	check( cpl_vector_unwrap(vslicup )) ;
	check( cpl_vector_unwrap(vsliclo )) ;
      }
      k+=nsel;
      xsh_free_table(&tbl);
      cpl_vector_unwrap(vypos );

    }
    cpl_table_select_all(res);
  }

  if(xsh_debug_level_get() >= XSH_DEBUG_LEVEL_MEDIUM) {

     /* save results */
     if ( instrument->mode == XSH_MODE_IFU)  {
        if (instrument->arm != XSH_ARM_UVB) {
           check(name_o=XSH_GET_TAG_FROM_ARM(XSH_MEASURE_FLAT_IFU_EDGES,instrument));
        } else {
           if(instrument->lamp == XSH_LAMP_QTH) {
              check(name_o=XSH_MEASURE_FLAT_QTH_IFU_EDGES_UVB);
           } else {
              check(name_o=XSH_MEASURE_FLAT_D2_IFU_EDGES_UVB);
           }
        }
     } else {
        if (instrument->arm != XSH_ARM_UVB) {
           check(name_o=XSH_GET_TAG_FROM_ARM(XSH_MEASURE_FLAT_SLIT_EDGES,instrument));
        } else {
           if(instrument->lamp == XSH_LAMP_QTH) {
              check(name_o=XSH_MEASURE_FLAT_QTH_SLIT_EDGES_UVB);
           } else {
              check(name_o=XSH_MEASURE_FLAT_D2_SLIT_EDGES_UVB);
           }
        }
     }
     sprintf(name_t,"%s%s",name_o,".fits");
     check(plist=cpl_propertylist_load(name,0));
     check(cpl_table_save(res,plist,NULL,name_t,CPL_IO_DEFAULT));
  }

 cleanup:
  check( xsh_free_polynomial( &sliclopoly));
  check( xsh_free_polynomial( &slicuppoly));
  check( xsh_free_polynomial( &edgelopoly));
  check( xsh_free_polynomial( &edgeuppoly));
  xsh_free_propertylist(&plist);
  xsh_free_image(&mflat);
  xsh_free_image(&filter_x);
  xsh_free_table(&tbl);
  return res;

}



/** 
  @brief
    Evaluate by chunk in Y the total and mean flux and the corresponding errors
    around x,y input position
  @param[in] pre
    The image frame
  @param[in] xc
    The x center of chunk
  @param[in] yc
    The y center of chunk
  @param[in] chunk_y_hsize
    The half size of chunk in y
  @param[in] x_hsize
    The half size of window in which we do the 
    @param[in] decode_bp bad pixel code
  @param[out] flux
    The flux of chunk (must be allocated) size x_hsize*2+1
  @param[out] noise 
    The errors associated to chunk (must be allocated) size x_hsize*2+1
 */
static void xsh_eval_y_avg_chunk(xsh_pre* pre, int xc, int yc, 
  int chunk_y_hsize, int x_hsize, const int decode_bp, double *flux, double *noise)
{
  int nx, ny;
  float *data = NULL, *errs = NULL;
  int *qual = NULL;
  int res_size=0;
  int i,j;
  int nb_good_pixels=0;

  /* Check parameters */
  XSH_ASSURE_NOT_NULL( pre);
  XSH_ASSURE_NOT_NULL( flux);
  XSH_ASSURE_NOT_NULL( noise);

  nx = pre->nx;
  ny = pre->ny;
  res_size = x_hsize*2+1;

  XSH_ASSURE_NOT_ILLEGAL( xc-x_hsize >= 0);
  XSH_ASSURE_NOT_ILLEGAL( xc+x_hsize < nx);
  XSH_ASSURE_NOT_ILLEGAL( yc-chunk_y_hsize >= 0);
  XSH_ASSURE_NOT_ILLEGAL( yc+chunk_y_hsize < ny);

  /* Get data,errs, qual*/  
  check( data = cpl_image_get_data_float( pre->data));
  check( errs = cpl_image_get_data_float( pre->errs));
  check( qual = cpl_image_get_data_int( pre->qual));

  /* init vectors */
  for(i=0; i< res_size; i++){
    flux[i]=0;
    noise[i]=0;

  }
  /* calculate flux and noise */
  for(i=xc-x_hsize; i <= (xc+x_hsize); i++){
    nb_good_pixels = 0;
    int pix_val=i-xc+x_hsize;

    for(j=yc-chunk_y_hsize; j <= (yc+chunk_y_hsize); j++){
      int j_nx_plus_i=j*nx+i;
      if ( (qual[j_nx_plus_i] & decode_bp) == 0){
        flux[pix_val]+=data[j_nx_plus_i];
        noise[pix_val]+=errs[j_nx_plus_i]*errs[j_nx_plus_i];
        nb_good_pixels++;
      }
    }
    if(nb_good_pixels>0) {
      flux[pix_val] /= nb_good_pixels;
      noise[pix_val]= sqrt(noise[pix_val])/nb_good_pixels;
    } else {
      noise[pix_val] = 1;
    }
  }

  cleanup:
    return;
}

 /**
    @brief    Detect Y position where flux is max
    @param    list        order list structure
    @param    chunk_hsize chunk half size
    @param    cen_poly    polynomial description order centres
    @param    cen_start   start y order centers
    @param    cen_end     end y order centers
    @param    pre         frame in pre format
    @param    maxy        found Y maximum
    @return   void
 */

static void 
xsh_detect_max_y( xsh_order_list* list, 
                  int chunk_hsize, 
                  cpl_polynomial *cen_poly,
                  int cen_start, 
                  int cen_end, 
                  xsh_pre *pre, 
                  const int decode_bp,
                  int* maxy)
{
  int y;
  float flux_max;
  int *qual = NULL;

  /* check parameters */
  XSH_ASSURE_NOT_NULL( cen_poly);
  XSH_ASSURE_NOT_NULL( pre);
  XSH_ASSURE_NOT_NULL( maxy);
  XSH_ASSURE_NOT_ILLEGAL( cen_start >=1);
  XSH_ASSURE_NOT_ILLEGAL( cen_end <= pre->ny);

  check( qual = cpl_image_get_data_int( pre->qual));
  flux_max = 0.0;
  for(y=cen_start+chunk_hsize; y<= cen_end-chunk_hsize; y++){
    int x;
    double flux, noise;

    check( x = xsh_order_list_eval_int( list, cen_poly, y));
    /* computes mean signal and noise evaluating all (good) pixels in a box of
       chunk_hsize half X size and 1 pix Y size */
    check( xsh_eval_y_avg_chunk( pre, x-1, y-1, chunk_hsize, 0,decode_bp,
      &flux, &noise));
    if ( flux > flux_max ){
      if ( (qual[x-1+(y-1)*pre->nx] & decode_bp) == 0 ){

      flux_max = flux;
      *maxy = y;
      }
    }
  }

  cleanup:
    return;
}
 /**
    @brief    Detect order edges: at each y position determines low (left) 
              and upper (right) order edges
    @param    list         order list structure
    @param    y            y position at which flux is max
    @param    cen_poly     polynomial description order centres
    @param    pre          frame in pre format
    @param    window_hsize window half (X) size
    @param    res_flux     data flux array pointer
    @param    res_noise    data noise array pointer
    @param    chunk_hsize  chunk half (Y) size
    @param    min_snr      minimum signal to noise ratio
    @param    flux_frac    flux fraction
    @param    min_size_x   minimum x size of flat size
    @param    x_min        output min x
    @param    x_cen_sdivn  output singnal to noise ratio at central x
    @param    xup          output upper x
    @param    xlow         output lower x
    @param    min_low      output flux min at low edge
    @param    min_up       output flux min at upp edge
    @return   void
 */

static void 
xsh_detect_edges( xsh_order_list* list,
                  int y, 
                  cpl_polynomial *cen_poly, 
                  xsh_pre* pre,
                  int window_hsize, 
                  double* res_flux, 
                  double* res_noise,
                  int chunk_hsize, 
                  double min_snr,  
                  double flux_frac,
                  int min_size_x,
                  const int decode_bp,
                  int *x_min,
                  float *x_cen_sdivn,
                  int *xup, 
                  int *xlow,
                  float *min_low, 
                  float *min_up)
{
  int x = 0;
  float min = 0.0, noise = 0.0, sdivn = 0.0;
  float threshold = 0.0;
  int j = 0, xmin = 0,xmax = 0;
  int window_size;
  //int pos_min=0;
  //int min_order_size_x =0;

  /* check Parameters */
  XSH_ASSURE_NOT_NULL( cen_poly);
  XSH_ASSURE_NOT_NULL( pre);
  XSH_ASSURE_NOT_NULL( res_flux);
  XSH_ASSURE_NOT_NULL( res_noise);
  
  XSH_ASSURE_NOT_NULL( x_min);
  XSH_ASSURE_NOT_NULL( x_cen_sdivn);
  XSH_ASSURE_NOT_NULL( xup);
  XSH_ASSURE_NOT_NULL( xlow);
  XSH_ASSURE_NOT_NULL( min_low);
  XSH_ASSURE_NOT_NULL( min_up);

  window_size = window_hsize*2+1;
  //min_order_size_x = floor(0.5*min_size_x);

  check( x = xsh_order_list_eval_int( list, cen_poly, y)); 
  xmin = x-window_hsize;
  *x_min= xmin;
  xmax = x+window_hsize;

  /* VALID X,Y coordinate*/
  if (xmin >= 1 && xmax <= pre->nx) {
    /* compute mean flux and corresponding error summing up pixel signal in 
       a rectangular box of  (2*window_half_hsize+1) X size and (2*chunk_hsize+1)
       Y size */
    check( xsh_eval_y_avg_chunk( pre, x-1, y-1, chunk_hsize, window_hsize,decode_bp,
      res_flux, res_noise)); 
    /* compute the Signal / Noise at center */
    noise = res_noise[window_hsize+1];
    sdivn = res_flux[window_hsize+1]/noise;
    *x_cen_sdivn = sdivn;
    /* Measure edges only for regions of sufficiently high S/N ratio */
    if ( sdivn > min_snr ){
 
      /* get the (order right) edge upper limit */
      /* find the MIN flux level along the X window size */
      min = res_flux[window_hsize+1];
      for(j = window_hsize+1; j<window_size; j++) {
        if (min > res_flux[j]){
          min = res_flux[j];
        }
      }
      /* compute the minimum flux THRESHOLD at a given Y pixel:

         ---------\<----flux max
                   \<-----order edge
                    \
                    |
                    |
                    |
                    |
                    \
                     \--------threshold(min)
                      \<-----this position
                       ----------- min (inter-order background)

       */
      threshold = (res_flux[window_hsize+1]-min) * flux_frac;
 
      j = window_hsize+1;
      while( (j < window_size-1) && ((res_flux[j]-min) >= threshold)){
        j++;
      }
      *xup = j;
      *min_up = min;

      if ( (res_flux[j]-min) >= threshold){
        xsh_msg("WARNING UP edge not detected. Increase window size");
        *x_cen_sdivn = -1;
      }
      /* get the (order left) edge lower limits */
      /* find the MIN flux level along the X window size */
      min = res_flux[window_hsize+1];
      //pos_min = window_hsize+1;

      for(j=0; j<=window_hsize+1; j++) {
        if (min > res_flux[j]){
          min = res_flux[j];
          //pos_min = j;       
        }
      }

      /* compute the minimum flux THRESHOLD at a given Y pixel:

                  flux max  ---->  /----------------
                 order edge --->  / 
                                 /  
                                 |             
                                 |             
                                 |             
                                 |             
                                 /             
         threshold(min)      ---/               
         look for this pos---> /               
         inter-ord bkg(min)---/                   

       */


      threshold = (res_flux[window_hsize+1]-min) * flux_frac;
      j = window_hsize+1;
      while( (j > 0) && ( (res_flux[j]-min) >= threshold)){
        j--;
      }
      *xlow = (double)j;
      *min_low = min;
      if ( (res_flux[j]-min) >= threshold){
        xsh_msg("WARNING LOW edge not detected. Increase window size");
        *x_cen_sdivn = -1;
      }
      if ( (*xup-*xlow) < min_size_x){
        xsh_msg_dbg_medium("y %d : Size of order in cross dispersion "\
          "to small %d < %d", y, *xup-*xlow, min_size_x);
        *x_cen_sdivn = -1;
      }
    }
    else{
      xsh_msg_dbg_medium("y %d Invalid s/n : %f > %f", y, sdivn, min_snr);
    }
  }
  else{
    xsh_msg_dbg_medium("y %d Invalid xmin %d  or xmax %d", y, xmin, xmax); 
    *x_cen_sdivn = -1;
  }
  cleanup:
    return;
} 
/* Measure a flux ratio at lower and upper edges with respect to flux at center */
static void xsh_detect_slitlet_ratio( double* res_flux, int window_hsize,
  double min_low, double min_up, int xlow, int xup, 
  double *ratio_low, double *ratio_up)
{
  double avg_cen = 0., avg_lo=0., avg_up=0.;
  int j;
  int size;
  int center;


  /* Check Parameters */
  XSH_ASSURE_NOT_NULL( res_flux);
  XSH_ASSURE_NOT_NULL( ratio_up);
  XSH_ASSURE_NOT_NULL( ratio_low);

  size = (xup-xlow)/3;  
  
  center = window_hsize+1;
  /* evaluate average flux level for each IFU slitlet: */
  /* evaluate average flux level for central IFU slitlet  */
  for( j=center-HALF_SLIC_WINDOW; 
    j <= center+HALF_SLIC_WINDOW ; j++ ){
    avg_cen += res_flux[j];
  }
  avg_cen /= (HALF_SLIC_WINDOW*2)+1;

  /* evaluate average flux level for low (left) IFU slitlet  */
  center = window_hsize+1-size;
  for( j=center-HALF_SLIC_WINDOW;         
    j <= center+HALF_SLIC_WINDOW ; j++ ){
    avg_lo += res_flux[j];
  }
  avg_lo /= (HALF_SLIC_WINDOW*2)+1;

  /* evaluate average flux level for up (right) IFU slitlet */
  center = window_hsize+1+size;
  for( j=center-HALF_SLIC_WINDOW;
    j <= center+HALF_SLIC_WINDOW ; j++ ){
    avg_up += res_flux[j];
  }
  avg_up /= (HALF_SLIC_WINDOW*2)+1;
  /* finally determines the slitlet flux ratio for upper and lower slitlet
     as fraction of average flux above the min slitlet background as compared
     to the mean central slitlet flux */
  *ratio_up = (avg_up-min_up)/(avg_cen-min_up);
  *ratio_low = (avg_lo-min_low)/(avg_cen-min_low);
  cleanup:
    return;
} 
/** 
  @brief
    Detect order edges and compute polynomial description of ordermin 
    and order max
  @param[in] frame
    The image frame [PRE]
  @param[in] cen_order_tab_frame 
    The frame [ORDER_TAB]
  @param[in] detectorder_par
    The detection parameters
  @param[in] instrument
    The instrument setting
  @return
    The edges order table containing polynomial description of the edges
 */

cpl_frame* xsh_detect_order_edge(cpl_frame *frame,
    cpl_frame *cen_order_tab_frame, xsh_detect_order_param *detectorder_par,
    xsh_instrument *instrument) {
  /* MUST BE DEALLOCATED in caller */
  cpl_frame * result = NULL;
  /* ALLOCATED locally */
  xsh_pre* pre = NULL;
  xsh_order_list* list = NULL;
  double* positions = NULL; /**< Y position */
  double* uppervalues = NULL; /**< Lower X position */
  double* lowervalues = NULL; /**< Upper X position */
  double * slicup = NULL; /**< Upper X position of center slice */
  double * sliclow = NULL; /**< Lower X position of center slice */
  cpl_vector* xpos = NULL;
  cpl_vector* upper = NULL;
  cpl_vector* lower = NULL;
  cpl_vector * vslicup = NULL;
  cpl_vector * vsliclow = NULL;

  /* Others */
  int y = 0;
  int size = 0, i = 0, k = 0;
  int is_ifu = 0;
  char *fname = NULL;
  const char * tag = NULL;
  //const char * arm_name = NULL;

  int window_size, min_order_size_x, chunk_hsize, window_hsize;
  double min_snr, slitlet_up_factor, slitlet_low_factor;
  double *res_flux = NULL, *res_noise = NULL;
  double flux_frac;
  int fixed_slice = 0;
  const char* method = NULL;

  cpl_table* tab_edges_res = NULL;
  int bad_points = 0;

  /* check input */
  XSH_ASSURE_NOT_NULL(frame);
  XSH_ASSURE_NOT_NULL(cen_order_tab_frame);
  XSH_ASSURE_NOT_NULL(detectorder_par);

  /* stores relevant recipe parameters in local variable */
  window_hsize = detectorder_par->search_window_hsize;
  window_size = window_hsize * 2 + 1;
  min_order_size_x = detectorder_par->min_order_size_x;

  flux_frac = detectorder_par->flux_thresh;
  min_snr = detectorder_par->min_sn;
  slitlet_low_factor = detectorder_par->slitlet_low_factor;
  slitlet_up_factor = detectorder_par->slitlet_up_factor;
  chunk_hsize = detectorder_par->chunk_hsize;
  fixed_slice = detectorder_par->fixed_slice;
  method = detectorder_par->method;

  /* make initial check and suggest solution if not satisfied */
  assure(window_size > 0, CPL_ERROR_ILLEGAL_INPUT,
      "window_size=%d (window_size=window_hsize*2+1) < 0 "
      "parameter detectorder-edges-search-window-half-size=%d "
      "may have been set to a too large value", window_size, window_hsize);

  /* Monitor values of relevant parameters */
  xsh_msg_dbg_medium("Parameters");
  xsh_msg_dbg_medium(
      " Window: %d,flux-Thresh: %.2f, S/N: %.2f", window_size, flux_frac, min_snr);
  xsh_msg_dbg_medium(
      " min-size-x: %d, Slitlet-low-factor: %.2f\
   Slitlet-up-factor: %.2f chunk-half-size %d", min_order_size_x, slitlet_low_factor, slitlet_up_factor, chunk_hsize);
  xsh_msg_dbg_medium(" fixed-slice = %s", BOOLEAN_TO_STRING(fixed_slice));

  /* load the frames */
  check( pre = xsh_pre_load( frame, instrument));

  check(list = xsh_order_list_load( cen_order_tab_frame, instrument));

  assure(
      min_order_size_x > 0 && min_order_size_x < (floor) (pre->nx / list->size),
      CPL_ERROR_ILLEGAL_INPUT, "parameter detectorder-min-order-size-x=%d "
      "has been set to a too small or too large value", min_order_size_x);

  //xsh_order_list_set_bin_x( list, pre->binx);
  //xsh_order_list_set_bin_y( list, pre->biny);

  XSH_REGDEBUG("binning %dx%d", list->bin_x, list->bin_y);
  /* clean header */
  xsh_free_propertylist(&(list->header));
  XSH_NEW_PROPERTYLIST( list->header);

  /* get the data */
  //arm_name = xsh_instrument_arm_tostring(instrument);

  is_ifu = xsh_instrument_get_mode(instrument) == XSH_MODE_IFU;
  if (is_ifu) {
    xsh_msg( "Detect Order Edges in IFU mode");
  } else {
    xsh_msg( "Detect Order Edges in SLIT mode");
  }

  /* allocate memory on variable storing intermediate results */
  /* detect order edge */
  /* TODO: is the size of this array ok? should not be pre->ny/list->bin_y? */
  XSH_CALLOC( positions, double, pre->ny*list->bin_y); /* y pos */
  XSH_CALLOC  ( uppervalues,double,pre->ny*list->bin_y); /* right edge x pos */
  XSH_CALLOC( lowervalues, double,pre->ny*list->bin_y); /* left edge x pos */
  XSH_CALLOC  ( res_flux, double, window_size); /* flux level */
  XSH_CALLOC( res_noise, double,window_size);   /* noise level */
  /* In case of IFU */
  XSH_CALLOC  ( slicup,double,pre->ny*list->bin_y); /* IFU upp slice (right) pos */
  XSH_CALLOC( sliclow, double,pre->ny*list->bin_y); /* IFU low slice (left) pos */

  /* slitlet init factor */
  int  decode_bp = instrument->decode_bp;
  /* for all orders */
  for (i = 0; i < list->size; i++) {
    int mean_size_up = 0;
    int mean_size_low = 0;
    int mean_size_slic_low = 0;
    int mean_size_slic_up = 0;
    double ratio_low = 0., ratio_up = 0.;
    int bin_starty;
    int bin_endy;

    size = 0;
    check( bin_starty = xsh_order_list_get_starty( list, i));
    check( bin_endy = xsh_order_list_get_endy( list, i));
    xsh_msg_dbg_medium( "***** Order %d (%d-->%d)", i, bin_starty, bin_endy);

    if (is_ifu && !fixed_slice) {
      int max_y = 0;
      float min_lo = 0.0, min_up = 0.0, sdivn = 0.0;
      int xmin = 0;
      int upperval = 0, lowval = 0;

      /* Scan the whole order and detect y position at which its flux is 
         maximum. The pixel must be a good pixel (we use also pixel code to 
         specify which pixel codes are good/bad) */
      check(
          xsh_detect_max_y( list, chunk_hsize, list->list[i].cenpoly, bin_starty, bin_endy, pre,decode_bp, &max_y));
      xsh_msg("Max at %d", max_y);

      /* detect order low (left) and upper (right) edge positions */
      check(
          xsh_detect_edges( list, max_y, list->list[i].cenpoly, pre, window_hsize, res_flux, res_noise, chunk_hsize, min_snr, flux_frac, min_order_size_x,decode_bp, &xmin, &sdivn, &upperval, &lowval, &min_lo, &min_up));

      /* estimate size of order along X */
      xsh_msg_dbg_medium("order size at center %d", upperval-lowval);
      /* estimate slitlet ratio at order center */
      /* estimate the slitlet flux ratio for upper and lower IFU slitlets
         as fraction of average flux above the min slitlet background as 
         compared to the mean central slitlet flux */
      check(
          xsh_detect_slitlet_ratio( res_flux, window_hsize, min_lo, min_up, lowval, upperval, &ratio_low, &ratio_up));
      xsh_msg_dbg_medium("ratio low %f up %f", ratio_low, ratio_up);
    }
    /* for all Y */
    bad_points = 0;
    for (y = 1 + chunk_hsize; y <= pre->ny - chunk_hsize; y++) {
      //if((y>= list->list[i].starty) &&
      // (y<=list->list[i].endy)) {
      float min_lo = 0.0, min_up = 0.0, sdivn = 0.0;
      int j = 0, xmin = 0;
      int upperval = 0, lowval = 0;
      double xslicup = 0.;
      double xsliclow = 0.;
      /* detect order low (left) and upper (right) edge positions */

      check(
          xsh_detect_edges( list, y, list->list[i].cenpoly, pre, window_hsize, res_flux, res_noise, chunk_hsize, min_snr, flux_frac, min_order_size_x,decode_bp, &xmin, &sdivn, &upperval, &lowval, &min_lo, &min_up));

      /* IFU - PRELIMINARY
       Starting from x (center of the order) calculate mean flux
       value using +-2 pixels
       Then find the slicup (from x toward nx): the edge is where
       the signal becomes lower than 90% of the avg signal at the
       center.
       Same for sliclow
       */
      /* limit edge detection to good S/N regions */
      if ((sdivn > min_snr) && is_ifu) {
        if (fixed_slice) {
          int slit_size = ceil((upperval - lowval + 1) / 3.0);

          xsliclow = lowval + slit_size;
          xslicup = upperval - slit_size;
        } else {
          double avg = 0.;
          double max;

          for (j = window_hsize + 1 - HALF_SLIC_WINDOW;
              j <= window_hsize + 1 + HALF_SLIC_WINDOW; j++) {
            avg += res_flux[j];
          }
          avg /= (HALF_SLIC_WINDOW * 2) + 1;
          max = (avg - min_up) * slitlet_up_factor * ratio_up;
          xslicup = 0;
          for (j = window_hsize + 1; j <= upperval; j++) {
            if ((res_flux[j] - min_up) < max) {
              /* Found position of slicup */
              xslicup = j - 1;
              break;
            }
          }
          xsliclow = 0;
          max = (avg - min_lo) * slitlet_low_factor * ratio_low;
          for (j = window_hsize + 1; j >= lowval; j--) {
            if ((res_flux[j] - min_lo) < max) {
              /* Found position of slicup */
              xsliclow = j + 1;
              break;
            }
          }
        }
      }
      /* store detect order edge */
      if ((sdivn > min_snr) && (upperval - lowval) >= min_order_size_x) {
        if (!is_ifu) {
          positions[size] = y;
          lowervalues[size] = lowval + xmin;
          uppervalues[size] = upperval + xmin;
          mean_size_low += window_hsize + 1 - lowval;
          mean_size_up += upperval - (window_hsize + 1);
          size++;
        } else if (xslicup != 0 && xsliclow != 0) {

          positions[size] = y;
          lowervalues[size] = lowval + xmin;
          uppervalues[size] = upperval + xmin;
          mean_size_low += window_hsize + 1 - lowval;
          mean_size_up += upperval - (window_hsize + 1);
          slicup[size] = xslicup + xmin;
          sliclow[size] = xsliclow + xmin;
          mean_size_slic_low += window_hsize + 1 - xsliclow;
          mean_size_slic_up += xslicup - (window_hsize + 1);
          size++;
        }
      } else {
        xsh_msg_dbg_medium(
            "Order %d edge detection: sn (%g) < sn_threshold (%g) or order size (%d) < min order size min (%d)", list->list[i].absorder, sdivn, min_snr, (upperval - lowval), min_order_size_x);
        bad_points++;
      }
      /* END VALID THRESH*/
      //}//end check starty < y < endy
    } // end loop over y
    if (bad_points > 1) {
      xsh_msg_dbg_medium(
          "Order %d edge detection summary: ", list->list[i].absorder);
      xsh_msg_dbg_medium(
          "%d out of %d not matching user defined min S/N (%g), or minimum order size", bad_points, pre->ny-2*chunk_hsize, min_snr);
    }

    /* put the start and end of order in Y */
    if (size <= 3 && detectorder_par->qc_mode == CPL_TRUE) {
      /* Set dummy values:
       -999 can occur only in QC mode and is used as flag to skip
       edge detection on a given order. This was explitly asked by QC.
       Normal user mode should never have this behaviour.
       */

      list->list[i].starty = -999;
      list->list[i].endy = -999;
      xsh_msg("PROBLEMS");
      //list->size=list->size-1;
      method = "fixed";
      xsh_msg_error(
          "%d out of %d not matching user defined min S/N (%g), or minimum order size", bad_points, pre->ny-2*chunk_hsize, min_snr);

      break;

    } else {
      assure(
          size > 3,
          CPL_ERROR_ILLEGAL_INPUT,
          "can't fit polynomial solution of degree %d to only %d data points "
          "parameter detectorder-edges-search-window-half-size=%d "
          "may have a too small value "
          "or parameter detectorder-min-sn value may be too big "
          "or parameter detectorder-chunk-half-size=%d "
          "may have been set to a too small or too large large value "
          "or parameter detectorder-edges-flux-thresh=%g "
          "may have been set to a too small or too large large value", list->list[i].pol_degree, size, window_hsize, chunk_hsize, flux_frac);

      list->list[i].starty = positions[0] - chunk_hsize;
      list->list[i].endy = positions[size - 1] + chunk_hsize;
    }

    mean_size_up = mean_size_up / size;
    mean_size_low = mean_size_low / size;
    xsh_msg_dbg_medium("mean size up %d low %d", mean_size_up, mean_size_low);
    if (is_ifu) {
      mean_size_slic_low = mean_size_slic_low / size;
      mean_size_slic_up = mean_size_slic_up / size;
    }
    xsh_msg_dbg_medium(
        "mean size Slitlets up %d low %d", mean_size_slic_up, mean_size_slic_low);
    /* arrange polynomial if start_y and end_y covers only a part of ny */
    xsh_msg_dbg_medium(
        "starty %d endy %d", list->list[i].starty, list->list[i].endy);

    for (y = 1; y < list->list[i].starty; y++) {
      int x_center;

      check(
          x_center = xsh_order_list_eval_int( list, list->list[i].cenpoly, y));
      positions[size] = y;
      lowervalues[size] = x_center - mean_size_low;
      uppervalues[size] = x_center + mean_size_up;
      if (is_ifu) {
        sliclow[size] = x_center - mean_size_slic_low;
        slicup[size] = x_center + mean_size_slic_up;
      }
      size++;
    }
    for (y = list->list[i].endy + 1; y <= pre->ny; y++) {
      int x_center;

      check(
          x_center = xsh_order_list_eval_int( list, list->list[i].cenpoly, y));
      positions[size] = y;
      lowervalues[size] = x_center - mean_size_low;
      uppervalues[size] = x_center + mean_size_up;

      if (is_ifu) {
        sliclow[size] = x_center - mean_size_slic_low;
        slicup[size] = x_center + mean_size_slic_up;
      }
      size++;
    }

    /*Detected points debugging */
    if (xsh_debug_level_get() >= XSH_DEBUG_LEVEL_MEDIUM) {
      FILE* debug_out = NULL;
      int newi = 0;
      char openmode[2];

      if (i == 0) {
        sprintf(openmode, "w");
      } else {
        sprintf(openmode, "a");
      }XSH_NAME_LAMP_MODE_ARM( fname, "detect_edges_points", ".log",
          instrument);
debug_out      = fopen(fname, openmode);

      for (newi = 0; newi < size; newi++) {
        fprintf(debug_out, "%f %f %f\n", lowervalues[newi], uppervalues[newi],
            positions[newi]);
      }
      fclose(debug_out);
      if (is_ifu) {
        XSH_NAME_LAMP_MODE_ARM( fname, "orders_slic", ".log", instrument);
debug_out        = fopen(fname, openmode);

        for (newi = 0; newi < size; newi++) {
          fprintf(debug_out, "%f %f %f\n", sliclow[newi], slicup[newi],
              positions[newi]);
        }
        fclose(debug_out);
      }
    }
    /* positions convert in binning 1x1 */
    list->list[i].starty *= list->bin_y;
    list->list[i].endy *= list->bin_y;

    for (k = 0; k < size; k++) {
      lowervalues[k] *= list->bin_x;
      uppervalues[k] *= list->bin_x;
      positions[k] *= list->bin_y;
      if (is_ifu) {
        sliclow[k] *= list->bin_x;
        slicup[k] *= list->bin_x;
      }
    }
    /* create vector from values */
    check(xpos = cpl_vector_wrap(size,positions));
    check(upper = cpl_vector_wrap(size,uppervalues));
    check(lower = cpl_vector_wrap(size,lowervalues));
    if (is_ifu) {
      check( vslicup = cpl_vector_wrap( size, slicup ));
      check( vsliclow = cpl_vector_wrap( size, sliclow ));
    }

    /* create polynomial solutions: fit a polynomial to the found order edges 
      (and eventually IFU lower and upper slices positions) */
    check( xsh_free_polynomial( &list->list[i].edguppoly));
    check(
        list->list[i].edguppoly = xsh_polynomial_fit_1d_create( xpos, upper, list->list[i].pol_degree, NULL));

    check( xsh_free_polynomial( &list->list[i].edglopoly));
    check(
        list->list[i].edglopoly = xsh_polynomial_fit_1d_create( xpos, lower, list->list[i].pol_degree, NULL));

    if (is_ifu) {
      check( xsh_free_polynomial( &list->list[i].sliclopoly));
      check(
          list->list[i].sliclopoly = xsh_polynomial_fit_1d_create( xpos, vsliclow, list->list[i].pol_degree, NULL));
      check( xsh_free_polynomial( &list->list[i].slicuppoly));
      check(
          list->list[i].slicuppoly = xsh_polynomial_fit_1d_create( xpos, vslicup, list->list[i].pol_degree,NULL));
    }


    /* ENDREGDEBUG */
    check( xsh_unwrap_vector(&xpos));
    check( xsh_unwrap_vector(&upper));
    check( xsh_unwrap_vector(&lower));
    if (is_ifu) {
      check( xsh_unwrap_vector( &vslicup));
      check( xsh_unwrap_vector( &vsliclow));
    }

  } /* end loop over i (order list counter) */
  /* REG comment due to important memory leaks */
  if (strcmp(method, "fixed") != 0) {
    check(tab_edges_res=xsh_compute_flat_edges(frame,list,instrument,method));
  }
  /* Finally save results in edge order table */
  tag = XSH_GET_TAG_FROM_LAMP( XSH_ORDER_TAB_EDGES,instrument);
  XSH_REGDEBUG( "tag %s", tag);
  XSH_NAME_LAMP_MODE_ARM( fname, XSH_ORDER_TAB_EDGES, ".fits", instrument);
check  ( result = xsh_order_list_save( list, instrument, fname, tag, pre->ny*list->bin_y));

  if (strcmp(method, "fixed") != 0) {
    check(cpl_table_save(tab_edges_res, NULL, NULL, fname, CPL_IO_EXTEND));
  }
  //check( xsh_add_temporary_file( fname));
  xsh_msg_dbg_high( " Created %s", fname);

  cleanup: if (cpl_error_get_code() != CPL_ERROR_NONE) {
    xsh_unwrap_vector(&xpos);
    xsh_unwrap_vector(&upper);
    xsh_unwrap_vector(&lower);
    xsh_unwrap_vector(&vslicup);
    xsh_unwrap_vector(&vsliclow);
  }
  xsh_pre_free(&pre);
  xsh_free_table(&tab_edges_res);

  xsh_order_list_free(&list);
  XSH_FREE( positions);
  XSH_FREE( uppervalues);
  XSH_FREE( lowervalues);
  XSH_FREE( res_flux);
  XSH_FREE( res_noise);
  XSH_FREE( slicup);
  XSH_FREE( sliclow);
  XSH_FREE( fname);
  return result;
}
/*---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------*/
/**@}*/
