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

   File name    :       sinfo_find_distortions.c
   Author       :    A. Modigliani
   Created on   :    Aug 12, 2004
   Description  :

 ---------------------------------------------------------------------------*/
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif
#include <sinfo_cpl_size.h>

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

#include "sinfo_new_find_distortions.h"
#include "sinfo_pro_save.h"
#include "sinfo_pro_types.h"
#include "sinfo_finddist_ini_by_cpl.h"
#include "sinfo_wave_calibration.h"
#include "sinfo_cube_construct.h"
#include "sinfo_absolute.h"
#include "sinfo_distortion.h"
#include "sinfo_utilities.h"
#include "sinfo_recipes.h"
#include "sinfo_utils_wrappers.h"
#include "sinfo_error.h"
#include "sinfo_globals.h"

/*----------------------------------------------------------------------------
                                Defines
 ---------------------------------------------------------------------------*/
#define SINFO_ARC_SATURATION                 100000
#define SINFO_ARC_MAX_WIDTH                  64


/**@{*/
/**
 * @addtogroup sinfo_rec_mflat Master flat generation
 *
 * TBD
 */


/*----------------------------------------------------------------------------
                             Function Definitions
 ---------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
   Function     :       sinfo_find_distortions()
   In           :
   Out          :
   Job          :

 ---------------------------------------------------------------------------*/
static double
new_compute_shift(double x,
          double y,
          double c00,
          double c10,
          double c01,
          double c11,
          double c20,
          double c02,
          double c21,
          double c12,
          double c30,
          double c03);

