/*                                                                            *
 *   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-01-16 21:09:42 $
 * $Revision: 1.6 $
 */
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

/*--------------------------------------------------------------------------*/
/**
 * @defgroup test_xsh_flux_conservation Test Flux Conservation 
 * @ingroup unit_tests
 *
 */
/*--------------------------------------------------------------------------*/
/**@{*/

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


#include <cpl.h>
#include <xsh_data_instrument.h>
#include <xsh_pfits.h>
#include <xsh_msg.h>
#include <xsh_utils.h>
#include <xsh_utils_image.h>
#include <xsh_data_order.h>
#include <tests.h>
#include <math.h>
#include <xsh_cpl_size.h>

static const double poly0_coeff[] = {
  -256., 1., 0.001 } ;
static const double poly1_coeff[] = {
  -256., 1., 0.001 } ;
/*---------------------------------------------------------------------------
                            Defines
 ---------------------------------------------------------------------------*/
#define MODULE_ID "XSH_FLUX"
/*---------------------------------------------------------------------------
                         Functions prototypes
 ---------------------------------------------------------------------------*/
static double 
derivative_x(const double a1, const double a2, const double x){
  
   return a1+2*a2*x;

}

static double 
derivative_y(const double a1, const double a2, const double y){

   return a1+2*a2*y;

}

