/*                                                                            *
 *   This file is part of the ESO X-shooter Pipeline                          *
 *   Copyright (C) 2006 European Southern Observatory                         *
 *                                                                            *
 *   This library is free software; you can redistribute it and/or modify     *
 *   it under the terms of the GNU General Public License as published by     *
 *   the Free Software Foundation; either version 2 of the License, or        *
 *   (at your option) any later version.                                      *
 *                                                                            *
 *   This program is distributed in the hope that it will be useful,          *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of           *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
 *   GNU General Public License for more details.                             *
 *                                                                            *
 *   You should have received a copy of the GNU General Public License        *
 *   along with this program; if not, write to the Free Software              *
 *   Foundation, 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA     *
 *                                                                            */

/*
 * $Author: amodigli $
 * $Date: 2012-12-18 14:15:44 $
 * $Revision: 1.33 $
 */

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

/*----------------------------------------------------------------------------*/
/**
 * @defgroup xsh_flat_merge Some flat utilities operations
 * @ingroup drl_functions
 *
 * Function ...
 */
/*----------------------------------------------------------------------------*/
/**@{*/

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

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

#include <xsh_badpixelmap.h>
#include <xsh_data_pre.h>
#include <xsh_dfs.h>
#include <xsh_pfits.h>
#include <xsh_error.h>
#include <xsh_msg.h>
#include <xsh_data_instrument.h>
#include <xsh_data_spectralformat.h>
#include <xsh_utils_image.h>
#include <cpl.h>

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

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


