/*                                                                            *
 *   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: 2011-12-02 14:13:14 $
 * $Revision: 1.3 $
 * $Name: not supported by cvs2svn $
 */
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

/*--------------------------------------------------------------------------*/
/**
  @defgroup xsh_test_tools     
    Test some tools functions for performances check
  @ingroup unit_tests
*/
/*--------------------------------------------------------------------------*/
/**@{*/

/*---------------------------------------------------------------------------
                                Includes
 ---------------------------------------------------------------------------*/
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <cpl.h>
#include <xsh_msg.h>
#include <xsh_dfs.h>
#include <xsh_utils.h>
#include <xsh_data_rec.h>
#include <xsh_pfits.h>
#include <xsh_parameters.h>

static cpl_image*
xsh_imagelist_collapse_create(cpl_imagelist* iml){

    cpl_image* res;


    cpl_image* tmp;

    cpl_binary* pbpm;
    int sx=0;
    int sy=0;
    int sz=0;
    double* flux;
    sz=cpl_imagelist_get_size(iml);
    tmp=cpl_imagelist_get(iml,0);
    sx=cpl_image_get_size_x(tmp);
    sy=cpl_image_get_size_y(tmp);
    cpl_mask* bpm;
    cpl_mask* bpmr;
    cpl_binary* pbpmr;
    double* pima;
    int good;
    int bad;
    int sx_j;
    int pix;
    cpl_vector* flux_vec;
    double* pres;
    cpl_binary bp_code;
    res=cpl_image_new(sx,sy,CPL_TYPE_DOUBLE);

    pres=cpl_image_get_data_double(res);

    flux= (double*) cpl_calloc(sz , sizeof(double));
    //XSH_MALLOC( flux, double, sz);
    bpmr=cpl_image_get_bpm(res);
    pbpmr=cpl_mask_get_data(bpmr);
    for(int j=0;j<sy;j++) {

        sx_j=sx*j;
        for(int i=0;i<sx;i++) {

            good=0;
            bad=0;
            pix=sx_j+i;
            bp_code=CPL_BINARY_0;
            for (int k = 0; k < sz; k++) {
                tmp=cpl_imagelist_get(iml,k);
                pima=cpl_image_get_data_double(tmp);
                bpm=cpl_image_get_bpm(tmp);
                pbpm=cpl_mask_get_data(bpm);
                if( pbpm[pix] == CPL_BINARY_0 ) {
                    flux[good]=pima[pix];
                    good++;
                } else {
                    flux[good+bad]=pima[pix];
                    bad++;
                    bp_code=CPL_BINARY_1;
                    //xsh_msg("found bp");
                }
            }

            if (good == 0) {
                flux_vec = cpl_vector_wrap( bad, flux);

            } else {
                flux_vec = cpl_vector_wrap( good, flux);

            }
           pres[pix] = cpl_vector_get_mean( flux_vec);
           pbpmr[pix] = bp_code;
           xsh_unwrap_vector(&flux_vec);
        }
    }

    cpl_free ( flux);
    return res;

}

