/*===========================================================================
  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_fastprepfibreff
 *
 */
/*---------------------------------------------------------------------------
  Includes
  --------------------------------------------------------------------------*/
/**
   @name  flames_fastprepfibreff()  
   @short  This function prepare aframe 
   @author G. Mulas  -  ITAL_FLAMES Consortium. Ported to CPL by A. Modigliani


   @param  INFIBREFFCAT
   @param  OUTFIBREFFCAT
   @param  MYORDER
   @param  BASENAME
   @param  BACKTABLE
   @param  MAXDISCARDFRACT
   @param  MAXBACKITERS
   @param  FRACSLICESTHRES
   @param  BKGPOL
   @param  BKGFITMETHOD
   @param  BKGBADSCAN
   @param  BKGBADWIN
   @param  BKGBADMAXFRAC
   @param  BKGBADMAXTOT
   @param  SIGMA
   @param  MINFIBREFRAC
   @param  OUTPUTI

   @return success or failure code, 


   DRS Functions called:          
   none
 
                                                                         
   Pseudocode:                                                             
 

   @note
*/



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

#include <flames_writeallff.h>
#include <flames_midas_def.h>
#include <flames_readframe.h>
#include <flames_frame2flat.h>
#include <flames_freeordpos.h>
#include <flames_freeframe2.h>
#include <flames_stripfitsext.h>
#include <flames_freeallflats.h>
#include <flames_uves.h>
#include <flames_fastfillholes.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <flames_readordpos.h>
#include <flames_allocallflats2.h>


