/*===========================================================================
  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");
            free(myflats);
            free(framebuffer);
            free(ordpos);
            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;
    		ifibre<=(ordpos->maxfibres-1) && ordpos->fibremask[ifibre]==FALSE;
                    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();

}
/**@}*/