cpl_error_code
test_mem(void) {
    cpl_image* ima;
    cpl_imagelist* iml;
    cpl_imagelist* iml1;
    cpl_imagelist* iml2;
    int sx=100;
    int sy=100;
    iml=cpl_imagelist_new();
    int sz=5;
    int niter=1;
    for(int i=0;i < sz;i++) {
        ima=cpl_image_new(sx,sy,CPL_TYPE_DOUBLE);
        cpl_imagelist_set(iml,ima,i);
    }



    for(int i=0;i < niter;i++) {
        iml1=cpl_imagelist_duplicate(iml);
        iml2=cpl_imagelist_duplicate(iml);

        cpl_imagelist_delete(iml1);
        cpl_imagelist_delete(iml2);
    }


    cpl_imagelist_delete(iml);

    return cpl_error_get_code();
}
static cpl_image*
xsh_compute_scale(cpl_imagelist* iml_data, cpl_mask* bpm,
                  const int mode, const int win_hsz)
{
    cpl_image* res;
    int sx_j;
    int pix;
    int win_hsx;
    int win_hsy;
    if(mode==0) {
       win_hsx=0;
       win_hsy=win_hsz;
    } else {
       win_hsx=win_hsz;
       win_hsy=0;
    }
    int win_sx=2*win_hsx+1;
    int win_sy=2*win_hsy+1;
    int sz=cpl_imagelist_get_size(iml_data);
    double sum_all;
    double sum_good;
    double sum_good_pix;
    double sum_tot_pix;
    double* pdata;
    //double sum_bad;
    double scale;

    cpl_image* ima_tmp;

    //cpl_imagelist* iml_tmp;
    cpl_imagelist* iml_good;
    cpl_imagelist* iml_all;
    cpl_binary* pbpm;
    cpl_binary* pbpm_tmp;

    cpl_mask* not=cpl_mask_duplicate(bpm);
    cpl_mask_not(not);
    cpl_binary* pnot=cpl_mask_get_data(not);
    cpl_mask* bpm_tmp;
    ima_tmp=cpl_imagelist_get(iml_data,0);
    cpl_imagelist* iml_copy=cpl_imagelist_duplicate(iml_data);

    int sx=cpl_image_get_size_x(ima_tmp);
    int sy=cpl_image_get_size_y(ima_tmp);
    double* pres;
    res=cpl_image_new(sx,sy,CPL_TYPE_DOUBLE);
    cpl_image_add_scalar(res,1.);
    pres=cpl_image_get_data(res);
    pbpm=cpl_mask_get_data(bpm);
    int point;
    int num_good_pix;
    int num_tot_pix;
    //int good;
    int frame_bad;
    int x,y;
    xsh_msg("total frames: %d",sz);

    for(int j=0;j<sy;j++) {
        //xsh_msg("j=%d",j);

        sx_j=sx*j;
        for(int i=0;i<sx;i++) {
            //xsh_msg("i=%d",i);

            pix=sx_j+i;
            frame_bad=0;
            //xsh_msg("pix=%d",pix);
            if ( pbpm[pix] == CPL_BINARY_0 ) {
                /* if the pixel was not flagged the scaling factor is 1 */
                pres[pix] = 1;

            }  else if ( pbpm[pix] == CPL_BINARY_1 ) {
                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;
                //sum_bad=0;
                //good=0;

                /* copy data to accessory imagelist (because we will unset only
                 * on the wrapped imagelist the frame at which we found a bad
                 * pixel in the original list */
                iml_all = cpl_imagelist_new();
                iml_good = cpl_imagelist_new();
                //iml_all=cpl_imagelist_duplicate(iml_data);
                //iml_good=cpl_imagelist_duplicate(iml_data);

                for(int k=0;k<sz;k++) {
                    ima_tmp=cpl_imagelist_get(iml_copy,k);

                    cpl_imagelist_set(iml_good,cpl_image_duplicate(ima_tmp),k);
                    cpl_imagelist_set(iml_all,cpl_image_duplicate(ima_tmp),k);

                }

                /* we search now on which frame image of the original list was
                 * present the flagged pixel and we un-set that frame in the
                 * wrapped list
                 */

                for(int k=0;k<sz-frame_bad;k++) {

                    ima_tmp=cpl_imagelist_get(iml_good,k);
                    pdata=cpl_image_get_data_double(ima_tmp);
                    bpm_tmp=cpl_image_get_bpm(ima_tmp);
                    pbpm_tmp=cpl_mask_get_data(bpm_tmp);

                    if(pbpm_tmp[pix] == CPL_BINARY_1) {
                        //xsh_msg("found bad pix unset frame %d",k);
                        ima_tmp=cpl_imagelist_unset(iml_good,k);
                        bpm_tmp=cpl_image_unset_bpm(ima_tmp);
                        cpl_mask_delete(bpm_tmp);
                        cpl_image_delete(ima_tmp);

                        //sum_bad = pdata[pix];
                        frame_bad++;
                    }
                }

                //xsh_msg("Found bad pix=%d",frame_bad);

                /* to sum only over good pixels we flag the bad ones */
                for(int k=0;k<sz-frame_bad;k++) {
                    ima_tmp=cpl_imagelist_get(iml_good,k);
                    bpm_tmp=cpl_image_set_bpm(ima_tmp,cpl_mask_duplicate(bpm));
                    cpl_mask_delete(bpm_tmp);
                }

                /* to sum only over good pixels we flag the bad ones */
                for(int k=0;k<sz;k++) {
                     ima_tmp=cpl_imagelist_get(iml_all,k);
                     bpm_tmp=cpl_image_set_bpm(ima_tmp,cpl_mask_duplicate(bpm));
                     cpl_mask_delete(bpm_tmp);

                }

                /* now search for the good pixels  in the remaining images of
                 * the wrapped imagelist around the bad pixel to compute the sum
                 * of good and the sum of all pixels
                 */
                xsh_msg("Compute sums");

                for(y=y_min; y <= y_max; y++) {
                    //xsh_msg("y=%d",y);
                    for(x=x_min; x <= x_max; x++) {
                        //xsh_msg("x=%d",x);
                        point=y*sx+x;

                        //xsh_msg("compute sum on all %d frames",sz);
                        for(int k=0;k<sz;k++) {
                            ima_tmp=cpl_imagelist_get(iml_all,k);
                            pdata=cpl_image_get_data_double(ima_tmp);
                            bpm_tmp=cpl_image_get_bpm(ima_tmp);
                            pbpm_tmp=cpl_mask_get_data(bpm_tmp);
                            if(pbpm_tmp[point] == CPL_BINARY_0) {
                                sum_all += pdata[point];
                            }
                            //xsh_msg("scan point %d at %d,%d",point,i,j);

                        }

                        //xsh_msg("compute sum on %d left frames",sz-frame_bad);
                        for(int k=0;k<sz-frame_bad;k++) {
                            ima_tmp=cpl_imagelist_get(iml_good,k);
                            pdata=cpl_image_get_data_double(ima_tmp);
                            bpm_tmp=cpl_image_get_bpm(ima_tmp);
                            pbpm_tmp=cpl_mask_get_data(bpm_tmp);
                            //xsh_msg("scan point %d at %d,%d",point,i,j);
                            if( pbpm[point] == CPL_BINARY_0 ) {
                                sum_good += pdata[point];
                            }
                        }

                        // determine the sum of good pixel at pos of bad pix
                        for(int k=0;k<sz-frame_bad;k++) {
                            ima_tmp=cpl_imagelist_get(iml_good,k);
                            pdata=cpl_image_get_data_double(ima_tmp);

                            if( pnot[pix] == CPL_BINARY_0 && pix != point) {
                                sum_good_pix += pdata[pix];
                                num_good_pix++;
                            }

                            if( pnot[pix] == CPL_BINARY_0 && pix == point) {
                                sum_tot_pix += pdata[pix];
                                num_tot_pix++;
                            }
                        }

                    }
                } //end loop to compute sum

                scale = sum_all / sum_good;
                //pres[pix] = scale*num_tot_pix/sz;
                //pres[pix] = scale*sum_tot_pix/sz;
                pres[pix]=scale*num_tot_pix/sz;  //good for uniform images case
                //pres[pix]=1;
                xsh_msg("sum all %g good %g good_pix %g num_good %d sum_tot_pix %g num_tot_pix %d scale %g res: %g",
                        sum_all,sum_good,sum_good_pix, num_good_pix, sum_tot_pix, num_tot_pix, scale, pres[pix]);

                xsh_print_rec_status(1);

                int n=cpl_imagelist_get_size(iml_good);
                xsh_msg("ok1 sz=%d n=%d",sz,n);
                for(int k=0;k<n;k++) {
                    ima_tmp=cpl_imagelist_get(iml_good,k);
                    cpl_image_delete(ima_tmp);
                }
                for(int k=0;k<sz;k++) {
                    ima_tmp=cpl_imagelist_get(iml_all,k);
                    cpl_image_delete(ima_tmp);
                }

                xsh_print_rec_status(3);
                //cpl_imagelist_delete(iml_good);
                //cpl_imagelist_delete(iml_all);
                //cpl_imagelist_empty(iml_good);
                //cpl_imagelist_empty(iml_all);
                cpl_imagelist_unwrap(iml_good);
                cpl_imagelist_unwrap(iml_all);
            }
        }
    }
    cpl_imagelist_delete(iml_copy);
    cpl_mask_delete(not);
    return res;
}



