/*===========================================================================
  Copyright (C) 2001 European Southern Observatory (ESO)
 
  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, Inc., 675 Massachusetss Ave, Cambridge, 
  MA 02139, USA.
 
  Corresponding concerning ESO-MIDAS should be addressed as follows:
  Internet e-mail: midas@eso.org
  Postal address: European Southern Observatory
  Data Management Division 
  Karl-Schwarzschild-Strasse 2
  D 85748 Garching bei Muenchen 
  GERMANY
  ===========================================================================*/
/*-------------------------------------------------------------------------*/
/**
 * @defgroup flames_dointerpolate  
 *
 */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <flames_midas_def.h>
#include <flames_dointerpolate.h>
#include <flames_newmatrix.h>
#include <flames_shiftcommon.h>
#include <flames_shiftall.h>

/**@{*/
/*---------------------------------------------------------------------------
  Implementation
  ---------------------------------------------------------------------------*/
/**
   @name  flames_dointerpolate()  
   @short 

   @author G. Mulas  -  ITAL_FLAMES Consortium. Ported to CPL by A. Modigliani
   @param allflatsout 
   @param fitdata 
   @param iorder 
   @param iframe 
   @param ifibre
   @param ix 
   @param iy
   @return 0 if success

                                                                         
   DRS Functions called: none                                             
                                                                        
   Pseudocode:                                                            
   Initialize an order table                                           

   @note
*/


flames_err 
dointerpolate(allflats *allflatsout, 
              fitstruct *fitdata, 
	      int32_t iorder, 
              int32_t iframe, 
              int32_t ifibre,
	      int32_t ix, 
              int32_t iy)
{
  int32_t i=0;
  double a11=0, a12=0, a22=0, b1=0, b2=0, deta=0;
  frame_data pixelavervalue=0, pixelaversigma=0;
  frame_data pixelintervalue=0, pixelintersigma=0;
  frame_data deviation=0;
  double dbuf1=0, dbuf2=0;

  frame_data *fdvecbuf1=0;
  frame_data *fdvecbuf2=0;
  frame_mask *fmvecbuf1=0;
  int32_t iyixindex=0;

  fdvecbuf1 = allflatsout->flatdata[iframe].data[0];
  fdvecbuf2 = allflatsout->flatdata[iframe].sigma[0];
  fmvecbuf1 = allflatsout->flatdata[iframe].badpixel[0];
  iyixindex = (iy*allflatsout->subcols)+ix;

  /* was I able to find anything? */
  if (fitdata->availpixels == 0) {
    /* no way, mark this as a bad pixel */
    fmvecbuf1[iyixindex] = 1;
  }
  /* did I find only one pixel? */
  else if (fitdata->availpixels==1) {
    /* just use that "better than nothing" single value I have */
    fmvecbuf1[iyixindex] = 0;
    fdvecbuf1[iyixindex] = (frame_data)(fitdata->value)[0];
    fdvecbuf2[iyixindex] = (frame_data)(fitdata->sigma)[0];
  }
  else {
    /* compute all the coefficients for linear interpolation */
    a11 = a12 = a22 = b1 = b2 = 0;
    for (i=0; i<=fitdata->availpixels-1; i++){
      dbuf1 = 1/fitdata->sigma[i];
      dbuf2 = fitdata->offset[i]*dbuf1;
      a12 += dbuf2;
      a11 += fitdata->offset[i]*dbuf2;
      a22 += dbuf1;
      b2 += (fitdata->value)[i]*dbuf1;
      b1 += (fitdata->value)[i]*dbuf2;
    }
    /* compute the determinant */
    deta = a11*a22-a12*a12;
    fmvecbuf1[iyixindex] = 0;
    /* compute anyway the simple weighted average */
    pixelavervalue = (frame_data)(b2/a22);
    pixelaversigma = (frame_data)(1/a22);
    if (deta <= DEPSILON) {
      /* just use the average */
      fdvecbuf1[iyixindex] = pixelavervalue;
      fdvecbuf2[iyixindex] = pixelaversigma;
    }
    else {
      /* try to interpolate */
      pixelintervalue = (frame_data)((b2*a11-b1*a12)/deta);
      pixelintersigma = (frame_data)(a11/deta);
      /* is the interpolation sensible? */
      deviation = pixelintervalue-pixelavervalue;
      if ((pixelintersigma > (9*pixelaversigma)) || 
	  ((deviation*deviation)>3*(pixelintersigma+pixelaversigma))) {
	/* probably numerical instability, fall back to the simple average */
	fdvecbuf1[iyixindex] = pixelavervalue;
	fdvecbuf2[iyixindex] = pixelaversigma;
      }
      else {
	/* yes, it is indeed sensible, use it */
	fdvecbuf1[iyixindex] = pixelintervalue;
	fdvecbuf2[iyixindex] = pixelintersigma;
      }
    }
  }

  return NOERR;

}
/**@}*/
