/*                                                                           *
 *   This file is part of the SINFONI   Pipeline                             *
 *   Copyright (C) 2002,2003 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    *
 *                                                                           */

/*
 * $Author: amodigli $
 * $Date: 2012-09-21 10:55:19 $
 * $Revision: 1.9 $
 * $Name: not supported by cvs2svn $
 */

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

/**@{*/

/*----------------------------------------------------------------------------*/
/**
 @defgroup sinfo_dump  Print CPL objects

 Functions that enables dumping (using CPL's messaging system) some
 otherwise non-dumpable CPL objects
 */
/*----------------------------------------------------------------------------*/

#include <sinfo_dump.h>
#include <sinfo_utils.h>
#include <sinfo_error.h>
#include <sinfo_msg.h>
#include <cpl.h>

/*----------------------------------------------------------------*/
/** 
 * @brief Print a property list.
 * @param pl      The property list to print.
 * @param low     Index of first property to print.
 * @param high    Index of first property not to print.
 * @return CPL_ERROR_NONE iff OK.
 *
 * This function prints all properties in the property list @em pl
 * in the range from @em low (included) to @em high (not included)
 * counting from zero.
 */
/*----------------------------------------------------------------*/
cpl_error_code
sinfo_print_cpl_propertylist(const cpl_propertylist *pl, long low, long high)
{
    cpl_property *prop;
    long i = 0;

    assure(0 <= low && high <= cpl_propertylist_get_size(pl) && low <= high,
                    CPL_ERROR_ILLEGAL_INPUT, "Illegal range");
    /* Printing an empty range is allowed but only when low == high */

    if (pl == NULL ) {
        sinfo_msg("NULL");
    }
    else if (cpl_propertylist_is_empty(pl)) {
        sinfo_msg("[Empty property list]");
    }
    else
        for (i = low; i < high; i++) {
            /* bug workaround: remove const cast when declaration
             of cpl_propertylist_get() is changed */
            prop = cpl_propertylist_get((cpl_propertylist *) pl, i);
            check(sinfo_print_cpl_property(prop), "Error printing property");
        }

    cleanup: return cpl_error_get_code();
}
/*----------------------------------------------------------------*/
/** 
 * @brief Print a property.
 * @param prop      The property to print.
 * @return CPL_ERROR_NONE iff OK.
 *
 * This function prints a property's name, value and comment.
 */
/*----------------------------------------------------------------*/

cpl_error_code
sinfo_print_cpl_property(const cpl_property *prop)
{
    cpl_type t;

    if (prop == NULL ) {
        sinfo_msg("NULL");
    }
    else {
        /* print property with this formatting
         NAME =
         VALUE
         COMMENT
         */

        /* print name */

        sinfo_msg("%s =", cpl_property_get_name(prop));

        /* print value */

        check(t = cpl_property_get_type(prop), "Could not read property type");

        switch (t & (~CPL_TYPE_FLAG_ARRAY))
            {
        case CPL_TYPE_CHAR:
            if (t & CPL_TYPE_FLAG_ARRAY) /* if type is string */
            {
                sinfo_msg("  '%s'", cpl_property_get_string(prop));
            }
            else /* an ordinary char */
            {
                sinfo_msg("  %c", cpl_property_get_char(prop));
            }
            break;
        case CPL_TYPE_BOOL:
            if (cpl_property_get_bool(prop)) {
                sinfo_msg("  true");
            }
            else {
                sinfo_msg("  false");
            }
            break;
        case CPL_TYPE_UCHAR:
            sinfo_msg("%c", cpl_property_get_char(prop));
            break;
        case CPL_TYPE_INT:
            sinfo_msg("%d", cpl_property_get_int(prop));
            break;
        case CPL_TYPE_UINT:
            sinfo_msg("%d", cpl_property_get_int(prop));
            break;
        case CPL_TYPE_LONG:
            sinfo_msg("%ld", cpl_property_get_long(prop));
            break;
        case CPL_TYPE_ULONG:
            sinfo_msg("%ld", cpl_property_get_long(prop));
            break;
        case CPL_TYPE_FLOAT:
            sinfo_msg("%f", cpl_property_get_float(prop));
            break;
        case CPL_TYPE_DOUBLE:
            sinfo_msg("%f", cpl_property_get_double(prop));
            break;
        case CPL_TYPE_POINTER:
            sinfo_msg("POINTER");
            break;
        case CPL_TYPE_INVALID:
            sinfo_msg("INVALID");
            break;
        default:
            sinfo_msg("  unrecognized property");
            break;
            }

        /* Is this property an array? */
        if (t & CPL_TYPE_FLAG_ARRAY) {
            cpl_msg_info(cpl_func, "  (array size = %" CPL_SIZE_FORMAT " )",
                            cpl_property_get_size(prop));
        }

        /* Print comment */
        if (cpl_property_get_comment(prop) != NULL ) {
            sinfo_msg("    %s", cpl_property_get_comment(prop));
        }
    }

    cleanup: return cpl_error_get_code();
}