static cpl_error_code
xsh_add_qc_tab(cpl_frame* d2_frame, cpl_frame* qth_frame,
    cpl_frame* merged_frame) {

  cpl_table* qc_d2_tab = NULL;
  cpl_table* qc_qth_tab = NULL;
  cpl_table* qc_tot_tab=NULL;
  cpl_propertylist* qc_qth_head = NULL;

  int nrow_d2=0;
  int nrow_qth=0;
  int nrow_tot=0;
  int i=0;
  int k=0;
  int* pord=NULL;
  int* pabs_ord=NULL;

  double* pcenterx=NULL;
  double* pcentery=NULL;
  double* pedgelox=NULL;
  double* pedgeupx=NULL;
  double* pedgelofx=NULL;
  double* pedgeupfx=NULL;
  double* pedgelo_resx=NULL;
  double* pedgeup_resx=NULL;


  int* pord_org=NULL;
  int* pabs_ord_org=NULL;
  double* pcenterx_org=NULL;
  double* pcentery_org=NULL;
  double* pedgelox_org=NULL;
  double* pedgeupx_org=NULL;
  double* pedgelofx_org=NULL;
  double* pedgeupfx_org=NULL;
  double* pedgelo_resx_org=NULL;
  double* pedgeup_resx_org=NULL;

  qc_d2_tab = cpl_table_load(cpl_frame_get_filename(d2_frame), 3,0);
  qc_qth_tab = cpl_table_load(cpl_frame_get_filename(qth_frame), 3,0);
  qc_qth_head = cpl_propertylist_load(cpl_frame_get_filename(qth_frame), 3);

  nrow_d2=cpl_table_get_nrow(qc_d2_tab);
  nrow_qth=cpl_table_get_nrow(qc_qth_tab);

  nrow_tot=nrow_d2+nrow_qth;
  qc_tot_tab=cpl_table_new(nrow_tot);


  cpl_table_copy_structure(qc_tot_tab,qc_qth_tab);
  cpl_table_fill_column_window_int(qc_tot_tab,"ORDER",0,nrow_tot,0);
  cpl_table_fill_column_window_int(qc_tot_tab,"ABSORDER",0,nrow_tot,0);
  cpl_table_fill_column_window_double(qc_tot_tab,"CENTERX",0,nrow_tot,0);
  cpl_table_fill_column_window_double(qc_tot_tab,"CENTERY",0,nrow_tot,0);
  cpl_table_fill_column_window_double(qc_tot_tab,"EDGELOX",0,nrow_tot,0);
  cpl_table_fill_column_window_double(qc_tot_tab,"EDGEUPX",0,nrow_tot,0);
  cpl_table_fill_column_window_double(qc_tot_tab,"EDGELOFX",0,nrow_tot,0);
  cpl_table_fill_column_window_double(qc_tot_tab,"EDGEUPFX",0,nrow_tot,0);
  cpl_table_fill_column_window_double(qc_tot_tab,"EDGELO_RESX",0,nrow_tot,0);
  cpl_table_fill_column_window_double(qc_tot_tab,"EDGEUP_RESX",0,nrow_tot,0);


  pord=cpl_table_get_data_int(qc_tot_tab,"ORDER");
  pabs_ord=cpl_table_get_data_int(qc_tot_tab,"ABSORDER");
  pcenterx=cpl_table_get_data_double(qc_tot_tab,"CENTERX");
  pcentery=cpl_table_get_data_double(qc_tot_tab,"CENTERY");
  pedgelox=cpl_table_get_data_double(qc_tot_tab,"EDGELOX");
  pedgeupx=cpl_table_get_data_double(qc_tot_tab,"EDGEUPX");
  pedgelofx=cpl_table_get_data_double(qc_tot_tab,"EDGELOFX");
  pedgeupfx=cpl_table_get_data_double(qc_tot_tab,"EDGEUPFX");
  pedgelo_resx=cpl_table_get_data_double(qc_tot_tab,"EDGELO_RESX");
  pedgeup_resx=cpl_table_get_data_double(qc_tot_tab,"EDGEUP_RESX");

  pord_org=cpl_table_get_data_int(qc_qth_tab,"ORDER");
  pabs_ord_org=cpl_table_get_data_int(qc_qth_tab,"ABSORDER");
  pcenterx_org=cpl_table_get_data_double(qc_qth_tab,"CENTERX");
  pcentery_org=cpl_table_get_data_double(qc_qth_tab,"CENTERY");
  pedgelox_org=cpl_table_get_data_double(qc_qth_tab,"EDGELOX");
  pedgeupx_org=cpl_table_get_data_double(qc_qth_tab,"EDGEUPX");
  pedgelofx_org=cpl_table_get_data_double(qc_qth_tab,"EDGELOFX");
  pedgeupfx_org=cpl_table_get_data_double(qc_qth_tab,"EDGEUPFX");
  pedgelo_resx_org=cpl_table_get_data_double(qc_qth_tab,"EDGELO_RESX");
  pedgeup_resx_org=cpl_table_get_data_double(qc_qth_tab,"EDGEUP_RESX");


  for (i = 0; i < nrow_qth; i++) {

    pord[i] = pord_org[i];
    pabs_ord[i] = pabs_ord_org[i];
    pcenterx[i] = pcenterx_org[i];
    pcentery[i] = pcentery_org[i];
    pedgelox[i] = pedgelox_org[i];
    pedgeupx[i] = pedgeupx_org[i];
    pedgelofx[i] = pedgelofx_org[i];
    pedgeupfx[i] = pedgeupfx_org[i];
    pedgelo_resx[i] = pedgelo_resx_org[i];
    pedgeup_resx[i] = pedgeup_resx_org[i];

  }


  pord_org = cpl_table_get_data_int(qc_d2_tab, "ORDER");
  pabs_ord_org = cpl_table_get_data_int(qc_d2_tab, "ABSORDER");
  pcenterx_org = cpl_table_get_data_double(qc_d2_tab, "CENTERX");
  pcentery_org = cpl_table_get_data_double(qc_d2_tab, "CENTERY");
  pedgelox_org = cpl_table_get_data_double(qc_d2_tab, "EDGELOX");
  pedgeupx_org = cpl_table_get_data_double(qc_d2_tab, "EDGEUPX");
  pedgelofx_org = cpl_table_get_data_double(qc_d2_tab, "EDGELOFX");
  pedgeupfx_org = cpl_table_get_data_double(qc_d2_tab, "EDGEUPFX");
  pedgelo_resx_org = cpl_table_get_data_double(qc_d2_tab, "EDGELO_RESX");
  pedgeup_resx_org = cpl_table_get_data_double(qc_d2_tab, "EDGEUP_RESX");

  for (i = 0; i < nrow_d2; i++) {
    k=i+nrow_qth;
    pord[k] = pord_org[i];
    pabs_ord[k] = pabs_ord_org[i];
    pcenterx[k] = pcenterx_org[i];
    pcentery[k] = pcentery_org[i];
    pedgelox[k] = pedgelox_org[i];
    pedgeupx[k] = pedgeupx_org[i];
    pedgelofx[k] = pedgelofx_org[i];
    pedgeupfx[k] = pedgeupfx_org[i];
    pedgelo_resx[k] = pedgelo_resx_org[i];
    pedgeup_resx[k] = pedgeup_resx_org[i];
  }

  cpl_table_save(qc_tot_tab, qc_qth_head, NULL, cpl_frame_get_filename(merged_frame), CPL_IO_EXTEND);

  /* cleanup */
  xsh_free_table(&qc_qth_tab);
  xsh_free_table(&qc_d2_tab);
  xsh_free_table(&qc_tot_tab);
  xsh_free_propertylist(&qc_qth_head);
  return cpl_error_get_code();
}
/*---------------------------------------------------------------------------*/
/** 
  @brief Merge two master flat fields and order tables according the spectral 
    format
  @param[in] qth_frame  QTH master flat
  @param[in] qth_order_tab_frame QTH order edges tab
  @param[in] d2_frame  D2 master flat
  @param[in] d2_order_tab_frame D2 order edges tab
  @param[in] qth_bkg_frame QTH inter-order background frame
  @param[in] d2_bkg_frame  D2 inter-order background frame
  @param[out] qth_d2_flat_frame Merged flat frame
  @param[out] qth_d2_bkg_frame  merged inter-order subtracted background
  @param[out] qth_d2_order_tab_frame merged inter-order table
  @param[in] instrument instrument arm and lamp settings

*/
/*---------------------------------------------------------------------------*/
void 
xsh_flat_merge_qth_d2( cpl_frame *qth_frame, cpl_frame *qth_order_tab_frame,  
                       cpl_frame *d2_frame,cpl_frame *d2_order_tab_frame,
                       cpl_frame *qth_bkg_frame, cpl_frame *d2_bkg_frame,
		       cpl_frame **qth_d2_flat_frame,
		       cpl_frame **qth_d2_bkg_frame,
		       cpl_frame **qth_d2_order_tab_frame,
		       xsh_instrument *instrument)

