/* $Id: naco_img_slitpos.c,v 1.60 2010-03-02 15:29:12 llundin Exp $
 *
 * This file is part of the NACO Pipeline
 * Copyright (C) 2002,2003 European Southern Observatory
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA
 */

/*
 * $Author: llundin $
 * $Date: 2010-03-02 15:29:12 $
 * $Revision: 1.60 $
 * $Name: not supported by cvs2svn $
 */

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

/*-----------------------------------------------------------------------------
                                Includes
 -----------------------------------------------------------------------------*/

#include "naco_recipe.h"
#include "irplib_slitpos.h"

/*-----------------------------------------------------------------------------
                            Recipe defines
 -----------------------------------------------------------------------------*/

#define RECIPE_STRING  "naco_img_slitpos"

/*-----------------------------------------------------------------------------
                            Private Functions prototypes
 -----------------------------------------------------------------------------*/

static cpl_error_code naco_img_slitpos_qc(cpl_propertylist *,
                                          cpl_propertylist *,
                                          const irplib_framelist *);

static cpl_error_code naco_img_slitpos_save(cpl_frameset *,
                                            const cpl_parameterlist *,
                                            const cpl_propertylist *,
                                            const cpl_propertylist *,
                                            const cpl_table *, int,
                                            const irplib_framelist *);

NACO_RECIPE_DEFINE(naco_img_slitpos, NACO_PARAM_SLIT_W,
                   "Slit Position recipe",
                   RECIPE_STRING " -- NACO imaging slit position recipe.\n"          
                   "The Set Of Frames (sof-file) must specify at least one file "
                   "which must be tagged\n"                                     
                   "raw-file.fits " NACO_IMG_SLITPOS_RAW "\n"
                   "\n"
                   "Each image is flipped around the x=y axis before the "
                   "analysis.");

/*----------------------------------------------------------------------------*/
/**
 * @defgroup naco_img_slitpos   Slit Position
 */
/*----------------------------------------------------------------------------*/

/*-----------------------------------------------------------------------------
                                Functions code
 -----------------------------------------------------------------------------*/


/*----------------------------------------------------------------------------*/
/**
  @brief    The recipe data reduction part is implemented here 
  @param    framelist   the frames list
  @param    parlist     the parameters list
  @return   0 iff everything is ok
 */
