/* 
 * This file is part of the KMOS 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

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

#include <string.h>

#include <cpl.h>

#include "kmo_utils.h"
#include "kmo_dfs.h"
#include "kmo_error.h"
#include "kmo_priv_fits_check.h"
#include "kmo_constants.h"
#include "kmo_debug.h"

static int kmo_fits_check_create(cpl_plugin *);
static int kmo_fits_check_exec(cpl_plugin *);
static int kmo_fits_check_destroy(cpl_plugin *);
static int kmo_fits_check(cpl_parameterlist *, cpl_frameset *);


static char kmo_fits_check_description[] =
"Recipe to print information on FITS files, contained data/noise values or\n"
"header keywords of all extensions of a fits file, preferably a KMOS fits-file\n"
"(RAW, F1I, F2I, F3I, F2D etc.). This recipe is intended for debugging purposes\n"
"only.\n"
"By default a short summary is printed.\n"
"The following data types of keywords are recognized: bool, char, double, float,\n"
"int, long, string\n"
"As input one fits-file is accepted, no output frame is generated.\n"
"\n"
"BASIC PARAMETERS:\n"
"-----------------\n"
"--h\n"
"With this parameter just the header keywords are printed:\n"
"  –1  prints the primary header and the headers of all the extensions\n"
"   0  prints just the primary header\n"
"   1  prints the header of the first extension etc.\n"
"\n"
"--d\n"
"With this parameter just the data (or depending on the extension: noise) is\n"
"printed:\n"
"  –1 prints the primary header and the headers of all the extensions\n"
"   0 prints data of the primary header which is empty for KMOS FITS frames\n"
"   1 prints the data/noise of the first extension etc.\n"
"This parameter should only be used with very small datasets, otherwise the\n"
"screen will be flooded with numbers.\n"
"\n"
"-------------------------------------------------------------------------------\n"
"  Input files:\n"
"\n"
"   DO                    KMOS                                                  \n"
"   category              Type   Explanation                    Required #Frames\n"
"   --------              -----  -----------                    -------- -------\n"
"   <none or any>         <any>  Any FITS file                      Y       1   \n"
"\n"
"  Output files:\n"
"\n"
"   DO                    KMOS\n"
"   category              Type   Explanation\n"
"   --------              -----  -----------\n"
"   <none>                <none> No output frames generated, only text output   \n"
"-------------------------------------------------------------------------------\n"
"\n";

/**
 * @defgroup kmo_fits_check kmo_fits_check Check contents of KMOS-fits-files.
 *
 * See recipe description for details.
 */

/**
  @brief    Build the list of available plugins, for this module. 
  @param    list    the plugin list
  @return   0 if everything is ok, -1 otherwise

  Create the recipe instance and make it available to the application using the 
  interface. This function is exported.
*/
int cpl_plugin_get_info(cpl_pluginlist *list)
{
    cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
    cpl_plugin *plugin = &recipe->interface;

    cpl_plugin_init(plugin,
                        CPL_PLUGIN_API,
                        KMOS_BINARY_VERSION,
                        CPL_PLUGIN_TYPE_RECIPE,
                        "kmo_fits_check",
                        "Check contents of a KMOS fits-file",
                        kmo_fits_check_description,
                        "Alex Agudo Berbel",
                        "usd-help@eso.org",
                        kmos_get_license(),
                        kmo_fits_check_create,
                        kmo_fits_check_exec,
                        kmo_fits_check_destroy);

    cpl_pluginlist_append(list, plugin);

    return 0;
}

