/*                                                                            *
 *   This file is part of the ESO X-shooter Pipeline                          *
 *   Copyright (C) 2006 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-01-02 15:27:33 $
 * $Revision: 1.12 $
 * $Name: not supported by cvs2svn $
 */

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

/*----------------------------------------------------------------------------*/
/**
   @defgroup xsh_dump     Print CPL objects
   @ingroup xsh_tools

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

/**@{*/

#include "xsh_dump.h"

#include <xsh_error.h>
#include <xsh_msg.h>

#include <cpl.h>
#include <xsh_cpl_size.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
xsh_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) {
    xsh_msg ("NULL");
  }
  else if (cpl_propertylist_is_empty (pl)) {
    xsh_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 (xsh_print_cpl_property (prop));
    }

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
xsh_print_cpl_property (const cpl_property * prop)
{
  cpl_type t;

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

    /* print name */

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

    /* print value */

    check (t = cpl_property_get_type (prop));

    switch (t & (~CPL_TYPE_FLAG_ARRAY)) {
    case CPL_TYPE_CHAR:
      if (t & CPL_TYPE_FLAG_ARRAY) {	/* if type is string */
	xsh_msg ("  '%s'", cpl_property_get_string (prop));
      }
      else {			/* an ordinary char */

	xsh_msg ("  %c", cpl_property_get_char (prop));
      }
      break;
    case CPL_TYPE_BOOL:
      if (cpl_property_get_bool (prop)) {
	xsh_msg ("  true");
      }
      else {
	xsh_msg ("  false");
      }
      break;
    case CPL_TYPE_UCHAR:
      xsh_msg ("  %c", cpl_property_get_char (prop));
      break;
    case CPL_TYPE_INT:
      xsh_msg ("  %d", cpl_property_get_int (prop));
      break;
    case CPL_TYPE_UINT:
      xsh_msg ("  %d", cpl_property_get_int (prop));
      break;
    case CPL_TYPE_LONG:
      xsh_msg ("  %ld", cpl_property_get_long (prop));
      break;
    case CPL_TYPE_ULONG:
      xsh_msg ("  %ld", cpl_property_get_long (prop));
      break;
    case CPL_TYPE_FLOAT:
      xsh_msg ("  %f", cpl_property_get_float (prop));
      break;
    case CPL_TYPE_DOUBLE:
      xsh_msg ("  %f", cpl_property_get_double (prop));
      break;
    case CPL_TYPE_POINTER:
      xsh_msg ("  POINTER");
      break;
    case CPL_TYPE_INVALID:
      xsh_msg ("  INVALID");
      break;
    default:
      xsh_msg ("  unrecognized property");
      break;
    }

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

    /* Print comment */
    if (cpl_property_get_comment (prop) != NULL) {
      xsh_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
xsh_print_cpl_frameset (cpl_frameset * frames)
{
  /* Two special cases: a NULL frame set and an empty frame set */

  if (frames == NULL) {
    xsh_msg ("NULL");
  }
  else {
    const cpl_frame *f = NULL;
    cpl_frameset_iterator* it = cpl_frameset_iterator_new(frames);
    f = cpl_frameset_iterator_get(it);

    if (f == NULL) {
      xsh_msg ("[Empty frame set]");
    }
    else {
      do {
	check (xsh_print_cpl_frame (f));
	cpl_frameset_iterator_advance(it, 1);
	f = cpl_frameset_iterator_get_const(it);

      }
      while (f != NULL);
    }
    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
xsh_print_cpl_frame (const cpl_frame * f)
{
  if (f == NULL) {
    xsh_msg ("NULL");
  }
  else {
    xsh_msg ("%-7s %-20s '%s'",
	     xsh_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));

    xsh_msg_dbg_low ("type \t= %s",
		   xsh_tostring_cpl_frame_type (cpl_frame_get_type (f)));
    xsh_msg_dbg_low ("group \t= %s",
		   xsh_tostring_cpl_frame_group (cpl_frame_get_group (f)));
    xsh_msg_dbg_low ("level \t= %s",
		   xsh_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 *
xsh_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 *
xsh_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 *
xsh_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 *
xsh_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";
    }
}

/**@}*/
