/* $Id: xsh_detmon.c,v 1.11 2013-07-19 12:00:24 jtaylor Exp $
 *
 * This file is part of the irplib package
 * 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: jtaylor $
 * $Date: 2013-07-19 12:00:24 $
 * $Revision: 1.11 $
 * $Name: not supported by cvs2svn $
 */

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

#include <complex.h>

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

#include <math.h>
#include <string.h>
#include <assert.h>
#include <float.h>

#include <cpl.h>

#include "xsh_detmon.h"

#include "xsh_ksigma_clip.h"
//#include "irplib_hist.h"
#include "irplib_utils.h"


/* Computes the square of an euclidean distance bet. 2 points */
#define pdist(x1,y1,x2,y2) (((x1-x2)*(x1-x2))+((y1-y2)*(y1-y2)))

#define cpl_drand() ((double)rand()/(double)RAND_MAX)
/**@{*/
/*--------------------------------------------------------------------------*/

/*
 * @defgroup xsh_detmon        Detector monitoring functions
 */

/*--------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------
                                  Defines
 ---------------------------------------------------------------------------*/


#define HIST_FACT 2.354820045

enum pixeltypes
{
    HOT = 0,
    DEAD = 1,
    NOISY = 2
};

enum stackingtypes
{
    MINMAX = 0,
    MEAN = 1,
    MEDIAN = 2,
    KSIGMA = 3
};

enum readouts
{
    HORIZONTAL = 1,
    VERTICAL = 2
};


static struct
{
    const char * ron_method;
    const char * dsnu_method;
    int         exts;
    int         nb_extensions;
    cpl_boolean opt_nir;
} xsh_detmon_dark_config;

#define NIR TRUE
#define OPT FALSE

/*---------------------------------------------------------------------------
  Private function prototypes
  ---------------------------------------------------------------------------*/

/* Functions for RON/Bias recipe, xsh_detmon_ronbias() */

cpl_error_code
xsh_detmon_rm_bpixs(cpl_image **,
                const double,
                int         ,
                int         );

/*---------------------------------------------------------------------------*/

/*
 * @brief  Fill input parameters values
 * @param  parlist      parameters list
 * @param  recipe_name  recipe name
 * @param  pipeline_name pipeline name
 * @param  npars  number of parameters

 * @return CPL_ERROR_NONE on success.
 */

/*---------------------------------------------------------------------------*/
cpl_error_code
xsh_detmon_fill_parlist(cpl_parameterlist * parlist,
                    const char *recipe_name,
                    const char *pipeline_name,
                    int npars, ...)
{

    va_list                 ap;

    char                   *group_name;

    int                     pars_counter = 0;

    group_name = cpl_sprintf("%s.%s", pipeline_name, recipe_name);
    assert(group_name != NULL);

#define insert_par(PARNAME, PARDESC, PARVALUE, PARTYPE)                      \
    do {                                                                     \
        char * par_name = cpl_sprintf("%s.%s", group_name, PARNAME);          \
        cpl_parameter * p;                                                       \
        assert(par_name != NULL);                                                \
        p = cpl_parameter_new_value(par_name, PARTYPE,                           \
                                    PARDESC, group_name, PARVALUE);              \
        cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, PARNAME);             \
        cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);                        \
        cpl_parameterlist_append(parlist, p);                                    \
        cpl_free(par_name);                                                      \
    } while(0);


    va_start(ap, npars);

    while(pars_counter < npars) {
        char                   *name = va_arg(ap, char *);
        char                   *desc = va_arg(ap, char *);
        char                   *type = va_arg(ap, char *);

        if(!strcmp(type, "CPL_TYPE_INT")) {
            int                     v1 = va_arg(ap, int);

            insert_par(name, desc, v1, CPL_TYPE_INT);
        } else if(!strcmp(type, "CPL_TYPE_BOOL")) {
            char                   *v2 = va_arg(ap, char *);

            if(!strcmp(v2, "CPL_FALSE"))
                insert_par(name, desc, CPL_FALSE, CPL_TYPE_BOOL);
            if(!strcmp(v2, "CPL_TRUE"))
                insert_par(name, desc, CPL_TRUE, CPL_TYPE_BOOL);
        } else if(!strcmp(type, "CPL_TYPE_STRING")) {
            char                   *v2 = va_arg(ap, char *);

            insert_par(name, desc, v2, CPL_TYPE_STRING);
        } else if(!strcmp(type, "CPL_TYPE_DOUBLE")) {
            double v3 = va_arg(ap, double);
            insert_par(name, desc, v3, CPL_TYPE_DOUBLE);
        }

        pars_counter++;
    }

    va_end(ap);

    cpl_free(group_name);

#undef insert_par
    return 0;
}

/*---------------------------------------------------------------------------*/

/*
 * @brief  Retrieve input int parameter
 * @param  pipeline_name        Input image
 * @param  recipe_name          Input image
 * @param  parlist              Shift to apply on the x-axis
 * @return CPL_ERROR_NONE on success.
 */

