
/*                                                                           *
 *   This file is part of the ESO SINFO Pipeline                             *
 *   Copyright (C) 2004,2005 European Southern Observatory                   *
 *                                                                           *
 *   This library 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, 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA    *
 *                                                                           */


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

/**@{*/
/*---------------------------------------------------------------------------*/
/**
   @defgroup sinfo_utils_wrappers  Utility functions (wrappers)

   This module contains wrapper functions, convenience functions and simple 
   extensions of CPL functions.

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


#include <sinfo_utils_wrappers.h>
#include <sinfo_functions.h>
#include <sinfo_dump.h>
#include <sinfo_utils.h>
#include <sinfo_error.h>
#include "sinfo_msg.h"
/*---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------*/
/**
   @brief    Sort a table by one column
   @param    t        Table
   @param    column   Column name
   @param    reverse  Flag indicating if column values are sorted descending
                      (CPL_TRUE) or ascending (CPL_FALSE)
   @return   CPL_ERROR_NONE iff OK

   This is a wrapper of @c cpl_table_sort().

 */
/*---------------------------------------------------------------------------*/
cpl_error_code
sinfo_sort_table_1(cpl_table *t, const char *column, cpl_boolean reverse)
{
    cpl_propertylist *plist = NULL;

    assure(t != NULL, CPL_ERROR_NULL_INPUT, "Null table");
    assure(cpl_table_has_column(t, column), CPL_ERROR_ILLEGAL_INPUT, 
           "No column '%s'", column);

    check(( plist = cpl_propertylist_new(),
                    cpl_propertylist_append_bool(plist, column, reverse)),
          "Could not create property list for sorting");

    check( cpl_table_sort(t, plist), "Could not sort table");

    cleanup:
    sinfo_free_propertylist(&plist);
    return cpl_error_get_code();
}

/*---------------------------------------------------------------------------*/
/**
   @brief    Sort a table by two columns
   @param    t        Table
   @param    column1  1st column name
   @param    column2  2nd column name
   @param    reverse1  Flag indicating if 1st column values are sorted
                       descending (true) or ascending (CPL_FALSE)
   @param    reverse2  Flag indicating if 2nd column values are sorted
                       descending (true) or ascending (CPL_TRUE)
   @return   CPL_ERROR_NONE iff OK

   This is a wrapper of @c cpl_table_sort(). @em column1 is the more
   significant column (i.e. values in @em column2 are compared, only if the
   values in @em column1 are equal).
 */
/*---------------------------------------------------------------------------*/
cpl_error_code
sinfo_sort_table_2(cpl_table *t, const char *column1, const char *column2, 
                   cpl_boolean reverse1, cpl_boolean reverse2)
{
    cpl_propertylist *plist = NULL;

    assure(t != NULL, CPL_ERROR_NULL_INPUT, "Null table");
    assure(cpl_table_has_column(t, column1), CPL_ERROR_ILLEGAL_INPUT, 
           "No column '%s'", column1);
    assure(cpl_table_has_column(t, column2), CPL_ERROR_ILLEGAL_INPUT,
           "No column '%s'", column2);

    check(( plist = cpl_propertylist_new(),
                    cpl_propertylist_append_bool(plist, column1, reverse1),
                    cpl_propertylist_append_bool(plist, column2, reverse2)),
          "Could not create property list for sorting");
    check( cpl_table_sort(t, plist), "Could not sort table");

    cleanup:
    sinfo_free_propertylist(&plist);
    return cpl_error_get_code();
}

/*---------------------------------------------------------------------------*/
/**
   @brief    Extract table rows
   @param    t        Table
   @param    column   Column name
   @param    operator Logical operator
   @param    value    Value used for comparison
   @return   A new table containing the extracted rows

   A table row is extracted if and only if the value in @em column is in the
   relation @em operator to the specified @em value. The specified column
   must have type CPL_TYPE_DOUBLE or CPL_TYPE_INT. If integer, the integer
   nearest to @em value is used for the comparison.

   Also see @c cpl_table_and_selected_<type>().

 */
