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

}
/**@}*/