{
  xsh_pre *qth_pre = NULL;
  xsh_pre *d2_pre = NULL;
  
  float *qth_data = NULL;
  float *d2_data = NULL;
  float *qth_errs = NULL;
  float *d2_errs = NULL;
  int *qth_qual = NULL;
  int *d2_qual = NULL;

  float *d2_bkg_data = NULL;

  float *qth_bkg_data = NULL;

  xsh_order_list *qth_list = NULL;
  xsh_order_list *d2_list = NULL;
  xsh_order_list *qth_d2_list = NULL;
  int y;
  cpl_polynomial *d2_limit = NULL;
  cpl_polynomial *qth_limit = NULL;
  cpl_image* d2_bkg_ima=NULL;
  cpl_image* qth_bkg_ima=NULL;

  const char* tag=NULL;
  const char* fname=NULL;
  char* name=NULL;
  char file_name[256];
  char file_tag[25];

  double qth_flux_min=0;
  double qth_flux_max=0;
  double d2_flux_min=0;
  double d2_flux_max=0;
  double flux_min=0;
  double flux_max=0;

 
  XSH_ASSURE_NOT_NULL( qth_frame);
  XSH_ASSURE_NOT_NULL( qth_order_tab_frame);
  XSH_ASSURE_NOT_NULL( d2_frame);
  XSH_ASSURE_NOT_NULL( d2_order_tab_frame);
  XSH_ASSURE_NOT_NULL( qth_d2_flat_frame);
  XSH_ASSURE_NOT_NULL( qth_bkg_frame);
  XSH_ASSURE_NOT_NULL( d2_bkg_frame);
  XSH_ASSURE_NOT_NULL( qth_d2_bkg_frame);
  XSH_ASSURE_NOT_NULL( qth_d2_order_tab_frame);
  XSH_ASSURE_NOT_NULL( instrument);

  xsh_msg_dbg_medium( "Entering xsh_flat_merge_qth_d2") ;

  /* load data */
  check( qth_pre = xsh_pre_load( qth_frame, instrument));
  check( d2_pre = xsh_pre_load( d2_frame, instrument));
  

  check( xsh_instrument_update_lamp( instrument, XSH_LAMP_QTH)); 
  check( qth_list = xsh_order_list_load( qth_order_tab_frame, instrument));
  xsh_order_list_set_bin_x( qth_list, qth_pre->binx);
  xsh_order_list_set_bin_y( qth_list, qth_pre->biny);
  check( xsh_instrument_update_lamp( instrument, XSH_LAMP_D2));
  check( d2_list = xsh_order_list_load( d2_order_tab_frame, instrument));
  xsh_order_list_set_bin_x( d2_list, d2_pre->binx);
  xsh_order_list_set_bin_y( d2_list, d2_pre->biny);

  check( qth_data = cpl_image_get_data_float( qth_pre->data));
  check( d2_data = cpl_image_get_data_float(d2_pre->data)); 
 
  fname=cpl_frame_get_filename(qth_bkg_frame);
  qth_bkg_ima=cpl_image_load(fname,CPL_TYPE_FLOAT,0,0);
  check( qth_bkg_data = cpl_image_get_data_float(qth_bkg_ima));

  fname=cpl_frame_get_filename(d2_bkg_frame);
  d2_bkg_ima=cpl_image_load(fname,CPL_TYPE_FLOAT,0,0);
  check( d2_bkg_data = cpl_image_get_data_float(d2_bkg_ima));


  check( qth_errs = cpl_image_get_data_float( qth_pre->errs));
  check( d2_errs = cpl_image_get_data_float(d2_pre->errs));
  
  check( qth_qual = cpl_image_get_data_int( qth_pre->qual));
  check( d2_qual = cpl_image_get_data_int(d2_pre->qual));
  


  /* find limit and merge flat */
  qth_limit = qth_list->list[qth_list->size-1].edglopoly;
  d2_limit = d2_list->list[0].edguppoly;
  int xd2=0, xqth=0;
  int x_avg=0;
  int x;
  int offset=0;
  int pixel=0;
  for( y=0; y < d2_pre->ny; y++){

    check( xd2 = xsh_order_list_eval_int( d2_list, d2_limit, y+1)-1);
    check( xqth = xsh_order_list_eval_int( qth_list, qth_limit, y+1)-1);
    x_avg = floor( 0.5*(xd2+xqth));
    xsh_msg_dbg_medium("D2  x %d y %d", xd2, y);
    xsh_msg_dbg_medium("QTH x %d y %d", xqth, y);
    xsh_msg_dbg_medium(" x_avg = %d", x_avg);
    /* merge images */
    offset=y*d2_pre->nx;

    for( x=x_avg; x< d2_pre->nx; x++){
      pixel=x+offset;
      d2_data[pixel] = qth_data[pixel];
      d2_errs[pixel] = qth_errs[pixel];
      d2_qual[pixel] = qth_qual[pixel];

      d2_bkg_data[pixel] = qth_bkg_data[pixel];
  

    }
  }

  /* construct the new order list */
  check( qth_d2_list = xsh_order_list_merge( qth_list, d2_list));

  check( xsh_instrument_update_lamp( instrument, XSH_LAMP_UNDEFINED));

  tag=XSH_GET_TAG_FROM_LAMP( XSH_MASTER_FLAT,instrument);
  XSH_NAME_LAMP_MODE_ARM( name, "MASTER_FLAT", ".fits", instrument);


  /* adjust QC FLUX MIN/MAX for master frame */
  check(qth_flux_min=cpl_propertylist_get_double(qth_pre->data_header,
                                                 XSH_QC_FLUX_MIN));
  check(qth_flux_max=cpl_propertylist_get_double(qth_pre->data_header,
                                                 XSH_QC_FLUX_MAX));
  check(d2_flux_min=cpl_propertylist_get_double(d2_pre->data_header,
                                                XSH_QC_FLUX_MIN));
  check(d2_flux_max=cpl_propertylist_get_double(d2_pre->data_header,
                                                XSH_QC_FLUX_MAX));

  flux_min=(qth_flux_min<d2_flux_min)? qth_flux_min:d2_flux_min;
  flux_max=(qth_flux_max>d2_flux_max)? qth_flux_max:d2_flux_max;

  check(cpl_propertylist_set_double(d2_pre->data_header,XSH_QC_FLUX_MIN,
                                    flux_min));
  check(cpl_propertylist_set_double(d2_pre->data_header,XSH_QC_FLUX_MAX,
                                    flux_max));



  check( *qth_d2_flat_frame = xsh_pre_save( d2_pre, name, tag,0));
  check( cpl_frame_set_tag( *qth_d2_flat_frame, tag));
  XSH_REGDEBUG("save %s %s", fname, tag);

  sprintf(file_tag,"MFLAT_BACK_%s_%s",
          xsh_instrument_mode_tostring(instrument),
          xsh_instrument_arm_tostring(instrument));

  sprintf(file_name,"%s.fits",file_tag);

  check(xsh_pfits_set_pcatg(d2_pre->data_header,file_tag));

  check(cpl_image_save(d2_bkg_ima,file_name,CPL_BPP_IEEE_FLOAT,
		       d2_pre->data_header,CPL_IO_DEFAULT));


  check(*qth_d2_bkg_frame=xsh_frame_product(file_name,file_tag, 
					    CPL_FRAME_TYPE_IMAGE,
					    CPL_FRAME_GROUP_CALIB,
					    CPL_FRAME_LEVEL_FINAL));


  tag= XSH_GET_TAG_FROM_LAMP( XSH_ORDER_TAB_EDGES, instrument);
  XSH_NAME_LAMP_MODE_ARM( name, "ORDER_TAB_EDGES", ".fits", instrument); 

  check( *qth_d2_order_tab_frame = xsh_order_list_save( qth_d2_list,instrument,
							name, tag,
							qth_pre->ny*d2_list->bin_y));

  check(xsh_add_qc_tab(d2_order_tab_frame,qth_order_tab_frame,*qth_d2_order_tab_frame));

  XSH_REGDEBUG("save %s %s",name, tag);
 

  cleanup:
    XSH_FREE( name);
    xsh_free_image(&d2_bkg_ima);
    xsh_free_image(&qth_bkg_ima);
 
    xsh_pre_free( &qth_pre);
    xsh_pre_free( &d2_pre);
    xsh_order_list_free( &qth_list);
    xsh_order_list_free( &d2_list);
    xsh_order_list_free( &qth_d2_list);
    return;

}