static cpl_image*
xsh_compute_scale_tab(cpl_imagelist* iml_data, cpl_mask* bpm, cpl_table* tab_bpm,
                  const int mode, const int win_hsz)
{
    cpl_image* res;
    int sx_j;
    int pix;
    int win_hsx;
    int win_hsy;
    if(mode==0) {
       win_hsx=0;
       win_hsy=win_hsz;
    } else {
       win_hsx=win_hsz;
       win_hsy=0;
    }
    int win_sx=2*win_hsx+1;
    int win_sy=2*win_hsy+1;
    int sz=cpl_imagelist_get_size(iml_data);
    double sum_all;
    double sum_good;
    double sum_good_pix;
    double sum_tot_pix;
    double* pdata;
    //double sum_bad;
    double scale;

    cpl_image* ima_tmp;

    //cpl_imagelist* iml_tmp;
    cpl_imagelist* iml_good;
    cpl_imagelist* iml_all;
    cpl_binary* pbpm;
    cpl_binary* pbpm_tmp;

    cpl_mask* not=cpl_mask_duplicate(bpm);
    cpl_mask_not(not);
    cpl_binary* pnot=cpl_mask_get_data(not);
    cpl_mask* bpm_tmp;
    ima_tmp=cpl_imagelist_get(iml_data,0);
    cpl_imagelist* iml_copy=cpl_imagelist_duplicate(iml_data);

    int sx=cpl_image_get_size_x(ima_tmp);
    int sy=cpl_image_get_size_y(ima_tmp);
    double* pres;
    res=cpl_image_new(sx,sy,CPL_TYPE_DOUBLE);
    cpl_image_add_scalar(res,1.);
    pres=cpl_image_get_data(res);

    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);
    pbpm=cpl_mask_get_data(bpm);
    int point;
    int num_good_pix;
    int num_tot_pix;
    //int good;
    int frame_bad;
    int x,y;
    xsh_msg("total frames: %d",sz);
    int i,j,m;
    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;

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

        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;
        //sum_bad=0;
        //good=0;

        /* copy data to accessory imagelist (because we will unset only
         * on the wrapped imagelist the frame at which we found a bad
         * pixel in the original list */
        iml_all = cpl_imagelist_new();
        iml_good = cpl_imagelist_new();
        //iml_all=cpl_imagelist_duplicate(iml_data);
        //iml_good=cpl_imagelist_duplicate(iml_data);

        for(int k=0;k<sz;k++) {
            ima_tmp=cpl_imagelist_get(iml_copy,k);

            cpl_imagelist_set(iml_good,cpl_image_duplicate(ima_tmp),k);
            cpl_imagelist_set(iml_all,cpl_image_duplicate(ima_tmp),k);

        }

        /* we search now on which frame image of the original list was
         * present the flagged pixel and we un-set that frame in the
         * wrapped list
         */

        for(int k=0;k<sz-frame_bad;k++) {

            ima_tmp=cpl_imagelist_get(iml_good,k);
            pdata=cpl_image_get_data_double(ima_tmp);
            bpm_tmp=cpl_image_get_bpm(ima_tmp);
            pbpm_tmp=cpl_mask_get_data(bpm_tmp);

            if(pbpm_tmp[pix] == CPL_BINARY_1) {
                //xsh_msg("found bad pix unset frame %d",k);
                ima_tmp=cpl_imagelist_unset(iml_good,k);
                bpm_tmp=cpl_image_unset_bpm(ima_tmp);
                cpl_mask_delete(bpm_tmp);
                cpl_image_delete(ima_tmp);

                //sum_bad = pdata[pix];
                frame_bad++;
            }
        }

        //xsh_msg("Found bad pix=%d",frame_bad);

        /* to sum only over good pixels we flag the bad ones */
        for(int k=0;k<sz-frame_bad;k++) {
            ima_tmp=cpl_imagelist_get(iml_good,k);
            bpm_tmp=cpl_image_set_bpm(ima_tmp,cpl_mask_duplicate(bpm));
            cpl_mask_delete(bpm_tmp);
        }

        /* to sum only over good pixels we flag the bad ones */
        for(int k=0;k<sz;k++) {
            ima_tmp=cpl_imagelist_get(iml_all,k);
            bpm_tmp=cpl_image_set_bpm(ima_tmp,cpl_mask_duplicate(bpm));
            cpl_mask_delete(bpm_tmp);

        }

        /* now search for the good pixels  in the remaining images of
         * the wrapped imagelist around the bad pixel to compute the sum
         * of good and the sum of all pixels
         */
        xsh_msg("Compute sums");

        for(y=y_min; y <= y_max; y++) {
            //xsh_msg("y=%d",y);
            for(x=x_min; x <= x_max; x++) {
                //xsh_msg("x=%d",x);
                point=y*sx+x;

                //xsh_msg("compute sum on all %d frames",sz);
                for(int k=0;k<sz;k++) {
                    ima_tmp=cpl_imagelist_get(iml_all,k);
                    pdata=cpl_image_get_data_double(ima_tmp);
                    bpm_tmp=cpl_image_get_bpm(ima_tmp);
                    pbpm_tmp=cpl_mask_get_data(bpm_tmp);
                    if(pbpm_tmp[point] == CPL_BINARY_0) {
                        sum_all += pdata[point];
                    }
                    //xsh_msg("scan point %d at %d,%d",point,i,j);

                }

                //xsh_msg("compute sum on %d left frames",sz-frame_bad);
                for(int k=0;k<sz-frame_bad;k++) {
                    ima_tmp=cpl_imagelist_get(iml_good,k);
                    pdata=cpl_image_get_data_double(ima_tmp);
                    bpm_tmp=cpl_image_get_bpm(ima_tmp);
                    pbpm_tmp=cpl_mask_get_data(bpm_tmp);
                    //xsh_msg("scan point %d at %d,%d",point,i,j);
                    if( pbpm[point] == CPL_BINARY_0 ) {
                        sum_good += pdata[point];
                    }
                }

                // determine the sum of good pixel at pos of bad pix
                for(int k=0;k<sz-frame_bad;k++) {
                    ima_tmp=cpl_imagelist_get(iml_good,k);
                    pdata=cpl_image_get_data_double(ima_tmp);

                    if( pnot[pix] == CPL_BINARY_0 && pix != point) {
                        sum_good_pix += pdata[pix];
                        num_good_pix++;
                    }

                    if( pnot[pix] == CPL_BINARY_0 && pix == point) {
                        sum_tot_pix += pdata[pix];
                        num_tot_pix++;
                    }
                }

            }
        } //end loop to compute sum

        scale = sum_all / sum_good;
        //scale = sum_tot_pix / num_tot_pix * num_good_pix / sum_good_pix;
        //pres[pix] = scale*num_tot_pix/num_good_pix;
        //pres[pix] = scale;
        pres[pix]=scale*num_tot_pix/sz;  //good for uniform images case
        //pres[pix]=1;
        xsh_msg("sum all %g good %g good_pix %g num_good %d sum_tot_pix %g num_tot_pix %d scale %g res: %g",
                sum_all,sum_good,sum_good_pix, num_good_pix, sum_tot_pix, num_tot_pix, scale, pres[pix]);

        xsh_print_rec_status(1);

        int n=cpl_imagelist_get_size(iml_good);
        xsh_msg("ok1 sz=%d n=%d",sz,n);
        for(int k=0;k<n;k++) {
            ima_tmp=cpl_imagelist_get(iml_good,k);
            cpl_image_delete(ima_tmp);
        }
        for(int k=0;k<sz;k++) {
            ima_tmp=cpl_imagelist_get(iml_all,k);
            cpl_image_delete(ima_tmp);
        }

        xsh_print_rec_status(3);
        //cpl_imagelist_delete(iml_good);
        //cpl_imagelist_delete(iml_all);
        //cpl_imagelist_empty(iml_good);
        //cpl_imagelist_empty(iml_all);
        cpl_imagelist_unwrap(iml_good);
        cpl_imagelist_unwrap(iml_all);

    }

    cpl_imagelist_delete(iml_copy);
    cpl_mask_delete(not);
    return res;
}



static cpl_error_code
xsh_compute_scale_tab2(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();
}



cpl_error_code
xsh_flag_bp_at_location(cpl_binary* pbpm, int pix, cpl_binary bp_code,
                        const int mode, const int sx)
{
    /*
    pima[pix-2]=0;
    pima[pix-1]=0;
    pima[pix]=0;
    pima[pix+1]=0;
    pima[pix+2]=0;
     */
    if(mode == 0) {
        pbpm[pix-2]=bp_code;
        pbpm[pix-1]=bp_code;
        pbpm[pix]=bp_code;
        pbpm[pix+1]=bp_code;
        pbpm[pix+2]=bp_code;
    } else {
        pbpm[pix-2*sx]=bp_code;
        pbpm[pix-1*sx]=bp_code;
        pbpm[pix]=bp_code;
        pbpm[pix+1*sx]=bp_code;
        pbpm[pix+2*sx]=bp_code;
    }

    return cpl_error_get_code();

}
/*---------------------------------------------------------------------------
                            Defines
 ---------------------------------------------------------------------------*/
