/*                                                                            *
 *   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 $
 * $Revision: 1.25 $
 */

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

/*----------------------------------------------------------------------------*/
/**
 * @defgroup xsh_combine_nod  Combine rectified NOD Frames
 * @ingroup drl_functions
 *
 * Function ...
 */
/*----------------------------------------------------------------------------*/
/**@{*/

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

#include <math.h>
#include <xsh_drl.h>

#include <xsh_badpixelmap.h>
#include <xsh_utils_image.h>
#include <xsh_data_pre.h>
#include <xsh_data_order.h>
#include <xsh_data_wavemap.h>
#include <xsh_data_localization.h>
#include <xsh_data_rec.h>
#include <xsh_dfs.h>
#include <xsh_pfits.h>
#include <xsh_error.h>
#include <xsh_msg.h>
#include <xsh_fit.h>
#include <xsh_badpixelmap.h>

#include <cpl.h>
#define combine_nod_old  0
/*-----------------------------------------------------------------------------
  Functions prototypes
  -----------------------------------------------------------------------------*/

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


void xsh_compute_slit_index( float slit_min, float slit_step,
		xsh_rec_list **from, int *slit_index_tab, int size)
{
	int i;

	XSH_ASSURE_NOT_NULL( from);
	XSH_ASSURE_NOT_NULL( slit_index_tab);

	for( i=0; i< size; i++){
		xsh_rec_list *list = NULL;
		float* nod_slit = NULL;

		list = from[i];
		check( nod_slit = xsh_rec_list_get_slit( list, 0));
		slit_index_tab[i] = (int)xsh_round_double((nod_slit[0]-slit_min)/slit_step);
	}
	cleanup:
	return;
}

/* TODO: NOT USED
static void
xsh_rec_list_add_scaled(xsh_rec_list *dest, xsh_rec_list **from,
                 int *slit_index, int nb_frames, int no,
                 int method, const int decode_bp)
{
    int nslit, from_slit, nlambda;
    float *dest_data1 = NULL, *dest_errs1 = NULL;
    int *dest_qual1 = NULL;
    float *from_data1 = NULL, *from_errs1 = NULL;
    int *from_qual1 = NULL;
    int ns, nl, nf;
    double *flux_tab = NULL;
    cpl_vector *flux_vect = NULL;
    double *err_tab = NULL;
    cpl_vector *err_vect = NULL;
    cpl_imagelist* all_iml;
    cpl_imagelist* flag_iml;
    cpl_image* all_ima;
    cpl_image* flag_ima;
    cpl_image* tmp_ima;
    cpl_image* scale_ima;
    float* pall_ima;
    float* pflag_ima;
    //float* pscale_ima;
    double scale;
    int sx=1;
    int sy=5;
    cpl_mask* bpm;
    cpl_binary* pbpm;
    int pix=0;
    int i,j;
    int nx=2*sx+1;
    int ny=2*sy+1;
    XSH_ASSURE_NOT_NULL( dest);
    XSH_ASSURE_NOT_NULL( from);
    XSH_ASSURE_NOT_NULL( slit_index);

    xsh_msg_dbg_medium(
                    "xsh_rec_list_add: nb frames: %d, order: %d", nb_frames, no);

    check( nslit = xsh_rec_list_get_nslit( dest, no));
    check( from_slit = xsh_rec_list_get_nslit( from[0], no));
    check( nlambda = xsh_rec_list_get_nlambda( dest, no));

    check( dest_data1 = xsh_rec_list_get_data1( dest, no));
    check( dest_errs1 = xsh_rec_list_get_errs1( dest, no));
    check( dest_qual1 = xsh_rec_list_get_qual1( dest, no));

    XSH_MALLOC( flux_tab, double, nb_frames);
    XSH_MALLOC  ( err_tab, double , nb_frames);

    for (nf = 0; nf < nb_frames; nf++) {
        xsh_msg_dbg_high(
                        "slit index: max %d min=%d", slit_index[nf], slit_index[nf]+from_slit);
    }
    //xsh_msg("nslit=%d nlambda=%d",nslit,nlambda);

    all_iml=cpl_imagelist_new();
    flag_iml=cpl_imagelist_new();

    for (nf = 0; nf < nb_frames; nf++) {
        all_ima=cpl_image_new(nx,ny,CPL_TYPE_FLOAT);
        cpl_imagelist_set(all_iml,cpl_image_duplicate(all_ima),nf);
        cpl_imagelist_set(flag_iml,cpl_image_duplicate(all_ima),nf);
        cpl_image_delete(all_ima);
    }

    for (ns = 0; ns < nslit; ns++) {
        for (nl = 0; nl < nlambda; nl++) {
            int dest_idx;
            int good = 0, bad = 0;
            //int isum =0;
            int x_min=-sx, x_max=sx, y_min=-sy, y_max=sy;
            //double dest_err = 0, dest_data = 0. ;
            //double bad_err = 0, bad_data = 0;
            unsigned int qflag = QFLAG_GOOD_PIXEL;
            unsigned int badflag = QFLAG_GOOD_PIXEL;

            dest_idx = nl + ns * nlambda;
            //xsh_msg("ok4");

            if (y_min < 0) {
                y_min = 0;
                y_max = ny;
            } else if (ns+y_max > nslit) {
                y_max=nslit;
                y_min=y_max-ny;
            }

            if (x_min < 0) {
                x_min = 0;
                x_max = nx;
            } else if (nl+x_max > nlambda) {
                x_max=nlambda;
                x_min=x_max-nx;
            }

            for (nf = 0; nf < nb_frames; nf++) {
                int from_idx;

                if ((ns < slit_index[nf]) || (ns >= (slit_index[nf] + from_slit))) {
                    continue;
                }
                from_idx = nl + (ns - slit_index[nf]) * nlambda;
                check( from_data1 = xsh_rec_list_get_data1( from[nf], no));
                check( from_errs1 = xsh_rec_list_get_errs1( from[nf], no));
                check( from_qual1 = xsh_rec_list_get_qual1( from[nf], no));
                //xsh_msg("ok6");

                tmp_ima=cpl_imagelist_get(all_iml,nf);
                pall_ima=cpl_image_get_data_float(tmp_ima);
                tmp_ima=cpl_imagelist_get(flag_iml,nf);
                pflag_ima=cpl_image_get_data_float(tmp_ima);
                bpm=cpl_image_get_bpm(tmp_ima);

                //xsh_msg("ok7 x_min=%d x_max=%d y_min=%d y_max=%d",x_min,x_max,y_min,y_max);

                for(j=y_min; j < y_max; j++) {
                   for(i=x_min; i < x_max; i++) {
                       pix=j*sx+i;

                       //xsh_msg("i=%d j=%d pix=%d size_ima=%d nf=%d slit_index[nf]=%d ns=%d nl=%d from_idx=%d from_idx+pix=%d",
                       //        i,j,pix,nx*ny,nf,slit_index[nf],ns,nl,from_idx,from_idx+pix);

                       pall_ima[pix]=from_data1[from_idx+pix]; // Invalid Write of size 4
                       pflag_ima[pix]=from_data1[from_idx+pix];// Invalid Write of size 4
                       //xsh_msg("all[%d,%d]=%g flag=%g",i,j,pall_ima[pix],pflag_ima[pix]);
                   }
                }

                pbpm=cpl_mask_get_data(bpm);
                // previous implementation separates good and bad pixels
                if ((from_qual1[from_idx] & decode_bp) == 0) {
                    qflag |= from_qual1[from_idx];
                    flux_tab[good] = from_data1[from_idx];
                    err_tab[good] = from_errs1[from_idx];
                    good++;

                } else if ((from_qual1[from_idx] & decode_bp) > 0) {
                    flux_tab[good + bad] = from_data1[from_idx];
                    err_tab[good + bad] = from_errs1[from_idx];
                    badflag |= from_qual1[from_idx];
                    for(j=y_min; j < y_max; j++) {
                        for(i=x_max; i < x_min; i++) {
                            //flag all plane
                            pbpm[j*sx+i]=CPL_BINARY_1;
                        }
                    }
                    bad++;
                }

            }

            // compute scale factors

            all_ima = cpl_imagelist_collapse_create(all_iml);
            flag_ima = cpl_imagelist_collapse_create(flag_iml);

            //cpl_image_save(all_ima, "all_ima.fits", CPL_TYPE_FLOAT, NULL, CPL_IO_DEFAULT);
            //cpl_image_save(flag_ima, "flag_ima.fits", CPL_TYPE_FLOAT, NULL, CPL_IO_DEFAULT);
            scale_ima=cpl_image_duplicate(all_ima);
            cpl_image_divide(scale_ima,flag_ima);

            scale=cpl_image_get_mean(scale_ima);
            //cpl_image_save(scale_ima, "scale_ima.fits", CPL_TYPE_FLOAT, NULL, CPL_IO_DEFAULT);
            xsh_msg("scale=%g",scale);
            cpl_image_delete(all_ima);
            cpl_image_delete(flag_ima);
            cpl_image_delete(scale_ima);

            // Dont calculate mean value, just sum
            // previous implementation separates good and bad pixels
            if (good == 0) {
                check( flux_vect = cpl_vector_wrap( bad, flux_tab));
                check( err_vect = cpl_vector_wrap( bad, err_tab));
                // No good pixel
                dest_qual1[dest_idx] |= badflag;
                scale=1;
            } else {
                dest_qual1[dest_idx] |= qflag;
                if(bad > 0) {
                    dest_qual1[dest_idx] |= QFLAG_INCOMPLETE_DATA;
                } else {
                    scale=1;
                }
                check( flux_vect = cpl_vector_wrap( good, flux_tab));
                check( err_vect = cpl_vector_wrap( good, err_tab));
            }

            if (method == COMBINE_MEAN_METHOD) {
                check( dest_data1[dest_idx] = cpl_vector_get_mean( flux_vect) *scale );
                check( dest_errs1[dest_idx] = xsh_vector_get_err_mean( err_vect));
            } else {
                check( dest_data1[dest_idx] = cpl_vector_get_median( flux_vect) *scale);
                check( dest_errs1[dest_idx] = xsh_vector_get_err_median( err_vect));
            }

            xsh_unwrap_vector(&flux_vect);
            xsh_unwrap_vector(&err_vect);
        }
    }

    cleanup:
    if (cpl_error_get_code() != CPL_ERROR_NONE) {
        xsh_unwrap_vector(&flux_vect);
        xsh_unwrap_vector(&err_vect);
    }

    XSH_FREE( flux_tab);
    XSH_FREE( err_tab);

    xsh_print_rec_status(15);
    return;
}
 */
