/* $Id: kmo_priv_make_image.c,v 1.1.1.1 2012-01-18 09:31:59 yjung Exp $
 *
 * 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
 */

/*
 * $Author: yjung $
 * $Date: 2012-01-18 09:31:59 $
 * $Revision: 1.1.1.1 $
 * $Name: not supported by cvs2svn $
 */

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

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

#include <string.h>

#include <cpl.h>

#include "kmo_debug.h"
#include "kmo_utils.h"
#include "kmo_dfs.h"
#include "kmo_error.h"
#include "kmo_priv_make_image.h"
#include "kmo_priv_functions.h"
#include "kmo_functions.h"

/*----------------------------------------------------------------------------*/
/**
    @defgroup kmos_priv_make_image     Helper functions for recipe kmo_make_image.

    @{
 */
/*----------------------------------------------------------------------------*/

/**
    @brief
        Identifies spectral slices of a cube to collapse.

    This function identifies spectral slices of a cube to collapse. Therefore it
    takes the wavelength values and data of the OH-spectrum, creates the
    wavelength values of the IFU and compares them (i.e. checks if they are
    overlapping), it takes a maximum threshold and a range-vector created with
    @c kmo_identify_ranges . The oh-spectrum is interpolated to match the
    spectrum of the IFU.

    @param spec_data_in   The data of the OH-spectrum.
    @param spec_lambda_in The wavelength values of the OH-spectrum.
    @param ranges         An even sized vector defining the wavelength ranges
                          (optional).
    @param threshold      The maximum threshold (if < 0 it will be ignored).
    @param ifu_crpix      Reference pixel position (CRPIX3 from FITS-header).
    @param ifu_crval      Value of reference pixel (CRVAL3 from FITS-header).
    @param ifu_cdelt      Delta between pixels (CDELT3 from FITS-header).
    @param size_ifu       The number of spectral slices of the IFU.

    @return A vector in case of success, NULL otherwise. The vector is of the
            same size as @c spec_data_in and contains ones for valid slices and
            zeros for invalid slices.

    The returned vector has to be deallocated with cpl_vector_delete().

    Possible cpl_error_code set in this function:
    @li CPL_ERROR_NULL_INPUT    if any input pointer is NULL
    @li CPL_ERROR_ILLEGAL_INPUT if @c spec_data_in and @c spec_lambda_in don't
                                have the same size
*/
cpl_vector* kmo_identify_slices_with_oh(cpl_vector *spec_data_in,
                                        cpl_vector *spec_lambda_in,
                                        cpl_vector *ranges,
                                        double threshold,
                                        int ifu_crpix,
                                        double ifu_crval,
                                        double ifu_cdelt,
                                        int size_ifu)
{
    cpl_vector      *slices           = NULL,
                    *spec_data_out    = NULL,
                    *ifu_lambda_in    = NULL;

    cpl_bivector    *bivec_ref        = NULL,
                    *bivec_out        = NULL;

    double          min_lambda        = -1.0,
                    max_lambda        = -1.0,
                    *data             = NULL;

    int             start_index       = 0,
                    stop_index        = 0,
                    i                 = 0,
            //        found             = FALSE,
                    size_spec         = 0,
                    ind               = 0;

    KMO_TRY
    {
        /* Check inputs */
        KMO_TRY_ASSURE((spec_data_in != NULL) &&
                       (spec_lambda_in != NULL),
                       CPL_ERROR_NULL_INPUT,
                       "Not all input data is provided!");

        size_spec = cpl_vector_get_size(spec_lambda_in);

        KMO_TRY_ASSURE(cpl_vector_get_size(spec_data_in) == size_spec,
                       CPL_ERROR_ILLEGAL_INPUT,
                       "Lambda- and data-vector of OH-line have "
                       "different sizes!");

        /* create lambda-vector for IFU */
        KMO_TRY_EXIT_IF_NULL(
            ifu_lambda_in = kmo_create_lambda_vec(size_ifu,
                                                  ifu_crpix,
                                                  ifu_crval,
                                                  ifu_cdelt));

        /* check if lambdas of IFU lie outside the range of lambdas of spec
           (it is assumed that values are ascending, but since the vectors have
           been created with kmo_create_lambda_vec(), they are!) */
        start_index = 0;
        stop_index = size_ifu - 1;

        min_lambda = cpl_vector_get(spec_lambda_in, 0);
        max_lambda = cpl_vector_get(spec_lambda_in, size_spec - 1);

        if ((cpl_vector_get(ifu_lambda_in, 0) <= min_lambda) ||
            (cpl_vector_get(ifu_lambda_in, size_ifu - 1) >= max_lambda)) {

            data = cpl_vector_get_data(ifu_lambda_in);
            for (i = 0; i < size_ifu; i++) {
                if (min_lambda <= data[i]) {
                    start_index = i;
                    break;
                }
            }
            for (i = size_ifu - 1; i >= 0; i--) {
                if (max_lambda >= data[i]) {
                    stop_index = i;
                    break;
                }
            }

            slices = cpl_vector_extract(ifu_lambda_in,
                                               start_index,
                                               stop_index, 1);
            cpl_vector_delete(ifu_lambda_in);
            ifu_lambda_in = slices; slices = NULL;
        }

        /* interpolate oh-line to match lambdas of IFU */
        KMO_TRY_EXIT_IF_NULL(
            spec_data_out = cpl_vector_new(stop_index - start_index + 1));
        KMO_TRY_EXIT_IF_NULL(
            bivec_ref = cpl_bivector_wrap_vectors(spec_lambda_in,
                                                  spec_data_in));
        KMO_TRY_EXIT_IF_NULL(
            bivec_out = cpl_bivector_wrap_vectors(ifu_lambda_in,
                                                  spec_data_out));

        KMO_TRY_EXIT_IF_ERROR(
            cpl_bivector_interpolate_linear(bivec_out, bivec_ref));

        cpl_bivector_unwrap_vectors(bivec_ref);
        cpl_bivector_unwrap_vectors(bivec_out);

        /* allocate output vector */
        KMO_TRY_EXIT_IF_NULL(
            slices = cpl_vector_new(size_ifu));

        KMO_TRY_EXIT_IF_ERROR(
            cpl_vector_fill(slices, 0.0));

        /* populate output vector with ones and zeroes
           one: slice will be taken into account when collapsing the cube
           zero: slice will be ignored */
        KMO_TRY_EXIT_IF_NULL(
            data = cpl_vector_get_data(slices));

        ind = 0;
        for (i = start_index; i <= stop_index; i++) {
            if ((ranges == NULL) ||
                kmo_is_in_range(ranges, ifu_lambda_in, ind))
            {
                if (((threshold > 0.0) &&
                      kmo_priv_is_below_threshold(threshold,
                                                  spec_data_out, ind)) ||
                    (threshold < 0.0))
                {
                    data[i] = 1;
                }
            }
            ind++;
        }
    }
    KMO_CATCH
    {
        KMO_CATCH_MSG();
        cpl_vector_delete(slices); slices = NULL;
    }

    cpl_vector_delete(spec_data_out); spec_data_out = NULL;
    cpl_vector_delete(ifu_lambda_in); ifu_lambda_in = NULL;

    return slices;
}