/**
  @brief    Setup the recipe options    
  @param    plugin  the plugin
  @return   0 if everything is ok

  Defining the command-line/configuration parameters for the recipe.
*/
static int kmo_fits_check_create(cpl_plugin *plugin)
{
    cpl_recipe *recipe;
    cpl_parameter *p;

    /* Check that the plugin is part of a valid recipe */
    if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
        recipe = (cpl_recipe *)plugin;
    else
        return -1;

    /* Create the parameters list in the cpl_recipe object */
    recipe->parameters = cpl_parameterlist_new();

    /* Fill the parameters list */
    /* --data */
    p = cpl_parameter_new_value("kmos.fits_check.data",
                                CPL_TYPE_INT,
                                "The extension whose data to print. "
                                "(0 is the empty primary extension, "
                                "-1 prints just all data extensions, "
                                "by default all headers and data of all "
                                "extensions are printed.",
                                "kmos.fits_check",
                                -2);
    cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "data");
    cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
    cpl_parameterlist_append(recipe->parameters, p);

    /* --header */
    p = cpl_parameter_new_value("kmos.fits_check.header",
                                CPL_TYPE_INT,
                                "The extension whose header to print"
                                "(0 is the empty primary extension, "
                                "-1 prints just all headers, "
                                "by default all headers and data of all "
                                "extensions are printed.",
                                "kmos.fits_check",
                                -2);
    cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "header");
    cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
    cpl_parameterlist_append(recipe->parameters, p);

    return 0;
}

/**
  @brief    Execute the plugin instance given by the interface
  @param    plugin  the plugin
  @return   0 if everything is ok
*/
static int kmo_fits_check_exec(cpl_plugin *plugin)
{
    cpl_recipe  *recipe;

    /* Get the recipe out of the plugin */
    if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
        recipe = (cpl_recipe *)plugin;
    else return -1 ;

    return kmo_fits_check(recipe->parameters, recipe->frames);
}

/**
  @brief    Destroy what has been created by the 'create' function
  @param    plugin  the plugin
  @return   0 if everything is ok
*/
static int kmo_fits_check_destroy(cpl_plugin *plugin)
{
    cpl_recipe *recipe;

    /* Get the recipe out of the plugin */
    if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
        recipe = (cpl_recipe *)plugin;
    else return -1 ;

    cpl_parameterlist_delete(recipe->parameters);
    return 0 ;
}



