/*===========================================================================
  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
===========================================================================*/
/* Program  : prepextract.c                                                */
/* Author   : G. Mulas  -  ITAL_FLAMES Consortium                          */
/* Date     :                                                              */
/*                                                                         */
/* Purpose  : Missing                                                      */
/*                                                                         */
/*                                                                         */
/* Input:  see interface                                                   */ 
/*                                                                      */
/* Output:                                                              */
/*                                                                         */
/* DRS Functions called:                                                   */
/* none                                                                    */ 
/*                                                                         */ 
/* Pseudocode:                                                             */
/* Missing                                                                 */ 
/*                                                                         */ 
/* Version  :                                                              */
/* Last modification date: 2002/08/05                                      */
/* Who     When        Why                Where                            */
/* AMo     02-08-05   Add header         header                            */
/*-------------------------------------------------------------------------*/

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

/* C functions include files */ 
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* MIDAS include files */
#include <flames_midas_def.h>
#include <flames_allocspectrum.h>
/* FLAMES-UVES include files */ 
#include <flames_prepextract.h>
#include <flames_quickprepextract.h>
#include <flames_uves.h>
#include <flames_newmatrix.h>
#include <uves_msg.h>
/**
 @name  prepextract()
 @author G. Mulas  -  ITAL_FLAMES Consortium. Ported to CPL by A. Modigliani

 @param ScienceFrame   input science frame to be extracted
 @param SingleFF       input all flat field frame base structure
 @param Order          input order traces structure
 @param normcover      array to hold fibre normalization factors
 @param orderoffset    order offset
 @param realfirstorder input first order to be extracted
 @param reallastorder  input last order to be extracted
 @param mask           output mask

 @ doc

     -find the lowest and highest lit fibres in this frame; 
     -initialises the overall mask to be used for the extraction and, 
      checks for adequate coverage of each fibre slice, to avoid ill-posed 
      problems altogether 
     -clean up the mask first 
     -we want to use only the pixels which are somewhat covered by some
      at least partially good fibre slice; hence initially mark all pixels
      to be bad in the overall mask, then clean up the ones for which the 
      following conditions hold:
      1) that pixel is good both in the fibre FF frame(s) and in the Science
         frame
      2) that pixel belongs at least to one extractible slice with good 
         enough coverage

     -the "out of boundaries" value in the mask is 3, it means that the
      pixel is not included in any slice to be extracted 
     -Then search for good slices:
      foreach fibre
         if the fibre is illuminated and the slit flat is illuminated
             foreach x
                if the slice is good
                   measure the fibre coverage 
                   and check it is more than a minimum threshold
                   if yes set the pixel as good
                   if not set it as bad:
                      either as bad from the fibre FF (2)
                      or as bad from the science frame (1)
                   endif
                else
                   set the slice as bad
                endif
             endfor
         endif
      endfor

      run a second loop over fibres, to make sure to exclude pixels which 
      are not good in all the slices to be extracted 

 
 */