int main(void)
{
   cpl_image* ima_orig=NULL;
   cpl_image* ima_warp=NULL;
   cpl_image* ima_gaus=NULL;
   cpl_image* ima_corr=NULL;
   cpl_image* dXdx=NULL;
   cpl_image* dYdy=NULL;
   cpl_image* dXdy=NULL;
   cpl_image* dYdx=NULL;


   cpl_polynomial* poly_u=NULL;
   cpl_polynomial* poly_v=NULL;
   cpl_vector* xprofile=NULL;
   cpl_vector* yprofile=NULL;

   int nx=2048;
   int ny=2048;
   int sx=256;
   int sy=256;
   double sigx=16;
   double sigy=16;
   int xc=sx/2;
   int yc=sy/2;
   double flux=5.e4;
   const int dim=2;
   cpl_size pows[dim];


   double f_new=0;
   double f_org=0;
  
   float* pdXdx=NULL;
   float* pdYdy=NULL;
   float* pdXdy=NULL;
   float* pdYdx=NULL;
   float* pcor=NULL;


   int i=0;
   int j=0;

   TESTS_INIT_WORKSPACE(MODULE_ID);
   TESTS_INIT(MODULE_ID);
   xsh_msg("detect_continuum");

   ima_orig=cpl_image_new(nx,ny,CPL_TYPE_FLOAT);
   check(ima_gaus=cpl_image_new(sx,sy,CPL_TYPE_FLOAT));

   check(cpl_image_fill_gaussian(ima_gaus,xc,yc,flux,sigx,sigy));
   cpl_image_copy(ima_orig,ima_gaus,1*(nx/4),1*(ny/4));

   check(cpl_image_fill_gaussian(ima_gaus,xc,yc,2*flux,sigx,sigy));
   cpl_image_copy(ima_orig,ima_gaus,3*(nx/4),1*(ny/4));

   check(cpl_image_fill_gaussian(ima_gaus,xc,yc,3*flux,sigx,sigy));
   cpl_image_copy(ima_orig,ima_gaus,2*(nx/4),2*(ny/4));

   check(cpl_image_fill_gaussian(ima_gaus,xc,yc,4*flux,sigx,sigy));
   cpl_image_copy(ima_orig,ima_gaus,1*(nx/4),3*(ny/4));

   check(cpl_image_fill_gaussian(ima_gaus,xc,yc,5*flux,sigx,sigy));
   cpl_image_copy(ima_orig,ima_gaus,3*(nx/4),3*(ny/4));
   //cpl_image_add_scalar(ima_orig,bias);

   cpl_image_save( ima_orig,"ima_orig.fits", CPL_BPP_IEEE_FLOAT, NULL,
                   CPL_IO_DEFAULT);
   check(f_org=cpl_image_get_flux(ima_orig));

   // Now warps the image
   poly_u=cpl_polynomial_new(2);
   poly_v=cpl_polynomial_new(2);


   pows[0]=0;
   pows[1]=0;
   cpl_polynomial_set_coeff(poly_v,pows,poly0_coeff[0]);


   pows[0]=0;
   pows[1]=1;
   cpl_polynomial_set_coeff(poly_v,pows,poly0_coeff[1]);


   pows[0]=0;
   pows[1]=2;
   cpl_polynomial_set_coeff(poly_v,pows,poly0_coeff[2]);


/* old version */
   pows[0]=1;
   pows[1]=0;
   cpl_polynomial_set_coeff(poly_u,pows,1.);

/*

   pows[0]=0;
   pows[1]=0;
   cpl_polynomial_set_coeff(poly_u,pows,poly1_coeff[0]);


   pows[0]=0;
   pows[1]=1;
   cpl_polynomial_set_coeff(poly_u,pows,poly1_coeff[1]);


   pows[0]=0;
   pows[1]=2;
   cpl_polynomial_set_coeff(poly_u,pows,poly1_coeff[2]);
*/
   cpl_polynomial_dump(poly_u,stdout);
   cpl_polynomial_dump(poly_v,stdout);


   check(ima_warp=cpl_image_new(nx,ny,CPL_TYPE_FLOAT));
   check(xprofile=cpl_vector_new(nx));
   check(yprofile=cpl_vector_new(ny));
               cpl_vector_fill_kernel_profile(xprofile, CPL_KERNEL_DEFAULT,
                                  CPL_KERNEL_DEF_WIDTH);
   cpl_vector_fill_kernel_profile(yprofile, CPL_KERNEL_DEFAULT,
                                  CPL_KERNEL_DEF_WIDTH);

  check(cpl_image_warp_polynomial(ima_warp,ima_orig,poly_u,poly_v,
  xprofile,CPL_KERNEL_DEF_WIDTH,
  yprofile,CPL_KERNEL_DEF_WIDTH));
 
  check(ima_corr=cpl_image_new(nx,ny,CPL_TYPE_FLOAT));
  // The following only with CPL4.5!!!
  //check(xsh_image_warp_polynomial_scale(ima_corr,poly_u,poly_v));
  cpl_image_save( ima_warp,"ima_warp.fits", CPL_BPP_IEEE_FLOAT, NULL,
                   CPL_IO_DEFAULT);
   check(f_new=cpl_image_get_flux(ima_warp));
  xsh_msg("Flux start: %g",f_org);  
  xsh_msg("Flux end: %g",f_new);



   // Construct derivatives images
  check(dXdx=cpl_image_new(nx,ny,CPL_TYPE_FLOAT));
  check(dYdy=cpl_image_new(nx,ny,CPL_TYPE_FLOAT));
  check(dXdy=cpl_image_new(nx,ny,CPL_TYPE_FLOAT));
  check(dYdx=cpl_image_new(nx,ny,CPL_TYPE_FLOAT));

  check(pdXdx=cpl_image_get_data_float(dXdx));
  check(pdYdy=cpl_image_get_data_float(dYdy));
  check(pdXdy=cpl_image_get_data_float(dXdy));
  check(pdYdx=cpl_image_get_data_float(dYdx));
  check(pcor=cpl_image_get_data_float(ima_corr));

  //check(sup=cpl_vector_new(2));
  //check(psup=cpl_vector_get_data(sup));
  //check(inf=cpl_vector_new(2));
  //check(pinf=cpl_vector_get_data(inf));

  //Fill images with derivatives
  for(j=1;j<ny-1;j++) {
     for(i=1;i<nx-1;i++) {
        //psup[0]=(double)(i+1);
        //psup[1]=(double)j;

        //pinf[0]=(double)(i-1);
        //pinf[1]=(double)j;

        pdXdx[i+j*nx]=1.;

        pdYdx[i+j*nx]=derivative_x(poly0_coeff[1],poly0_coeff[2],(double)i);

        //psup[0]=(double)i;
        //psup[1]=(double)(j+1);

        //pinf[0]=(double)i;
        //pinf[1]=(double)(j-1);


        pdXdy[i+j*nx]=0.;

        pdYdy[i+j*nx]=derivative_y(poly0_coeff[1],poly0_coeff[2],(double)j);

   
        //xsh_msg("i=%d j=%d pdYdx=%g pdXdy=%g",i,j,pdYdx[i+j*nx],pdXdy[i+j*nx]);

        pcor[i+j*nx]=fabs(pdXdx[i+j*nx]*pdYdy[i+j*nx]-
                               pdXdy[i+j*nx]*pdYdx[i+j*nx]);
        
     }
  }


  cpl_image_save( ima_corr,"ima_corr.fits", CPL_BPP_IEEE_FLOAT, NULL,
                   CPL_IO_DEFAULT);

  cpl_image_multiply(ima_warp,ima_corr);

  cpl_image_save( ima_warp,"ima_end.fits", CPL_BPP_IEEE_FLOAT, NULL,
                   CPL_IO_DEFAULT);


  check(f_new=cpl_image_get_flux(ima_warp));
  xsh_msg("Flux corr: %g",f_new);  





  cleanup:
  xsh_free_image(&ima_orig);
  xsh_free_image(&ima_warp);
  xsh_free_image(&ima_gaus);
  xsh_free_image(&ima_corr);
  xsh_free_image(&dXdx);
  xsh_free_image(&dYdy);
  xsh_free_image(&dXdy);
  xsh_free_image(&dYdx);


  xsh_free_polynomial(&poly_u);
  xsh_free_polynomial(&poly_v);
  xsh_free_vector(&xprofile);
  xsh_free_vector(&yprofile);

  TESTS_CLEAN_WORKSPACE(MODULE_ID);
   if (cpl_error_get_code() != CPL_ERROR_NONE) {
      xsh_error_dump(CPL_MSG_ERROR);
      return 1;
   } 
   else {
      return 0;
   }

}

/**@}*/