/* TODO: NOT USED YET
static cpl_image*
xsh_rec_list_compute_scale(xsh_rec_list *dest, xsh_rec_list **from,
                 int *slit_index, int nb_frames, int no,
                 int method, const int decode_bp)
{

    cpl_image* scale;
    float *from_data1 = NULL;
    int *from_qual1 = NULL;
    float *dest_data1 = NULL;
    int *dest_qual1 = NULL;
    int nslit, from_slit, nlambda;
    int ns, nl, nf;
    XSH_ASSURE_NOT_NULL( dest);
    XSH_ASSURE_NOT_NULL( from);
    XSH_ASSURE_NOT_NULL( slit_index);

    nslit = xsh_rec_list_get_nslit( dest, no);
    from_slit = xsh_rec_list_get_nslit( from[0], no);
    nlambda = xsh_rec_list_get_nlambda( dest, no);

    dest_data1 = xsh_rec_list_get_data1( dest, no);
    dest_qual1 = xsh_rec_list_get_qual1( dest, no);

    //cpl_image* from_ima_tmp;
    //cpl_imagelist* from_iml;
    scale=cpl_image_new(nlambda,nslit,CPL_TYPE_FLOAT);
    float sum_good_pix;
    float sum_tot_pix;
    int num_good_pix;
    int num_tot_pix;
    int win_hsx=3;
    int win_hsy=3;
    int win_sx=2*win_hsx+1;
    int win_sy=2*win_hsy+1;
    float sum_all;
    float sum_good;
    cpl_imagelist* iml_good;
    cpl_imagelist* iml_all;
    cpl_imagelist* iml_copy;
    cpl_image* ima_tmp;
    int frame_bad;
    float* pdata;
    float* pscale=cpl_image_get_data_float(scale);



    for (ns = 0; ns < nslit; ns++) {
         for (nl = 0; nl < nlambda; nl++) {
             int dest_idx;
             int good = 0, bad = 0;
             int isum =0;

             dest_idx = nl + ns * nlambda;

             for (nf = 0; nf < nb_frames; nf++) {
                   int from_idx;

                   if ((ns < slit_index[nf]) || (ns >= (slit_index[nf] + from_slit))) {
                       continue;
                   }
                   from_idx = nl + (ns - slit_index[nf]) * nlambda;
                   from_data1 = xsh_rec_list_get_data1( from[nf], no);
                   from_qual1 = xsh_rec_list_get_qual1( from[nf], no);


             }
         }
    }
    cleanup:
    return scale;

}
 */

/*
static cpl_error_code
xsh_compute_scale_tab4(cpl_imagelist* iml_data, cpl_table* tab_bpm,
                  cpl_imagelist* scale_frames,cpl_image** ima_corr)
{
	xsh_msg("start of function");
    cpl_image* scale_ima;
    int sx_j;
    int pix;

    int sz=cpl_imagelist_get_size(iml_data);
    double norm_good_pix;
    double* pdata;
    cpl_image* ima_tmp;
    cpl_binary* pbpm;

    cpl_mask* bpm_tmp;

    ima_tmp=cpl_imagelist_get(iml_data,0);
    int sx=cpl_image_get_size_x(ima_tmp);
    //int sy=cpl_image_get_size_y(ima_tmp);


    int* px=cpl_table_get_data_int(tab_bpm,"x");
    int* py=cpl_table_get_data_int(tab_bpm,"y");
    int size=cpl_table_get_nrow(tab_bpm);
    int num_good_pix;

    int i,j,m;
    char name[80];
    double* pscale;
    double* pcor=cpl_image_get_data_double(*ima_corr);
    for(m=0;m<size;m++) {

        i=px[m];
        j=py[m];
        xsh_msg("j=%d",j);
        xsh_msg("i=%d",i);
        sx_j=sx*j;
        pix=sx_j+i;

        //xsh_msg("pix=%d",pix);

        norm_good_pix=0;
        num_good_pix=0;

        // to sum only over good pixels we flag the bad ones
        for(int k=0;k<sz;k++) {
            ima_tmp=cpl_imagelist_get(iml_data,k);
            bpm_tmp=cpl_image_get_bpm(ima_tmp);
            pbpm=cpl_mask_get_data(bpm_tmp);
            sprintf(name,"bad_%d.fits",k);
            cpl_mask_save(bpm_tmp,name,NULL,CPL_IO_DEFAULT);

            if( pbpm[pix] == CPL_BINARY_0 ) {
            	pdata=cpl_image_get_data_double(ima_tmp);
            	//xsh_msg("k=%d j=%d pdata=%g",k,j,pdata[pix]);
                scale_ima=cpl_imagelist_get(scale_frames,k);
                pscale=cpl_image_get_data_double(scale_ima);
                //xsh_msg("k=%d j=%d pscale=%g",k,j,pscale[j]);
            	norm_good_pix += pdata[pix]/pscale[j];
            	num_good_pix++;
                //xsh_msg("k=%d j=%d ratio=%g",k,j,pdata[pix]/pscale[j]);

            }


        }
        norm_good_pix /= num_good_pix;
        xsh_msg("m=%d norm=%g num=%d",m,norm_good_pix,num_good_pix);
        pcor[pix] = norm_good_pix;

    }
    xsh_msg("end of function");
    return cpl_error_get_code();
}
 */

static cpl_imagelist*
xsh_compute_scale_factors_by_object(cpl_imagelist* scaled, cpl_image* scale,
		const int nlambda,const int nslit,const int no,const double smin,
		const double smax)
{

	cpl_imagelist* scale_factors = cpl_imagelist_new();

	double med;
	//double avg;
	//double rms;
	double* pscale;
	int nb_frames=cpl_imagelist_get_size(scaled);
	cpl_image* ima_tmp;
	int slit_min = (int) smin;
	int slit_max = (int) smax;

	int nbad;
	const cpl_mask* mask;
	for (int nf = 0; nf < nb_frames; nf++) {
		scale=cpl_image_new(1,nslit,CPL_TYPE_DOUBLE);
		cpl_image_add_scalar(scale,1.);
		pscale=cpl_image_get_data_double(scale);


		ima_tmp=cpl_imagelist_get(scaled,nf);
		mask=cpl_image_get_bpm_const(ima_tmp);
		nbad=cpl_mask_count_window(mask,1,slit_min,nlambda,slit_max);

		if( nbad < nlambda * (slit_max-slit_min) ) {
			//avg=cpl_image_get_mean_window(ima_tmp,1,slit_min,nlambda,slit_max);
			med=cpl_image_get_median_window(ima_tmp,1,slit_min,nlambda,slit_max);
			//rms=cpl_image_get_stdev_window(ima_tmp,1,slit_min,nlambda,slit_max);
			/*
 			xsh_msg("frame %d slice %d mean=%g median=%g rm==%g",
 					nf, ns, avg,med,rms);
			 */
		}
		//xsh_msg("order %d frame %d slice %d scale med=%g",no, nf, ns, med);
		for (int ns = slit_min; ns <= slit_max; ns++) {
			pscale[ns]=med;
		}

		cpl_imagelist_set(scale_factors,scale,nf);
	}

	char fname[80];
	sprintf(fname,"scale_factors_obj_%d.fits",no);
	cpl_imagelist_save(scale_factors,fname,CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);
	//cpl_imagelist_delete(scaled);
	return scale_factors;

}

static cpl_imagelist*
xsh_compute_scale_factors_by_slice(cpl_imagelist* scaled, cpl_image* scale,
		const int nlambda,const int nslit,const int no)
{

	cpl_imagelist* scale_factors = cpl_imagelist_new();

	double med;
	//double rms;
	//double avg;
	double* pscale;
	int nb_frames=cpl_imagelist_get_size(scaled);
	cpl_image* ima_tmp;
	int nbad;
	const cpl_mask* mask;
	for (int nf = 0; nf < nb_frames; nf++) {
		scale=cpl_image_new(1,nslit,CPL_TYPE_DOUBLE);
		cpl_image_add_scalar(scale,1.);
		pscale=cpl_image_get_data_double(scale);
		for (int ns = 0; ns < nslit; ns++) {

			ima_tmp=cpl_imagelist_get(scaled,nf);
			mask=cpl_image_get_bpm_const(ima_tmp);
			nbad=cpl_mask_count_window(mask,1,ns+1,nlambda,ns+1);

			if(nbad<nlambda) {
				//avg=cpl_image_get_mean_window(ima_tmp,1,ns+1,nlambda,ns+1);
				med=cpl_image_get_median_window(ima_tmp,1,ns+1,nlambda,ns+1);
				//rms=cpl_image_get_stdev_window(ima_tmp,1,ns+1,nlambda,ns+1);
				/*
 			xsh_msg("frame %d slice %d mean=%g median=%g rm==%g",
 					nf, ns, avg,med,rms);
				 */
			}
			//xsh_msg("order %d frame %d slice %d scale med=%g",no, nf, ns, med);
			pscale[ns]=med;
		}
		cpl_imagelist_set(scale_factors,scale,nf);
	}

	char fname[80];
	sprintf(fname,"scale_factors_slices_%d.fits",no);
	cpl_imagelist_save(scale_factors,fname,CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);
	//cpl_imagelist_delete(scaled);

	return scale_factors;

}