/*----------------------------------------------------------------*/
/** 
 * @brief Print a frame set
 * @param frames Frame set to print
 * @return CPL_ERROR_NONE iff OK.
 *
 * This function prints all frames in a CPL frame set.
 */
/*----------------------------------------------------------------*/
cpl_error_code
sinfo_print_cpl_frameset(const cpl_frameset *frames)
{
    /* Two special cases: a NULL frame set and an empty frame set */

    if (frames == NULL ) {
        sinfo_msg("NULL");
    }
    else {

        cpl_frameset_iterator* it = cpl_frameset_iterator_new(frames);
        const cpl_frame *f = cpl_frameset_iterator_get_const(it);

        if (f == NULL ) {
            sinfo_msg("[Empty frame set]");
        }
        else {
            while (f != NULL ) {
                check(sinfo_print_cpl_frame(f), "Could not print frame");

                cpl_frameset_iterator_advance(it, 1);
                f = cpl_frameset_iterator_get_const(it);

            }
        }
        cpl_frameset_iterator_delete(it);
    }

    cleanup: return cpl_error_get_code();
}

/*----------------------------------------------------------------*/
/** 
 * @brief Print a frame
 * @param f Frame to print
 * @return CPL_ERROR_NONE iff OK.
 *
 * This function prints a CPL frame.
 */
/*----------------------------------------------------------------*/
cpl_error_code
sinfo_print_cpl_frame(const cpl_frame *f)
{
    if (f == NULL ) {
        sinfo_msg("NULL");
    }
    else {
        sinfo_msg("%-7s %-20s '%s'",
                        sinfo_tostring_cpl_frame_group(cpl_frame_get_group(f)),
                        cpl_frame_get_tag(f) != NULL ? cpl_frame_get_tag(f) : "Null",
                        cpl_frame_get_filename(f));

        sinfo_msg_debug("type \t= %s",
                        sinfo_tostring_cpl_frame_type(cpl_frame_get_type(f)));
        sinfo_msg_debug("group \t= %s",
                        sinfo_tostring_cpl_frame_group(cpl_frame_get_group(f)));
        sinfo_msg_debug("level \t= %s",
                        sinfo_tostring_cpl_frame_level(cpl_frame_get_level(f)));
    }

    return cpl_error_get_code();
}

/*----------------------------------------------------------------*/
/** 
 * @brief Convert a frame type to a string
 * @param ft  Frame type to convert
 * @return A textual representation of @em  ft.
 */
/*----------------------------------------------------------------*/
const char *
sinfo_tostring_cpl_frame_type(cpl_frame_type ft)
{
    switch (ft)
        {
    case CPL_FRAME_TYPE_NONE:
        return "NONE";
    case CPL_FRAME_TYPE_IMAGE:
        return "IMAGE";
    case CPL_FRAME_TYPE_MATRIX:
        return "MATRIX";
    case CPL_FRAME_TYPE_TABLE:
        return "TABLE";
    default:
        return "unrecognized frame type";
        }
}

