/*===========================================================================
  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;

}
/**@}*/