flames_err prepextract(flames_frame *ScienceFrame, allflats *Shifted_FF, 
		       orderpos *Order, frame_data **normcover, 
		       int32_t orderoffset, int32_t realfirstorder, 
		       int32_t reallastorder, frame_mask **mask)
{

  char output[CATREC_LEN+1];
  int32_t nm=0, mj=0, k=0, l=0, m=0, n=0;
  frame_data ffcoverage=0;

  frame_data *fdvecbuf1=0;
  frame_data *fdvecbuf2=0;
  frame_mask *fmvecbuf1=0;
  frame_mask *fmvecbuf2=0;
  frame_mask *fmvecbuf3=0;
  frame_mask *fmvecbuf4=0;
  int32_t *lvecbuf1=0;
  int32_t *lvecbuf2=0;
  int32_t kluplimit=0;
  int32_t klindex=0;
  int32_t iorder=0;
  int32_t iframe=0;
  int32_t iordernindex=0;
  int32_t iordernloffset=0;
  int32_t iorder2=0;
  int32_t iorder2loffset=0;
  int32_t iorder2lindex=0;
  int32_t iordernlindex=0;

  /* find the lowest and highest lit fibres in this frame; we actually want
     fibres to be lit also in the fibre ff frames, or we will be unable to
     extract them anyway, but we will check for that later. */
  SCTPUT("Searching for lit fibres");

  nm=0;

  ScienceFrame->num_lit_fibres=0;
  for (nm=0; 
       nm<=(ScienceFrame->maxfibres-1) && 
	 (ScienceFrame->fibremask[nm]!=TRUE || 
	  Shifted_FF->fibremask[nm]!=TRUE); nm++);
  uves_msg_debug("nm=%d",nm);


  if (nm<=(ScienceFrame->maxfibres-1)) {
    ScienceFrame->min_lit_fibre = nm;
    ScienceFrame->max_lit_fibre = nm;
    ScienceFrame->ind_lit_fibres[0] = nm;
    ScienceFrame->num_lit_fibres = 1;
    for (nm++; nm<=(ScienceFrame->maxfibres-1); nm++) {
      uves_msg_debug("Science FibreMask[%d]=%d Sfifted_FF Fibremask[%d]=%d",
		     nm,ScienceFrame->fibremask[nm],nm,Shifted_FF->fibremask[nm]);
      if (ScienceFrame->fibremask[nm] && Shifted_FF->fibremask[nm]) {
	ScienceFrame->max_lit_fibre=nm;
	ScienceFrame->ind_lit_fibres[ScienceFrame->num_lit_fibres]=nm;
	ScienceFrame->num_lit_fibres++;
	uves_msg_debug("FibreMask[%d]=%d",nm,ScienceFrame->fibremask[nm]);
      } 
    }
  }
  else {
    /* no fibres lit both in the Science Frame and in the FF frames, 
       bail out */
    SCTPUT("No extractable fibres in this frame");
    return flames_midas_fail();
  }

  sprintf(output,"min = %d ; max = %d ; num = %d",
	  ScienceFrame->min_lit_fibre,
	  ScienceFrame->max_lit_fibre, 
	  ScienceFrame->num_lit_fibres);
  SCTPUT(output);
  memset(output, 0, 70);


  /* the following section initialises the overall mask to be used for 
     the extraction and, in the same loop, it checks for adequate coverage of 
     each fibre slice, to avoid ill-posed problems altogether */
  /* clean up the mask first */
  /* I want to use only the pixels which are somewhat covered by some
     at least partially good fibre slice; hence initially mark all pixels
     to be bad in the overall mask, then clean up the ones for which the 
     following conditions hold:
     1) that pixel is good both in the fibre FF frame(s) and in the Science
     frame
     2) that pixel belongs at least to one extractible slice with good 
     enough coverage
  */

  /*
    sprintf(output,"Initializing the mask");
    SCTPUT(output);
  */
  /* the "out of boundaries" value in the mask is 3, it means that the
     pixel is not included in any slice to be extracted */
  kluplimit = (ScienceFrame->subrows*ScienceFrame->subcols)-1;
  fmvecbuf1 = mask[0];
  fmvecbuf2 = Shifted_FF->goodfibres[0][0];
  fmvecbuf3 = ScienceFrame->badpixel[0];
  fdvecbuf1 = normcover[0];
  lvecbuf1 = Shifted_FF->lowfibrebounds[0][0];
  lvecbuf2 = Shifted_FF->highfibrebounds[0][0];
  for (klindex=0; klindex<=kluplimit; klindex++) {
    fmvecbuf1[klindex] = 3;
  }


  /* run the first loop over fibres */
  for (m=0; m<=(ScienceFrame->num_lit_fibres-1); m++) {
    /* run the loop over orders only if appropriate */
    n=ScienceFrame->ind_lit_fibres[m];
    iframe = Shifted_FF->fibre2frame[n];
    fmvecbuf4 = Shifted_FF->flatdata[iframe].badpixel[0];
    fdvecbuf2 = Shifted_FF->flatdata[iframe].data[0];
    if(ScienceFrame->fibremask[n]==TRUE && Shifted_FF->fibremask[n]==TRUE) {
      for (mj=realfirstorder; mj<=reallastorder; mj++) {

	iorder = mj-Order->firstorder;
	iordernindex = (iorder*Shifted_FF->maxfibres)+n;
	iordernloffset = iordernindex*ScienceFrame->subcols;
	iorder2 = iorder-orderoffset;
	iorder2loffset = iorder2*ScienceFrame->subcols;

	/* now run the loop over x */
	for (l=0; l<=(ScienceFrame->subcols-1); l++) {
	  iorder2lindex = iorder2loffset+l;
	  iordernlindex = iordernloffset+l;

	  /* is this slice any good at all? */
	  if (fmvecbuf2[iordernlindex]!=BADSLICE) {
	    /* yes, therefore run the loop over y */
	    ffcoverage=0;

	    for (k=lvecbuf1[iordernlindex]; k<=lvecbuf2[iordernlindex]; k++) {

	      klindex = (k*ScienceFrame->subcols)+l;
	      /* is this pixel good everywhere? */
	      if (fmvecbuf3[klindex]==0 && fmvecbuf4[klindex]==0) {
		/* add its contribution to the fibre coverage factor */


		ffcoverage += fdvecbuf2[klindex];


	      }
	    }


	    /* divide by the normalisation fraction */
	    ffcoverage /= fdvecbuf1[iorder2lindex];
	    /* does the fraction of collected light for this fibre exceed the 
	       threshold making it worth extracting? */
	    if(ffcoverage<Shifted_FF->minfibrefrac) {


	      /* no, forget it and mark this fact where it belongs */
	      fmvecbuf2[iordernlindex]=BADSLICE;
	    }
	    else {


	      /* yes, mark good pixels good in the overall mask */
	      for (k=lvecbuf1[iordernlindex]; 
		   k<=lvecbuf2[iordernlindex]; k++) {
		klindex = (k*ScienceFrame->subcols)+l;
		/* is this pixel good everywhere? */


		if (fmvecbuf3[klindex]==0) {
		  if (fmvecbuf4[klindex]==0) {
		    /* mark it good */
		    fmvecbuf1[klindex] = 0;
		  }
		  else {
		    /* mark it bad from the fibre FF */
		    fmvecbuf1[klindex] = 2;
		  }
		}
		else {
		  /* mark it bad from the ScienceFrame */
		  fmvecbuf1[klindex] = 1;
		}


	      }


	    }


	  }


	}


      }


    }


  }


  /* run the second loop over fibres, to make sure to exclude pixels which 
     are not good in all the slices to be extracted */
  for (m=0; m<=(ScienceFrame->num_lit_fibres-1); m++) {
    /* run the loop over orders only if appropriate */
    n=ScienceFrame->ind_lit_fibres[m];
    iframe = Shifted_FF->fibre2frame[n];
    fmvecbuf4 = Shifted_FF->flatdata[iframe].badpixel[0];
    if(ScienceFrame->fibremask[n]==TRUE && Shifted_FF->fibremask[n]==TRUE) {
      for (mj=realfirstorder; mj<=reallastorder; mj++) {
	iorder = mj-Order->firstorder;
	iordernindex = (iorder*Shifted_FF->maxfibres)+n;
	iordernloffset = iordernindex*ScienceFrame->subcols;
	/* now run the loop over x */
	for (l=0; l<=(ScienceFrame->subcols-1); l++) {
	  iordernlindex = iordernloffset+l;
	  /* is this slice any good at all? */
	  if (fmvecbuf2[iordernlindex]!=BADSLICE) {
	    /* yes, therefore run the loop over y */
	    for (k=lvecbuf1[iordernlindex]; k<=lvecbuf2[iordernlindex]; k++) {
	      klindex = (k*ScienceFrame->subcols)+l;
	      /* is this pixel bad anywhere? */
	      if (fmvecbuf3[klindex]!=0) {
		/* mark it bad from the ScienceFrame */
		fmvecbuf1[klindex] = 1;
	      }
	      if (fmvecbuf4[klindex]!=0) {
		/* mark this pixel as bad in the composite mask */
		fmvecbuf1[klindex]=2;
	      }
	    }
	  }
	}
      }
    }
  }


  alloc_spectrum(ScienceFrame);

  sprintf(output,"firstorder (from ScienceFrame) is %d", 
	  ScienceFrame->firstorder);
  SCTPUT(output);
  memset(output, 0, 70);
  sprintf(output,"lastorder (from ScienceFrame) is %d", 
	  ScienceFrame->lastorder);
  SCTPUT(output);
  memset(output, 0, 70);


  return NOERR;

}