static cpl_image*
xsh_define_gauss_profile(const int sx, const int sy,
                           const double A, const double sigma, const double bkg,
                           cpl_vector* trace,const int min, const int max,
                           const int mode)
{

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

    cpl_image* gauss = cpl_image_new(sx, sy, CPL_TYPE_DOUBLE);
    double* pgauss = NULL;
    pgauss = cpl_image_get_data_double(gauss);

    double arg = 0;
    int i, j;
    double x=0,y=0;
    double* pvec = cpl_vector_get_data(trace);
    if (mode == 0) {
        /* uniform along X (horizontal direction) Gauss along Y (vertical)  */
        for (j = min; j <= max; j++) {
            y=j;
            for (i = 0; i < sx; i++) {
                arg = (y - pvec[i]) / sigma;
                arg *= arg;
                //xsh_msg("arg=%g",arg);
                pgauss[j * sx + i] += A * exp(-0.5 * arg) + bkg;
                //xsh_msg("val=%g",pgauss[j * sx + i]);
            }
        }
    } else {
        for (j = 0; j < sy; j++) {
            for (i = min; i <= max; i++) {
                x=i;

                arg = (x - pvec[j]) / sigma;
                arg *= arg;
                //xsh_msg("arg=%g",arg);
                pgauss[j * sx + i] += A * exp(-0.5 * arg) + bkg;
                //xsh_msg("val=%g",pgauss[j * sx + i]);
            }
        }
    }
    return gauss;
}

static cpl_error_code
test_xsh_set_min_max(const int sx, const int sy, const int mode,
                     int* min, int* max) {
    if (mode == 0) {
        *min=2*sy/5;
        *max=3*sy/5;
    } else {
        *min=2*sx/5;
        *max=3*sx/5;
    }
    return cpl_error_get_code();
}

static cpl_vector*
test_xsh_set_trace(const int sx, const int sy, const int mode) {
    cpl_vector* trace=cpl_vector_new(sx);
    if (mode == 0) {
        for(int i=0;i<sx;i++) {
            cpl_vector_set(trace,i,sy/2);
        }
    } else {
        for(int j=0;j<sy;j++) {
            cpl_vector_set(trace,j,sx/2);
        }
    }
    return trace;
}

static cpl_error_code
test_xsh_fill_bpm(const int sx, const int sy, const int mode, const int i,
                  cpl_image** ima, cpl_mask** bpm_tot) {
    cpl_mask* bpm=NULL;

    cpl_binary* pbpm=CPL_BINARY_0;

    int pix;

    if(i==0) {
        pix=sy*sx/4+sx/4;
        bpm=cpl_mask_new(sx,sy);
        pbpm=cpl_mask_get_data(bpm);
        xsh_flag_bp_at_location(pbpm, pix,CPL_BINARY_1,mode,sx);
        cpl_image_set_bpm(*ima,cpl_mask_duplicate(bpm));
        *bpm_tot=cpl_mask_duplicate(bpm);
        cpl_mask_delete(bpm);
    }


    if(i==1) {
        //bpm=cpl_image_get_bpm(ima);
        bpm=cpl_mask_new(sx,sy);
        pbpm=cpl_mask_get_data(bpm);
        xsh_msg("flag image %d",i);
        pix=sy*sx/2+sx/2;

        xsh_flag_bp_at_location(pbpm, pix,CPL_BINARY_1,mode,sx);
        //pix=(sy+2)*sx/2+sx/2;
        //xsh_flag_bp_at_location(pbpm, pix,CPL_BINARY_1);
        cpl_image_set_bpm(*ima,cpl_mask_duplicate(bpm));
        cpl_mask_or(*bpm_tot,bpm);
        cpl_mask_delete(bpm);

    }

    if(i==2) {
        bpm=cpl_mask_new(sx,sy);
        pbpm=cpl_mask_get_data(bpm);
        pix=3*sy*sx/4+sx/4;
        xsh_flag_bp_at_location(pbpm, pix,CPL_BINARY_1,mode,sx);
        cpl_image_set_bpm(*ima,cpl_mask_duplicate(bpm));
        cpl_mask_or(*bpm_tot,bpm);
        cpl_mask_delete(bpm);
    }


    if(i==3) {
        bpm=cpl_mask_new(sx,sy);
        pbpm=cpl_mask_get_data(bpm);
        pix=3*sy*sx/4+3*sx/4;
        xsh_flag_bp_at_location(pbpm, pix,CPL_BINARY_1,mode,sx);
        //pix=3*sy*sx/4+sx/4;
        //xsh_flag_bp_at_location(pbpm, pix,CPL_BINARY_1,mode,sx);
        cpl_image_set_bpm(*ima,cpl_mask_duplicate(bpm));
        cpl_mask_or(*bpm_tot,bpm);
        cpl_mask_delete(bpm);
    }

    if(i==4) {
        bpm=cpl_mask_new(sx,sy);
        pbpm=cpl_mask_get_data(bpm);
        pix=sy*sx/4+3*sx/4;
        xsh_flag_bp_at_location(pbpm, pix,CPL_BINARY_1,mode,sx);
        cpl_image_set_bpm(*ima,cpl_mask_duplicate(bpm));
        cpl_mask_or(*bpm_tot,bpm);
        cpl_mask_delete(bpm);
    }

    return cpl_error_get_code();
}

static cpl_table*
test_xsh_bpm2tab(const cpl_mask* bpm)
{

    const int size=cpl_mask_count(bpm);
    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);
    int* px=cpl_table_get_data_int(xy_pos,"x");
    int* py=cpl_table_get_data_int(xy_pos,"y");
    int sx=cpl_mask_get_size_x(bpm);
    int sy=cpl_mask_get_size_y(bpm);
    cpl_binary* pbpm=cpl_mask_get_data(bpm);
    int j_nx;
    int pix;
    int k=0;
    //xsh_msg("copy bad pixels in table");
    for(int j=0;j<sy;j++){
        j_nx=j*sx;
        for(int i=0;i<sx;i++){
            pix=j_nx+i;
            if ( pbpm[pix] == CPL_BINARY_1 ) {
                //xsh_msg("found bad pixel at [%d,%d]",i,j);
                px[k]=i;
                py[k]=j;
                k++;
            }
        }
    }

    return xy_pos;
}