static cpl_imagelist*
xsh_compute_scale_factors_pix_pix(cpl_imagelist* scaled, cpl_image* scale,
		const int nlambda,const int nslit,const int no)
{

	cpl_imagelist* scale_factors = cpl_imagelist_new();

	double med=0;
	//double rms=0;
	//double avg=0;
	double* pscale;
	cpl_binary* pbpm=NULL;
	cpl_mask* bpm;
	int nb_frames=cpl_imagelist_get_size(scaled);
	cpl_image* ima_tmp;
	int nbad;
	const cpl_mask* mask;
	//xsh_msg("nlambda=%d",nlambda);


	int hbox_sz=6;// was 6
	int lmin=0, lmax=0;
	int sx=0;
	int sy=0;
	for (int nf = 0; nf < nb_frames; nf++) {
		ima_tmp=cpl_imagelist_get(scaled,nf);
		mask=cpl_image_get_bpm_const(ima_tmp);
		sx=cpl_mask_get_size_x(mask);
		sy=cpl_mask_get_size_y(mask);
		//xsh_msg("nlambda=%d",nlambda);
		scale=cpl_image_new(nlambda,nslit,CPL_TYPE_DOUBLE);
		cpl_image_add_scalar(scale,1.);
		pscale=cpl_image_get_data_double(scale);
		bpm=cpl_image_get_bpm(scale);
		pbpm=cpl_mask_get_data(bpm);
                // AMO TBD: for (int ns = 0; ns < nslit-1; ns++) {
		for (int ns = 0; ns < nslit; ns++) {

			for (int nl = hbox_sz; nl < nlambda-hbox_sz; nl++) {
				lmin=nl-hbox_sz+1;
				lmax=nl+hbox_sz+1;
				/*


				if(lmin <=1 || ns+1 <=1 || lmax>=sx || ns+1 >= sy) {
				  xsh_msg("lmin=%d lmax=%d ns+1=%d sx=%d sy=%d",lmin,lmax,ns+1,sx,sy);
				}
				*/
				 check(nbad=cpl_mask_count_window(mask,lmin,ns+1,lmax,ns+1));

				 if(nbad<lmax-lmin) {
					 //avg=cpl_image_get_mean_window(ima_tmp,lmin,ns+1,lmax,ns+1);
					 med=cpl_image_get_median_window(ima_tmp,lmin,ns+1,lmax,ns+1);
					 //check(rms=cpl_image_get_stdev_window(ima_tmp,lmin,ns+1,lmax,ns+1));
					 /*
 			        xsh_msg("frame %d slice %d mean=%g median=%g rm==%g",
 					nf, ns, avg,med,rms);
					  */
				 }

                /*
				if (no == 4 && nl > 1855 && nl < 1865 && ns > 39 && ns < 41) {
					xsh_msg("pix pix: order %d frame %d scale[%d,%d] med=%g",
							no, nf, nl, ns, med);
				}
				*/


				 if(med != 0 ) {
					 pscale[ns*nlambda+nl]=med;
				 } else {
					 pbpm[ns*nlambda+nl]=CPL_BINARY_1;
					 /*
					xsh_msg("lmin=%d lmax=%d ns=%d nslit=%d nlambda=%d",
					                    				lmin,lmax,ns,nslit,nlambda);
					cpl_image_save(ima_tmp, "ima_tmp.fits", XSH_PRE_DATA_BPP,
							NULL, CPL_IO_DEFAULT);
					mask=cpl_image_get_bpm_const(ima_tmp);
					cpl_mask_save(mask,"mask_tmp.fits",NULL,CPL_IO_DEFAULT);
					exit(0);
					  */
				 }
			}

			/* wave edge regions */

			for (int nl = 0; nl < hbox_sz; nl++) {
				lmin=nl+1;
				lmax=nl+2*hbox_sz+1;
				lmax=(lmax < nlambda) ? lmax : nlambda-1;
				//lmin=(lmin < lmax) ? lmin : lmax-hbox_sz;
				lmin=(lmin < lmax) ? lmin : lmax-1;
				/*
                                if( ns == (nslit-1) ) {
        		                xsh_msg("lmin=%d lmax=%d sx=%d sy=%d ns=%d nslit=%d nlambda=%d",
        				lmin,lmax,sx,sy,ns,nslit,nlambda);
                                }
				 */
				nbad=cpl_mask_count_window(mask,lmin,ns+1,lmax,ns+1);

				if(nbad<lmax-lmin) {
					//avg=cpl_image_get_mean_window(ima_tmp,lmin,ns+1,lmax,ns+1);
					med=cpl_image_get_median_window(ima_tmp,lmin,ns+1,lmax,ns+1);

					//check(rms=cpl_image_get_stdev_window(ima_tmp,lmin,ns+1,lmax,ns+1));
					/*
 			        xsh_msg("frame %d slice %d mean=%g median=%g rm==%g",
 					nf, ns, avg,med,rms);
					 */
				}

				//xsh_msg("order %d frame %d slice %d scale med=%g",no, nf, ns, med);
				if(med != 0 ) {
					pscale[ns*nlambda+nl]=med;
				} else {
					pbpm[ns*nlambda+nl]=CPL_BINARY_1;
				}

			}

			for (int nl = nlambda-1; nl > nlambda-hbox_sz-1; nl--) {
				lmax=nl+1;
				lmin=nl-2*hbox_sz+1;
				lmin=(lmin > 0) ? lmin : 1;
				lmax=(lmax > lmin) ? lmax : lmin+1;
				//xsh_msg("lmin=%d lmax=%d ns=%d nslit=%d nlambda=%d",lmin,lmax,ns,nslit,nlambda);
				check(nbad=cpl_mask_count_window(mask,lmin,ns+1,lmax,ns+1));

				if(nbad<lmax-lmin) {
					//avg=cpl_image_get_mean_window(ima_tmp,lmin,ns+1,lmax,ns+1);
					med=cpl_image_get_median_window(ima_tmp,lmin,ns+1,lmax,ns+1);

					//check(rms=cpl_image_get_stdev_window(ima_tmp,lmin,ns+1,lmax,ns+1));
					/*
 			        xsh_msg("frame %d slice %d mean=%g median=%g rm==%g",
 					nf, ns, avg,med,rms);
					 */
				}
				//xsh_msg("order %d frame %d slice %d scale med=%g",no, nf, ns, med);
				if(med != 0 ) {
					pscale[ns*nlambda+nl]=med;
				} else {
					pbpm[ns*nlambda+nl]=CPL_BINARY_1;
				}
			}

		} /*  end loop over s */

		cpl_imagelist_set(scale_factors,scale,nf);

	}

	char fname[80];
	sprintf(fname,"scale_factors_pix_pix_%d.fits",no);
	//cpl_imagelist_save(scale_factors,fname,CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);
	cleanup:
	//cpl_imagelist_delete(scaled);
	xsh_print_rec_status(0);
	return scale_factors;

}

/* This routine creates a table containing for each pixels how many frames
 * contributed. Pixels for wich at least one frame has a bad pixel are also
 * flagged.
*/
static cpl_table*
xsh_qual2tab_frames(int nframes,const int code, int *slit_index,
		xsh_rec_list *dest, xsh_rec_list **from,const int no)
{



	int m=0;

	int nf=0;
	int ns=0;
	int nl=0;


	int *from_qual1 = NULL;
	int from_idx=0;
	int* dest_qual1 = xsh_rec_list_get_qual1( dest, no);
	int nlambda = xsh_rec_list_get_nlambda( dest, no);
	int nslit = xsh_rec_list_get_nslit( dest, no);
	int from_slit = xsh_rec_list_get_nslit( from[0], no);
	const int size=nlambda*nslit;
	cpl_table* xy_pos=cpl_table_new(size);
	cpl_table_new_column(xy_pos,"x",CPL_TYPE_INT);
	cpl_table_new_column(xy_pos,"y",CPL_TYPE_INT);
	cpl_table_new_column(xy_pos,"ngood",CPL_TYPE_INT);
	char cname[8];

	for(int i=0; i < nframes;i++) {
		sprintf(cname,"f%d",i);
		cpl_table_new_column(xy_pos,cname,CPL_TYPE_INT);
	}
	int* px=cpl_table_get_data_int(xy_pos,"x");
	int* py=cpl_table_get_data_int(xy_pos,"y");
	int* pg=cpl_table_get_data_int(xy_pos,"ngood");
	int nbad=0;

	//xsh_msg("copy bad pixels in table");
	for (ns = 0; ns < nslit; ns++) {
		for (nl = 0; nl < nlambda; nl++) {
			int dest_idx = nl + ns * nlambda;
			for(nf=0;nf<nframes;nf++) {
				if ((ns < slit_index[nf]) || (ns >= (slit_index[nf] + from_slit))) {
					continue;
				}
			    if ( (dest_qual1[dest_idx] & code) > 0) {
				    xsh_msg("found bad pixel at [%d,%d]",nl,ns);
				    px[m]=nl;
				    py[m]=ns;
					from_qual1 = xsh_rec_list_get_qual1( from[nf], no);
					sprintf(cname,"f%d",nf);
					int* pq=cpl_table_get_data_int(xy_pos,cname);
					from_idx = nl + (ns - slit_index[nf]) * nlambda;
					nbad=0;
					if ( (from_qual1[from_idx] & code) > 0) {
						pq[m]=1;
						nbad++;
					}
					pg[m]=nframes-nbad;
					m++;
				}

			}
		}
	}
	cpl_table_set_size(xy_pos,m);
	char fname[80];
	sprintf(fname,"bad_pix_ord_%d.fits",no);
    cpl_table_save(xy_pos,NULL,NULL,fname,CPL_IO_DEFAULT);
	return xy_pos;
}