/*---------------------------------------------------------------------------*/
int
xsh_detmon_retrieve_par_int(const char *parn,
                        const char *pipeline_name,
                        const char *recipe_name,
                        const cpl_parameterlist * parlist)
{
    char                   *par_name;
    const cpl_parameter    *par;
    int                     value;

    par_name = cpl_sprintf("%s.%s.%s", pipeline_name, recipe_name, parn);
    assert(par_name != NULL);
    par = cpl_parameterlist_find_const(parlist, par_name);
    value = cpl_parameter_get_int(par);
    cpl_free(par_name);

    return value;
}

/*---------------------------------------------------------------------------*/

/*
 * @brief  Retrieve input double parameter
 * @param  pipeline_name        Input image
 * @param  recipe_name          Input image
 * @param  parlist              Shift to apply on the x-axis
 * @return CPL_ERROR_NONE on success.
 */

/*---------------------------------------------------------------------------*/
double
xsh_detmon_retrieve_par_double(const char *parn,
                           const char *pipeline_name,
                           const char *recipe_name,
                           const cpl_parameterlist * parlist)
{
    char                   *par_name;
    const cpl_parameter    *par;
    double                  value;

    par_name = cpl_sprintf("%s.%s.%s", pipeline_name, recipe_name, parn);
    assert(par_name != NULL);
    par = cpl_parameterlist_find_const(parlist, par_name);
    value = cpl_parameter_get_double(par);
    cpl_free(par_name);

    return value;
}


/*---------------------------------------------------------------------------*/

/*
 * @brief  Retrieve exposure time
 * @param  plist      parameter list
 * @return "EXPTIME" keyword value.
 */

/*---------------------------------------------------------------------------*/

double
irplib_pfits_get_exptime(const cpl_propertylist * plist)
{
    double                  exptime;

    exptime = cpl_propertylist_get_double(plist, "EXPTIME");

    return exptime;
}

/*---------------------------------------------------------------------------*/
/*
 * @brief  Generate propertylist with product category, type, technique
 * @param  procatg product category
 * @param  protype product type
 * @param  protech product technique
 * @param  proscience switch to identify a science product
 * @return filled cpl_propertylist (to be deallocated)
 */
/*---------------------------------------------------------------------------*/
cpl_propertylist *
xsh_detmon_fill_prolist(const char * procatg,
                    const char * protype,
                    const char * protech,
                    cpl_boolean  proscience)
{
    cpl_propertylist * prolist = cpl_propertylist_new();

    cpl_propertylist_append_string(prolist, CPL_DFS_PRO_CATG,    procatg);
    cpl_propertylist_append_bool(prolist,   CPL_DFS_PRO_SCIENCE, proscience);
    if (protype) {
        cpl_propertylist_append_string(prolist, CPL_DFS_PRO_TYPE,    protype);
    }
    if (protech) {
        cpl_propertylist_append_string(prolist, CPL_DFS_PRO_TECH,    protech);
    }

    return prolist;
}

/*---------------------------------------------------------------------------*/

/*
 * @brief  Remove bad pixels
 * @param  image  input/output image
 * @param  kappa  kappa for kappa-sigma clip
 * @param  nffts  number of fft
 * @param  nsamples number of sampling areas
 * @return CPL_ERROR_NONE on success.
 */

/*---------------------------------------------------------------------------*/


cpl_error_code
xsh_detmon_rm_bpixs(cpl_image ** image,
                const double kappa, int nffts, int nsamples)
{
    int                     i, j;

    float                  *data = cpl_image_get_data_float(*image);
    int k = 0;
    for(i = 0; i < nffts; i++) {
        for(j = 0; j < nsamples; j++) {
            float                   neighbours = 0;
            int                     nneighs = 0;
            float                   average = 0;

            /*
             * Look for the way to optimize this:
             * Some of the points added to neighbours coincide
             * in one iteration and the following
             */
            if(i > 0) {
                neighbours += *(data + (i - 1) * nsamples + j);
                nneighs++;
            }
            if(i < nffts - 1) {
                neighbours += *(data + (i + 1) * nsamples + j);
                nneighs++;
            }
            if(j > 0) {
                neighbours += *(data + i * nsamples + (j - 1));
                nneighs++;
            }
            if(j < nsamples - 1) {
                neighbours += *(data + i * nsamples + (j + 1));
                nneighs++;
            }
            average = neighbours / nneighs;
            if(average > 0) {
                if(*(data + i * nsamples + j) < average * (-1 * kappa) ||
                   *(data + i * nsamples + j) > average * (kappa)) {
                    k++;
                    *(data + i * nsamples + j) = average;
                }
            }
            if(average < 0) {
                if(*(data + i * nsamples + j) > average * (-1 * kappa) ||
                   *(data + i * nsamples + j) < average * (kappa)) {
                    k++;
                    *(data + i * nsamples + j) = average;
                }
            }

        }
    }


    return cpl_error_get_code();

}

void
detmon_print_rec_status(void) {
   if(cpl_error_get_code() != CPL_ERROR_NONE) {
      /* cpl_msg_error(cpl_func,"Function status at %d",val); */
      cpl_msg_error(cpl_func,"%s",(const char*) cpl_error_get_message());
      cpl_msg_error(cpl_func,"%s",(const char*) cpl_error_get_where());
      return;
   }
   return;
}

/**@}*/