static cpl_imagelist*
xsh_find_image_scale_factors(const cpl_imagelist* iml_in, cpl_image* ima_in)
{
	cpl_imagelist* scale_factors;
	cpl_imagelist* iml_copy=cpl_imagelist_duplicate(iml_in);
	cpl_image* scale;
	const cpl_image* ima;
	cpl_mask* bpm;
	cpl_mask* bpm_copy;
	int sx;
	int sy;
	double avg;
	double med;
	double rms;
	double* pima;
	double* pscale;
	int nbad;
	double val;
	cpl_binary* pbpm;
	int pix;
	int size = cpl_imagelist_get_size(iml_copy);
	scale_factors=cpl_imagelist_new();
    bpm_copy=cpl_image_unset_bpm(ima_in);
    char fname[80];
	for(int k = 0; k < size; k++) {
		ima=cpl_imagelist_get_const(iml_copy,k);
		sx=cpl_image_get_size_x(ima);
		sy=cpl_image_get_size_y(ima);
		sprintf(fname,"orig_%d.fits",k);
		cpl_image_save(ima,fname,CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);
		cpl_image_divide(ima,ima_in);
		sprintf(fname,"scaled_%d.fits",k);
		cpl_image_save(ima,fname,CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);
		pima=cpl_image_get_data_double(ima);
		val=pima[0];
		bpm=cpl_image_get_bpm(ima);
		pbpm=cpl_mask_get_data(bpm);
		for(int j=0; j < sy; j++)  {
			for(int i=0; i < sx; i++)  {
				pix=i+j*sx;
				if(  (pbpm[pix] == CPL_BINARY_1) ||
						isnan(pima[pix]) || isinf(pima[pix]) )
				{
					pbpm[pix] = CPL_BINARY_1;
				}

			}
		}
		scale=cpl_image_new(1,sy,CPL_TYPE_DOUBLE);
		pscale=cpl_image_get_data_double(scale);
		for(int j=0;j<sy;j++){
			nbad=cpl_mask_count_window(bpm,j+1,1,j+1,sx);
			if( nbad < sx) {
	   			avg=cpl_image_get_mean_window(ima,1,j+1,sx,j+1);
	    	    med=cpl_image_get_median_window(ima,1,j+1,sx,j+1);
	    	    rms=cpl_image_get_stdev_window(ima,1,j+1,sx,j+1);
                /*
	    	    xsh_msg("frame %d slice %d mean=%g median=%g rm==%g",
	    	        					k, j, avg,med,rms);

	    	    xsh_msg("val=%g scaled=%g",val,val/avg);
	    	    */
			}
			pscale[j]=med;
		}
		cpl_imagelist_set(scale_factors,scale,k);

	}
	cpl_image_set_bpm(ima_in,bpm_copy);
	cpl_imagelist_delete(iml_copy);
	return scale_factors;
}

static cpl_error_code
test_combine_ima_gauss(const int mode,const int win_hsz) {


    cpl_image* ima=NULL;
    cpl_image* res=NULL;
    cpl_image* corr;
    cpl_imagelist* flag=NULL;
    cpl_imagelist* all=NULL;
    int sx=100;
    int sy=100;
    double value=1;
    double step=0;
    const int nframes=5;
    cpl_mask* bpm;
    cpl_mask* bpm_tot=NULL;
    //double* pima=NULL;
    cpl_image* scale;
    cpl_image* flagged;
    cpl_image* norm;
    //int pix;
    //cpl_binary* pbpm=CPL_BINARY_0;
    flag=cpl_imagelist_new();
    all=cpl_imagelist_new();
    double A;
    double sigma=3;
    double bkg=10;
    int min=2*sy/5;
    int max=3*sy/5;

    cpl_vector* trace=test_xsh_set_trace(sx,sy,mode);
    test_xsh_set_min_max(sx,sy,mode,&min,&max);
    char name[80];
    //cpl_vector_dump(trace,stdout);
    for(int i=0;i<nframes;i++) {
        //ima=cpl_image_new(sx,sy,CPL_TYPE_DOUBLE);
        xsh_msg("frame value %g",value+i*step);
        A=i*10;
        ima=xsh_define_gauss_profile(sx,sy,A,sigma, bkg, trace,min,max,mode);

        cpl_image_add_scalar(ima,value+i*step);
        cpl_imagelist_set(all,cpl_image_duplicate(ima),i);


        //pima=cpl_image_get_data_double(ima);

        /* on one image we set some pixels as bad to simulate the change of
           * intensity in the image resulting from image combination
           */

        test_xsh_fill_bpm(sx, sy, mode, i, &ima, &bpm_tot);
        bpm=cpl_image_get_bpm(ima);
        sprintf(name,"bpm_%d.fits",i);
        cpl_mask_save(bpm,name,NULL,CPL_IO_DEFAULT);
        //cpl_image_set_bpm(ima,bpm);
        cpl_imagelist_set(flag,cpl_image_duplicate(ima),i);
        cpl_image_delete(ima);
    }

    cpl_table* tab_bp=test_xsh_bpm2tab(bpm_tot);
    cpl_table_save(tab_bp,NULL,NULL,"tab_bp.fits",CPL_IO_DEFAULT);
    cpl_vector_delete(trace);
    cpl_imagelist_save(flag,"flag.fits",CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);

    flagged = xsh_imagelist_collapse_create(flag);

    for(int i=0;i < nframes;i++) {
         ima=cpl_imagelist_get(flag,i);
         bpm=cpl_image_get_bpm(ima);
         //sprintf(name,"bpm_%d.fits",i);
         //cpl_mask_save(bpm,name,NULL,CPL_IO_DEFAULT);
    }
    sprintf(name,"bpm_tot.fits");
    cpl_mask_save(bpm_tot,name,NULL,CPL_IO_DEFAULT);
    //flagged = cpl_imagelist_collapse_create(flag);
    //scale = xsh_compute_scale(flag,bpm_tot,mode,win_hsz);
    scale = xsh_compute_scale_tab(flag,bpm_tot,tab_bp,mode,win_hsz);
    for(int i=0;i < nframes;i++) {
         ima=cpl_imagelist_get(flag,i);
         bpm=cpl_image_get_bpm(ima);
         //sprintf(name,"bpm3_%d.fits",i);
         //cpl_mask_save(bpm,name,NULL,CPL_IO_DEFAULT);
    }


    cpl_image_save(scale,"scale.fits",CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);
    bpm=cpl_image_get_bpm(flagged);
    cpl_mask_save(bpm,"bpm.fits",NULL, CPL_IO_DEFAULT);

    norm = cpl_imagelist_collapse_create(all);
    res=cpl_image_duplicate(flagged);
    if( scale != NULL ) {
       cpl_image_multiply(res,scale);
    }
    cpl_image_save(res,"res.fits",CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);
    corr=cpl_image_duplicate(flagged);
    cpl_image_multiply(corr,res);
    cpl_image_save(flagged,"flagged.fits",CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);
    cpl_image_save(norm,"norm.fits",CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);

    cpl_mask_delete(bpm_tot);
    cpl_image_delete(res);
    cpl_image_delete(flagged);
    cpl_image_delete(scale);
    cpl_image_delete(norm);
    cpl_image_delete(corr);
    cpl_imagelist_delete(flag);
    cpl_imagelist_delete(all);
    cpl_table_delete(tab_bp);
    return cpl_error_get_code();

}