/*---------------------------------------------------------------------------*/
/**
  @brief Merge two order edges tables according the spectral format
  @param[in] qth_order_tab_frame QTH order edges tab
  @param[in] d2_order_tab_frame D2 order edges tab
  @param[in] instrument instrument arm and lamp settings
  @return merged order edges table
*/
/*---------------------------------------------------------------------------*/

cpl_frame*
xsh_flat_merge_qth_d2_tabs(cpl_frame *qth_edges_tab,cpl_frame *d2_edges_tab,xsh_instrument *instrument)

{
  cpl_frame* full_edges_tab=NULL;

  xsh_order_list *qth_list = NULL;
  xsh_order_list *d2_list = NULL;
  xsh_order_list *qth_d2_list = NULL;
  char* name=NULL;
  const char* tag=NULL;

  xsh_msg("binx=%d biny=%d",instrument->binx,instrument->biny);
  xsh_instrument_update_lamp( instrument, XSH_LAMP_QTH);
  qth_list = xsh_order_list_load( qth_edges_tab, instrument);
  xsh_order_list_set_bin_x( qth_list, instrument->binx);
  xsh_order_list_set_bin_y( qth_list, instrument->biny);
  xsh_instrument_update_lamp( instrument, XSH_LAMP_D2);
  d2_list = xsh_order_list_load( d2_edges_tab, instrument);
  xsh_order_list_set_bin_x( d2_list, instrument->binx);
  xsh_order_list_set_bin_y( d2_list, instrument->biny);
  qth_d2_list = xsh_order_list_merge( qth_list, d2_list);

  xsh_instrument_update_lamp( instrument, XSH_LAMP_UNDEFINED);
  tag= XSH_GET_TAG_FROM_LAMP( XSH_ORDER_TAB_EDGES, instrument);
  XSH_NAME_LAMP_MODE_ARM( name, "ORDER_TAB_EDGES", ".fits", instrument);
  full_edges_tab = xsh_order_list_save( qth_d2_list,instrument,
              name, tag,instrument->config->ny*instrument->biny);

   cleanup:

   XSH_FREE( name);
   xsh_order_list_free( &qth_list);
   xsh_order_list_free( &d2_list);
   xsh_order_list_free( &qth_d2_list);

  return full_edges_tab;
}