static cpl_imagelist*
xsh_find_image_scale_factors(xsh_rec_list *dest, xsh_rec_list **from,
		int *slit_index, int nb_frames, int no,
		int method, const int decode_bp, int scale_method)
{

	cpl_image* scale;

	int nslit, from_slit, nlambda;
	nslit = xsh_rec_list_get_nslit( dest, no);
	from_slit = xsh_rec_list_get_nslit( from[0], no);
	nlambda = xsh_rec_list_get_nlambda( dest, no);


	float *dest_data1 = NULL;
	float *dest_errs1 = NULL;

	int *dest_qual1 = NULL;
	dest_data1 = xsh_rec_list_get_data1( dest, no);
	dest_errs1 = xsh_rec_list_get_errs1( dest, no);
	dest_qual1 = xsh_rec_list_get_qual1( dest, no);


	/* transform rec list into imagelist to easily handle operations */
	int ns, nl, nf;
	cpl_image* ima_tmp;
	cpl_image* ima_tmp2;
	cpl_image* ima_tmp3;
	cpl_imagelist* scaled = cpl_imagelist_new();
	cpl_imagelist* data = cpl_imagelist_new();
	cpl_imagelist* qual = cpl_imagelist_new();
	/* create imagelist */

	for (nf = 0; nf < nb_frames; nf++) {
		ima_tmp=cpl_image_new(nlambda,nslit,CPL_TYPE_FLOAT);
		cpl_imagelist_set(scaled,ima_tmp,nf);
		ima_tmp2=cpl_image_new(nlambda,nslit,CPL_TYPE_FLOAT);
		cpl_imagelist_set(data,ima_tmp2,nf);
		ima_tmp3=cpl_image_new(nlambda,nslit,CPL_TYPE_INT);
		cpl_imagelist_set(qual,ima_tmp3,nf);
	}

	/* fill image list with values and flag bad pixels */
	float* pscaled=NULL;
	float* pdata=NULL;
	int* pqual=NULL;
	cpl_binary* pmsk;
	float *from_data1 = NULL;
	float *from_errs1 = NULL;
	int *from_qual1 = NULL;
	char fname[80];

	for (ns = 0; ns < nslit; ns++) {
		for (nl = 0; nl < nlambda; nl++) {
			int dest_idx;

			dest_idx = nl + ns * nlambda;

			for (nf = 0; nf < nb_frames; nf++) {
				int from_idx;
				ima_tmp=cpl_imagelist_get(scaled,nf);
				pscaled=cpl_image_get_data_float(ima_tmp);
				ima_tmp2=cpl_imagelist_get(data,nf);
				pdata=cpl_image_get_data_float(ima_tmp2);
				ima_tmp3=cpl_imagelist_get(qual,nf);
				pqual=cpl_image_get_data_int(ima_tmp3);


				pmsk=cpl_mask_get_data(cpl_image_get_bpm(ima_tmp));
				if ((ns < slit_index[nf]) || (ns >= (slit_index[nf] + from_slit))) {
					continue;
				}

				from_idx = nl + (ns - slit_index[nf]) * nlambda;
				from_data1 = xsh_rec_list_get_data1( from[nf], no);
				from_errs1 = xsh_rec_list_get_errs1( from[nf], no);
				from_qual1 = xsh_rec_list_get_qual1( from[nf], no);
				//xsh_msg("ns=%d nl=%d dest_idx=%d from_idx=%d",ns,nl,dest_idx,from_idx);
				pscaled[dest_idx] = from_data1[from_idx] / dest_data1[dest_idx];
				/*
				if (no == 4 && nl > 1855 && nl < 1865 && ns > 39 && ns < 41) {
					xsh_msg("scale factors: ord %d frm %d num=%g den=%g num_e=%g den_e=%g num_e/num=%g den_e/den=%g scale=%g",
							no, nf, from_data1[from_idx], dest_data1[dest_idx],
							        from_errs1[from_idx], dest_errs1[dest_idx],
									fabs(from_errs1[from_idx]/from_data1[from_idx]),
									fabs(dest_errs1[from_idx]/dest_data1[from_idx]),
									pscaled[dest_idx]);
				}
				*/
				pdata[dest_idx] = from_data1[from_idx] ;
				pqual[dest_idx] = from_qual1[from_idx] ;
				if(   ( ( dest_qual1[dest_idx] & decode_bp ) > 0 ) ||
					  ( ( from_qual1[from_idx] & decode_bp ) > 0 ) ||
						isnan(pscaled[dest_idx]) ||
						isinf(pscaled[dest_idx]) ||
						fabs(from_errs1[from_idx]/from_data1[from_idx]) > 5 ||
						fabs(dest_errs1[from_idx]/dest_data1[from_idx]) > 5
						) {
					pmsk[dest_idx]=CPL_BINARY_1;
					/* force to be 1 (otherwhise it would be NAN) */
					pscaled[dest_idx]=1;
					/*
                      if (no > 0) {
                    	  int sx=xsh_rec_list_get_nlambda( from[nf], no);
                    	  int sy=xsh_rec_list_get_nslit( from[nf], no);
                    	  cpl_image* ima=NULL;
                    	  xsh_msg("sx=%d sy=%d",sx,sy);
                    	  ima=cpl_image_wrap(sx,sy,CPL_TYPE_FLOAT,from_data1);
                    	  cpl_image_save(ima, "from_data.fits", XSH_PRE_DATA_BPP, NULL, CPL_IO_DEFAULT);

                    	  cpl_image_unwrap(ima);
                       	  ima=cpl_image_wrap(sx,sy,CPL_TYPE_INT,from_qual1);
                          cpl_image_save(ima, "from_qual.fits", XSH_PRE_QUAL_BPP, NULL, CPL_IO_DEFAULT);



                          xsh_msg("nlambda: %d nslit: %d",nlambda,nslit);
                          xsh_msg("from size: %d %d",
                        		  xsh_rec_list_get_nlambda( from[nf], no),
								  xsh_rec_list_get_nslit( from[nf], no));

                          xsh_msg("dest size: %d %d",
                        		  xsh_rec_list_get_nlambda( dest, no),
								  xsh_rec_list_get_nslit( dest, no));

                    	  xsh_msg("from_data=%g dest_data=%g nl=%d ns=%d",
                    			  from_data1[from_idx],dest_data1[dest_idx],nl,ns);
                    	  xsh_msg("nf=%d slit index=%d from_idx=%d",
                    			  nf, slit_index[nf],from_idx);
                    	  sx=xsh_rec_list_get_nlambda( dest, no);
                    	  sy=xsh_rec_list_get_nslit( dest, no);
                    	  cpl_image_unwrap(ima);
                    	  ima=cpl_image_wrap(sx,sy,CPL_TYPE_FLOAT,dest_data1);
                    	  cpl_image_save(ima, "dest_data.fits", XSH_PRE_DATA_BPP, NULL, CPL_IO_DEFAULT);


                      	  cpl_image_unwrap(ima);
                          ima=cpl_image_wrap(sx,sy,CPL_TYPE_INT,dest_data1);
                          cpl_image_save(ima, "dest_qual.fits", XSH_PRE_QUAL_BPP, NULL, CPL_IO_DEFAULT);

                    	  cpl_image_unwrap(ima);
                    	  ima=cpl_image_wrap(sx,sy,CPL_TYPE_FLOAT,pscaled);
                    	  cpl_image_save(ima, "scaled.fits", XSH_PRE_DATA_BPP, NULL, CPL_IO_DEFAULT);


                          cpl_image_unwrap(ima);
                    	  exit(0);
                      }
					 */
				}
			}
		}
	}


	sprintf(fname,"data_rectified_order_%d.fits",no);
	//cpl_imagelist_save(data,fname,CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);
	sprintf(fname,"qual_rectified_order_%d.fits",no);
	//cpl_imagelist_save(qual,fname,CPL_TYPE_INT,NULL,CPL_IO_DEFAULT);

	sprintf(fname,"scale_rectified_order_%d.fits",no);
	//cpl_imagelist_save(scaled,fname,CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);
	/* determine scale factors: one at each Y (spatial) position
	 * we assume the scale is approximatively uniform along X (wavelength)
	 */

	/* we should correct scaling only where the object is */
	cpl_imagelist* scale_factors;
	double slit_ext_min, slit_ext_max, slit_step;
	if(scale_method > 0) {

		slit_step = xsh_pfits_get_rectify_bin_space( dest->header);
		xsh_rec_get_nod_extract_slit_min_max(dest, slit_step,&slit_ext_min,
				&slit_ext_max);
		slit_ext_min += 1;
		slit_ext_max -= 1;
	}

	switch(scale_method) {

	case 0:
		check(scale_factors=xsh_compute_scale_factors_by_slice(scaled,
				scale, nlambda, nslit, no));
		break;

	case 1:
		check(scale_factors=xsh_compute_scale_factors_by_object(scaled,
				scale, nlambda, nslit, no, slit_ext_min, slit_ext_max));
		break;

	case 2:
		check(scale_factors=xsh_compute_scale_factors_pix_pix(scaled,
				scale, nlambda, nslit, no));
		break;
	}
	cleanup:
	cpl_imagelist_delete(scaled);
	cpl_imagelist_delete(data);
	cpl_imagelist_delete(qual);
	xsh_print_rec_status(0);
	return scale_factors;
}

/*
static cpl_image*
xsh_rec_list_compute_scale2(xsh_rec_list *dest, xsh_rec_list **from,
                 int *slit_index, int nb_frames, int no,
                 int method, const int decode_bp)
{


    float *from_data1 = NULL;
    float *dest_data1 = NULL;

    //int *from_qual1 = NULL;
    int *dest_qual1 = NULL;
    int nslit, from_slit, nlambda;
    int ns, nl, nf;
    XSH_ASSURE_NOT_NULL( dest);
    XSH_ASSURE_NOT_NULL( from);
    XSH_ASSURE_NOT_NULL( slit_index);

    nslit = xsh_rec_list_get_nslit( dest, no);
    from_slit = xsh_rec_list_get_nslit( from[0], no);
    nlambda = xsh_rec_list_get_nlambda( dest, no);

    dest_data1 = xsh_rec_list_get_data1( dest, no);
    dest_qual1 = xsh_rec_list_get_qual1( dest, no);
    cpl_image* ima_tmp;
    cpl_imagelist* scaled = cpl_imagelist_new();
    float* pscaled=NULL;
    cpl_binary* pmsk;
    // to easy coding copy rec list on an imagelist and transfer
    // the qualifier info in the associated BP map

    for (nf = 0; nf < nb_frames; nf++) {
         ima_tmp=cpl_image_new(nlambda,nslit,CPL_TYPE_FLOAT);
         cpl_imagelist_set(scaled,ima_tmp,nf);
    }

    for (ns = 0; ns < nslit; ns++) {
         for (nl = 0; nl < nlambda; nl++) {
             int dest_idx;
             //int good = 0, bad = 0;
             //int isum =0;

             dest_idx = nl + ns * nlambda;

             for (nf = 0; nf < nb_frames; nf++) {
                   int from_idx;
                   ima_tmp=cpl_imagelist_get(scaled,nf);
                   pscaled=cpl_image_get_data_float(ima_tmp);
                   pmsk=cpl_mask_get_data(cpl_image_get_bpm(ima_tmp));
                   if ((ns < slit_index[nf]) || (ns >= (slit_index[nf] + from_slit))) {
                       continue;
                   }

                   from_idx = nl + (ns - slit_index[nf]) * nlambda;
                   from_data1 = xsh_rec_list_get_data1( from[nf], no);
                   //xsh_msg("ns=%d nl=%d dest_idx=%d from_idx=%d",ns,nl,dest_idx,from_idx);
                   pscaled[dest_idx] = from_data1[from_idx] / dest_data1[dest_idx];
                   if( (  ( dest_qual1[dest_idx] > decode_bp ) > 0 ) ||
                	   isnan(pscaled[dest_idx]) || isinf(pscaled[dest_idx]) ) {
                      pmsk[dest_idx]=CPL_BINARY_1;
                   }
             }
         }
    }
    float avg;
    float med;
    float rms;
    int nbad;
    const cpl_mask* mask;
    for (nf = 0; nf < nb_frames; nf++) {
    	for (ns = 0; ns < nslit; ns++) {

    		ima_tmp=cpl_imagelist_get(scaled,nf);
    		mask=cpl_image_get_bpm_const(ima_tmp);
    		check(nbad=cpl_mask_count_window(mask,1,ns+1,nlambda,ns+1));
    		if(nbad<nlambda) {
    			check(avg=cpl_image_get_mean_window(ima_tmp,1,ns+1,nlambda,ns+1));
    			check(med=cpl_image_get_median_window(ima_tmp,1,ns+1,nlambda,ns+1));
    			check(rms=cpl_image_get_stdev_window(ima_tmp,1,ns+1,nlambda,ns+1));
    			xsh_msg("frame %d slice %d mean=%g median=%g rm==%g",
    					nf, ns, avg,med,rms);
    		}
    	}

    }
    char fname[80];
    cleanup:

	sprintf(fname,"scaled_%d.fits",no);
	cpl_imagelist_save(scaled,fname,CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);
	cpl_imagelist_delete(scaled);
	xsh_print_rec_status(0);
    return NULL;

}
 */
/*
static void
xsh_fill_gauss(float** pgauss, const int sx, const int sy, const double A,
               const double sigma, const double bkg, const int i,
               const double gauss_c,const int min, const int max)
{

    // add Gauss profile positioned where the trace is
    // I=A*exp( -0.5*( (X-Xo)/sigma )^2 ) +bkg


    double arg = 0;
    int j;
    double y=0;

    // uniform along X (horizontal direction) Gauss along Y (vertical)
    for (j = min; j <= max; j++) {
        y=j;

        arg = (y - gauss_c) / sigma;
        arg *= arg;
        xsh_msg("j=%d i=%d arg=%g,sx=%d val=%g",j,i,arg,sx,A * exp(-0.5 * arg) + bkg);
        //  *pgauss[j * sx + i] += (float) (A * exp(-0.5 * arg) + bkg);
 *pgauss[j * sx + i] = 1;
        //xsh_msg("val=%g",pgauss[j * sx + i]);

    }

    return;
}
 */