/*----------------------------------------------------------------------------*/
static int naco_img_slitpos(cpl_frameset            * framelist,
                            const cpl_parameterlist * parlist)
{
    irplib_framelist* allframes = NULL;
    irplib_framelist* rawframes = NULL;
    irplib_framelist* oneframe  = NULL;
    cpl_frame       * frame     = NULL;
    cpl_image       * image     = NULL;
    cpl_table       * out_table = NULL;
    cpl_propertylist* qclist    = cpl_propertylist_new();
    cpl_propertylist* paflist   = cpl_propertylist_new();

    int               slit_width;
    int               nframes;
    int               i;


    slit_width = naco_parameterlist_get_int(parlist, RECIPE_STRING,
                                            NACO_PARAM_SLIT_W);
    bug_if(0);

    /* Identify the RAW and CALIB frames in the input frameset */
    skip_if (naco_dfs_set_groups(framelist));

    allframes = irplib_framelist_cast(framelist);
    bug_if(allframes == NULL);

    irplib_check(rawframes
                 = irplib_framelist_extract(allframes, NACO_IMG_SLITPOS_RAW),
                 "Could not load the raw frames");
    irplib_framelist_empty(allframes);

    nframes = irplib_framelist_get_size(rawframes);

    oneframe = irplib_framelist_new();

    /* Reduce each frame separately */
    for (i=0 ; i < nframes ; i++) {
        const char * name;
        int          slit_length;
        double       xpos, ypos, angle;
        double       slit_y0, slit_yn;
        double       slit_c0, slit_cn;

        /* Slit analysis */
        cpl_msg_info(cpl_func, "Analysing slit of frame %d out of %d", i+1,
                     nframes);

        frame = irplib_framelist_unset(rawframes, 0, NULL);
        bug_if(irplib_framelist_set(oneframe, frame, 0));

        name = cpl_frame_get_filename(frame);
        frame = NULL;
        bug_if(name == NULL);

        irplib_check(image = cpl_image_load(name, CPL_TYPE_FLOAT, 0, 0),
                     "Could not load FITS-image");

        bug_if(cpl_image_flip(image, 1));

        out_table = irplib_slitpos_analysis(image, slit_width, NULL);
        cpl_image_delete(image);
        image = NULL;
        skip_if (out_table == NULL);

        /* THE SLIT LENGTH */
        /* Find the slit angle in degrees with the horizontal axis   */
        slit_length = cpl_table_get_nrow(out_table);

        slit_y0 = cpl_table_get(out_table, "SLIT_Y", 0,             NULL);
        slit_yn = cpl_table_get(out_table, "SLIT_Y", slit_length-1, NULL);
        bug_if(0);

        slit_c0 = cpl_table_get(out_table, "SLIT_CENTER", 0,             NULL);
        slit_cn = cpl_table_get(out_table, "SLIT_CENTER", slit_length-1, NULL);
        bug_if(0);

        /* THE ANGLE: 180 degrees for a perfectly aligned slit */
        angle = 180.0 + CPL_MATH_DEG_RAD * atan2(slit_cn - slit_c0,
                                                    slit_yn - slit_y0);

        /* THE SLIT CENTER POSITION */
        ypos = (slit_c0 + slit_cn)/2.0;
        xpos = (slit_y0 + slit_yn)/2.0;
        
        /* Print the results */
        cpl_msg_info(cpl_func, "Slit angle  : %g", angle);
        cpl_msg_info(cpl_func, "Slit length : %d", slit_length);
        cpl_msg_info(cpl_func, "Slit center : %g %g", xpos, ypos);

        skip_if(irplib_framelist_load_propertylist_all(oneframe, 0, "^("
                                                       NACO_PFITS_REGEXP_SLITPOS "|"
                                                       NACO_PFITS_REGEXP_SLITPOS_PAF
                                                       ")$", CPL_FALSE));

        /* Add QC parameters */
        bug_if(cpl_propertylist_append_double(qclist, "ESO QC SLIT POSANG",
                                               angle));
        bug_if(cpl_propertylist_append_double(qclist, "ESO QC SLIT XPOS",
                                               xpos));
        bug_if(cpl_propertylist_append_double(qclist, "ESO QC SLIT YPOS",
                                               ypos));

        skip_if (naco_img_slitpos_qc(qclist, paflist, oneframe));

        /* PRO.CATG */
        bug_if (cpl_propertylist_append_string(paflist, CPL_DFS_PRO_CATG,
                                               NACO_IMG_SLITPOS_RES));

        skip_if (naco_img_slitpos_save(framelist, parlist, qclist, paflist,
                                       out_table, i+1, oneframe));

        cpl_table_delete(out_table);
        out_table = NULL;

        cpl_propertylist_empty(qclist);
        cpl_propertylist_empty(paflist);

        /* Empty the list - and deallocate the propertylists */
        irplib_framelist_empty(oneframe);

        bug_if(irplib_framelist_get_size(oneframe) != 0);

    }

    bug_if(irplib_framelist_get_size(rawframes) != 0);

    end_skip;

    cpl_image_delete(image);
    cpl_table_delete(out_table);

    irplib_framelist_delete(oneframe);
    irplib_framelist_delete(allframes);
    irplib_framelist_delete(rawframes);
    cpl_propertylist_delete(qclist);
    cpl_propertylist_delete(paflist);

    cpl_frame_delete(frame);

    return cpl_error_get_code();
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Append the QC parameters to the propertylist
  @param    qclist    List of QC parameters
  @param    paflist   List of PAF parameters
  @param    rawframes List of rawframes and their propertylists
  @return   0 iff everything is ok
 */
/*----------------------------------------------------------------------------*/
static cpl_error_code naco_img_slitpos_qc(cpl_propertylist       * qclist,
                                          cpl_propertylist       * paflist,
                                          const irplib_framelist * rawframes)
{

    cpl_errorstate cleanstate = cpl_errorstate_get();
    const cpl_propertylist * reflist
        = irplib_framelist_get_propertylist_const(rawframes, 0);
    const char               pafcopy[] = "^(" NACO_PFITS_REGEXP_SLITPOS_PAF ")$";
    const char             * filter;


    bug_if (0);

    filter = naco_pfits_get_filter(reflist);
    if (cpl_error_get_code())
        naco_error_reset("Could not get FITS key:");
    else
        bug_if(cpl_propertylist_append_string(qclist, "ESO QC FILTER OBS",
                                              filter));

    /* THE PAF FILE FOR QC PARAMETERS */

    /* Get the QC params in qclist and keys for paf in paflist */
    bug_if(cpl_propertylist_copy_property_regexp(paflist, reflist, pafcopy, 0));

    bug_if(cpl_propertylist_append(paflist, qclist));


    end_skip;

    return cpl_error_get_code();
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Save the product of the recipe
  @param    set         the input frame set
  @param    parlist     the input list of parameters
  @param    qclist      List of QC parameters
  @param    paflist     List of PAF parameters
  @param    out_table   the table with the slit position
  @param    file_nb     file number
  @param    oneframe    The list of one reduced frame
  @return   0 iff everything is ok
 */
/*----------------------------------------------------------------------------*/
static cpl_error_code naco_img_slitpos_save(cpl_frameset            * set,
                                            const cpl_parameterlist * parlist,
                                            const cpl_propertylist  * qclist,
                                            const cpl_propertylist  * paflist,
                                            const cpl_table         * out_table,
                                            int                       file_nb,
                                            const irplib_framelist  * oneframe)
{

    cpl_frameset * rawframes = irplib_frameset_cast(oneframe);
    char         * filename  = NULL;


    bug_if (0);

    /* Write the FITS file */
    filename = cpl_sprintf(RECIPE_STRING "_%02d" CPL_DFS_FITS, file_nb);
    skip_if (irplib_dfs_save_table(set, parlist, rawframes, out_table, NULL,
                               RECIPE_STRING, NACO_IMG_SLITPOS_RES, qclist, NULL,
                               naco_pipe_id, filename));

    cpl_free(filename);
    filename = cpl_sprintf(RECIPE_STRING "_%02d" CPL_DFS_PAF, file_nb);
    skip_if (cpl_dfs_save_paf("NACO", RECIPE_STRING, paflist, filename));

    end_skip;

    cpl_free(filename);
    cpl_frameset_delete(rawframes);

    return cpl_error_get_code();
}