/*---------------------------------------------------------------------------*/
/**
  @brief Merge two master flat fields and order tables according the spectral
    format
  @param[in] qth_frame  QTH master flat
  @param[in] qth_order_tab_frame QTH order edges tab
  @param[in] d2_frame  D2 master flat
  @param[in] d2_order_tab_frame D2 order edges tab
  @param[in] qth_bkg_frame QTH inter-order background frame
  @param[in] d2_bkg_frame  D2 inter-order background frame
  @param[out] qth_d2_flat_frame Merged flat frame
  @param[out] qth_d2_bkg_frame  merged inter-order subtracted background
  @param[out] qth_d2_order_tab_frame merged inter-order table
  @param[in] instrument instrument arm and lamp settings

*/
/*---------------------------------------------------------------------------*/

void
xsh_flat_merge_qth_d2_smooth( cpl_frame *qth_frame, cpl_frame *qth_order_tab_frame,
                       cpl_frame *d2_frame,cpl_frame *d2_order_tab_frame,
                       cpl_frame *qth_bkg_frame, cpl_frame *d2_bkg_frame,
           cpl_frame **qth_d2_flat_frame,
           cpl_frame **qth_d2_bkg_frame,
           cpl_frame **qth_d2_order_tab_frame,
           xsh_instrument *instrument)