/**
    @brief
        Checks if a value in a vector is below a certain threshold.

    This function checks if a value at a specified position in @c spec_data_out
    is below @c threshold.

    @param threshold     The threshold value.
    @param spec_data_out The data-vector of a certain IFU.
    @param index         The index to the value in @c spec_data_out to examine.
                         Starts at zero.

    @return 1 if value is below threshold, 0 otherwise.

    Possible cpl_error_code set in this function:

    @c CPL_ERROR_NULL_INPUT    Not enough inputs defined
    @c CPL_ERROR_ILLEGAL_INPUT index is larger or smaller than the size of
                               @c ifu_lambda_in
*/
int kmo_priv_is_below_threshold(double threshold,
                                cpl_vector *spec_data_out,
                                int index)
{
    double  val     = 0.0;
    int ret_val = 0;

    KMO_TRY
    {
        /* Check inputs */
        KMO_TRY_ASSURE(spec_data_out != NULL,
                       CPL_ERROR_NULL_INPUT,
                       "Not all input data is provided!");

        KMO_TRY_ASSURE((index >= 0) &&
                       (index < cpl_vector_get_size(spec_data_out)),
                       CPL_ERROR_NULL_INPUT,
                       "Index < 0 or larger than vector!");

        val = cpl_vector_get(spec_data_out, index);
        KMO_TRY_CHECK_ERROR_STATE();

        if (threshold > val) {
            ret_val = 1;
        }
    }
    KMO_CATCH
    {
        KMO_CATCH_MSG();
        ret_val = 0;
    }
    return ret_val;
}

/** @} */