int
sinfo_new_find_distortions(const char* plugin_id,
                           cpl_parameterlist* config,
                           cpl_frameset* sof,
			   cpl_frameset* set_fibre_ns)
{

  finddist_config * cfg=NULL ;
  cpl_image * imonind=NULL ;
  cpl_image * impoly=NULL ;
  cpl_image * im=NULL ;
  cpl_image *  map=NULL ;
  cpl_image *  mask=NULL ;

  int*            degx=NULL;
  int*            degy=NULL;
  int* n_found_lines=NULL;
  int* sum_pointer=NULL;
  int** row_clean=NULL;
  int pdensity=0;


  int x_l=SIZEX/4*1;
  int x_u=SIZEX/4*3;
  int y_l=SIZEY/4*1;
  int y_u=SIZEY/4*3;
  int x_c=SIZEX/4*2;
  int y_c=SIZEY/4*2;
  const int pdx=4;
  const int pdy=4;
  int check = 0;
  int i = 0;
  int lx=0;
  int ly=0;


  int sum=0;
  int n_lines=0;
  int fit=0;
  int n=0;
  int j=0;
  cpl_size coef_pow[2];
  int arcs_window_size=0;

  float value=0;
  float newval=0;
  float total_dist=0;
  float shift=0;

  float* distances=NULL;
  float** wavelength_clean=NULL;
  float** slit_pos=NULL;
  float** acoefs=NULL;
  float* wave=NULL;
  float* intens=NULL;
  float* first =NULL;

  double*         coef=NULL;

  double xshift=0.;
  double arcs_thres_factor=0;

  double arcs_min_arclen_factor=0;
  double pcf[pdx][pdy];


  char tbl_name[FILE_NAME_SZ];
  char key_name[FILE_NAME_SZ];

  cpl_table* poly_tbl=NULL;
  cpl_table* tbl_spos=NULL;
  cpl_table* tbl_line_list=NULL;

  FitParams** par=NULL;

  cpl_frameset* stk=NULL;
  cpl_table* qclog_tbl=NULL;

  cpl_polynomial* distor_poly=NULL;
  cpl_apertures       *   arcs=NULL ;
  cpl_parameter* p=NULL;
  int smooth_rad=0;


  check_nomsg(p=cpl_parameterlist_find(config,"sinfoni.product.density"));
  check_nomsg(pdensity=cpl_parameter_get_int(p));

  /*
    parse the file names and parameters to the finddist_config
    data structure cfg
   */
  check_nomsg(stk=cpl_frameset_new());
  cknull(cfg = sinfo_parse_cpl_input_finddist(config,sof,&stk),
     "could not parse CPL input!");

  if(sinfo_is_fits_file (cfg->inFrame) != 1) {
    sinfo_msg_error("Input file %s is not FITS",cfg->inFrame);
    goto cleanup;
  }

  /* load the emission line frame--- */
  check(im = cpl_image_load(cfg->inFrame,CPL_TYPE_FLOAT,0,0),
    "could not load arc image");

  /* load the fake on - fake off frame--- */
  check(imonind = cpl_image_load(cfg->nsFrame,CPL_TYPE_FLOAT,0,0),
    "could not load on-off fake image");

  check(impoly  = cpl_image_load(cfg->nsFrame,CPL_TYPE_FLOAT,0,0),
    "could not load on-off fake image");

  /* load the fake on - fake off frame--- */
  check(mask = cpl_image_load(cfg->mask,CPL_TYPE_FLOAT,0,0),
    "could not load mask image");

  check(cpl_image_multiply (im,mask),
    "Failing to correct arc ima by bp mask");

  check(cpl_image_multiply (imonind,mask),
    "Failing to correct on-off fake ima by bp mask");

  check(cpl_image_multiply(impoly,mask),
    "Failing to correct on-off fake ima by bp mask");

  sinfo_free_image(&mask);

  check_nomsg(lx = cpl_image_get_size_x(im));
  check_nomsg(ly = cpl_image_get_size_y(im));
  /* TO BE CHENGED THE FOLLOWING INPUT */
  /* open the line list and read the number of lines */
  check(tbl_line_list = cpl_table_load(cfg->lineList,1,0),
    "problems loading table %s",cfg->lineList);

  check_nomsg(n_lines = cpl_table_get_nrow(tbl_line_list));
  check_nomsg(wave=cpl_table_get_data_float(tbl_line_list,"wave"));
  check_nomsg(intens = cpl_table_get_data_float(tbl_line_list,"int"));

  /*
       #---------------------------------------------------------------------
       #---------------------------FINDLINES---------------------------------
       #---------------------------------------------------------------------
  */

  sinfo_msg("Find Lines");
  /*
       do the wavelength calibration, that means:
       find the dispersion relation and parameterize its coefficients
  */

  acoefs  = sinfo_new_2Dfloatarray(cfg->nrDispCoefficients, lx);
  /* allocate memory */
  n_found_lines    = sinfo_new_intarray(lx);
  row_clean        = sinfo_new_2Dintarray(lx, n_lines);
  wavelength_clean = sinfo_new_2Dfloatarray(lx, n_lines);
  sum_pointer      = sinfo_new_intarray(1);

  /* find the emission lines in each image column */
  sinfo_new_intarray_set_value(sum_pointer, 0, 0);

  ck0(check = sinfo_new_find_lines(im,
                   wave,
                   intens,
                   n_lines,
                   row_clean,
                   wavelength_clean,
                   cfg->guessBeginWavelength,
                   cfg->guessDispersion1,
                   cfg->guessDispersion2,
                   cfg->mindiff,
                   cfg->halfWidth,
                   n_found_lines,
                   cfg->sigma,
                   sum_pointer ),
      "FindLines failed!");

  sinfo_free_table(&tbl_line_list);

  /*
   #-------------------------------------------------------------------------
   #---------------------------WAVECALIB-------------------------------------
   #-------------------------------------------------------------------------
    */
  sinfo_msg("Do wave calib");
  sum = sinfo_new_intarray_get_value(sum_pointer,0);

  /* #allocate memory for the fit parameters */
  cknull(par = sinfo_new_fit_params( sum ),
     "sinfo_new_fit_params failed!");

  /*
      fit each line, make a polynomial fit and fit the resulting fit
       coefficients across the columns of the slitlet
  */
  cknull(map = sinfo_new_wave_cal(im,
                             par,
                      acoefs,
                      cfg->nslitlets,
                      row_clean,
                      wavelength_clean,
                      n_found_lines,
                      cfg->guessDispersion1,
                      cfg->halfWidth,
                      cfg->minAmplitude,
                      cfg->maxResidual,
                      cfg->fwhm,
                      cfg->nrDispCoefficients,
                      cfg->nrCoefCoefficients,
                      cfg->sigmaFactor,
                      cfg->pixeldist,
                      cfg->pixel_tolerance),
     "sinfo_waveCal failed!");
  /* here mem leak */

  sinfo_msg("Check line positions");
  shift = sinfo_new_check_line_positions (im, acoefs,
                                          cfg->nrDispCoefficients,
                                          cfg->guessDispersion1,par);

  if (FLAG == shift) {
    sinfo_msg_error ( "checkForLinePositions failed!");
    goto cleanup;
  }
  sinfo_free_image(&map);


 /* free memory */
  sinfo_new_destroy_2Dfloatarray ( &wavelength_clean, lx );
  sinfo_new_destroy_2Dintarray (&row_clean, lx);
  sinfo_new_destroy_intarray(&n_found_lines );
  sinfo_new_destroy_intarray(&sum_pointer );
  sinfo_new_destroy_2Dfloatarray ( &acoefs, cfg->nrDispCoefficients );
  /*
  sinfo_new_destroy_array (& wave );
  sinfo_new_destroy_array (& intens );
  */
  /*
  #----------------------------------------------------------------------------
  #-------------------------SLITFITS-------------------------------------------
  #----------------------------------------------------------------------------
  #--fit the slitlet sinfo_edge positions if desired--
  */

  sinfo_msg("Find slit pos");
  /*allocate memory for the slitlet position array */
  slit_pos = sinfo_new_2Dfloatarray(32,2);

  fit = sinfo_new_fit_slits_boltz( im, par, slit_pos, cfg->boxLength,
                      cfg->yBox, cfg->diffTol );


  if (fit < 0) {
    sinfo_msg_error( "sinfo_fitSlitsBoltz failed" );
    goto cleanup;
  }
  sinfo_new_destroy_fit_params(&par);

  check_nomsg(tbl_spos=cpl_table_new(32));
  check_nomsg(cpl_table_new_column(tbl_spos,"pos1", CPL_TYPE_DOUBLE));
  check_nomsg(cpl_table_new_column(tbl_spos,"pos2", CPL_TYPE_DOUBLE));
  check_nomsg(cpl_table_set_column_format(tbl_spos,"pos1", "15.9f"));
  check_nomsg(cpl_table_set_column_format(tbl_spos,"pos2", "15.9f"));

  for (i =0; i< 32; i++) {
      check_nomsg(cpl_table_set_double(tbl_spos,"pos1",i,
                                sinfo_new_array2D_get_value(slit_pos,i,0)));
      check_nomsg(cpl_table_set_double(tbl_spos,"pos2",i,
                                sinfo_new_array2D_get_value(slit_pos,i,1)));

  }

  if(pdensity > 2) {
    strcpy(tbl_name,"out_slitlets_pos_predist.fits");
    ck0(sinfo_pro_save_tbl(tbl_spos,set_fibre_ns,sof,tbl_name,
			   PRO_SLITLETS_POS_PREDIST,NULL,plugin_id,config),
	"cannot save tbl %s", tbl_name);
  }
  sinfo_free_table(&tbl_spos);

  /*
  #---------------------------------------------------------
  # do the north - south - test
  #---------------------------------------------------------
  */
  sinfo_msg("Do north south test");
  /*
  sinfo_msg("cfg->nslits =%d\n", cfg->nslits);
  sinfo_msg("cfg->nshalfWidth =%d\n", cfg->nshalfWidth);
  sinfo_msg("cfg->nsfwhm=%f\n",cfg->nsfwhm );
  sinfo_msg("cfg->minDiff=%f\n", cfg->minDiff);
  sinfo_msg("cfg->estimated_dist=%f\n", cfg->estimated_dist);
  sinfo_msg("cfg->devtol=%f\n", cfg->devtol);
  sinfo_msg("cfg->loPos=%d\n", cfg->loPos);
  sinfo_msg("cfg->hiPos=%d\n",cfg->hiPos);
  */
  cknull(distances = sinfo_north_south_test(imonind,
                      cfg->nslits,
                      cfg->nshalfWidth,
                      cfg->nsfwhm ,
                      cfg->minDiff,
                      cfg->estimated_dist,
                      cfg->devtol,
                      cfg->loPos,
                      cfg->hiPos),
     "north_south_test failed");

  sinfo_free_image(&imonind);

  /*
  #---------------------------------------------------------
  # get firstcol
  #---------------------------------------------------------
  */
  sinfo_msg("get first col");
  first = sinfo_new_floatarray(61);
  total_dist=0;
  n=0;

  for (i=0; i< 31; i++) {
    total_dist=total_dist+sinfo_new_array_get_value(distances,i);

    for (j=0; j< 2; j++) {
      if (j == 0) {
        if (i != 30) {
      newval = sinfo_new_array2D_get_value(slit_pos,i+1,j) - total_dist;
      sinfo_new_array_set_value(first, newval, n);
      n = n+1;
        }
      }
      if (j == 1) {
        newval = sinfo_new_array2D_get_value(slit_pos,i,j) - total_dist;
        sinfo_new_array_set_value(first, newval, n);
        n = n+1;
      }
    }
  }
  value = sinfo_new_f_median(first,61);
  sinfo_msg("Firstcol =%f", value);
  sinfo_new_destroy_array(&first);
  sinfo_new_destroy_array(&distances);
  sinfo_new_destroy_2Dfloatarray ( &slit_pos, 32 );

  /*
  #---------------------------------------------------------
  # Determine distortions
  #---------------------------------------------------------
  */
  sinfo_msg("Determine distortions");
  degx=cpl_calloc(8,sizeof(int));
  degy=cpl_calloc(8,sizeof(int));
  coef=cpl_calloc(8,sizeof(double));

  check_nomsg(p=cpl_parameterlist_find(config,
                "sinfoni.distortion.arcs_thresh_factor"));
  check_nomsg(arcs_thres_factor=cpl_parameter_get_double(p));

  check_nomsg(p=cpl_parameterlist_find(config,
                "sinfoni.distortion.arcs_min_arclen_factor"));
  check_nomsg(arcs_min_arclen_factor=cpl_parameter_get_double(p));

  check_nomsg(p=cpl_parameterlist_find(config,
                "sinfoni.distortion.arcs_window_size"));
  check_nomsg(arcs_window_size=cpl_parameter_get_int(p));

  check_nomsg(p=cpl_parameterlist_find(config,
                "sinfoni.distortion.smooth_rad"));
  check_nomsg(smooth_rad=cpl_parameter_get_int(p));


  cknull(distor_poly=sinfo_distortion_estimate_new(impoly,
						   0,
						   0,
                                                 cpl_image_get_size_x(impoly),
                                                 cpl_image_get_size_y(impoly),
                                                   FALSE,
                                                   SINFO_ARC_SATURATION,
                                                   SINFO_ARC_MAX_WIDTH,
                                                   arcs_thres_factor,
                                                   arcs_min_arclen_factor,
                                                   arcs_window_size,
                                                   smooth_rad,
                                                   3,
                                                   (double)value,
                                                   &arcs),
     "cannot estimage distortion") ;
  /*AMo: additional mem leaks */

  sinfo_free_apertures(&arcs);
  coef_pow[0]=0;
  coef_pow[1]=0;
  check_nomsg(pcf[0][0]=cpl_polynomial_get_coeff(distor_poly,coef_pow));
  sinfo_msg("Polynomial fit results: coeff[%d][%d]=%g",0,0,pcf[0][0]);
  /*
  pcf[0][0]+=value;
  */
  sinfo_msg("Polynomial fit results: coeff[%d][%d]=%g",0,0,pcf[0][0]);
  check_nomsg(cpl_polynomial_set_coeff(distor_poly,coef_pow,pcf[0][0]));

  /* up to here ok */
  /* To check mem leaks */
  sinfo_free_image(&impoly);

  //sinfo_msg("Polynomial fit results: deg=%d",
  //      cpl_polynomial_get_degree(distor_poly));


  coef_pow[0]=0;
  coef_pow[1]=0;
  check_nomsg(pcf[0][0]=cpl_polynomial_get_coeff(distor_poly,coef_pow));
  //sinfo_msg("Polynomial fit results: coeff[%d][%d]=%g",0,0,pcf[0][0]);

  coef_pow[0]=1;
  coef_pow[1]=0;
  check_nomsg(pcf[1][0]=cpl_polynomial_get_coeff(distor_poly,coef_pow));
  //sinfo_msg("Polynomial fit results: coeff[%d][%d]=%g",1,0,pcf[1][0]);

  coef_pow[0]=0;
  coef_pow[1]=1;
  check_nomsg(pcf[0][1]=cpl_polynomial_get_coeff(distor_poly,coef_pow));
  //sinfo_msg("Polynomial fit results: coeff[%d][%d]=%g",0,1,pcf[0][1]);

  coef_pow[0]=1;
  coef_pow[1]=1;
  check_nomsg(pcf[1][1]=cpl_polynomial_get_coeff(distor_poly,coef_pow));
  //sinfo_msg("Polynomial fit results: coeff[%d][%d]=%g",1,1,pcf[1][1]);

  coef_pow[0]=2;
  coef_pow[1]=0;
  check_nomsg(pcf[2][0]=cpl_polynomial_get_coeff(distor_poly,coef_pow));
  //sinfo_msg("Polynomial fit results: coeff[%d][%d]=%g",2,0,pcf[2][0]);

  coef_pow[0]=0;
  coef_pow[1]=2;
  check_nomsg(pcf[0][2]=cpl_polynomial_get_coeff(distor_poly,coef_pow));
  //sinfo_msg("Polynomial fit results: coeff[%d][%d]=%g",0,2,pcf[0][2]);

  coef_pow[0]=2;
  coef_pow[1]=1;
  check_nomsg(pcf[2][1]=cpl_polynomial_get_coeff(distor_poly,coef_pow));
  //sinfo_msg("Polynomial fit results: coeff[%d][%d]=%g",2,1,pcf[2][1]);

  coef_pow[0]=1;
  coef_pow[1]=2;
  check_nomsg(pcf[1][2]=cpl_polynomial_get_coeff(distor_poly,coef_pow));
  //sinfo_msg("Polynomial fit results: coeff[%d][%d]=%g",1,2,pcf[1][2]);

  coef_pow[0]=3;
  coef_pow[1]=0;
  check_nomsg(pcf[3][0]=cpl_polynomial_get_coeff(distor_poly,coef_pow));
  //sinfo_msg("Polynomial fit results: coeff[%d][%d]=%g",3,0,pcf[3][0]);

  coef_pow[0]=0;
  coef_pow[1]=3;
  check_nomsg(pcf[0][3]=cpl_polynomial_get_coeff(distor_poly,coef_pow));
  //sinfo_msg("Polynomial fit results: coeff[%d][%d]=%g",0,3,pcf[0][3]);

  sinfo_msg("Save results");

  check_nomsg(poly_tbl=cpl_table_new(10));
  check_nomsg(cpl_table_new_column(poly_tbl,"degx", CPL_TYPE_INT));
  check_nomsg(cpl_table_new_column(poly_tbl,"degy", CPL_TYPE_INT));
  check_nomsg(cpl_table_new_column(poly_tbl,"coeff", CPL_TYPE_DOUBLE));
  check_nomsg(cpl_table_set_int(poly_tbl,"degx",0,0));
  check_nomsg(cpl_table_set_int(poly_tbl,"degx",1,1));
  check_nomsg(cpl_table_set_int(poly_tbl,"degx",2,0));
  check_nomsg(cpl_table_set_int(poly_tbl,"degx",3,1));
  check_nomsg(cpl_table_set_int(poly_tbl,"degx",4,2));
  check_nomsg(cpl_table_set_int(poly_tbl,"degx",5,0));
  check_nomsg(cpl_table_set_int(poly_tbl,"degx",6,2));
  check_nomsg(cpl_table_set_int(poly_tbl,"degx",7,1));
  check_nomsg(cpl_table_set_int(poly_tbl,"degx",8,3));
  check_nomsg(cpl_table_set_int(poly_tbl,"degx",9,0));

  check_nomsg(cpl_table_set_int(poly_tbl,"degy",0,0));
  check_nomsg(cpl_table_set_int(poly_tbl,"degy",1,0));
  check_nomsg(cpl_table_set_int(poly_tbl,"degy",2,1));
  check_nomsg(cpl_table_set_int(poly_tbl,"degy",3,1));
  check_nomsg(cpl_table_set_int(poly_tbl,"degy",4,0));
  check_nomsg(cpl_table_set_int(poly_tbl,"degy",5,2));
  check_nomsg(cpl_table_set_int(poly_tbl,"degy",6,1));
  check_nomsg(cpl_table_set_int(poly_tbl,"degy",7,2));
  check_nomsg(cpl_table_set_int(poly_tbl,"degy",8,0));
  check_nomsg(cpl_table_set_int(poly_tbl,"degy",9,3));

  check_nomsg(cpl_table_set_double(poly_tbl,"coeff",0,pcf[0][0]));
  check_nomsg(cpl_table_set_double(poly_tbl,"coeff",1,pcf[1][0]));
  check_nomsg(cpl_table_set_double(poly_tbl,"coeff",2,pcf[0][1]));
  check_nomsg(cpl_table_set_double(poly_tbl,"coeff",3,pcf[1][1]));
  check_nomsg(cpl_table_set_double(poly_tbl,"coeff",4,pcf[2][0]));
  check_nomsg(cpl_table_set_double(poly_tbl,"coeff",5,pcf[0][2]));
  check_nomsg(cpl_table_set_double(poly_tbl,"coeff",6,pcf[2][1]));
  check_nomsg(cpl_table_set_double(poly_tbl,"coeff",7,pcf[1][2]));
  check_nomsg(cpl_table_set_double(poly_tbl,"coeff",8,pcf[3][0]));
  check_nomsg(cpl_table_set_double(poly_tbl,"coeff",9,pcf[0][3]));

  //sinfo_msg("Polynomial distortion coefficients \n");
  //sinfo_msg("c= %g   %g  %g  %g  %g  %g  %g  %g %g %g\n",
  //       pcf[0][0],pcf[1][0],pcf[0][1],pcf[1][1],
  //           pcf[2][0],pcf[0][2],pcf[2][1],pcf[1][2],pcf[3][0],pcf[0][3]);

  /* QC LOG */
  check_nomsg(qclog_tbl = sinfo_qclog_init());
  snprintf(key_name,MAX_NAME_SIZE-1,"%s%d%d","QC COEFF",0,0);
  ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,key_name,pcf[0][0],
             "Polynomial distortion coefficient","%g"));

  snprintf(key_name,MAX_NAME_SIZE-1,"%s%d%d","QC COEFF",1,0);
  ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,key_name,pcf[1][0],
             "Polynomial distortion coefficient","%g"));

  snprintf(key_name,MAX_NAME_SIZE-1,"%s%d%d","QC COEFF",0,1);
  ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,key_name,pcf[0][1],
             "Polynomial distortion coefficient","%g"));

  snprintf(key_name,MAX_NAME_SIZE-1,"%s%d%d","QC COEFF",1,1);
  ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,key_name,pcf[1][1],
             "Polynomial distortion coefficient","%g"));

  snprintf(key_name,MAX_NAME_SIZE-1,"%s%d%d","QC COEFF",2,0);
  ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,key_name,pcf[2][0],
             "Polynomial distortion coefficient","%g"));

  snprintf(key_name,MAX_NAME_SIZE-1,"%s%d%d","QC COEFF",0,2);
  ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,key_name,pcf[0][2],
             "Polynomial distortion coefficient","%g"));

  snprintf(key_name,MAX_NAME_SIZE-1,"%s%d%d","QC COEFF",2,1);
  ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,key_name,pcf[2][1],
             "Polynomial distortion coefficient","%g"));

  snprintf(key_name,MAX_NAME_SIZE-1,"%s%d%d","QC COEFF",1,2);
  ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,key_name,pcf[1][2],
             "Polynomial distortion coefficient","%g"));

  snprintf(key_name,MAX_NAME_SIZE-1,"%s%d%d","QC COEFF",3,0);
  ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,key_name,pcf[3][0],
             "Polynomial distortion coefficient","%g"));

  snprintf(key_name,MAX_NAME_SIZE-1,"%s%d%d","QC COEFF",0,3);
  ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,key_name,pcf[0][3],
             "Polynomial distortion coefficient","%g"));

  snprintf(key_name,MAX_NAME_SIZE-1,"%s","QC OFFSET");
  ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,key_name,value,
             "Polynomial distortion coefficient","%g"));

  xshift=new_compute_shift(x_c,y_c,pcf[0][0],pcf[1][0],pcf[0][1],
                                   pcf[1][1],pcf[2][0],pcf[0][2],
                                   pcf[2][1],pcf[1][2],pcf[3][0],pcf[0][3]);

  ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,"QC XSHIFT CC",xshift,
                                   "X shift in x_c,y_c","%g"));


  xshift=new_compute_shift(x_l,y_l,pcf[0][0],pcf[1][0],pcf[0][1],
                                   pcf[1][1],pcf[2][0],pcf[0][2],
                                   pcf[2][1],pcf[1][2],pcf[3][0],pcf[0][3]);

  ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,"QC XSHIFT LL",xshift,
                                   "X shift in x_l,y_l","%g"));

  xshift=new_compute_shift(x_l,y_u,pcf[0][0],pcf[1][0],pcf[0][1],
                                   pcf[1][1],pcf[2][0],pcf[0][2],
                                   pcf[2][1],pcf[1][2],pcf[3][0],pcf[0][3]);

  ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,"QC XSHIFT UL",xshift,
                                   "X shift in x_l,y_u","%g"));

  xshift=new_compute_shift(x_u,y_u,pcf[0][0],pcf[1][0],pcf[0][1],
                                   pcf[1][1],pcf[2][0],pcf[0][2],
                                   pcf[2][1],pcf[1][2],pcf[3][0],pcf[0][3]);

  ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,"QC XSHIFT UR",xshift,
                                   "X shift in x_u,y_u","%g"));


  xshift=new_compute_shift(x_u,y_l,pcf[0][0],pcf[1][0],pcf[0][1],
                                   pcf[1][1],pcf[2][0],pcf[0][2],
                                   pcf[2][1],pcf[1][2],pcf[3][0],pcf[0][3]);

  ck0_nomsg(sinfo_qclog_add_double(qclog_tbl,"QC XSHIFT LR",xshift,
                                   "X shift in x_u,y_l","%g"));


  ck0(sinfo_pro_save_tbl(poly_tbl,set_fibre_ns,sof,cfg->outName,
             PRO_DISTORTION,qclog_tbl,plugin_id,config),
      "cannot dump tbl %s", cfg->outName);

  sinfo_free_table(&poly_tbl);
  sinfo_free_table(&qclog_tbl);
  sinfo_free_polynomial(&distor_poly);
  sinfo_free_int(&degx);
  sinfo_free_int(&degy);
  sinfo_free_double(&coef);
  sinfo_free_image(&im);
  sinfo_free_frameset(&stk);
  sinfo_finddist_free (&cfg);

  return 0;

 cleanup:
  sinfo_free_table(&poly_tbl);
  sinfo_free_table(&qclog_tbl);
  sinfo_free_polynomial(&distor_poly);
  sinfo_free_int(&degx);
  sinfo_free_int(&degy);
  sinfo_free_double(&coef);
  sinfo_free_apertures(&arcs);



  /*if(wave != NULL) sinfo_new_destroy_array (& wave );*/
  /*if(intens != NULL) sinfo_new_destroy_array (& intens );*/
  if(first != NULL) sinfo_new_destroy_array(&first);
  sinfo_free_table(&tbl_spos);
  if(slit_pos != NULL) sinfo_new_destroy_2Dfloatarray (&slit_pos,32);
  if(distances != NULL) sinfo_new_destroy_array(&distances);
  if(par!=NULL) sinfo_new_destroy_fit_params(&par);
  if(n_found_lines != NULL) sinfo_new_destroy_intarray(&n_found_lines );
  if(row_clean != NULL) sinfo_new_destroy_2Dintarray(&row_clean, lx);
  if(wavelength_clean != NULL) {
      sinfo_new_destroy_2Dfloatarray(&wavelength_clean,lx);
  }
  if(sum_pointer != NULL) sinfo_new_destroy_intarray(&sum_pointer);
  if(acoefs != NULL) {
      sinfo_new_destroy_2Dfloatarray(&acoefs, cfg->nrDispCoefficients );
  }
  sinfo_free_table(&tbl_line_list);
  sinfo_free_image(&mask);
  sinfo_free_image(&impoly);
  sinfo_free_image(&imonind);
  sinfo_free_image(&map);
  sinfo_free_image(&im);
  sinfo_finddist_free (&cfg);
  sinfo_free_frameset(&stk);
  return -1;

}


static double
new_compute_shift(double x,
              double y,
              double c00,
              double c10,
              double c01,
              double c11,
              double c20,
              double c02,
              double c21,
              double c12,
              double c30,
              double c03)
{

  double x_shift=0;
  double shift=0;
  //sinfo_msg("c= %g   %g  %g  %g  %g  %g  %g  %g %g %g\n",
  //       c00,c10,c01,c11,
  //       c20,c02,c21,c12,c30,c03);

  shift=c00+c10*x+c01*y+
        c11*x*y+c20*x*x+c02*y*y+
        c21*x*x*y+c12*x*y*y+c30*x*x*x+c03*y*y*y;
  x_shift=x-shift;
  return x_shift;



}
/**@}*/