/**
  @brief    Interpret the command line options and execute the data processing
  @param    parlist     the parameters list
  @param    frameset   the frames list
  @return   0 if everything is ok

  Possible _cpl_error_code_ set in this function:
*/
static int kmo_fits_check(cpl_parameterlist *parlist, cpl_frameset *frameset)
{
    int                 i                   = 0,
                        ret_val             = 0,
                        info                = FALSE,
                        valid               = TRUE,
                        h                   = 0,
                        d                   = 0;
    cpl_imagelist       *imglist            = NULL;
    cpl_image           *img                = NULL;
    kmclipm_vector      *vec                = NULL;
    cpl_frame           *frame              = NULL;
    cpl_propertylist    *pl                 = NULL;
    cpl_table           *tbl                = NULL;
    main_fits_desc      desc;
    const char          *xtension = NULL;

    KMO_TRY
    {
        kmo_init_fits_desc(&desc);

        /* --- check input --- */
        KMO_TRY_ASSURE((parlist != NULL) &&
                       (frameset != NULL),
                       CPL_ERROR_NULL_INPUT,
                       "Not all input data is provided!");

        if (cpl_frameset_get_size(frameset) == 0) {
            KMO_TRY_ASSURE(cpl_frameset_get_size(frameset) == 1,
                           CPL_ERROR_ILLEGAL_INPUT,
                           "Recipe needs a FITS file to inspect!");
        } else {
            KMO_TRY_ASSURE(cpl_frameset_get_size(frameset) == 1,
                           CPL_ERROR_ILLEGAL_INPUT,
                           "Recipe can check just one frame!");
        }

        KMO_TRY_EXIT_IF_NULL(
            frame = kmo_dfs_get_frame(frameset, "0"));

        cpl_msg_info("", "--- Parameter setup for kmo_fits_check ----");

        h = kmo_dfs_get_parameter_int(parlist, "kmos.fits_check.header");
        KMO_TRY_CHECK_ERROR_STATE();
        KMO_TRY_EXIT_IF_ERROR(
            kmo_dfs_print_parameter_help(parlist, "kmos.fits_check.header"));

        d = kmo_dfs_get_parameter_int(parlist, "kmos.fits_check.data");
        KMO_TRY_CHECK_ERROR_STATE();
        KMO_TRY_EXIT_IF_ERROR(
            kmo_dfs_print_parameter_help(parlist, "kmos.fits_check.data"));

        cpl_msg_info("", "-------------------------------------------");

        cpl_msg_severity msg_level = cpl_msg_get_level();
        cpl_msg_set_level(CPL_MSG_OFF);
        desc = kmo_identify_fits_header(cpl_frame_get_filename(frame));
        cpl_msg_set_level(msg_level);

        if (cpl_error_get_code() == CPL_ERROR_DATA_NOT_FOUND) {
            // This doesn't seem to be a valid KMOS FITS frame
            valid = FALSE;
            cpl_error_reset();
        } else {
            valid = TRUE;

            if (desc.frame_type == illegal_frame) {
                valid = FALSE;
                cpl_error_reset();
            }
        }

        if ((h == -2) && (d == -2)) {
            // default case, print info
            info = TRUE;
        }

        if (info) {
            /* print info */
            KMO_TRY_EXIT_IF_ERROR(
                kmo_fits_check_print_info(valid, &desc, frame));
        } else if (((h == -1) && (d > cpl_frame_get_nextensions(frame)+1)) ||
                   ((d == -1) && (h > cpl_frame_get_nextensions(frame)+1))) {
            printf("++++++++++++++++++++++++++++++++++++++++"
                   "++++++++++++++++++++++++++++++++++++++++\n");

            printf("ERROR: Supplied fits file has only %d extensions!\n",
                   cpl_frame_get_nextensions(frame)+1);

            printf("++++++++++++++++++++++++++++++++++++++++"
                   "++++++++++++++++++++++++++++++++++++++++\n");
        } else {
            /* print requested header or data section (-1 prints all of them) */
            int nr_ext = 0;
            if (valid) {
                nr_ext = desc.nr_ext;
            } else {
                nr_ext = cpl_frame_get_nextensions(frame);
            }

            if ((h < -2) || (d < -2)) {
                printf(">>> The specified extension number must be "
                       "equal or greater than 0 (-1 to display all headers)!\n");
            } else if ((h > nr_ext) || (d > nr_ext)) {
                if (nr_ext == 0) {
                    printf(">>> The file has only a primary extension!\n");
                } else if (nr_ext == 1) {
                    printf(">>> The file has only 1 extension!\n");
                } else {
                    printf(">>> The file has only %d extensions!\n", nr_ext);
                }
            } else {
                for (i = 0; i <= nr_ext; i++) {
                    KMO_TRY_EXIT_IF_NULL(
                        pl = kmclipm_propertylist_load(cpl_frame_get_filename(frame),
                                                  i));

                    // print label
                    if (((h == -1) || (d == -1)) ||
                        ((h == i) && (d == -2)) ||
                        ((h == -1) && (d == -2)) ||
                        ((h == -2) && (d == i)) ||
                        ((h == -2) && (d == -1)) ||
                        ((h == d) && (h == i))) {
                        if (i == 0) {
                            printf("++++++++++++++++++++++++++++++++++++++++"
                                   "++++++++++++++++++++++++++++++++++++++++\n");
                            if (cpl_propertylist_get_int(pl, NAXIS) == 0) {
                                printf("Extension 0, primary\n");
                                printf("--------------------\n");
                            } else {
                                printf("Extension 0\n");
                                printf("-----------\n");
                            }
                        } else {
                            printf("++++++++++++++++++++++++++++++++++++++++"
                                   "++++++++++++++++++++++++++++++++++++++++\n");
                            printf("Extension %d\n", i);
                            printf("------------\n");
                        }
                    }

                    // print header
                    if (((h == -1) && (d == -1)) ||
                        ((d == -2) && (h == i)) ||
                        ((d == -2) && (h == -1)) ||
                        ((h == d) && (h == i)))
                    {
                        KMO_TRY_EXIT_IF_ERROR(
                            kmo_fits_check_print_header(pl));
                    }

                    // print separator between header and data
                    if (d == h) {
                        printf("---------------------------\n");
                    }

                    // print data
                    if (((h == -1) && (d == -1)) ||
                        ((h == -2) && (d == i)) ||
                        ((h == -2) && (d == -1)) ||
                        ((h == d) && (h == i))) {

                        if (cpl_propertylist_get_int(pl, NAXIS) == 0) {
                            printf("empty\n");
                        } else {
                            if (cpl_propertylist_has(pl, XTENSION)) {
                                xtension = cpl_propertylist_get_string(pl,
                                                                    XTENSION);
                            } else {
                                xtension = "";
                            }

                            if ((desc.fits_type == f3i_fits) ||
                                ((cpl_propertylist_get_int(pl, NAXIS) == 3) &&
                                        (desc.fits_type == illegal_fits))) {
                                KMO_TRY_EXIT_IF_NULL(
                                    imglist = kmclipm_imagelist_load(
                                                  cpl_frame_get_filename(frame),
                                                  CPL_TYPE_FLOAT, i));

                                KMO_TRY_EXIT_IF_ERROR(
                                    kmo_fits_check_print_imagelist(imglist));

                                cpl_imagelist_delete(imglist); imglist = NULL;
                            } else if ((desc.fits_type == f2d_fits) ||
                                       (desc.fits_type == b2d_fits) ||
                                       (desc.fits_type == f2i_fits) ||
                                       (desc.fits_type == raw_fits) ||
                                       ((cpl_propertylist_get_int(pl, NAXIS) == 2) &&
                                        (desc.fits_type == illegal_fits) &&
                                        (strcmp(xtension, "BINTABLE") != 0)))
                            {
                                KMO_TRY_EXIT_IF_NULL(
                                    img = kmclipm_image_load(
                                                  cpl_frame_get_filename(frame),
                                                  CPL_TYPE_FLOAT, 0, i));

                                KMO_TRY_EXIT_IF_ERROR(
                                    kmo_fits_check_print_image(img));

                                cpl_image_delete(img); img = NULL;
                            } else if ((desc.fits_type == f1i_fits) ||
                                       (desc.fits_type == f1d_fits) ||
                                       (desc.fits_type == f1s_fits) ||
                                       ((cpl_propertylist_get_int(pl, NAXIS) == 1) &&
                                        (desc.fits_type == illegal_fits)))
                            {
                                KMO_TRY_EXIT_IF_NULL(
                                    vec = kmclipm_vector_load(
                                                  cpl_frame_get_filename(frame),
                                                  i));

                                KMO_TRY_EXIT_IF_ERROR(
                                    kmo_fits_check_print_vector(vec));

                                kmclipm_vector_delete(vec); vec = NULL;
                            } else if ((desc.fits_type == f1l_fits) ||
                                       (desc.fits_type == f2l_fits) ||
                                       (strcmp(xtension, "BINTABLE") == 0))
                            {
                                KMO_TRY_EXIT_IF_NULL(
                                    tbl = kmclipm_table_load(
                                                  cpl_frame_get_filename(frame),
                                                  i, 0));

                                KMO_TRY_EXIT_IF_ERROR(
                                    kmo_fits_check_print_table(tbl));

                                cpl_table_delete(tbl); tbl = NULL;
                            }
                        }
                    }
                    cpl_propertylist_delete(pl); pl = NULL;
                }
                printf("++++++++++++++++++++++++++++++++++++++++"
                       "++++++++++++++++++++++++++++++++++++++++\n");

                if (desc.fits_type == raw_fits) {
                    printf(">>> Attention: It is assumed that the file\n");
                    printf(">>>            is a RAW-fits with 4 extensions\n");
                }
            }
        }
    }
    KMO_CATCH
    {
        KMO_CATCH_MSG();

        ret_val = -1;
    }

    kmo_free_fits_desc(&desc);

    return ret_val;
}

/**@}*/