/*---------------------------------------------------------------------------*/
cpl_table *
sinfo_extract_table_rows(const cpl_table *t, const char *column,
                         cpl_table_select_operator operator, double value)
{
    cpl_table *result = NULL;
    assure( t != NULL, CPL_ERROR_NULL_INPUT, "Null table");
    assure( cpl_table_has_column(t, column), CPL_ERROR_INCOMPATIBLE_INPUT,
            "No such column: %s", column);

    /* 1. Extract (duplicate) the entire table
       2. remove rows *not* satisfying the criterion */

    check(result = cpl_table_duplicate(t),"selecting");
    check(sinfo_select_table_rows(result, column, operator, value),"select");
    check(cpl_table_not_selected(result),"Inverses selection");
    check(cpl_table_erase_selected(result),"erase selection");//problems

    /*
    check(( result = cpl_table_duplicate(t),
        sinfo_select_table_rows(result, column, operator, value),
        cpl_table_not_selected(result),  // Inverses selection 
        cpl_table_erase_selected(result)),
       "Error extracting rows");
     */

    cleanup:
    if (cpl_error_get_code() != CPL_ERROR_NONE)
    {
        sinfo_free_table(&result);
    }
    return result;
}


/*---------------------------------------------------------------------------*/
/**
   @brief    Select table rows
   @param    t        Table
   @param    column   Column name
   @param    operator Logical operator
   @param    value    Value used for comparison
   @return   Number of selected rows

   A row is selected if and only if the value in @em column is in the
   relation @em operator to the specified @em value. The specified column must
   have type CPL_TYPE_DOUBLE or CPL_TYPE_INT. If integer, the integer nearest
   to @em value is used for the comparison.

   Also see @c cpl_table_and_selected_<type>().

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

int
sinfo_select_table_rows(cpl_table *t,  const char *column, 
                        cpl_table_select_operator operator, double value)
{
    int result = 0;
    cpl_type type;
    assure( t != NULL, CPL_ERROR_NULL_INPUT, "Null table");
    assure( cpl_table_has_column(t, column), CPL_ERROR_INCOMPATIBLE_INPUT, 
            "No such column: %s", column);

    type = cpl_table_get_column_type(t, column);

    assure( type == CPL_TYPE_DOUBLE ||
            type == CPL_TYPE_INT, CPL_ERROR_INVALID_TYPE,
            "Column '%s' must be double or int. %s found", column,
            sinfo_tostring_cpl_type(type));

    check( cpl_table_select_all(t), "Error selecting rows");

    if      (type == CPL_TYPE_DOUBLE)
    {
        result = cpl_table_and_selected_double(t, column, operator, value);
    }
    else if (type == CPL_TYPE_INT)
    {
        result = cpl_table_and_selected_int   (t, column, operator, 
                        sinfo_round_double(value));
    }
    else { /*impossible*/ passure(CPL_FALSE, ""); }

    cleanup:
    return result;

}

/**
   @brief    Deallocate an image and set the pointer to NULL
   @param    p        parameter to deallocate
 */
/*---------------------------------------------------------------------------*/
/* TODO: not used */
void sinfo_free_parameter(cpl_parameter **p) 
{if(p){cpl_parameter_delete(*p);            *p = NULL;}}



/**
   @brief    Deallocate an aperture and set the pointer to NULL
   @param    a        parameter to deallocate
 */
/*---------------------------------------------------------------------------*/
/* TODO: not used */
void sinfo_free_apertures(cpl_apertures **a) 
{if(a){cpl_apertures_delete(*a);            *a = NULL;}}
/*---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------*/
/**
   @brief    Deallocate an image and set the pointer to NULL
   @param    i        Image to deallocate
 */
/*---------------------------------------------------------------------------*/
void sinfo_free_image(cpl_image **i)  {if(i){cpl_image_delete(*i); *i = NULL;}}


/*---------------------------------------------------------------------------*/
/**
   @brief    Deallocate an image and set the pointer to NULL
   @param    v Vector to deallocate
 */
/*---------------------------------------------------------------------------*/
void sinfoni_free_vector(cpl_vector **v)  {if(v){cpl_vector_delete(*v); *v = NULL;}}