static void
xsh_rec_list_fill_gauss(xsh_rec_list *dest, xsh_rec_list **from,
		int *slit_index, int nb_frames, int no,
		int method, const int decode_bp)
{

	int nslit, from_slit, nlambda;
	//float *dest_data1 = NULL, *dest_errs1 = NULL;
	//int *dest_qual1 = NULL;
	nslit = xsh_rec_list_get_nslit( dest, no);
	from_slit = xsh_rec_list_get_nslit( from[0], no);
	nlambda = xsh_rec_list_get_nlambda( dest, no);

	//dest_data1 = xsh_rec_list_get_data1( dest, no);
	//dest_errs1 = xsh_rec_list_get_errs1( dest, no);
	//dest_qual1 = xsh_rec_list_get_qual1( dest, no);

	int ns, nl, nf;
	//cpl_vector* trace;
	int  sy=nslit;
	//int sx=nlambda;

	double gauss_c=sy/2;
	//double sigma=3;
	//double bkg=1;
	//int min=2*sy/5;
	//int max=3*sy/5;
	//double y;
	//double arg;
	xsh_msg("gauss_c=%g from_slit=%d nb_frames=%d",gauss_c,from_slit,nb_frames);
	char fname[80];
	cpl_image* ima;

	/* reset data to 0 */
	float *from_data1 = NULL;
	//float *from_errs1 = NULL;
	for (nf = 0; nf < nb_frames; nf++) {
		xsh_msg("slit_index[%d]=%d",nf,slit_index[nf]);
		sprintf(fname,"data_%d.fits",nf);
		from_data1 = xsh_rec_list_get_data1( from[nf], no);
		//from_errs1 = xsh_rec_list_get_errs1( from[nf], no);
		int from_idx;
		for (ns = 0; ns < nslit; ns++) {
			for (nl = 0; nl < nlambda; nl++) {

				if ((ns < slit_index[nf]) || (ns >= (slit_index[nf] + from_slit))) {
					continue;
				}

				from_idx = nl + (ns - slit_index[nf]) * nlambda;
				from_data1[from_idx] = 0;
				//from_data1[ns*nlambda+nl] = 0;
			}
		}

	}
	/*
    for (ns = 0; ns < nslit; ns++) {
        int from_idx;
        for (nl = 0; nl < nlambda; nl++) {
            for (nf = 0; nf < nb_frames; nf++) {
                if ((ns < slit_index[nf]) || (ns >= (slit_index[nf] + from_slit))) {
                    continue;
                }
                from_data1 = xsh_rec_list_get_data1( from[nf], no);
                from_errs1 = xsh_rec_list_get_errs1( from[nf], no);
                from_qual1 = xsh_rec_list_get_qual1( from[nf], no);

                from_idx = nl + (ns - slit_index[nf]) * nlambda;

                double A=(nf+1)*10;

                y=ns-slit_index[nf];
                arg = (y - gauss_c) / sigma;
                //xsh_msg("ns=%d gauss_c=%g arg=%g",ns,gauss_c,arg);
                arg *= arg;
                //xsh_msg("j=%d i=%d arg=%g,sx=%d val=%g",j,i,arg,sx,A * exp(-0.5 * arg) + bkg);
                from_data1[from_idx] += (float) (A * exp(-0.5 * arg) + bkg);
                //from_data1[from_idx] = 1;

                //xsh_fill_gauss(&from_data1,sx,sy,A,sigma, bkg,nl,gauss_c,min,max);
            }
        }
    }
	 */
	for (nf = 0; nf < nb_frames; nf++) {
		sprintf(fname,"data_%d.fits",nf);
		from_data1 = xsh_rec_list_get_data1( from[nf], no);
		//from_errs1 = xsh_rec_list_get_errs1( from[nf], no);
		//int* from_qual1 = xsh_rec_list_get_qual1( from[nf], no);
		ima= cpl_image_wrap_float(nlambda,nslit,from_data1);
		if(no==0) {
			cpl_image_save(ima, fname,CPL_TYPE_FLOAT, NULL, CPL_IO_DEFAULT);
		} else {
			cpl_image_save(ima, fname,CPL_TYPE_FLOAT, NULL, CPL_IO_EXTEND);
		}
	}

	return;

}

/* TODO: NOT USED
static double
xsh_compute_scale_nod(xsh_rec_list **from,int *slit_index,
                  int nb_frames, int no,const int decode_bp, int pix)
{

    /// TODO TO BE VERIFIED ima_tmp not initialised i,j=0
    double scale=0;
    float *from_data1 = NULL, *from_errs1 = NULL;
    int *from_qual1 = NULL;
    int win_hsx;
    int win_hsy;
    int mode=0;
    int win_hsz=3;

    int num_good_pix;
    int num_tot_pix;
    double sum_all;
    double sum_good;
    double sum_good_pix;
    double sum_tot_pix;
    cpl_image* ima_tmp;
    int i=0;
    int j=0;
    int sx=cpl_image_get_size_x(ima_tmp);
    int sy=cpl_image_get_size_y(ima_tmp);

    if(mode==0) {
        win_hsx=0;
        win_hsy=win_hsz;
    } else if (mode == 1) {
        win_hsx=win_hsz;
        win_hsy=0;
    } else {
        win_hsx=win_hsz;
        win_hsy=win_hsz;
    }
    int win_sx=2*win_hsx+1;
    int win_sy=2*win_hsy+1;

    for (int nf = 0; nf < nb_frames; nf++) {

        sum_good_pix=0;
        num_good_pix=0;
        sum_tot_pix=0;
        num_tot_pix=0;
        xsh_msg("found bad pix at pos[%d,%d]",i,j);
        /// if the pixel is flagged we compute the scaling factor
        int y_min=j-win_hsy, y_max=j+win_hsy;
        //xsh_msg("init y_min=%d y_max=%d",y_min,y_max);
        /// Not to hit image edges use asymmetric interval at image edges
        if (y_min < 0) {
            xsh_msg("y case1");
            y_min = 0;
            y_max = win_sy;
        } else if ( y_max > sy) {
            //xsh_msg("y case2 j=%d j+y_max=%d,sy=%d",j,j+y_max,sy);
            y_max=sy;
            y_min=y_max-win_sy;
        }
        //xsh_msg("corrected y_min=%d y_max=%d",y_min,y_max);
        int x_min=i-win_hsx, x_max=i+win_hsx;
        //xsh_msg("init x_min=%d x_max=%d",x_min,x_max);
        if (x_min < 0) {
            //xsh_msg("x case1")/;
            x_min = 0;
            x_max = win_sx;
        } else if ( x_max > sx) {
            //xsh_msg("x case2 i=%d i+x_max=%d,sx=%d",i,i+x_max,sx);
            x_max=sx;
            x_min=x_max-win_sx;
        }
        //xsh_msg("corrected x_min=%d x_max=%d",x_min,x_max);
        sum_all=0;
        sum_good=0;


        from_data1 = xsh_rec_list_get_data1( from[nf], no);
        from_errs1 = xsh_rec_list_get_errs1( from[nf], no);
        from_qual1 = xsh_rec_list_get_qual1( from[nf], no);




    }
    return scale;
}
 */


 static cpl_error_code
  xsh_rec_list_qc(xsh_rec_list *dest, xsh_rec_list **from,
  		int *slit_index, int nb_frames, int no,
  		int method, const int decode_bp, const int nf)
  {
  	int nslit, from_slit, nlambda;
  	float *dest_data1 = NULL, *dest_errs1 = NULL;
  	int *dest_qual1 = NULL;
  	float *from_data1 = NULL, *from_errs1 = NULL;
  	int *from_qual1 = NULL;
  	int ns, nl=0;

  	XSH_ASSURE_NOT_NULL( dest);
  	XSH_ASSURE_NOT_NULL( from);
  	XSH_ASSURE_NOT_NULL( slit_index);

  	xsh_msg_dbg_medium(
  			"xsh_rec_list_add: nb frames: %d, order: %d", nb_frames, no);

  	check( nslit = xsh_rec_list_get_nslit( dest, no));
  	check( from_slit = xsh_rec_list_get_nslit( from[0], no));
  	check( nlambda = xsh_rec_list_get_nlambda( dest, no));
  	check( dest_data1 = xsh_rec_list_get_data1( dest, no));
  	check( dest_errs1 = xsh_rec_list_get_errs1( dest, no));
  	check( dest_qual1 = xsh_rec_list_get_qual1( dest, no));

  	char name[80];
  	cpl_frame* frm=NULL;
  	//double scale=0;



  	for (ns = 0; ns < nslit; ns++) {
  		for (nl = 0; nl < nlambda; nl++) {
  			int dest_idx;
  			dest_idx = nl + ns * nlambda;
  			dest_data1[dest_idx] = 0;
  			dest_errs1[dest_idx] = 0;
  			dest_qual1[dest_idx] = 0;
  		}
  	}

  	//sprintf(name,"dummy_resampled_shifted_%d.fits",nf);
  	//frm=xsh_rec_list_save2(dest,name,"test");
  	//xsh_add_temporary_file(name);
  	//xsh_free_frame(&frm);

  	for (ns = 0; ns < nslit; ns++) {
  		for (nl = 0; nl < nlambda; nl++) {

  			int dest_idx;
  			int from_idx;
  			dest_idx = nl + ns * nlambda;

  			//xsh_msg("ns=%d slit_index=%d from_slit=%d",ns,slit_index[nf],from_slit);
  			if ((ns < slit_index[nf]) || (ns >= (slit_index[nf] + from_slit))) {
  				continue;
  			}
  			from_idx = nl + (ns - slit_index[nf]) * nlambda;
  			check( from_data1 = xsh_rec_list_get_data1( from[nf], no));
  			check( from_errs1 = xsh_rec_list_get_errs1( from[nf], no));
  			check( from_qual1 = xsh_rec_list_get_qual1( from[nf], no));

  			dest_data1[dest_idx] = from_data1[from_idx];
  			dest_errs1[dest_idx] = from_errs1[from_idx];
  			dest_qual1[dest_idx] = from_qual1[from_idx];

  		}

  	}
  	//xsh_msg("no=%d rec_input_list=%p",no,rec_input_list);
  	sprintf(name,"input_resampled_shifted_%d.fits",nf);
  	frm=xsh_rec_list_save2(dest,name,"test");
  	xsh_add_temporary_file(name);
  	xsh_free_frame(&frm);


  	cleanup:
 	return cpl_error_get_code();

  }