static cpl_error_code
test_combine_ima_gauss2(const int mode) {

    cpl_image* ima=NULL;
    cpl_imagelist* flag=NULL;
    cpl_imagelist* all=NULL;
    int sx=100;
    int sy=100;
    double value=1;
    double step=0;
    const int nframes=5;
    cpl_mask* bpm;
    cpl_mask* bpm_tot=NULL;
    //double* pima=NULL;

    cpl_image* flagged;
    cpl_image* norm;
    //int pix;
    //cpl_binary* pbpm=CPL_BINARY_0;
    flag=cpl_imagelist_new();
    all=cpl_imagelist_new();
    double A;
    double sigma=3;
    double bkg=0;
    int min=2*sy/5;
    int max=3*sy/5;
    xsh_msg("ok0");
    xsh_print_rec_status(0);
    cpl_vector* trace=test_xsh_set_trace(sx,sy,mode);
    test_xsh_set_min_max(sx,sy,mode,&min,&max);
    char name[80];
    //cpl_vector_dump(trace,stdout);
    xsh_msg("ok1");
    xsh_print_rec_status(1);
    for(int i=0;i<nframes;i++) {
        //ima=cpl_image_new(sx,sy,CPL_TYPE_DOUBLE);
        xsh_msg("frame value %g",value+i*step);
        A=i*10;
        ima=xsh_define_gauss_profile(sx,sy,A,sigma, bkg, trace,min,max,mode);

        cpl_image_add_scalar(ima,value+i*step);
        cpl_imagelist_set(all,cpl_image_duplicate(ima),i);


        //pima=cpl_image_get_data_double(ima);

        /* on one image we set some pixels as bad to simulate the change of
           * intensity in the image resulting from image combination
           */

        test_xsh_fill_bpm(sx, sy, mode, i, &ima, &bpm_tot);
        bpm=cpl_image_get_bpm(ima);
        sprintf(name,"bpm_%d.fits",i);
        cpl_mask_save(bpm,name,NULL,CPL_IO_DEFAULT);
        //cpl_image_set_bpm(ima,bpm);
        cpl_imagelist_set(flag,cpl_image_duplicate(ima),i);
        cpl_image_delete(ima);
    }
    xsh_msg("ok0");
    xsh_print_rec_status(0);
    cpl_imagelist_save(flag,"flag.fits",CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);

    sprintf(name,"bpm_tot.fits");
    cpl_mask_save(bpm_tot,name,NULL,CPL_IO_DEFAULT);
    xsh_msg("ok1");
    xsh_print_rec_status(1);
    cpl_table* tab_bp=test_xsh_bpm2tab(bpm_tot);
    cpl_table_save(tab_bp,NULL,NULL,"tab_bp.fits",CPL_IO_DEFAULT);
    cpl_vector_delete(trace);
    xsh_msg("ok2");
    xsh_print_rec_status(2);
    flagged = xsh_imagelist_collapse_create(flag);
    cpl_image_save(flagged,"flagged1.fits",CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);
    xsh_msg("ok3");
    xsh_print_rec_status(3);
    for(int i=0;i<nframes;i++) {

         ima=cpl_imagelist_get(flag,i);
         bpm=cpl_image_get_bpm(ima);
         sprintf(name,"chk_%d.fits",i);
         cpl_mask_save(bpm,name,NULL,CPL_IO_DEFAULT);

     }
    xsh_msg("ok4");
    xsh_print_rec_status(4);
    cpl_imagelist* sf=xsh_find_image_scale_factors(flag,flagged);
    cpl_imagelist_save(sf,"sf.fits",CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);
    //exit(0);
    xsh_compute_scale_tab2(flag,tab_bp,sf,&flagged);
    cpl_image_save(flagged,"flagged2.fits",CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);
    xsh_msg("ok3");
    xsh_print_rec_status(3);
    bpm=cpl_image_get_bpm(flagged);
    cpl_mask_save(bpm,"bpm.fits",NULL, CPL_IO_DEFAULT);

    norm = cpl_imagelist_collapse_create(all);
    cpl_image_save(flagged,"result.fits",CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);

    cpl_image_save(flagged,"flagged.fits",CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);
    cpl_image_save(norm,"norm.fits",CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);
    xsh_msg("ok4");
    xsh_print_rec_status(4);
    cpl_mask_delete(bpm_tot);
    cpl_image_delete(flagged);
    cpl_image_delete(norm);
    cpl_imagelist_delete(flag);
    cpl_imagelist_delete(all);
    cpl_table_delete(tab_bp);
    return cpl_error_get_code();

}


