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

/**
   @name  flames_fillnormfactors()  
   @short  Computes normalization factors and their sigmas
   @author G. Mulas  -  ITAL_FLAMES Consortium. Ported to CPL by A. Modigliani


   @param allflatsin 
   @param shiftdata 
   @param badifibre 
   @param iorder 
   @param iframe 
   @param ifibre 
   @param ix 
   @param ixindex 
   @param normdata

   @return success or failure code, 


   DRS Functions called:          
   none


   Pseudocode:                                                             


   @note
   @doc this structure contains the temporary data used to compute 
   normalisation 
   factors and their sigmas, for bad pixel filling in the fibre FF frames;
   one issue of this structure will be used for each offset to be used for 
   filling, hence an array of these structures will be necessary 

 */


#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_uves.h>
#include <flames_newmatrix.h>
#include <flames_shiftcommon.h>
#include <flames_fillholes.h>
#include <flames_fillnormfactors.h>


flames_err 
fillnormfactors(
                allflats *allflatsin, 
                shiftstruct *shiftdata, 
                badifibrestruct *badifibre, 
                int32_t iorder, 
                int32_t iframe, 
                int32_t ifibre, 
                int32_t ix, 
                int32_t ixindex, 
                normstruct* normdata)
{
    int32_t i=0, j=0;
    int32_t iy=0;
    tnormfactorstruct *tnormdata=0;
    tnormfactorstruct *tnormdatai=0;

    shiftstruct *shiftdataix=0;
    badifibrestruct *mybadifibre=0;
    badixstruct *mybadixs=0;
    int32_t *lvecbuf1=0;
    int32_t *lvecbuf2=0;
    frame_data *fdvecbuf1=0;
    frame_data *fdvecbuf2=0;
    frame_mask *fmvecbuf1=0;
    int32_t iorderifibreindex=0;
    int32_t iorderifibreixindex=0;
    int32_t iorderifibreshiftixindex=0;
    int32_t iyixindex=0;
    int32_t shiftiy=0;
    int32_t shiftix=0;
    int32_t shiftiyshiftixindex=0;

    shiftdataix = shiftdata+ix;
    lvecbuf1 = allflatsin->lowfibrebounds[0][0];
    lvecbuf2 = allflatsin->highfibrebounds[0][0];
    mybadifibre = badifibre+ifibre;
    mybadixs = mybadifibre->badixs+ixindex;
    fdvecbuf1 = allflatsin->flatdata[iframe].data[0];
    fdvecbuf2 = allflatsin->flatdata[iframe].sigma[0];
    fmvecbuf1 = allflatsin->flatdata[iframe].badpixel[0];

    tnormdata = (tnormfactorstruct *) calloc((size_t)(shiftdataix->numoffsets),
                    sizeof(tnormfactorstruct));

    iorderifibreindex = (iorder*allflatsin->maxfibres)+ifibre;
    iorderifibreixindex = (iorderifibreindex*allflatsin->subcols)+ix;

    /* initialise to zero numerators and denominators */
    for (i=0; i<=shiftdataix->numoffsets-1;i++) {
        tnormdatai = tnormdata+i;
        tnormdatai->numerator = 0;
        tnormdatai->numsigma = 0;
        tnormdatai->denominator = 0;
        tnormdatai->densigma = 0;
        tnormdatai->yshift = calloc((size_t) 2, sizeof(int32_t));
        tnormdatai->yshift[0] = (int32_t) floor(shiftdataix->yfracoffsets[i])
                      - shiftdataix->yintoffsets[i];
        tnormdatai->yshift[1] = (int32_t) ceil(shiftdataix->yfracoffsets[i])
                      - shiftdataix->yintoffsets[i];
        tnormdatai->yshiftnum =
                        (tnormdata[i].yshift[1] - tnormdata[i].yshift[0])>DEPSILON? 1 : 0;
        tnormdatai->yshiftfrac = calloc((size_t) 2, sizeof(double));
        tnormdatai->yshiftfrac[0] = 1-fabs(shiftdataix->yfracoffsets[i]-
                        floor(shiftdataix->yfracoffsets[i]));
        tnormdatai->yshiftfrac[1] = 1-fabs(shiftdataix->yfracoffsets[i]-
                        ceil(shiftdataix->yfracoffsets[i]));
        tnormdatai->overlapfrac = 0;
    }
    mybadixs->badiycount = 0;
    if (lvecbuf2[iorderifibreixindex] >= lvecbuf1[iorderifibreixindex]) {
        mybadixs->badiy =
                        (int32_t *) calloc((size_t)(lvecbuf2[iorderifibreixindex]-
                                        lvecbuf1[iorderifibreixindex]+1),
                                        sizeof(int32_t));
    }
    for (iy=lvecbuf1[iorderifibreixindex];
                    iy<=lvecbuf2[iorderifibreixindex];
                    iy++) {
        iyixindex = (iy*allflatsin->subcols)+ix;
        /* is this pixel good? */
        if (fmvecbuf1[iyixindex] == 0) {
            /* yes, it is good, try to add its contribution to numerator,
	 denominator, errors */
            for (i=0; i<=shiftdataix->numoffsets-1;i++) {
                tnormdatai = tnormdata+i;
                shiftix = shiftdataix->ixoffsets[i];
                iorderifibreshiftixindex =
                                (iorderifibreindex*allflatsin->subcols)+shiftix;
                for (j=0;j<=tnormdatai->yshiftnum;j++) {
                    /* is the shifted iy within fibre boundaries? */
                    shiftiy = iy+tnormdatai->yshift[j];
                    if ((shiftiy >= lvecbuf1[iorderifibreshiftixindex])
                                    && (shiftiy <= lvecbuf2[iorderifibreshiftixindex])) {
                        /* yes, within boundaries, but good shifted pixel? */
                        shiftiyshiftixindex = (shiftiy*allflatsin->subcols)+shiftix;
                        if (fmvecbuf1[shiftiyshiftixindex] == 0) {
                            /* yes, good pixel, do add it to normalisation factors */
                            tnormdatai->overlapfrac += tnormdatai->yshiftfrac[j];
                            tnormdatai->numerator += fdvecbuf1[iyixindex]*
                                            tnormdatai->yshiftfrac[j];
                            tnormdatai->numsigma += fdvecbuf2[iyixindex]*
                                            tnormdatai->yshiftfrac[j];
                            tnormdatai->denominator += fdvecbuf1[shiftiyshiftixindex]*
                                            tnormdatai->yshiftfrac[j];
                            tnormdatai->densigma += fdvecbuf2[shiftiyshiftixindex]*
                                            tnormdatai->yshiftfrac[j];
                        }
                    }
                }
            }
        }
        else {
            /* this pixel is not good, add it to the list of pixels to be
	 corrected */
            mybadixs->badiy[mybadixs->badiycount]=iy;
            mybadixs->badiycount++;
        }
    }
    /* ok, numerators, denominators and errors computed, calculate normalisation
     factors */
    for (i=0; i<=shiftdataix->numoffsets-1;i++){
        tnormdatai = tnormdata+i;
        normstruct* normdatai = normdata+i;
        if (((tnormdatai->overlapfrac*allflatsin->substepy)/
                        (2*allflatsin->halfibrewidth) >=
                        (allflatsin->minfibrefrac)) &&
                        (tnormdatai->denominator > DEPSILON) &&
                        (tnormdatai->numerator > DEPSILON)) {
            /* enough overlap between these two ixs */
            normdatai->normfactor = tnormdatai->numerator/tnormdatai->denominator;
            normdatai->normsigma = (tnormdatai->numsigma/
                            (tnormdatai->numerator*tnormdatai->numerator)+
                            tnormdatai->densigma/
                            (tnormdatai->denominator*
                                            tnormdatai->denominator))*
                                                            normdatai->normfactor;
            normdatai->goodoverlap = 0; /* use this as a marker for good overlap */
        }
        else {
            /* not enough overlap */
            normdatai->goodoverlap = 1;
        }
        free(tnormdatai->yshift);
        free(tnormdatai->yshiftfrac);
    }


    free(tnormdata);
    return(NOERR);

}
/**@}*/
