/*                                                                              *
 *   This file is part of the X-SHOOTER 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: 2011-12-08 13:59:20 $
 * $Revision: 1.23 $
 * $Name: not supported by cvs2svn $
 * $Log: not supported by cvs2svn $
 * Revision 1.22  2010/09/24 09:32:03  amodigli
 * put back QFITS dependency to fix problem spot by NRI on FIBER mode (with MIDAS calibs) data
 *
 * Revision 1.20  2007/08/21 13:08:26  jmlarsen
 * Removed irplib_access module, largely deprecated by CPL-4
 *
 * Revision 1.19  2007/06/06 08:17:33  amodigli
 * replace tab with 4 spaces
 *
 * Revision 1.18  2007/04/24 12:50:29  jmlarsen
 * Replaced cpl_propertylist -> uves_propertylist which is much faster
 *
 * Revision 1.17  2007/04/24 09:26:11  jmlarsen
 * Do not crash on NULL strings
 *
 * Revision 1.16  2006/11/24 09:36:07  jmlarsen
 * Removed obsolete comment
 *
 * Revision 1.15  2006/11/16 14:12:21  jmlarsen
 * Changed undefined trace number from 0 to -1, to support zero as an actual trace number
 *
 * Revision 1.14  2006/11/15 15:02:14  jmlarsen
 * Implemented const safe workarounds for CPL functions
 *
 * Revision 1.12  2006/11/15 14:04:08  jmlarsen
 * Removed non-const version of parameterlist_get_first/last/next which is already
 * in CPL, added const-safe wrapper, unwrapper and deallocator functions
 *
 * Revision 1.11  2006/11/13 14:23:55  jmlarsen
 * Removed workarounds for CPL const bugs
 *
 * Revision 1.10  2006/11/06 15:19:41  jmlarsen
 * Removed unused include directives
 *
 * Revision 1.9  2006/08/17 13:56:52  jmlarsen
 * Reduced max line length
 *
 * Revision 1.8  2006/08/16 11:46:30  jmlarsen
 * Support printing NULL frame filename
 *
 * Revision 1.7  2006/05/12 15:02:05  jmlarsen
 * Support NULL tags
 *
 * Revision 1.6  2006/02/28 09:15:22  jmlarsen
 * Minor update
 *
 * Revision 1.5  2006/02/15 13:19:15  jmlarsen
 * Reduced source code max. line length
 *
 * Revision 1.4  2005/12/19 16:17:56  jmlarsen
 * Replaced bool -> int
 *
 */

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

#include <uves_cpl_size.h>
/*----------------------------------------------------------------------------*/
/**
   @defgroup uves_dump  Print CPL objects

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

/**@{*/

#include <uves_dump.h>