{
  xsh_pre *qth_pre = NULL;
  xsh_pre *d2_pre = NULL;

  //float *qth_data = NULL;
  //float *d2_data = NULL;
  float *qth_errs = NULL;
  float *d2_errs = NULL;
  int *qth_qual = NULL;
  int *d2_qual = NULL;

  float *d2_bkg_data = NULL;

  float *qth_bkg_data = NULL;


  xsh_order_list *qth_list = NULL;
  xsh_order_list *d2_list = NULL;
  xsh_order_list *qth_d2_list = NULL;
  int y;
  cpl_polynomial *d2_limit = NULL;
  cpl_polynomial *qth_limit = NULL;
  cpl_image* d2_bkg_ima=NULL;
  cpl_image* qth_bkg_ima=NULL;

  const char* tag=NULL;
  const char* fname=NULL;
  char* name=NULL;
  char file_name[256];
  char file_tag[25];

  double qth_flux_min=0;
  double qth_flux_max=0;
  double d2_flux_min=0;
  double d2_flux_max=0;
  double flux_min=0;
  double flux_max=0;

  cpl_image* merged=NULL;
  XSH_ASSURE_NOT_NULL( qth_frame);
  XSH_ASSURE_NOT_NULL( qth_order_tab_frame);
  XSH_ASSURE_NOT_NULL( d2_frame);
  XSH_ASSURE_NOT_NULL( d2_order_tab_frame);
  XSH_ASSURE_NOT_NULL( qth_d2_flat_frame);
  XSH_ASSURE_NOT_NULL( qth_bkg_frame);
  XSH_ASSURE_NOT_NULL( d2_bkg_frame);
  XSH_ASSURE_NOT_NULL( qth_d2_bkg_frame);
  XSH_ASSURE_NOT_NULL( qth_d2_order_tab_frame);
  XSH_ASSURE_NOT_NULL( instrument);

  xsh_msg_dbg_medium( "Entering xsh_flat_merge_qth_d2") ;

  /* load data */
  check( qth_pre = xsh_pre_load( qth_frame, instrument));
  check( d2_pre = xsh_pre_load( d2_frame, instrument));


  check( xsh_instrument_update_lamp( instrument, XSH_LAMP_QTH));
  check( qth_list = xsh_order_list_load( qth_order_tab_frame, instrument));
  xsh_order_list_set_bin_x( qth_list, qth_pre->binx);
  xsh_order_list_set_bin_y( qth_list, qth_pre->biny);
  check( xsh_instrument_update_lamp( instrument, XSH_LAMP_D2));
  check( d2_list = xsh_order_list_load( d2_order_tab_frame, instrument));
  xsh_order_list_set_bin_x( d2_list, d2_pre->binx);
  xsh_order_list_set_bin_y( d2_list, d2_pre->biny);

  //check( qth_data = cpl_image_get_data_float( qth_pre->data));
  //check( d2_data = cpl_image_get_data_float(d2_pre->data));

  fname=cpl_frame_get_filename(qth_bkg_frame);
  qth_bkg_ima=cpl_image_load(fname,CPL_TYPE_FLOAT,0,0);
  check( qth_bkg_data = cpl_image_get_data_float(qth_bkg_ima));

  fname=cpl_frame_get_filename(d2_bkg_frame);
  d2_bkg_ima=cpl_image_load(fname,CPL_TYPE_FLOAT,0,0);
  check( d2_bkg_data = cpl_image_get_data_float(d2_bkg_ima));


  check( qth_errs = cpl_image_get_data_float( qth_pre->errs));
  check( d2_errs = cpl_image_get_data_float(d2_pre->errs));

  check( qth_qual = cpl_image_get_data_int( qth_pre->qual));
  check( d2_qual = cpl_image_get_data_int(d2_pre->qual));



  /* find limit and merge flat */
  qth_limit = qth_list->list[qth_list->size-1].edglopoly;
  d2_limit = d2_list->list[0].edguppoly;

  for( y=0; y < d2_pre->ny; y++){
    int xd2=0, xqth=0;
    int x_avg=0;
    int x;

    check( xd2 = xsh_order_list_eval_int( d2_list, d2_limit, y+1)-1);
    check( xqth = xsh_order_list_eval_int( qth_list, qth_limit, y+1)-1);
    x_avg = floor( (xd2+xqth)/2.0);
    xsh_msg_dbg_medium("D2  x %d y %d", xd2, y);
    xsh_msg_dbg_medium("QTH x %d y %d", xqth, y);
    xsh_msg_dbg_medium(" x_avg = %d", x_avg);
    /* merge images */
    for( x=x_avg; x< d2_pre->nx; x++){
      //d2_data[x+y*d2_pre->nx] = qth_data[x+y*d2_pre->nx];
      d2_errs[x+y*d2_pre->nx] = qth_errs[x+y*d2_pre->nx];
      d2_qual[x+y*d2_pre->nx] = qth_qual[x+y*d2_pre->nx];

      d2_bkg_data[x+y*d2_pre->nx] = qth_bkg_data[x+y*d2_pre->nx];


    }
  }

  /* construct the new order list */
  check( qth_d2_list = xsh_order_list_merge( qth_list, d2_list));

  /* now that we have a common list we can smoothly merge the flats, errors, bkg */
  merged=xsh_combine_flats(qth_pre->data,d2_pre->data,qth_list,d2_list,5,5);
  d2_pre->data=cpl_image_duplicate(merged);
  //cpl_image_save(merged,"merged_flat.fits", CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
  d2_pre->data=cpl_image_duplicate(merged);
  xsh_free_image(&merged);
  /*
  merged=xsh_combine_flats(qth_pre->errs,d2_pre->errs,qth_list,d2_list,5,5);
  d2_pre->errs=cpl_image_duplicate(merged);
  cpl_image_save(merged,"merged_errs.fits", CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
  d2_pre->errs=cpl_image_duplicate(merged);
  xsh_free_image(&merged);
  */
  merged=xsh_combine_flats(qth_bkg_ima,d2_bkg_ima,qth_list,d2_list,5,5);
  d2_bkg_ima=cpl_image_duplicate(merged);
  //cpl_image_save(merged,"merged_bkg.fits", CPL_BPP_IEEE_FLOAT,NULL,CPL_IO_DEFAULT);
  d2_bkg_ima=cpl_image_duplicate(merged);
  xsh_free_image(&merged);

  check( xsh_instrument_update_lamp( instrument, XSH_LAMP_UNDEFINED));

  tag=XSH_GET_TAG_FROM_LAMP( XSH_MASTER_FLAT,instrument);
  XSH_NAME_LAMP_MODE_ARM( name, "MASTER_FLAT", ".fits", instrument);


  /* adjust QC FLUX MIN/MAX for master frame */
  check(qth_flux_min=cpl_propertylist_get_double(qth_pre->data_header,
                                                 XSH_QC_FLUX_MIN));
  check(qth_flux_max=cpl_propertylist_get_double(qth_pre->data_header,
                                                 XSH_QC_FLUX_MAX));
  check(d2_flux_min=cpl_propertylist_get_double(d2_pre->data_header,
                                                XSH_QC_FLUX_MIN));
  check(d2_flux_max=cpl_propertylist_get_double(d2_pre->data_header,
                                                XSH_QC_FLUX_MAX));

  flux_min=(qth_flux_min<d2_flux_min)? qth_flux_min:d2_flux_min;
  flux_max=(qth_flux_max>d2_flux_max)? qth_flux_max:d2_flux_max;

  check(cpl_propertylist_set_double(d2_pre->data_header,XSH_QC_FLUX_MIN,
                                    flux_min));
  check(cpl_propertylist_set_double(d2_pre->data_header,XSH_QC_FLUX_MAX,
                                    flux_max));



  check( *qth_d2_flat_frame = xsh_pre_save( d2_pre, name, tag,0));
  check( cpl_frame_set_tag( *qth_d2_flat_frame, tag));
  XSH_REGDEBUG("save %s %s", fname, tag);

  sprintf(file_tag,"MFLAT_BACK_%s_%s",
          xsh_instrument_mode_tostring(instrument),
          xsh_instrument_arm_tostring(instrument));

  sprintf(file_name,"%s.fits",file_tag);

  check(xsh_pfits_set_pcatg(d2_pre->data_header,file_tag));

  check(cpl_image_save(d2_bkg_ima,file_name,CPL_BPP_IEEE_FLOAT,
           d2_pre->data_header,CPL_IO_DEFAULT));


  check(*qth_d2_bkg_frame=xsh_frame_product(file_name,file_tag,
              CPL_FRAME_TYPE_IMAGE,
              CPL_FRAME_GROUP_CALIB,
              CPL_FRAME_LEVEL_FINAL));


  tag= XSH_GET_TAG_FROM_LAMP( XSH_ORDER_TAB_EDGES, instrument);
  XSH_NAME_LAMP_MODE_ARM( name, "ORDER_TAB_EDGES", ".fits", instrument);

  check( *qth_d2_order_tab_frame = xsh_order_list_save( qth_d2_list,instrument,
              name, tag,
              qth_pre->ny*d2_list->bin_y));


  XSH_REGDEBUG("save %s %s",name, tag);


  cleanup:
    XSH_FREE( name);
    xsh_free_image(&d2_bkg_ima);
    xsh_free_image(&qth_bkg_ima);

    xsh_pre_free( &qth_pre);
    xsh_pre_free( &d2_pre);
    xsh_order_list_free( &qth_list);
    xsh_order_list_free( &d2_list);
    xsh_order_list_free( &qth_d2_list);
    return;

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

/**@}*/