static cpl_error_code
test_combine_ima_gauss3(const int mode) {

    cpl_image* ima=NULL;
    cpl_imagelist* flag=NULL;
    cpl_imagelist* all=NULL;
    int sx=100;
    int sy=100;
    double value=1.e-6;
    double step=0;
    const int nframes=15;
    cpl_mask* bpm;
    cpl_mask* bpm_tot=NULL;
    //double* pima=NULL;

    cpl_image* flagged;
    cpl_image* norm;
    //int pix;
    //cpl_binary* pbpm=CPL_BINARY_0;
    flag=cpl_imagelist_new();
    all=cpl_imagelist_new();
    double A=10.;
    double sigma=15;
    double bkg=0;
    int min=0*sy/5;
    int max=5*sy/5;
    xsh_msg("ok0");
    xsh_print_rec_status(0);
    cpl_vector* trace=test_xsh_set_trace(sx,sy,mode);
    test_xsh_set_min_max(sx,sy,mode,&min,&max);
    char name[80];
    //cpl_vector_dump(trace,stdout);
    xsh_msg("ok1");
    xsh_print_rec_status(1);
    double factor=1.;
    for(int i=0;i<nframes;i++) {
        //ima=cpl_image_new(sx,sy,CPL_TYPE_DOUBLE);

        factor=0.8+i/10.;
        xsh_msg("frame value %g factor=%g",value+i*step,factor);
        ima=xsh_define_gauss_profile(sx,sy,A,sigma, bkg, trace,min,max,mode);
        cpl_image_multiply_scalar(ima,factor);
        cpl_image_add_scalar(ima,value+i*step);
        cpl_imagelist_set(all,cpl_image_duplicate(ima),i);


        //pima=cpl_image_get_data_double(ima);

        /* on one image we set some pixels as bad to simulate the change of
           * intensity in the image resulting from image combination
           */

        test_xsh_fill_bpm(sx, sy, mode, i, &ima, &bpm_tot);
        bpm=cpl_image_get_bpm(ima);
        sprintf(name,"bpm_%d.fits",i);
        cpl_mask_save(bpm,name,NULL,CPL_IO_DEFAULT);
        //cpl_image_set_bpm(ima,bpm);
        cpl_imagelist_set(flag,cpl_image_duplicate(ima),i);
        cpl_image_delete(ima);
    }
    xsh_msg("ok0");
    xsh_print_rec_status(0);
    cpl_imagelist_save(flag,"flag.fits",CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);

    sprintf(name,"bpm_tot.fits");
    cpl_mask_save(bpm_tot,name,NULL,CPL_IO_DEFAULT);
    xsh_msg("ok1");
    xsh_print_rec_status(1);
    cpl_table* tab_bp=test_xsh_bpm2tab(bpm_tot);
    cpl_table_save(tab_bp,NULL,NULL,"tab_bp.fits",CPL_IO_DEFAULT);
    cpl_vector_delete(trace);
    xsh_msg("ok2");
    xsh_print_rec_status(2);
    flagged = xsh_imagelist_collapse_create(flag);
    cpl_image_save(flagged,"flagged1.fits",CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);
    xsh_msg("ok3");
    xsh_print_rec_status(3);
    for(int i=0;i<nframes;i++) {

         ima=cpl_imagelist_get(flag,i);
         bpm=cpl_image_get_bpm(ima);
         sprintf(name,"chk_%d.fits",i);
         cpl_mask_save(bpm,name,NULL,CPL_IO_DEFAULT);

     }
    xsh_msg("ok4");
    xsh_print_rec_status(4);
    cpl_imagelist* sf=xsh_find_image_scale_factors(flag,flagged);
    cpl_imagelist_save(sf,"sf.fits",CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);
    //exit(0);
    xsh_compute_scale_tab2(flag,tab_bp,sf,&flagged);
    cpl_image_save(flagged,"flagged2.fits",CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);
    xsh_msg("ok3");
    xsh_print_rec_status(3);
    bpm=cpl_image_get_bpm(flagged);
    cpl_mask_save(bpm,"bpm.fits",NULL, CPL_IO_DEFAULT);

    norm = cpl_imagelist_collapse_create(all);
    cpl_image_save(flagged,"result.fits",CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);

    cpl_image_save(flagged,"flagged.fits",CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);
    cpl_image_save(norm,"norm.fits",CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);
    xsh_msg("ok4");
    xsh_print_rec_status(4);
    cpl_mask_delete(bpm_tot);
    cpl_image_delete(flagged);
    cpl_image_delete(norm);
    cpl_imagelist_delete(flag);
    cpl_imagelist_delete(all);
    cpl_table_delete(tab_bp);
    return cpl_error_get_code();

}

 static cpl_error_code
 test_combine_ima_uniform2(const int mode) {

     cpl_image* ima=NULL;
     cpl_imagelist* flag=NULL;
     cpl_imagelist* all=NULL;
     int sx=100;
     int sy=100;
     double value=100;
     double step=2;
     const int nframes=5;
     cpl_mask* bpm;
     cpl_mask* bpm_tot=NULL;
     //double* pima=NULL;

     cpl_image* flagged;
     cpl_image* norm;
     //int pix;
     char name[80];
     //cpl_binary* pbpm=CPL_BINARY_0;
     flag=cpl_imagelist_new();
     all=cpl_imagelist_new();
     for(int i=0;i<nframes;i++) {
         ima=cpl_image_new(sx,sy,CPL_TYPE_DOUBLE);
         xsh_msg("frame value %g",value+i*step);
         cpl_image_add_scalar(ima,value+i*step);
         cpl_imagelist_set(all,cpl_image_duplicate(ima),i);

         //pima=cpl_image_get_data_double(ima);

         /* on one image we set some pixels as bad to simulate the change of
            * intensity in the image resulting from image combination
            */

         test_xsh_fill_bpm(sx, sy, mode, i, &ima, &bpm_tot);
         //cpl_image_set_bpm(ima,bpm);
         bpm=cpl_image_get_bpm(ima);
         sprintf(name,"bpm_%d.fits",i);
          cpl_mask_save(bpm,name,NULL,CPL_IO_DEFAULT);
         cpl_imagelist_set(flag,cpl_image_duplicate(ima),i);
         cpl_image_delete(ima);
     }
     cpl_imagelist_save(flag,"flag.fits",CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);

     sprintf(name,"bpm_tot.fits");
     cpl_mask_save(bpm_tot,name,NULL,CPL_IO_DEFAULT);

     cpl_table* tab_bp=test_xsh_bpm2tab(bpm_tot);
     cpl_table_save(tab_bp,NULL,NULL,"tab_bp.fits",CPL_IO_DEFAULT);

     flagged = xsh_imagelist_collapse_create(flag);
     //cpl_image_save(flagged,"flagged1.fits",CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);

     cpl_imagelist* sf=xsh_find_image_scale_factors(flag,flagged);

     xsh_compute_scale_tab2(flag,tab_bp,sf,&flagged);

     cpl_image_save(flagged,"result.fits",CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);

     bpm=cpl_image_get_bpm(flagged);
     cpl_mask_save(bpm,"bpm_flagged.fits",NULL, CPL_IO_DEFAULT);

     norm = cpl_imagelist_collapse_create(all);
     cpl_image_save(norm,"norm.fits",CPL_TYPE_FLOAT,NULL,CPL_IO_DEFAULT);

     cpl_mask_delete(bpm_tot);
     cpl_image_delete(flagged);
     cpl_image_delete(norm);
     cpl_imagelist_delete(flag);
     cpl_imagelist_delete(all);
     cpl_imagelist_delete(sf);
     cpl_table_delete(tab_bp);

     return cpl_error_get_code();

 }

 static xsh_rec_list*
 test_xsh_create_list_from_image(const char* fname, const char* lname) {

     cpl_frame* frame=cpl_frame_new();
     cpl_frame_set_filename(frame, fname);
     xsh_instrument* instr=xsh_instrument_new();
     xsh_rec_list * rec_list=xsh_rec_list_load_eso(frame, instr);
     cpl_frame* tmp=xsh_rec_list_save2(rec_list, lname, "TEST");

     xsh_instrument_free(&instr);
     xsh_free_frame(&tmp);
     xsh_free_frame(&frame);
     return rec_list;
 }


 static cpl_error_code
 test_create_ima_uniform(const int sx, const int sy, const double bkg,
                       const double RON, const double gain, const char* fname)
 {

     cpl_image* ima=NULL;
     cpl_image* err=NULL;
     cpl_image* qua=NULL;
     const int mode=0;
     int i=0;

     cpl_mask* bpm_tot=NULL;
     cpl_propertylist* plist=NULL;

     ima=cpl_image_new(sx,sy,CPL_TYPE_FLOAT);
     cpl_image_add_scalar(ima,bkg);

     test_xsh_fill_bpm(sx, sy, mode, i, &ima, &bpm_tot);

     plist=cpl_propertylist_new();
     int crpix1=0;
     double crval1=0.;
     double cdelt1=1;
     int crpix2=0;
     double crval2=0.;
     double cdelt2=1;

     xsh_pfits_set_wcs1(plist,crpix1,crval1,cdelt1);
     xsh_pfits_set_wcs2(plist,crpix2,crval2,cdelt2);

     cpl_propertylist_append_string(plist,"EXTNAME","FLUX");
     cpl_propertylist_append_double(plist,XSH_RECTIFY_BIN_SPACE,cdelt1);

     //cpl_propertylist_append_string(plist,XSH_RECTIFY_BIN_SPACE,cdelt1);
     cpl_image_save(ima,fname,CPL_TYPE_FLOAT,plist,CPL_IO_DEFAULT);
     err=cpl_image_duplicate(ima);
     cpl_image_divide_scalar(err,gain);

     double RON2=RON*RON;
     cpl_image_add_scalar(err,RON2);
     qua=cpl_image_new(sx,sy,CPL_TYPE_INT);
     cpl_image_power(err,0.5);
     cpl_image_save(err, fname, CPL_TYPE_FLOAT,plist,CPL_IO_EXTEND);
     cpl_image_save(qua, fname,CPL_TYPE_INT,plist,CPL_IO_EXTEND);

     cpl_mask_delete(bpm_tot);
     cpl_image_delete(ima);
     cpl_image_delete(err);
     cpl_image_delete(qua);
     xsh_free_propertylist(&plist);

     xsh_msg("ok6");

     return cpl_error_get_code();
 }





 static cpl_error_code
 test_create_ima_gauss(const int sx, const int sy, const double bkg,
                       const double RON, const double gain, const double A,
                       const double sigma, const char* fname)
 {

     cpl_image* ima=NULL;
     cpl_image* err=NULL;
     cpl_image* qua=NULL;
     const int mode=0;
     int min=2*sy/5;
     int max=3*sy/5;
     int i=0;

     cpl_mask* bpm_tot=NULL;
     cpl_vector* trace=test_xsh_set_trace(sx,sy,mode);
     test_xsh_set_min_max(sx,sy,mode,&min,&max);
     cpl_propertylist* plist=NULL;

     ima=xsh_define_gauss_profile(sx,sy,A,sigma, bkg, trace,min,max,mode);
     cpl_image_add_scalar(ima,bkg);
     test_xsh_fill_bpm(sx, sy, mode, i, &ima, &bpm_tot);
     plist=cpl_propertylist_new();
     int crpix1=0;
     double crval1=0.;
     double cdelt1=1;

     int crpix2=0;
     double crval2=0.;
     double cdelt2=1;

     xsh_pfits_set_wcs1(plist,crpix1,crval1,cdelt1);
     xsh_pfits_set_wcs2(plist,crpix2,crval2,cdelt2);
     cpl_propertylist_append_string(plist,"EXTNAME","FLUX");
     cpl_propertylist_append_double(plist,XSH_RECTIFY_BIN_SPACE,cdelt1);
     //cpl_propertylist_append_string(plist,XSH_RECTIFY_BIN_SPACE,cdelt1);
     cpl_image_save(ima,fname,CPL_TYPE_FLOAT,plist,CPL_IO_DEFAULT);
     err=cpl_image_duplicate(ima);
     cpl_image_divide_scalar(err,gain);
     double RON2=RON*RON;
     cpl_image_add_scalar(err,RON2);
     qua=cpl_image_new(sx,sy,CPL_TYPE_INT);
     cpl_image_power(err,0.5);
     cpl_image_save(err, fname, CPL_TYPE_FLOAT,plist,CPL_IO_EXTEND);
     cpl_image_save(qua, fname,CPL_TYPE_INT,plist,CPL_IO_EXTEND);

     cpl_mask_delete(bpm_tot);
     cpl_vector_delete(trace);
     cpl_image_delete(ima);
     cpl_image_delete(err);
     cpl_image_delete(qua);
     xsh_free_propertylist(&plist);

     xsh_msg("ok6");
     xsh_print_rec_status(6);
     return cpl_error_get_code();
 }


 static cpl_error_code
  test_combine_lists(void)
  {

     const int sx=1000;
     const int sy=100;
     const double bkg=10;
     const double RON=3;
     const double gain=1;
     double A1=10;
     double sigma1=2;
     double A2=100;
     double sigma2=3;
     xsh_print_rec_status(0);
     xsh_msg("ok0");

     test_create_ima_gauss(sx, sy, bkg, RON, gain, A1, sigma1, "data1.fits");
     xsh_rec_list* l1=test_xsh_create_list_from_image("data1.fits","list1.fits");

     test_create_ima_gauss(sx, sy, bkg, RON, gain, A2, sigma2, "data2.fits");
     xsh_rec_list* l2=test_xsh_create_list_from_image("data2.fits","list2.fits");

     test_create_ima_uniform(sx, sy, bkg, RON, gain, "result.fits");
     xsh_rec_list* lr=test_xsh_create_list_from_image("result.fits","result.fits");

     const int decode_bp=0;
     int method = COMBINE_MEAN_METHOD;
     int no=0;
     int nb_frames=2;
     int *slit_index = NULL;
     float* nod_slit = NULL;
     float slit_min=999, slit_max=-999;
     float nod_slit_min, nod_slit_max;

     int nslit = xsh_rec_list_get_nslit( l1, 0);

     nod_slit = xsh_rec_list_get_slit( l1, 0);




     xsh_rec_list **rec_input_list = NULL ;
     XSH_CALLOC( rec_input_list, xsh_rec_list *, nb_frames);
     rec_input_list[0] = l1;
     rec_input_list[1] = l2;
     nod_slit_min = nod_slit[0];
     nod_slit_max = nod_slit[nslit-1];
     xsh_msg("nslit=%d nod_slit_min=%g nod_slit_max=%g",
             nslit,nod_slit_min, nod_slit_max);

     /* Search for limits in slit */
     for ( int 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;
       }
     }

     cpl_propertylist* header = xsh_rec_list_get_header( l1);
     double slit_step = xsh_pfits_get_rectify_bin_space( header);
     xsh_msg("slit_min=%g slit_max=%g slit_step=%g",slit_min, slit_max,slit_step);

     XSH_CALLOC( slit_index, int, nb_frames);
     xsh_compute_slit_index( slit_min,  slit_step, rec_input_list, slit_index, nb_frames);

     xsh_msg("ok3 nb_frames=%d",nb_frames);
     /*
     xsh_rec_list *result_list = NULL ;
     int nb_orders=1;
     xsh_instrument* instrument=xsh_instrument_new();
     xsh_instrument_set_arm(instrument,XSH_ARM_NIR);
     xsh_print_rec_status(1);
     result_list =  xsh_rec_list_create_with_size( nb_orders, instrument);
     */
     xsh_print_rec_status(2);
     xsh_msg("sk2");
     xsh_rec_list_add(lr,rec_input_list, slit_index,nb_frames, no, method, decode_bp);
     xsh_rec_list_save2(lr,"lr.fits", "TEST");
     xsh_print_rec_status(3);
     xsh_msg("sk3");
     exit(0);
     xsh_print_rec_status(4);
     xsh_msg("ok4 nb_frames=%d",nb_frames);

     cleanup:
     xsh_rec_list_free(&l1);
     xsh_rec_list_free(&l2);
     xsh_rec_list_free(&lr);
     if ( rec_input_list != NULL){
       for ( int i = 0 ; i < nb_frames ; i++ ) {
         xsh_rec_list_free(  &rec_input_list[i]);
       }
     }
     XSH_FREE( slit_index);
     XSH_FREE( rec_input_list);
     return cpl_error_get_code();
  }
 static cpl_error_code
 test_combine_rec_list(const int mode,const int win_hsz) {
     // create two images with known profile
     test_combine_lists();
     // load that images as rec lists
     // combine rec lists
     // save results to check

     return cpl_error_get_code();
 }
/*--------------------------------------------------------------------------*/
/**
  @brief
    Some test about performances
  @return
 */
/*--------------------------------------------------------------------------*/
int main(int argc, char **argv)
{

    cpl_test_init(PACKAGE_BUGREPORT,CPL_MSG_INFO);
    const int mode=1;
    const int win_hsz=2;
    //test_combine_ima_gauss(mode,win_hsz);
    test_combine_ima_gauss3(mode);
    //test_combine_ima_uniform(mode,win_hsz);
    //test_combine_ima_uniform2(mode);

    //test_combine_rec_list(mode,win_hsz);
    //test_mem();
    cpl_test_error(CPL_ERROR_NONE);
    return cpl_test_end(0);
}


/**@}*/