void
xsh_rec_list_add(xsh_rec_list *dest, xsh_rec_list **from,
		int *slit_index, int nb_frames, int no,
		int method, const int decode_bp)
{
	int nslit, from_slit, nlambda;
	float *dest_data1 = NULL, *dest_errs1 = NULL;
	int *dest_qual1 = NULL;
	float *from_data1 = NULL, *from_errs1 = NULL;
	int *from_qual1 = NULL;
	int ns, nl=0, nf;
	double *flux_tab = NULL;
	cpl_vector *flux_vect = NULL;
	double *err_tab = NULL;
	cpl_vector *err_vect = NULL;

	XSH_ASSURE_NOT_NULL( dest);
	XSH_ASSURE_NOT_NULL( from);
	XSH_ASSURE_NOT_NULL( slit_index);


	char fname[80];
	cpl_frame* frm=NULL;
	for (nf = 0; nf < nb_frames; nf++) {
		sprintf(fname,"list_%d.fits",nf);
		//frm=xsh_rec_list_save( from[nf], fname, "TEST",0);
		xsh_free_frame(&frm);
	}

	xsh_msg_dbg_medium(
			"xsh_rec_list_add: nb frames: %d, order: %d", nb_frames, no);

	check( nslit = xsh_rec_list_get_nslit( dest, no));
	check( from_slit = xsh_rec_list_get_nslit( from[0], no));
	check( nlambda = xsh_rec_list_get_nlambda( dest, no));

	check( dest_data1 = xsh_rec_list_get_data1( dest, no));
	check( dest_errs1 = xsh_rec_list_get_errs1( dest, no));
	check( dest_qual1 = xsh_rec_list_get_qual1( dest, no));

	XSH_MALLOC( flux_tab, double, nb_frames);
	XSH_MALLOC  ( err_tab, double , nb_frames);

	for (nf = 0; nf < nb_frames; nf++) {
		xsh_msg_dbg_high(
				"slit index: max %d min=%d", slit_index[nf], slit_index[nf]+from_slit);
	}


	//double scale=0;
	for (ns = 0; ns < nslit; ns++) {
		for (nl = 0; nl < nlambda; nl++) {

			int dest_idx;
			int good = 0, bad = 0;
			int isum =0;
			//double dest_err = 0, dest_data = 0. ;
			//double bad_err = 0, bad_data = 0;
			unsigned int qflag = QFLAG_GOOD_PIXEL;
			unsigned int badflag = QFLAG_GOOD_PIXEL;
			int from_idx;
			dest_idx = nl + ns * nlambda;

			for (nf = 0; nf < nb_frames; nf++) {

				//xsh_msg("ns=%d slit_index=%d from_slit=%d",ns,slit_index[nf],from_slit);
				if ((ns < slit_index[nf]) || (ns >= (slit_index[nf] + from_slit))) {
					continue;
				}
				from_idx = nl + (ns - slit_index[nf]) * nlambda;
				check( from_data1 = xsh_rec_list_get_data1( from[nf], no));
				check( from_errs1 = xsh_rec_list_get_errs1( from[nf], no));
				check( from_qual1 = xsh_rec_list_get_qual1( from[nf], no));

				//xsh_msg("2 isum=%d flux_tab=%p",isum,flux_tab);

#if combine_nod_old

				/* previous implementation separates good and bad pixels */
				if ((from_qual1[from_idx] & decode_bp) == 0) {
					qflag |= from_qual1[from_idx];
					flux_tab[good] = from_data1[from_idx];
					err_tab[good] = from_errs1[from_idx];
					good++;

				} else if ((from_qual1[from_idx] & decode_bp) > 0) {
					flux_tab[good + bad] = from_data1[from_idx];
					err_tab[good + bad] = from_errs1[from_idx];
					badflag |= from_qual1[from_idx];
					bad++;

				}

#else

				/* new implementation: we combine good and bad pixels but also quality */
				//xsh_msg("new combine_nod");

				qflag |= from_qual1[from_idx];

				flux_tab[isum] = from_data1[from_idx];

				err_tab[isum] = from_errs1[from_idx];

				isum++;
				//xsh_msg("3 isum=%d flux_tab=%p",isum,flux_tab);
#endif
			}

			//xsh_msg("4 isum=%d flux_tab=%p",isum,flux_tab);

			/* Dont calculate mean value, just sum */
#if combine_nod_old
			/* previous implementation separates good and bad pixels */
			if (good == 0) {
				check( flux_vect = cpl_vector_wrap( bad, flux_tab));
				check( err_vect = cpl_vector_wrap( bad, err_tab));
				// No good pixel
				dest_qual1[dest_idx] |= badflag;
			} else {
				dest_qual1[dest_idx] |= qflag;
				if(bad > 0) {
					dest_qual1[dest_idx] |= QFLAG_INCOMPLETE_NOD;
					//scale=xsh_compute_scale_nod(from,slit_index,nb_frames,no,decode_bp,from_idx);
				}
				check( flux_vect = cpl_vector_wrap( good, flux_tab));
				check( err_vect = cpl_vector_wrap( good, err_tab));
			}

#else
			/* new implementation: we combine good and bad pixels but also quality */
			//xsh_msg("5 isum=%d flux_tab=%p",isum,flux_tab);

			dest_qual1[dest_idx] |= qflag;

			//xsh_msg("6 isum=%d flux_tab=%p",isum,flux_tab);

			check( flux_vect = cpl_vector_wrap( isum, flux_tab));
			check( err_vect = cpl_vector_wrap( isum, err_tab));
#endif

			if (method == COMBINE_MEAN_METHOD) {
				check( dest_data1[dest_idx] = cpl_vector_get_mean( flux_vect));
				check( dest_errs1[dest_idx] = xsh_vector_get_err_mean( err_vect));
			} else {
				check( dest_data1[dest_idx] = cpl_vector_get_median( flux_vect));
				check( dest_errs1[dest_idx] = xsh_vector_get_err_median( err_vect));
			}
			xsh_unwrap_vector(&flux_vect);
			xsh_unwrap_vector(&err_vect);

		}
	}
	cpl_image* ima_bp=cpl_image_wrap_int(nl,ns,dest_qual1);
	sprintf(fname,"ima_bp_%d.fits",no);
	//cpl_image_save(ima_bp, fname, XSH_PRE_DATA_BPP, NULL, CPL_IO_DEFAULT);

	cpl_table* tab_bp=xsh_qual2tab(ima_bp,QFLAG_INCOMPLETE_NOD);
	sprintf(fname,"tab_bp_%d.fits",no);
	//cpl_table_save(tab_bp,NULL,NULL,fname,CPL_IO_DEFAULT);
	cpl_image_unwrap(ima_bp);


	cleanup:

	if (cpl_error_get_code() != CPL_ERROR_NONE) {
		xsh_unwrap_vector(&flux_vect);
		xsh_unwrap_vector(&err_vect);
	}
	xsh_free_table(&tab_bp);
	XSH_FREE( flux_tab);
	XSH_FREE( err_tab);
	return;
}
cpl_error_code
xsh_correct_scale_w(xsh_rec_list *dest, xsh_rec_list **from,
		int *slit_index, int nb_frames, int no, int method, const int decode_bp,
		cpl_imagelist* scale_factors, const int scale_method, const cpl_table* bp)
{

	/* Here for each point of the bp table we need to compute two sums:
	 * 1) Sum of the good pixels in a small range (along wavelength) from all
	 *    frames (including the ones that are coming from a frame that had a bad
	 *    pixel)
	 * 2) Sum of the good pixels coming only from the frames that have good
	 *    pixels at the flagged pixel
	 *    Then the scale is scale=sum(1)/sum(2)
	 *    To get the sum we need to use the original structures (from).
	 *
	 */
	//xsh_msg("start of function");
	//cpl_image* scale_ima;
	int nlambda_ns;
	int pix;

	double sum_good_pix=0.;
	double sum_bad_pix=0.;
	double norm_good_pix=0.;
	XSH_ASSURE_NOT_NULL( dest);
	XSH_ASSURE_NOT_NULL( from);
	XSH_ASSURE_NOT_NULL( slit_index);

	int nslit = xsh_rec_list_get_nslit( dest, no );
	int nlambda = xsh_rec_list_get_nlambda( dest, no );
	int win_hsz=3; // this sets the size of the box to search for good pixels
	int win_hsx=win_hsz;
	int win_sx=2*win_hsx+1;
	int num_good_pix;
	int num_bad_pix;
	double sum_all_pix;

	int ns,nl,m;
	char fname[80];
	//double* pscale;
	float* dest_data1;
	int from_slit = xsh_rec_list_get_nslit( from[0], no);


	int *dest_qual1 = NULL;
	dest_qual1 = xsh_rec_list_get_qual1( dest, no);

	cpl_image* ima_bp=cpl_image_wrap_int(nlambda,nslit,dest_qual1);
	sprintf(fname,"ima_bp_%d.fits",no);
	//cpl_image_save(ima_bp, fname, XSH_PRE_DATA_BPP, NULL, CPL_IO_DEFAULT);

	/* selects only points for which not all frames contributed
	 * (some pixel is bad) */
	cpl_table* tab_bpm=xsh_qual2tab(ima_bp,QFLAG_INCOMPLETE_NOD);
	sprintf(fname,"tab_bp_%d.fits",no);
	cpl_table_save(tab_bpm,NULL,NULL,fname,CPL_IO_DEFAULT);
	//exit(0);
	cpl_image_unwrap(ima_bp);

	int size=cpl_table_get_nrow(tab_bpm);
	int* px=cpl_table_get_data_int(tab_bpm,"x");
	int* py=cpl_table_get_data_int(tab_bpm,"y");
	int ns_min=-999;
	int ns_max=999;
    double scale=1;
	double slit_ext_min=0;
	double slit_ext_max=0;
	double slit_step = xsh_pfits_get_rectify_bin_space( dest->header);
	xsh_rec_get_nod_extract_slit_min_max(dest, slit_step,&slit_ext_min,
	    		&slit_ext_max);

	for (int nf = 0; nf < nb_frames; nf++) {
		//xsh_msg("slit index: max %d min=%d", slit_index[nf], slit_index[nf]+from_slit);
		if(slit_index[nf]>ns_min) {
			ns_min=slit_index[nf];
		}
		if( (slit_index[nf]+from_slit) < ns_max) {
			ns_max=(slit_index[nf]+from_slit);
		}
	}
	//xsh_msg("ck1");
	//xsh_msg("ns min=%d max=%d",ns_min,ns_max);

	//xsh_msg("slit_ext_min=%g slit_ext_max=%g slit_step=%g",
	//  slit_ext_min,slit_ext_max,slit_step);
	//ns_min=slit_ext_min;
	//ns_max=slit_ext_max;
	//exit(0);
	dest_data1 = xsh_rec_list_get_data1( dest, no);
	dest_qual1 = xsh_rec_list_get_qual1( dest, no);
	cpl_image* ima;
	ima=cpl_image_wrap_float(nlambda,nslit,dest_data1);
	//cpl_image_save(ima, "ima_org.fits", CPL_TYPE_FLOAT, NULL, CPL_IO_DEFAULT);
	cpl_image_unwrap(ima);
	//int pix_scale;
	//cpl_mask* mask;
	char cname[80];
	//cpl_binary* pbpm;
	for(m=0;m<size;m++) {

		nl=px[m];
		ns=py[m];

		int x_min=nl-win_hsx, x_max=nl+win_hsx;
		/* treats properly evaluation box edges */
		//xsh_msg("init x_min=%d x_max=%d",x_min,x_max);
		if (x_min < 0) {
			//xsh_msg("x case1")/;
			x_min = 0;
			x_max = win_sx;
		} else if ( x_max > nlambda) {
			//xsh_msg("x case2 i=%d i+x_max=%d,sx=%d",i,i+x_max,sx);
			x_max=nlambda;
			x_min=x_max-win_sx;
		}

		//xsh_msg("order %d nl=%d ns=%d",no,nl,ns);
		if( (ns > ns_min) && (ns < ns_max) ) {
			nlambda_ns=nlambda*ns;
			pix=nlambda_ns+nl;

			//xsh_msg("pix=%d",pix);

			sum_good_pix=0.;
			sum_bad_pix=0.;
			num_good_pix=0;
			num_bad_pix=0;
			norm_good_pix=0.;
			//int sign_from=0;
			//int sign_scal=0;
			// to sum only over good pixels we flag the bad ones
			for(int i=x_min;i<=x_max;i++) {
				for(int nf=0; nf < nb_frames; nf++) {

					int from_idx;
					if ((ns < slit_index[nf]) || (ns >= (slit_index[nf] + from_slit))) {

						xsh_msg("continued i=%d",i);
						continue;

					}
					//i is like nl
					from_idx = i + (ns - slit_index[nf]) * nlambda;

					sprintf(cname,"f%d",nf);
					int* pq=cpl_table_get_data_int(bp,cname);

					float * from_data1 = xsh_rec_list_get_data1( from[nf], no);
					//float * from_errs1 = xsh_rec_list_get_errs1( from[nf], no);
					int* from_qual1 = xsh_rec_list_get_qual1( from[nf], no);
					//xsh_msg("order %d nf=%d from_idx=%d",no,nf,from_idx);
					if( (from_qual1[from_idx] & decode_bp) == 0 ) {
						/* sum over good pixels */
						//xsh_msg("correct pix ns=%d nl=%d",ns,nl);
						//xsh_msg("k=%d j=%d pdata=%g",k,j,pdata[pix]);
                        // pq==0 it to pick-up those pixels that are good
						// in at least one frame
						if((ns >= slit_ext_min && ns <= slit_ext_max) &&
								pq[m]==0 && i != 0) {
							sum_good_pix += (from_data1[from_idx]);
							num_good_pix++;
						} else {
							sum_bad_pix += (from_data1[from_idx]);
							num_bad_pix++;
						}
					}

				} /* end sum over frames */
			} /* end loop over small box along X (wavelength) */
			//double sum=norm_good_pix;
			sum_all_pix= sum_good_pix+sum_bad_pix;
			//norm_good_pix=
			scale = sum_all_pix/sum_good_pix*num_good_pix/nb_frames;

			if(isinf(scale) || isnan(scale)) {
				xsh_msg("found infinite sum_good: %g sum_bad: %g num_good: %g",
						sum_good_pix, sum_bad_pix, num_good_pix);
				xsh_msg("x_min=%d x_max=%d",x_min,x_max);



				scale=1;
				//xsh_msg("sum=%g num=%d",sum,sum_good_pix);
				//exit(0);
			}
			//xsh_msg("dest before=%g norm=%g",dest_data1[pix],norm_good_pix);

			dest_data1[pix] = scale;
			dest_qual1[pix] -= QFLAG_INCOMPLETE_NOD;
			dest_qual1[pix] |= QFLAG_SCALED_NOD;

		} //end check if on overlapping NOD images

	}  //end loop over bad pix table

	ima=cpl_image_wrap_float(nlambda,nslit,dest_data1);
	sprintf(fname,"ima_cor_%d.fits",no);
	cpl_image_save(ima, fname, CPL_TYPE_FLOAT, NULL, CPL_IO_DEFAULT);
	cpl_table_save(bp,NULL,NULL,"bp_tab.fits",CPL_IO_DEFAULT);
	cpl_image_unwrap(ima);
	cpl_table_delete(tab_bpm);
	cleanup:
	//xsh_msg("end of function");
	//exit(0);
	return cpl_error_get_code();
}