/*---------------------------------------------------------------------------*/
/**
   @brief    Deallocate an array and set the pointer to NULL
   @param    i        array to deallocate
 */
/*---------------------------------------------------------------------------*/
void sinfo_free_array(cpl_array **i)  {if(i){cpl_array_delete(*i); *i = NULL;}}

/*---------------------------------------------------------------------------*/
/**
   @brief    Deallocate an image mask and set the pointer to NULL
   @param    m        Mask to deallocate
 */
/*---------------------------------------------------------------------------*/
void sinfo_free_mask(cpl_mask **m)  {if(m){cpl_mask_delete(*m); *m = NULL;}}
/*---------------------------------------------------------------------------*/
/**
   @brief    Deallocate an image list and set the pointer to NULL
   @param    i        Image list to deallocate
 */
/*---------------------------------------------------------------------------*/
void sinfo_free_imagelist(cpl_imagelist **i) 
{if(i){cpl_imagelist_delete(*i);        *i = NULL;}}
/*---------------------------------------------------------------------------*/
/**
   @brief    Deallocate a table and set the pointer to NULL
   @param    t        Table to deallocate
 */
/*---------------------------------------------------------------------------*/
void sinfo_free_table(cpl_table **t) {if(t){cpl_table_delete(*t); *t = NULL;}}
/*---------------------------------------------------------------------------*/
/**
   @brief    Deallocate a property list and set the pointer to NULL
   @param    p        Property list to deallocate
 */
/*---------------------------------------------------------------------------*/
void sinfo_free_propertylist(cpl_propertylist **p)   
{if(p){cpl_propertylist_delete(*p);     *p = NULL;}}
/*---------------------------------------------------------------------------*/
/**
   @brief    Deallocate a polynomial and set the pointer to NULL
   @param    p        Polynomial to deallocate
 */
/*---------------------------------------------------------------------------*/
void sinfo_free_polynomial(cpl_polynomial **p)       
{if(p){cpl_polynomial_delete(*p);       *p = NULL;}}
/*---------------------------------------------------------------------------*/
/**
   @brief    Deallocate a matrix and set the pointer to NULL
   @param    m        Matrix to deallocate
 */
/*---------------------------------------------------------------------------*/
/* similar also present in svd.c */
void sinfoni_free_matrix(cpl_matrix **m) 
{if(m){cpl_matrix_delete(*m); *m = NULL;}}

/*---------------------------------------------------------------------------*/
/**
   @brief    Deallocate a parameter list and set the pointer to NULL
   @param    p        Parameter list to deallocate
 */
/*---------------------------------------------------------------------------*/
/* TODO: not used */
void sinfo_free_parameterlist(cpl_parameterlist **p) 
{if(p){cpl_parameterlist_delete(*p);    *p = NULL;}}
/*----------------------------------------------------------------------------*/
/**
   @brief    Deallocate a vector and set the pointer to NULL
   @param    f        Frame set to deallocate
 */
/*---------------------------------------------------------------------------*/
void sinfo_free_frameset(cpl_frameset **f) 
{if(f){cpl_frameset_delete(*f);    *f = NULL;}}


/*---------------------------------------------------------------------------*/
/**
   @brief    Deallocate a vector and set the pointer to NULL
   @param    f        Frame to deallocate
 */
/*---------------------------------------------------------------------------*/
void sinfo_free_frame(cpl_frame **f) 
{if(f){cpl_frame_delete(*f);    *f = NULL;}}


/*---------------------------------------------------------------------------*/
/**
   @brief    Deallocate a vector and set the pointer to NULL
   @param    i        int to deallocate
 */
/*---------------------------------------------------------------------------*/
void sinfo_free_int(int **i) {if(i){cpl_free(*i);    *i = NULL;}}


/*---------------------------------------------------------------------------*/
/**
   @brief    Deallocate a vector and set the pointer to NULL
   @param    f float to deallocate
 */
/*---------------------------------------------------------------------------*/
void sinfo_free_float(float **f) {if(f){cpl_free(*f);    *f = NULL;}}



/*---------------------------------------------------------------------------*/
/**
   @brief    Deallocate a vector and set the pointer to NULL
   @param    d double to deallocate
 */