/* Here goes the main() */
int 
flames_fastprepfibreff(
		       const cpl_frameset *INFIBREFFCAT,
		       cpl_frameset **OUTFIBREFFCAT,
		       const char *MYORDER,
		       const char *BASENAME,
		       const char *BACKTABLE,
		       const double *MAXDISCARDFRACT,
		       const int *MAXBACKITERS,
		       const double *FRACSLICESTHRES,
		       const int *BKGPOL,
		       const char *BKGFITMETHOD,
		       const char *BKGBADSCAN,
		       const int *BKGBADWIN,
		       const double *BKGBADMAXFRAC,
		       const int *BKGBADMAXTOT,
		       const double *SIGMA,
		       const double *MINFIBREFRAC,
		       int *OUTPUTI)
{
  char output[CATREC_LEN+1];
  int tid=0;
  int actvals=0;
  int unit=0;
  int null=0;
  int entrynum=0;
  int i=0;
  int maxbackiters=0;
  double maxdiscardfract=0;
  const cpl_frameset *catname;
  cpl_frameset **outcatname; 
  char backname[CATREC_LEN+1];
  char filename[CATREC_LEN+5];
  char basename[CATREC_LEN+1]; 
  char ordername[CATREC_LEN+1]; 
  char identifier[CATREC_LEN+1];
  int bxdegree=0, bydegree=0;
  double kappa=0;
  double kappa2=0;
  scatterswitch bkgswitch=USEALL;
  scatterswitch2 bkgswitch2=NOBADSCAN;
  int badwinxsize=0;
  int badwinysize=0;
  double badfracthres=0;
  int badtotthres=0;
  char keytype=0;
  int nval=0;
  int noelem=0;
  int bytelem=0;
  int32_t ifibre=0;
  double fracslicesthres=0;
  char bkgfitmethod[CATREC_LEN+1];
  int32_t firstifibre=0;
  int32_t lastifibre=0;
  double newcentre=0;
  allflats *myflats=0;
  flames_frame *framebuffer=0;
  orderpos *ordpos=0;

  memset(output, 0, CATREC_LEN+1);
  //memset(catname, 0, CATREC_LEN+1);
  //memset(outcatname, 0, CATREC_LEN+1);
  memset(backname, 0, CATREC_LEN+1);
  memset(filename, 0, CATREC_LEN+5);
  memset(basename, 0, CATREC_LEN+1);
  memset(ordername, 0, CATREC_LEN+1);
  memset(identifier, 0, CATREC_LEN+1);
  memset(bkgfitmethod, 0, CATREC_LEN+1);

  bkgswitch = USEALL;

  /* allocate pointers */
  myflats = (allflats *) calloc(1, sizeof(allflats));
  framebuffer = calloc(1, sizeof(flames_frame));
  ordpos = (orderpos *) calloc(1, sizeof(orderpos));

  /* enter the MIDAS environment */
  SCSPRO("fastprepfibreff");

  //Not needed as passed in interface the cpl_framest*
  /* read the INFIBREFFCAT keyword to know the name of the catalog file
     containing the list of input fibre FF frames */
  if (SCKGETC_fs(INFIBREFFCAT, 1, CATREC_LEN, &actvals, &catname) != 0) {
    /* the keyword seems undefined, protest... */
     free(myflats);
     free(framebuffer);
     free(ordpos);
     return flames_midas_fail();
  }

  //Not needed as passed in interface the cpl_framest*
  /* read the OUTFIBREFFCAT keyword to know the name of the catalog file
     containing the list of output fibre FF frames */
  if (SCKGETC_fsp(OUTFIBREFFCAT, 1, CATREC_LEN, &actvals, &outcatname) != 0) {
    /* the keyword seems undefined, protest... */
     free(myflats);
     free(framebuffer);
     free(ordpos);
    return flames_midas_fail();
  }

  /* read the MYORDER keyword to know the name of the order table */
  if (SCKGETC(MYORDER, 1, CATREC_LEN, &actvals, ordername)!= 0) {
    /* the keyword seems undefined, protest... */
     free(myflats);
     free(framebuffer);
     free(ordpos);
    return flames_midas_fail();
  }

  /* read the BASENAME keyword to know the base file name of the newly
     produced FF frames */
  if (SCKGETC(BASENAME, 1, CATREC_LEN, &actvals, filename) != 0) {
    /* the keyword seems undefined, protest... */
     free(myflats);
     free(framebuffer);
     free(ordpos);
    return flames_midas_fail();
  }
  /* strip filename of the .fits extension, if it has one */
  if (stripfitsext(filename, basename) != NOERR) {
    /* error stripping extension */
     free(myflats);
     free(framebuffer);
     free(ordpos);
    return flames_midas_fail();
  }

  /* read the BACKTABLE keyword to know the name of background table file */
  if (SCKGETC(BACKTABLE, 1, CATREC_LEN, &actvals, backname) != 0) {
    /* the keyword seems undefined, protest... */
     free(myflats);
     free(framebuffer);
     free(ordpos);
    return flames_midas_fail();
  }
  /* initialise MAXDISCARDFRACT from keyword */
  if (SCKRDD(MAXDISCARDFRACT, 1, 1, &actvals, &maxdiscardfract, &unit, 
	     &null) != 0) {
    /* problems reading MAXDISCARDFRACT */
    SCTPUT("Error reading the MAXDISCARDFRACT keyword");
     free(myflats);
     free(framebuffer);
     free(ordpos);
    return flames_midas_fail();
  }
  /* initialise MAXBACKITERS from keyword */
  if (SCKRDI(MAXBACKITERS, 1, 1, &actvals, &maxbackiters, &unit, 
	     &null) != 0) {
    /* problems reading MAXBACKITERS */
    SCTPUT("Error reading the MAXBACKITERS keyword");
     free(myflats);
     free(framebuffer);
     free(ordpos);
    return flames_midas_fail();
  }
  /* initialise FRACSLICESTHRES from keyword */
  if (SCKRDD(FRACSLICESTHRES, 1, 1, &actvals, &fracslicesthres, &unit, 
	     &null) != 0) {
    /* problems reading FRACSLICESTHRES */
    SCTPUT("Error reading the FRACSLICESTHRES keyword");
     free(myflats);
     free(framebuffer);
     free(ordpos);
    return flames_midas_fail();
  }
  /* initialise background fitting scalars */
  if (SCKRDI(BKGPOL, 1, 1, &actvals, &bxdegree, &unit, &null) 
      != 0) {
    /* problems reading xdegree */
    SCTPUT("Error reading the x degree of the background polynomial");
     free(myflats);
     free(framebuffer);
     free(ordpos);
    return flames_midas_fail();
  }
  if (SCKRDI(BKGPOL, 2, 1, &actvals, &bydegree, &unit, &null) 
      != 0) {
    /* problems reading xdegree */
    SCTPUT("Error reading the y degree of the background polynomial");
     free(myflats);
     free(framebuffer);
     free(ordpos);
    return flames_midas_fail();
  }
  /* before trying to read it, make sure that BKGFITMETHOD exists and it is
     of the appropriate type */
  if (SCKFND_string(BKGFITMETHOD, &keytype, &noelem, &bytelem) != 0) {
    /* SCKFND failed, give up! */
    SCTPUT("Internal MIDAS error in prepfibreff: SCKFND failed");
     free(myflats);
     free(framebuffer);
     free(ordpos);
    return flames_midas_fail();
  }
  switch(keytype) {
  case 'C':
    /* it exists and it is a character keyword, go ahead and read it */
    if (SCKGETC(BKGFITMETHOD, 1, CATREC_LEN, &nval, bkgfitmethod) 
	!= 0) {
      /* problems reading BKGFITMETHOD */
      SCTPUT("Warning: error reading the BKGFITMETHOD keyword, falling back to \
default");
    }
    else {
      /* is the string long enough to be unambiguous? */
      if (nval<2) {
	/* no, fall back to the default */
	SCTPUT("Warning: BKGFITMETHOD is ambiguous, falling back to default");
      }
      else {
	/* convert bkgfitmethod to upper case, to ease the subsequent check */
	for (i=0; i<=(nval-1); i++) bkgfitmethod[i] = toupper(bkgfitmethod[i]);
	/* compare as many letters as we have with the expected values */
	if (strncmp("ALL", bkgfitmethod, (size_t) nval) == 0)
	  bkgswitch = USEALL;
	else if (strncmp("MEDIAN", bkgfitmethod, (size_t) nval)
		 == 0) bkgswitch = USEMEDIAN;
	else if (strncmp("MINIMUM", bkgfitmethod, (size_t) nval)
		 == 0) bkgswitch = USEMINIMUM;
	else if (strncmp("AVERAGE", bkgfitmethod, (size_t) nval)
		 == 0) bkgswitch = USEAVERAGE;
	else {
	  SCTPUT("Warning: unsupported BKGFITMETHOD value, falling back to \
default");
	}
      }
    }
    break;
  case ' ':
    /* the keyword does not exist at all */
    SCTPUT("Warning: BKGFITMETHOD is undefined, falling back to default");
    break;
  default:
    /* the keyword is of the wrong type */
    SCTPUT("Warning: BKGFITMETHOD is not a string, falling back to default");
    break;
  }

  /* before trying to read it, make sure that BKGFITMETHOD exists and it is
     of the appropriate type */
  if (SCKFND_string(BKGBADSCAN, &keytype, &noelem, &bytelem) != 0) {
    /* SCKFND failed, give up! */
    SCTPUT("Internal MIDAS error in mainopt: SCKFND failed");
    free(myflats);
    free(framebuffer);
    free(ordpos);
    return flames_midas_fail();
  }
  switch(keytype) {
  case 'C':
    /* it exists and it is a character keyword, go ahead and read it */
    if (SCKGETC(BKGBADSCAN, 1, CATREC_LEN, &nval, bkgfitmethod) 
	!= 0) {
      /* problems reading BKGFITMETHOD */
      SCTPUT("Warning: error reading the BKGBADSCAN keyword, falling back to \
default");
    }
    else {
      /* is the string long enough to be unambiguous? */
      if (nval<1) {
	/* no, fall back to the default */
	SCTPUT("Warning: BKGBADSCAN is ambiguous, falling back to default");
      }
      else {
	/* convert bkgfitmethod to upper case, to ease the subsequent check */
	for (i=0; i<=(nval-1); i++) bkgfitmethod[i] = toupper(bkgfitmethod[i]);
	/* compare as many letters as we have with the expected values */
	if (strncmp("NONE", bkgfitmethod, (size_t) nval) == 0)
	  bkgswitch2 = NOBADSCAN;
	else if (strncmp("FRACTION", bkgfitmethod, (size_t) nval)
		 == 0) bkgswitch2 = FRACBADSCAN;
	else if (strncmp("ABSOLUTE", bkgfitmethod, (size_t) nval)
		 == 0) bkgswitch2 = ABSBADSCAN;
	else {
	  SCTPUT("Warning: unsupported BKGBADSCAN value, falling back to \
default");
	}
      }
    }
    break;
  case ' ':
    /* the keyword does not exist at all */
    SCTPUT("Warning: BKGBADSCAN is undefined, falling back to default");
    break;
  default:
    /* the keyword is of the wrong type */
    SCTPUT("Warning: BKGBADSCAN is not a string, falling back to default");
    break;
  }

  /* if neighborhood bad pixel scanning was requested, read the other 
     keywords needed */
  if (bkgswitch2 == FRACBADSCAN) {
    if ((SCKRDI(BKGBADWIN, 1, 1, &actvals, &badwinxsize, &unit, &null) != 0)
	|| (SCKRDI(BKGBADWIN, 2, 1, &actvals, &badwinysize, &unit, &null) 
	    != 0)) {
      SCTPUT("Error reading the BKGBADWIN keyword");
      free(myflats);
      free(framebuffer);
      free(ordpos);
      return flames_midas_fail();
    }
    if (SCKRDD(BKGBADMAXFRAC, 1, 1, &actvals, &badfracthres, &unit, 
	       &null) != 0) {
      SCTPUT("Error reading the BKGBADMAXFRAC keyword");
      free(myflats);
      free(framebuffer);
      free(ordpos);
      return flames_midas_fail();
    }
    /* check the values read for consistence */
    if ((badwinxsize < 0) || (badwinysize < 0)) {
      SCTPUT("Warning: BKGBADWIN values must be non negative, disabling \
BKGBADSCAN");
      bkgswitch2 = NOBADSCAN;
    }
    if (badfracthres < 0) {
      SCTPUT("Warning: BKGBADMAXFRAC value must be non negative, disabling \
BKGBADSCAN");
      bkgswitch2 = NOBADSCAN;
    }
  }
  else if (bkgswitch2 == ABSBADSCAN) {
    if ((SCKRDI(BKGBADWIN, 1, 1, &actvals, &badwinxsize, &unit, &null) != 0)
	|| (SCKRDI(BKGBADWIN, 2, 1, &actvals, &badwinysize, &unit, &null) 
	    != 0)) {
      SCTPUT("Error reading the BKGBADWIN keyword");
      return flames_midas_fail();
    }
    if (SCKRDI(BKGBADMAXTOT, 1, 1, &actvals, &badtotthres, &unit, 
	       &null) != 0) {
      SCTPUT("Error reading the BKGBADMAXTOT keyword");
      return flames_midas_fail();
    }
    /* check the values read for consistence */
    if ((badwinxsize < 0) || (badwinysize < 0)) {
      SCTPUT("Warning: BKGBADWIN values must be non negative, disabling \
BKGBADSCAN");
      bkgswitch2 = NOBADSCAN;
    }
    if (badtotthres < 0) {
      SCTPUT("Warning: BKGBADMAXTOT value must be non negative, disabling \
BKGBADSCAN");
      bkgswitch2 = NOBADSCAN;
    }
  }

  /* read the kappa factor to be used later in kappa-sigma clipping */
  if (SCKRDD(SIGMA, 1, 1, &actvals, &kappa, &unit, &null)!=0) {
    /* something went wrong while reading the kappa-sigma factor */
    SCTPUT("Error while reading SIGMA keyword");
    return flames_midas_fail();
  }
  /* compute once and for all the square of kappa, as we will be using that */
  kappa2 = kappa*kappa;

  /* first open the catalog and count the FF frames present */
  myflats->nflats = 0;
  entrynum = 0;
  do {
    if (SCCGET(catname, 0 , filename, identifier, &entrynum) != 0) {
      /* error getting catalog entry */
      return flames_midas_fail();
    }
    /* did I get a valid catalog entry? */
    if (filename[0] != ' ') {
      myflats->nflats++;
    }
  } while (filename[0] != ' ');

  /* check that nflats>0, otherwise, well... */
  if (myflats->nflats == 0) {
    return flames_midas_fail();
  }

  /* read the first frame */
  entrynum = 0;
  if (SCCGET(catname, 0 , filename, identifier, &entrynum) != 0) {
    /* error getting catalog entry */
    return flames_midas_fail();
  }
  if (readframe(framebuffer, filename) != NOERR) {
    /* error reading frame */
    return flames_midas_fail();
  }
  /* copy some scalars from framebuffer to myflats */
  myflats->subrows = framebuffer->subrows;
  myflats->subcols = framebuffer->subcols;
  myflats->maxfibres = framebuffer->maxfibres;
  myflats->substartx = framebuffer->substartx;
  myflats->substarty = framebuffer->substarty;
  myflats->substepx = framebuffer->substepx;
  myflats->substepy = framebuffer->substepy;
  myflats->chipchoice = framebuffer->chipchoice;
  myflats->ron = framebuffer->ron;
  myflats->gain = framebuffer->gain;

  /* read in ordpos, in order to fill in the last scalars in myflats */
  /* initialise the ordpos structure from the dummy table descriptors */
  if(readordpos(ordername, ordpos) != NOERR) {
    /* something went wrong in the initialisation */
    return flames_midas_fail();
  }

  /* check whether frames and order chip choices match */
  if (ordpos->chipchoice != myflats->chipchoice) {
    /* no, they don't match */
    SCTPUT("Error: chip mismatch between frames and order table");
    return flames_midas_fail();
  }

  /* is this an already corrected order table? */
  if (ordpos->corrected == 't') {
    /* yes, it is, and it must not! */
    SCTPUT("Error: this procedure must use an uncorrected order table");
    return flames_midas_fail();
  }
  else if (ordpos->corrected != 'f') {
    /* meaningless value of the corrected flag */
    SCTPUT("Error: the CORRECTED descriptor must be either t or f");
    return flames_midas_fail();
  }

  /* initialise scalars in myflats from values in ordpos */
  myflats->halfibrewidth = ordpos->halfibrewidth;
  myflats->firstorder = ordpos->firstorder;
  myflats->lastorder = ordpos->lastorder;
  myflats->tab_io_oshift = ordpos->tab_io_oshift;
  myflats->shiftable = 'n';
  myflats->normalised = 'n';

  /* allocate some internal arrays of myflats */
  if (allocallflats2(myflats) != NOERR) {
    /* error allocating myflats arrays */
    return flames_midas_fail();
  }
  /* copy pointers from framebuffer to first myflats single flat frame */
  if (frame2flat(framebuffer, myflats, 0) != NOERR) {
    /* error copying data */
    return flames_midas_fail();
  }
  /* free unused arrays in framebuffer, so that it can be reused */
  if (freeframe2(framebuffer) != NOERR) {
    /* error freing memory */
    return flames_midas_fail();
  }

  /* now run a loop to fetch the other FF frames */
  for (entrynum=1; entrynum<=myflats->nflats-1; entrynum++) {
    i = entrynum;
    /* get filename */
    if (SCCGET(catname, 0 , filename, identifier, &i) != 0) {
      /* error getting catalog entry */
      return flames_midas_fail();
    }
    /* read frame */
    if (readframe(framebuffer, filename) != NOERR) {
      /* error reading frame */
      return flames_midas_fail();
    }
    /* copy pointers and data from framebuffer to first myflats single flat 
       frame */
    if (frame2flat(framebuffer, myflats, entrynum) != NOERR) {
      /* error copying data */
      return flames_midas_fail() ;
    }
    /* free unused arrays in framebuffer, so that it can be reused */
    if (freeframe2(framebuffer) != NOERR) {
      /* error freing memory */
      return flames_midas_fail();
    }
  }

  /* as last touch, initialise scalars taken from MIDAS context */
  if (SCKRDD(MINFIBREFRAC, 1, 1, &actvals, &myflats->minfibrefrac, 
	     &unit, &null) != 0) {
    /* problems getting value from MINFIBREFRAC keyword */
    return flames_midas_fail();
  }

  /* everything ready, finally do our job: fill those darn holes */
  if (fastfillholes(myflats, ordpos, backname, bxdegree, 
		    bydegree, bkgswitch, bkgswitch2, badwinxsize, 
		    badwinysize, badfracthres, badtotthres, kappa2, 
		    (int32_t) maxbackiters, maxdiscardfract,
		    fracslicesthres, OUTPUTI)!= NOERR) {
    /* problems filling holes */
    return flames_midas_fail();
  }

  /* write the self-shift corrections to disk, as descriptors of the order
     table */
  if (TCTOPN(ordername, F_D_MODE, &tid)!= 0) {
    /* I could not open the input order table: protest... */
    sprintf(output, "Error: I couldn't open the %s table\n", ordername);
    SCTPUT(output);
    return flames_midas_fail();   
  }
  /* Find the first and last fibre which were left standing */
  for (ifibre=0; 
       ordpos->fibremask[ifibre]==FALSE && ifibre<=(ordpos->maxfibres-1);
       ifibre++);
  if (ordpos->fibremask[ifibre]==FALSE) {
    /* ouch, no fibre was left standing, bail out */
    SCTPUT("Error: no fibre with adequate coverage is left!");
    return flames_midas_fail();
  }
  firstifibre = lastifibre = ifibre;
  for (ifibre++; ifibre<=(ordpos->maxfibres-1); ifibre++) {
    if (ordpos->fibremask[ifibre]==TRUE) lastifibre = ifibre;
  }
  /* compute the order centre between the first and last lit fibre */
  newcentre = (ordpos->fibrepos[firstifibre]+ordpos->fibrepos[lastifibre])/2;
  /* move the order position and related data accordingly */
  ordpos->orderpol[0][0] += newcentre;
  ordpos->tab_io_yshift += newcentre;
  /* move the fibre positions in the opposite direction, so that the sum 
     does not change, of course */
  for (ifibre=0; ifibre<=(ordpos->maxfibres-1); ifibre++) {
    ordpos->fibrepos[ifibre] -= newcentre;
  }
  /* write this stuff appropriately to the order table */
  if (SCDWRI(tid, "FIBREMASK", ordpos->fibremask, 1, 
	     ordpos->maxfibres, &unit) != 0) {
    sprintf (output, "Error writing FIBREMASK descriptor in %s table", 
	     ordername);
    SCTPUT(output);
    return flames_midas_fail();
  }
  if (SCDWRD(tid, "FIBREPOS", ordpos->fibrepos, 1, ordpos->maxfibres, 
	     &unit)!=0) {
    sprintf (output, "Error writing FIBREPOS descriptor in %s table", 
	     ordername);
    SCTPUT(output);
    return flames_midas_fail();
  }
  if (SCDWRD(tid, "COEFFD", ordpos->orderpol[0], 1, 1, &unit)!=0) {
    sprintf (output, "Error writing COEFFD descriptor in %s table", 
	     ordername);
    SCTPUT(output);
    return flames_midas_fail();
  }
  if (SCDWRD(tid, "TAB_IN_OUT_YSHIFT", &ordpos->tab_io_yshift, 1, 1, 
	     &unit)!=0) {
    sprintf (output, "Error writing TAB_IN_OUT_YSHIFT descriptor in %s table", 
	     ordername);
    SCTPUT(output);
    return flames_midas_fail();
  }
  /* we can close the table now */
  if (TCTCLO(tid)!=0) {
    /* I could not close the order table: protest... */
    sprintf(output, "Error: I couldn't close the %s table\n", ordername);
    SCTPUT(output);
    return flames_midas_fail();   
  }


  /* dump myflats with filled holes to disk */
  if (writeallff(myflats, basename, OUTFIBREFFCAT) != NOERR) {
    /* error writing myflats to disk */
    return flames_midas_fail();
  }

  /* time to free memory */
  /* free the internal arrays of myflats */
  if (freeallflats(myflats) != NOERR) {
    /* error freeing myflats arrays */
    return flames_midas_fail();
  }
  /* free myflats itself */
  free(myflats);
  /* the pointers to the internal arrays of framebuffer were moved to
     myflats, and therefore have been freed already; I only need to 
     free framebuffer itself */
  free(framebuffer);
  /* free the internal members of ordpos */
  if (freeordpos(ordpos) != NOERR) {
    /* error freeing ordpos arrays */
    return flames_midas_fail();
  }
  /* free ordpos itself */
  free(ordpos);

  /* it's over, exit MIDAS and return*/
  return SCSEPI();

}
/**@}*/