cpl_error_code
xsh_correct_scale(xsh_rec_list *dest, xsh_rec_list **from,
		int *slit_index, int nb_frames, int no,
		int method, const int decode_bp,
		cpl_imagelist* scale_factors,const int scale_method)
{
	//xsh_msg("start of function");
	cpl_image* scale_ima;
	int nlambda_ns;
	int pix;

	double norm_good_pix=0.;

	XSH_ASSURE_NOT_NULL( dest);
	XSH_ASSURE_NOT_NULL( from);
	XSH_ASSURE_NOT_NULL( slit_index);

	int nslit = xsh_rec_list_get_nslit( dest, no );
	int nlambda = xsh_rec_list_get_nlambda( dest, no );

	int num_good_pix;

	int ns,nl,m;
	char fname[80];
	double* pscale;
	float* dest_data1;
	int from_slit = xsh_rec_list_get_nslit( from[0], no);


	int *dest_qual1 = NULL;
	dest_qual1 = xsh_rec_list_get_qual1( dest, no);

	cpl_image* ima_bp=cpl_image_wrap_int(nlambda,nslit,dest_qual1);
	sprintf(fname,"ima_bp_%d.fits",no);
	//cpl_image_save(ima_bp, fname, XSH_PRE_DATA_BPP, NULL, CPL_IO_DEFAULT);

	cpl_table* tab_bpm=xsh_qual2tab(ima_bp,QFLAG_INCOMPLETE_NOD);
	sprintf(fname,"tab_bp_%d.fits",no);
	//cpl_table_save(tab_bpm,NULL,NULL,fname,CPL_IO_DEFAULT);
	cpl_image_unwrap(ima_bp);

	int size=cpl_table_get_nrow(tab_bpm);
	int* px=cpl_table_get_data_int(tab_bpm,"x");
	int* py=cpl_table_get_data_int(tab_bpm,"y");
	int ns_min=-999;
	int ns_max=999;

	double slit_ext_min=0;
	double slit_ext_max=0;
	double slit_step = xsh_pfits_get_rectify_bin_space( dest->header);
	xsh_rec_get_nod_extract_slit_min_max(dest, slit_step,&slit_ext_min,
	    		&slit_ext_max);

	for (int nf = 0; nf < nb_frames; nf++) {
		//xsh_msg("slit index: max %d min=%d", slit_index[nf], slit_index[nf]+from_slit);
		if(slit_index[nf]>ns_min) {
			ns_min=slit_index[nf];
		}
		if( (slit_index[nf]+from_slit) < ns_max) {
			ns_max=(slit_index[nf]+from_slit);
		}
	}
	//xsh_msg("ck1");
	//xsh_msg("ns min=%d max=%d",ns_min,ns_max);

	//xsh_msg("slit_ext_min=%g slit_ext_max=%g slit_step=%g",
	//  slit_ext_min,slit_ext_max,slit_step);
	//ns_min=slit_ext_min;
	//ns_max=slit_ext_max;
	//exit(0);
	dest_data1 = xsh_rec_list_get_data1( dest, no);
	dest_qual1 = xsh_rec_list_get_qual1( dest, no);
	cpl_image* ima;
	ima=cpl_image_wrap_float(nlambda,nslit,dest_data1);
	//cpl_image_save(ima, "ima_org.fits", CPL_TYPE_FLOAT, NULL, CPL_IO_DEFAULT);
	cpl_image_unwrap(ima);
	int pix_scale;
	cpl_mask* mask;
	cpl_binary* pbpm;
	for(m=0;m<size;m++) {

		nl=px[m];
		ns=py[m];
		//xsh_msg("order %d nl=%d ns=%d",no,nl,ns);
		if( (ns > ns_min) && (ns < ns_max) ) {
			nlambda_ns=nlambda*ns;
			pix=nlambda_ns+nl;

			//xsh_msg("pix=%d",pix);

			norm_good_pix=0.;
			num_good_pix=0;
			//int sign_from=0;
			//int sign_scal=0;
			// to sum only over good pixels we flag the bad ones
			for(int nf=0; nf < nb_frames; nf++) {

				int from_idx;
				if ((ns < slit_index[nf]) || (ns >= (slit_index[nf] + from_slit))) {
					continue;
				}
				from_idx = nl + (ns - slit_index[nf]) * nlambda;
				if(scale_method < 2) {
					pix_scale=ns;
				} else {
					pix_scale=pix;
				}

				float * from_data1 = xsh_rec_list_get_data1( from[nf], no);
				//float * from_errs1 = xsh_rec_list_get_errs1( from[nf], no);
				int* from_qual1 = xsh_rec_list_get_qual1( from[nf], no);
				//xsh_msg("order %d nf=%d from_idx=%d",no,nf,from_idx);
				if( (from_qual1[from_idx] & decode_bp) == 0 ) {
					//xsh_msg("correct pix ns=%d nl=%d",ns,nl);
					//xsh_msg("k=%d j=%d pdata=%g",k,j,pdata[pix]);
					scale_ima=cpl_imagelist_get(scale_factors,nf);
					mask=cpl_image_get_bpm(scale_ima);
					pbpm=cpl_mask_get_data(mask);
					//xsh_msg("sk1 %d %d",cpl_image_get_size_x(scale_ima),cpl_image_get_size_y(scale_ima));
					pscale=cpl_image_get_data_double(scale_ima);
					/*
                    if ( (nl > 1765 && nl < 1775) && (ns > 27 && ns < 35) ) {
    				xsh_msg("no=%d nf=%d ns=%d nl=%d data=%g pscale=%g r=%g",
    						no,nf,ns,nl,from_data1[from_idx],pscale[pix_scale],
							from_data1[from_idx]/pscale[pix_scale]);
                    }
					 */


                    /*
				    if(no==4 && (nl > 1860 && nl < 1862) && (ns > 39 && ns < 41)) {
						xsh_msg("no=%d nf=%d ns=%d nl=%d data=%g pscale=%g r=%g",
						         no,nf,ns,nl,from_data1[from_idx],pscale[pix_scale],
													from_data1[from_idx]/pscale[pix_scale]);
						sprintf(fname,"scale_ima_ord_%d_frame_%d.fits",no,nf);
						cpl_image_save(scale_ima,fname,CPL_TYPE_FLOAT,NULL,CPL_IO_CREATE);
					}
					*/

					if((ns >= slit_ext_min && ns <= slit_ext_max) &&
							pbpm[pix_scale]==CPL_BINARY_0) {
						norm_good_pix += (from_data1[from_idx]) /
								(pscale[pix_scale]);
						/*
						if(no==4 && (nl > 1860 && nl < 1862) && (ns > 39 && ns < 41)) {
			    		xsh_msg("norm=%g       num=%d       slit_ext_min=%g slit_ext_max=%g",
			    				 norm_good_pix,num_good_pix,slit_ext_min,   slit_ext_max);
			    		}
			    		*/

					} else {
                                                /*
						sign_from = (from_data1[from_idx] > 0) ? 1 : -1;
						sign_scal = (pscale[pix_scale] > 0) ? -1 : 1;
						norm_good_pix += (sign_from*from_data1[from_idx]) /
								(sign_scal*pscale[pix_scale]);
                                                */

					}

					num_good_pix++;
					/*
    				if(isinf(norm_good_pix)) {
    					xsh_msg("add=%g scale=%g",from_data1[from_idx],pscale[pix_scale]);
    				}
					 */

				}

			}
			//double sum=norm_good_pix;
			norm_good_pix /= num_good_pix;
            /*
			if(no==4 && (nl > 1860 && nl < 1862) && (ns > 39 && ns < 41)) {
    		xsh_msg("m=%d norm=%g       num=%d       slit_ext_min=%g slit_ext_max=%g",
    				 m,   norm_good_pix,num_good_pix,slit_ext_min,slit_ext_max);
    		}
    		*/

			if(isinf(norm_good_pix)) {
				xsh_msg("found infinite");
				//xsh_msg("sum=%g num=%d",sum,num_good_pix);
				//exit(0);
			}
			//xsh_msg("dest before=%g norm=%g",dest_data1[pix],norm_good_pix);

			dest_data1[pix] = norm_good_pix;
			dest_qual1[pix] -= QFLAG_INCOMPLETE_NOD;
			dest_qual1[pix] |= QFLAG_SCALED_NOD;

		} //end check if on overlapping NOD images

	}  //end loop over bad pix table

	ima=cpl_image_wrap_float(nlambda,nslit,dest_data1);
	//cpl_image_save(ima, "ima_cor.fits", CPL_TYPE_FLOAT, NULL, CPL_IO_DEFAULT);
	cpl_image_unwrap(ima);
	cpl_table_delete(tab_bpm);
	cleanup:
	//xsh_msg("end of function");
	return cpl_error_get_code();
}


/*****************************************************************************/
/** 
 * Adds (combine) all the shifted rectified frames (nodding). Combination
 * is made for each order.
 * 
 * @param nod_frames Frameset of the shifted rectified frames
 * @param nod_par Parameters of combination
 * @param tag  pro catg of combined frame
 * @param instrument Instrument description
 * @param res_frame_ext combined frame in ESO format 
 * @return The combined frame, inf/upp suggested values for extraction
 */