/*---------------------------------------------------------------------------*/
void sinfo_free_double(double **d) {if(d){cpl_free(*d);    *d = NULL;}}


/*---------------------------------------------------------------------------*/
/**
   @brief    Deallocate a vector and set the pointer to NULL
   @param    a array to deallocate
 */
/*---------------------------------------------------------------------------*/
void sinfo_free_array_imagelist(cpl_imagelist ***a) 
{if(*a){cpl_free(*a); *a = NULL;}}

/*---------------------------------------------------------------------------*/
/**
   @brief    Deallocate a vector and set the pointer to NULL
   @param    a array to deallocate
 */
/*---------------------------------------------------------------------------*/
void sinfo_free_array_image(cpl_image ***a) {if(*a){cpl_free(*a); *a = NULL;}}


/*---------------------------------------------------------------------------*/
/**
   @brief    Deallocate an image array and set the pointer to NULL
   @param    a array to deallocate
   @param    n array size
 */
/*---------------------------------------------------------------------------*/
void sinfo_free_image_array(cpl_image ***a, const int n) 
{

    if((*a) != NULL) {
        for (int i=0; i < n; i++) {
            if((*a)[i] != NULL) {
                sinfo_free_image(&(*a)[i]);
                (*a)[i]=NULL;
            }
        }
        sinfo_free_array_image(&(*a));
        *a=NULL;
    }
}

/*---------------------------------------------------------------------------*/
/**
   @brief    Deallocate an array of float arrays and set the pointer to NULL
   @param    a array to deallocate
   @param    n array size
 */
/*---------------------------------------------------------------------------*/
void sinfo_free_float_array(float ***a, const int n) 
{

    if((*a) != NULL) {
        for (int i=0; i < n; i++) {
            if((*a)[i] != NULL) {
                sinfo_free_float(&(*a)[i]);
                (*a)[i]=NULL;
            }
        }
        cpl_free(*a);
        *a=NULL;
    }
}

/*---------------------------------------------------------------------------*/
/**
   @brief    Deallocate a vector and set the pointer to NULL
   @param    v        Vector to deallocate
 */
/*---------------------------------------------------------------------------*/

void 
sinfo_free_my_vector(cpl_vector **v) {if(v){cpl_vector_delete(*v);*v = NULL;}}


/*---------------------------------------------------------------------------*/
/**
   @brief    Deallocate a vector and set the pointer to NULL
   @param    bv        Vector to deallocate
 */
/*---------------------------------------------------------------------------*/

void 
sinfo_free_bivector(cpl_bivector **bv) {
    if(bv){
        cpl_bivector_delete(*bv);
        *bv = NULL;
    }
}

/*---------------------------------------------------------------------------*/
/**
   @brief    Deallocate a stats object and set the pointer to NULL
   @param    s        Stats object to deallocate
 */
/*---------------------------------------------------------------------------*/
/* TODO: not used */
void sinfo_free_stats(cpl_stats **s) {if(s){cpl_stats_delete(*s); *s = NULL;}}
/*---------------------------------------------------------------------------*/
/**
   @brief    Unwrap a vector and set the pointer to NULL
   @param    v        Vector to unwrap
 */
/*---------------------------------------------------------------------------*/
void 
sinfo_unwrap_vector(cpl_vector **v) {if(v){cpl_vector_unwrap(*v); *v = NULL;}}

/*---------------------------------------------------------------------------*/
/**
   @brief    Unwrap a matrix and set the pointer to NULL
   @param    m        matrix to unwrap
 */
/*---------------------------------------------------------------------------*/
void sinfo_unwrap_matrix(cpl_matrix **m) 
{if(m){cpl_matrix_unwrap(*m); *m = NULL;}}

/*---------------------------------------------------------------------------*/
/**
   @brief    Unwrap a bi-vector and set the pointer to NULL
   @param    b        Bi-vector to deallocate
 */
/*---------------------------------------------------------------------------*/
/* TODO: not used */
void sinfo_unwrap_bivector_vectors(cpl_bivector **b) 
{if(b){cpl_bivector_unwrap_vectors(*b); *b = NULL;}}

/**@}*/