#include <uves_msg.h>
#include <uves_error.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
uves_print_uves_propertylist(const uves_propertylist *pl, long low, long high)
{
    const cpl_property *prop;
    long i = 0;
    
    assure (0 <= low && high <= uves_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){
    uves_msg("NULL");
    }
    else if (uves_propertylist_is_empty(pl))  {
    uves_msg("[Empty property list]");
    }
    else    
    for (i = low; i < high; i++)
        {
        prop = uves_propertylist_get_const(pl, i);
        check (uves_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
uves_print_cpl_property(const cpl_property *prop)
{
    cpl_type t;

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

        /* print name */
        
        uves_msg("%s =", cpl_property_get_name(prop) != NULL ?
                     cpl_property_get_name(prop) : "NULL");
            
        /* 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 */
            {
                uves_msg("  '%s'", cpl_property_get_string(prop) != NULL ?
                                cpl_property_get_string(prop) : "NULL");
            }
            else                          /* an ordinary char */
            {
                uves_msg("  %c", cpl_property_get_char(prop));
            }
            break;
        case CPL_TYPE_BOOL:    if (cpl_property_get_bool(prop))
            {uves_msg("  true");}
        else
            {uves_msg("  false");}
            break;
        case CPL_TYPE_UCHAR:   uves_msg("  %c", cpl_property_get_char(prop));  break;
        case CPL_TYPE_INT:     uves_msg("  %d", cpl_property_get_int(prop));   break;
        case CPL_TYPE_UINT:    uves_msg("  %d", cpl_property_get_int(prop));   break;
        case CPL_TYPE_LONG:    uves_msg("  %ld", cpl_property_get_long(prop)); break;
        case CPL_TYPE_ULONG:   uves_msg("  %ld", cpl_property_get_long(prop)); break;
        case CPL_TYPE_FLOAT:   uves_msg("  %f", cpl_property_get_float(prop)); break;
        case CPL_TYPE_DOUBLE:  uves_msg("  %f", cpl_property_get_double(prop));break;
        case CPL_TYPE_POINTER: uves_msg("  POINTER");                          break;
        case CPL_TYPE_INVALID: uves_msg("  INVALID");                          break;
        default: uves_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){
        uves_msg("    %s", cpl_property_get_comment(prop) != NULL ? 
                    cpl_property_get_comment(prop) : "NULL");
        }
    }

  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
uves_print_cpl_frameset(const cpl_frameset *frames)
{
    /* Two special cases: a NULL frame set and an empty frame set */

    if (frames == NULL)
    {
        uves_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)
        {
            uves_msg("[Empty frame set]");
        }
        else
        {
            while(f != NULL)
            {
                check( uves_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
uves_print_cpl_frame(const cpl_frame *f)
{
    if (f == NULL)
    {
        uves_msg("NULL");
    }
    else
    {
        const char *filename = cpl_frame_get_filename(f);

        if (filename == NULL)
        {
            cpl_error_reset();
            filename = "Null";
        }

        uves_msg("%-7s %-20s '%s'", 
             uves_tostring_cpl_frame_group(cpl_frame_get_group(f)),
             cpl_frame_get_tag(f)      != NULL ? cpl_frame_get_tag(f) : "Null",
             filename);
        
        uves_msg_debug("type \t= %s",   uves_tostring_cpl_frame_type (cpl_frame_get_type (f)));
        uves_msg_debug("group \t= %s",  uves_tostring_cpl_frame_group(cpl_frame_get_group(f)));
        uves_msg_debug("level \t= %s",  uves_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 *
uves_tostring_cpl_frame_type(cpl_frame_type ft)
{    
    switch(ft)
    {
    case CPL_FRAME_TYPE_NONE:   return "NONE";      break;
    case CPL_FRAME_TYPE_IMAGE:  return "IMAGE";     break;
    case CPL_FRAME_TYPE_MATRIX: return "MATRIX";    break;
    case CPL_FRAME_TYPE_TABLE:  return "TABLE";     break;
    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 *
uves_tostring_cpl_frame_group(cpl_frame_group fg)
{
    switch(fg)
    {
    case CPL_FRAME_GROUP_NONE:    return "NONE";                       break;
    case CPL_FRAME_GROUP_RAW:     return CPL_FRAME_GROUP_RAW_ID;       break;
    case CPL_FRAME_GROUP_CALIB:   return CPL_FRAME_GROUP_CALIB_ID;     break;
    case CPL_FRAME_GROUP_PRODUCT: return CPL_FRAME_GROUP_PRODUCT_ID;   break;
    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 *
uves_tostring_cpl_frame_level(cpl_frame_level fl)
{
    
    switch(fl)
    {
    case CPL_FRAME_LEVEL_NONE:        return "NONE";        break;
    case CPL_FRAME_LEVEL_TEMPORARY:   return "TEMPORARY";   break;
    case CPL_FRAME_LEVEL_INTERMEDIATE:return "INTERMEDIATE";break;
    case CPL_FRAME_LEVEL_FINAL:       return "FINAL";       break;
    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 *
uves_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";    break;
        case CPL_TYPE_UCHAR:      return "uchar";   break;
        case CPL_TYPE_BOOL:       return "boolean"; break;
        case CPL_TYPE_INT:        return "int";     break;
        case CPL_TYPE_UINT:       return "uint";    break;
        case CPL_TYPE_LONG:       return "long";    break;
        case CPL_TYPE_ULONG:      return "ulong";   break;
        case CPL_TYPE_FLOAT:      return "float";   break;
        case CPL_TYPE_DOUBLE:     return "double";  break;
        case CPL_TYPE_POINTER:    return "pointer"; break;
/* not in CPL3.0: case CPL_TYPE_COMPLEX:    return "complex"; break; */
        case CPL_TYPE_INVALID:    return "invalid"; break;
        default:
        return "unrecognized type";
        }
    else
    switch(t & (~CPL_TYPE_FLAG_ARRAY))
        {
        case CPL_TYPE_CHAR:       return "string (char array)"; break;
        case CPL_TYPE_UCHAR:      return "uchar array";         break;
        case CPL_TYPE_BOOL:       return "boolean array";       break;
        case CPL_TYPE_INT:        return "int array";           break;
        case CPL_TYPE_UINT:       return "uint array";          break;
        case CPL_TYPE_LONG:       return "long array";          break;
        case CPL_TYPE_ULONG:      return "ulong array";         break;
        case CPL_TYPE_FLOAT:      return "float array";         break;
        case CPL_TYPE_DOUBLE:     return "double array";        break;
        case CPL_TYPE_POINTER:    return "pointer array";       break;
/* not in CPL3.0: case CPL_TYPE_COMPLEX:    return "complex array"; break; */
        case CPL_TYPE_INVALID:    return "invalid (array)";     break;
        default:
        return "unrecognized type";
        }
}
/**@}*/