/*****************************************************************************/
cpl_frame* xsh_combine_nod( cpl_frameset *nod_frames, 
		xsh_combine_nod_param * nod_par,
		const char * tag,
		xsh_instrument *instrument,
		cpl_frame** res_frame_ext,
		const int scale_nod)
{
	xsh_rec_list *result_list = NULL ;
	cpl_frame *result = NULL ;
	int nb_frames = 0 ;
	int i, no, nb_orders;
	float slit_min=999, slit_max=-999;
	double slit_step =0.0;
	double lambda_min, lambda_max, lambda_step;
	xsh_rec_list **rec_input_list = NULL ;
	xsh_rec_list *rec_first = NULL;
	//float *rec_first_slit = NULL;
	float *result_slit = NULL;
	int nslit;
	char *fname = NULL ;
	char *tag_drl = NULL ;
	char *fname_drl = NULL ;
	int *slit_index = NULL;
	int slit_ext_min=-9999;
	int slit_ext_max=9999;
	cpl_propertylist *header = NULL;
	int ncrh_tot=0;

	XSH_ASSURE_NOT_NULL( nod_frames);
	XSH_ASSURE_NOT_NULL( nod_par);
	XSH_ASSURE_NOT_NULL( instrument);
	XSH_ASSURE_NOT_NULL( tag);
	XSH_ASSURE_NOT_NULL( res_frame_ext);

	/* Create list of_reclist */
	check( nb_frames = cpl_frameset_get_size( nod_frames));
	xsh_msg( "---xsh_combine_nod (method %s) - Nb frames = %d",
			COMBINE_METHOD_PRINT( nod_par->method), nb_frames);

	/* create the list of pointers to input rec lists */
	XSH_CALLOC( rec_input_list, xsh_rec_list *, nb_frames);

	/* Populate the input lists */
	for ( i = 0 ; i < nb_frames ; i++ ) {
		cpl_frame * nod_frame = NULL ;
		xsh_rec_list * list = NULL;

		check( nod_frame = cpl_frameset_get_frame( nod_frames, i));
		check( list = xsh_rec_list_load( nod_frame, instrument));
		rec_input_list[i] = list;
		if (cpl_propertylist_has((rec_input_list[i])->header,XSH_QC_CRH_NUMBER) > 0 ){
		    ncrh_tot += xsh_pfits_get_qc_ncrh((rec_input_list[i])->header);
		}


		char name[80];

		//xsh_msg("no=%d rec_input_list=%p",no,rec_input_list);
		sprintf(name,"input_resampled_%d.fits",i);
		cpl_frame* frm=xsh_rec_list_save2(rec_input_list[i],name,"test");
		xsh_add_temporary_file(name);
		xsh_free_frame(&frm);

	}
	/* Search for limits in slit */
	for ( i = 0 ; i < nb_frames ; i++ ) {
		float nod_slit_min, nod_slit_max;
		xsh_rec_list * list = NULL;
		nslit=0;
		float* nod_slit = NULL;

		list = rec_input_list[i];
		check( nslit = xsh_rec_list_get_nslit( list, 0));
		check( nod_slit = xsh_rec_list_get_slit( list, 0));
		nod_slit_min = nod_slit[0];
		nod_slit_max = nod_slit[nslit-1];

		if ( nod_slit_min < slit_min){
			slit_min = nod_slit_min;
		}
		if (nod_slit_max > slit_max){
			slit_max = nod_slit_max;
		}
	}
	rec_first = rec_input_list[0];
	//check( rec_first_slit = xsh_rec_list_get_slit( rec_first, 0));
	check( header = xsh_rec_list_get_header( rec_first));
	check( slit_step = xsh_pfits_get_rectify_bin_space( header));
	nslit = (slit_max-slit_min)/slit_step+1;

	/* Create result slit */
	XSH_CALLOC( result_slit, float, nslit);
	for ( i = 0 ; i < nslit; i++ ) {
		result_slit[i] = slit_min+i*slit_step;
	}

	xsh_msg("Combine nod slit : (%f,%f) step %f nslit %d", slit_min, slit_max,
			slit_step, nslit);

	nb_orders = rec_first->size;
	check( result_list =  xsh_rec_list_create_with_size( nb_orders,
			instrument));

	for ( no = 0 ; no < nb_orders ; no++ ) {
		int absorder, nlambda;
		double *dnew = NULL;
		double *dold = NULL;
		float *dslit = NULL;

		absorder = xsh_rec_list_get_order( rec_first, no);
		nlambda = xsh_rec_list_get_nlambda( rec_first, no);
		check( xsh_rec_list_set_data_size( result_list, no, absorder, nlambda,
				nslit));
		/* copy lambda */
		dold = xsh_rec_list_get_lambda( rec_first, no);
		dnew = xsh_rec_list_get_lambda( result_list, no);
		memcpy( dnew, dold, nlambda*sizeof( double));
		/* copy slit */
		dslit = xsh_rec_list_get_slit( result_list, no);
		memcpy( dslit, result_slit, nslit*sizeof( float));
	}

	/* compute slit index */
	XSH_CALLOC( slit_index, int, nb_frames);
	check( xsh_compute_slit_index( slit_min,  slit_step, rec_input_list,
			slit_index, nb_frames));



	/* Set header from science header */
	check( cpl_propertylist_append( result_list->header,
			rec_first->header));


	/* Now combine */
	xsh_msg("Nod combination save extra files to evaluate pixel scaling");
	for ( int nf = 0; nf < nb_frames; nf++) {
		for ( no = 0; no < nb_orders; no++) {
			//xsh_msg("order %d",no);

			xsh_rec_list_qc( result_list, rec_input_list, slit_index,
					nb_frames, no, nod_par->method,instrument->decode_bp,nf);

		}
	}

	for ( no = 0; no < nb_orders; no++) {

		/*
      check( xsh_rec_list_fill_gauss( result_list, rec_input_list, slit_index,
            nb_frames, no, nod_par->method,instrument->decode_bp) ) ;
		 */


		check( xsh_rec_list_add( result_list, rec_input_list, slit_index,
				nb_frames, no, nod_par->method,instrument->decode_bp) ) ;


		if(scale_nod>0) {
			xsh_msg("combine-nod: scale flagged pixel");
			int scale_method=2;
			cpl_imagelist* sf = NULL;
			cpl_table* tab_bp=NULL;
			if(scale_nod>1) {

				xsh_msg("filling table");
				tab_bp =
						xsh_qual2tab_frames(nb_frames,instrument->decode_bp, slit_index, result_list,
								rec_input_list, no);
				xsh_msg("filling table ok");
			} else {


				check(sf =xsh_find_image_scale_factors(result_list, rec_input_list,
						slit_index, nb_frames, no, nod_par->method,
						instrument->decode_bp,scale_method));
			}
			if (scale_nod>1) {
				check(xsh_correct_scale_w(result_list, rec_input_list, slit_index,
						nb_frames, no, nod_par->method, instrument->decode_bp, sf,
						scale_method, tab_bp));
			} else {
				check(xsh_correct_scale(result_list, rec_input_list, slit_index,
						nb_frames, no, nod_par->method, instrument->decode_bp, sf,
						scale_method));
			}
			xsh_free_imagelist(&sf);

			/*
	      cpl_image* scale_ima;
	      check( scale_ima=xsh_rec_list_compute_scale2( result_list,
	      rec_input_list, slit_index, nb_frames, no, nod_par->method,
	      instrument->decode_bp) ) ;
			 */

			/*
		       float* data;
			   float* errs;
			   int* qual;
		       data=xsh_rec_list_get_data1(result_list,no);
		       errs=xsh_rec_list_get_errs1(result_list,no);
		       qual=xsh_rec_list_get_qual1(result_list,no);
			 */


			//sprintf(name,"result_resampled_%d.fits",no);
			//xsh_rec_list_save2(result_list,name,"test");


		}




	}

	/* Now save result list s frame */
	fname = xsh_stringcat_any( tag, ".fits", (void*)NULL);
	tag_drl = xsh_stringcat_any( tag, "_DRL", (void*)NULL);
	fname_drl = xsh_stringcat_any( "DRL_", fname, (void*)NULL);


	/* Add bin_lambda and bin_space to property list */
	check( lambda_step = xsh_pfits_get_rectify_bin_lambda(
			result_list->header));
	check( lambda_min = xsh_pfits_get_rectify_lambda_min(
			result_list->header));
	check( lambda_max = xsh_pfits_get_rectify_lambda_max(
			result_list->header));
	check( xsh_pfits_set_rectify_bin_lambda( result_list->header,
			lambda_step));
	check( xsh_pfits_set_rectify_bin_space( result_list->header,
			slit_step));

	/* Add lambda min and max (global) */
	/* Lambda min is lambda_min of last order */
	/* Lambda Max is lambda_max of first order */
	check( xsh_pfits_set_rectify_lambda_min( result_list->header,
			lambda_min)) ;
	check( xsh_pfits_set_rectify_lambda_max( result_list->header,
			lambda_max));


	/* Now compute slit min/max for 1D extraction: AMO: should we control
     this bit of code via some parameters??
	 */

	if(1) {
		int nf=0;
		int from_slit=0;
		for ( no = 0; no < nb_orders; no++) {
			check( from_slit = xsh_rec_list_get_nslit( rec_input_list[0], no));

			for( nf = 0 ; nf < nb_frames ; nf++ ) {
				slit_ext_min=(slit_index[nf]>slit_ext_min) ? slit_index[nf]: slit_ext_min;
				slit_ext_max=(slit_index[nf]+from_slit<slit_ext_max) ? slit_index[nf]+from_slit: slit_ext_max;

			}
		}
	}

	xsh_msg("slit index: min %f max=%f",
			slit_min,slit_max);

	//result_list->slit_min = slit_min-slit_step/2.0;
	//result_list->slit_max = slit_max+slit_step/2.0;
	result_list->slit_min = slit_min;
	result_list->slit_max = slit_max;

	//xsh_rec_list_set_slit_min(result_slit,slit_min);
	//xsh_rec_list_set_slit_max(result_slit,slit_max);
	/*
  xsh_msg("slit index: min %f max=%f",
	  result_list->slit_min,result_list->slit_max);
	 */


	check( xsh_pfits_set_rectify_space_min( result_list->header,
			result_list->slit_min));
	check( xsh_pfits_set_rectify_space_max( result_list->header,
			result_list->slit_max));
	check( xsh_pfits_set_pcatg( result_list->header, tag));

	xsh_pfits_set_extract_slit_min(result_list->header,slit_ext_min);
	xsh_pfits_set_extract_slit_max(result_list->header,slit_ext_max);
	xsh_pfits_set_qc_ncrh_tot(result_list->header,ncrh_tot);
	xsh_pfits_set_qc_ncrh_mean(result_list->header,ncrh_tot/nb_frames);

	check( *res_frame_ext=xsh_rec_list_save2( result_list, fname, tag));
	check( result = xsh_rec_list_save( result_list, fname_drl, tag_drl, 1));
	xsh_add_temporary_file(fname_drl);
	cleanup:
	xsh_print_rec_status(10);
	if (cpl_error_get_code() != CPL_ERROR_NONE){
		xsh_free_frame( &result);
		xsh_free_frame( res_frame_ext);
	}
	xsh_rec_list_free( &result_list);
	if ( rec_input_list != NULL){
		for ( i = 0 ; i < nb_frames ; i++ ) {
			xsh_rec_list_free(  &rec_input_list[i]);
		}
	}
	XSH_FREE( result_slit);
	XSH_FREE( slit_index);
	XSH_FREE( tag_drl);
	XSH_FREE( fname_drl);
	XSH_FREE( fname);
	XSH_FREE( rec_input_list);
	return result ;
}
/*****************************************************************************/

/**@}*/