/*----------------------------------------------------------------*/
/** 
 * @brief Convert a frame group to a string
 * @param fg  Frame group to convert
 * @return A textual representation of @em  fg.
 */
/*----------------------------------------------------------------*/
const char *
sinfo_tostring_cpl_frame_group(cpl_frame_group fg)
{
    switch (fg)
        {
    case CPL_FRAME_GROUP_NONE:
        return "NONE";
    case CPL_FRAME_GROUP_RAW:
        return CPL_FRAME_GROUP_RAW_ID;
    case CPL_FRAME_GROUP_CALIB:
        return CPL_FRAME_GROUP_CALIB_ID;
    case CPL_FRAME_GROUP_PRODUCT:
        return CPL_FRAME_GROUP_PRODUCT_ID;
    default:
        return "unrecognized frame group";
        }
}

/*----------------------------------------------------------------*/
/** 
 * @brief Convert a frame level to a string
 * @param fl  Frame level to convert
 * @return A textual representation of @em  fl.
 */
/*----------------------------------------------------------------*/
const char *
sinfo_tostring_cpl_frame_level(cpl_frame_level fl)
{

    switch (fl)
        {
    case CPL_FRAME_LEVEL_NONE:
        return "NONE";
    case CPL_FRAME_LEVEL_TEMPORARY:
        return "TEMPORARY";
    case CPL_FRAME_LEVEL_INTERMEDIATE:
        return "INTERMEDIATE";
    case CPL_FRAME_LEVEL_FINAL:
        return "FINAL";
    default:
        return "unrecognized frame level";
        }
}

/*----------------------------------------------------------------*/
/** 
 * @brief Convert a CPL type to a string
 * @param t  Type to convert
 * @return A textual representation of @em  t.
 */
/*----------------------------------------------------------------*/
const char *
sinfo_tostring_cpl_type(cpl_type t)
{

    /* Note that CPL_TYPE_STRING is shorthand
     for CPL_TYPE_CHAR | CPL_TYPE_FLAG_ARRAY . */

    if (!(t & CPL_TYPE_FLAG_ARRAY))
        switch (t & (~CPL_TYPE_FLAG_ARRAY))
            {
        case CPL_TYPE_CHAR:
            return "char";
        case CPL_TYPE_UCHAR:
            return "uchar";
        case CPL_TYPE_BOOL:
            return "boolean";
        case CPL_TYPE_INT:
            return "int";
        case CPL_TYPE_UINT:
            return "uint";
        case CPL_TYPE_LONG:
            return "long";
        case CPL_TYPE_ULONG:
            return "ulong";
        case CPL_TYPE_FLOAT:
            return "float";
        case CPL_TYPE_DOUBLE:
            return "double";
        case CPL_TYPE_POINTER:
            return "pointer";
            /* not in CPL3.0: case CPL_TYPE_COMPLEX:    return "complex"; */
        case CPL_TYPE_INVALID:
            return "invalid";
        default:
            return "unrecognized type";
            }
    else
        switch (t & (~CPL_TYPE_FLAG_ARRAY))
            {
        case CPL_TYPE_CHAR:
            return "string (char array)";
        case CPL_TYPE_UCHAR:
            return "uchar array";
        case CPL_TYPE_BOOL:
            return "boolean array";
        case CPL_TYPE_INT:
            return "int array";
        case CPL_TYPE_UINT:
            return "uint array";
        case CPL_TYPE_LONG:
            return "long array";
        case CPL_TYPE_ULONG:
            return "ulong array";
        case CPL_TYPE_FLOAT:
            return "float array";
        case CPL_TYPE_DOUBLE:
            return "double array";
        case CPL_TYPE_POINTER:
            return "pointer array";
            /* not in CPL3.0: case CPL_TYPE_COMPLEX:    return "complex array"; */
        case CPL_TYPE_INVALID:
            return "invalid (array)";
        default:
            return "unrecognized type";
            }
}
/**@}*/
