/* $Id: kmo_debug.c,v 1.5 2013-06-17 07:52:26 aagudo 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: aagudo $
 * $Date: 2013-06-17 07:52:26 $
 * $Revision: 1.5 $
 * $Name: not supported by cvs2svn $
 */

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

#include <string.h>

#include <cpl.h>

#include "kmclipm_constants.h"

#include "kmo_debug.h"
#include "kmo_error.h"

/**
    @defgroup kmos_debug  Debugging functions

    @{
*/

/**
    @brief
        All properties contained in @c header are printed as pairs of keyword
        and data for debugging purposes.

    @param header The propertylist to print.

    @return
        The function returns CPL_ERROR_NONE on success or a CPL error code
        otherwise.

    Possible cpl_error_code set in this function:

    @li CPL_ERROR_NULL_INPUT if @c header is NULL.
*/
cpl_error_code kmo_debug_header(const cpl_propertylist *header)
{
    int                 i       = 0;
    const cpl_property  *p      = NULL;
    cpl_type            t;
    cpl_error_code      ret_error   = CPL_ERROR_NONE;

    KMO_TRY
    {
        cpl_msg_debug("", "===== START HEADER =====");
        if (header == NULL) {
            cpl_msg_warning("", "Empty header!");
        } else {
            for (i = 0; i < cpl_propertylist_get_size(header); i++) {
                KMO_TRY_EXIT_IF_NULL(
                    p = cpl_propertylist_get_const(header, i));

                t = cpl_property_get_type (p);
                KMO_TRY_CHECK_ERROR_STATE();
                switch (t) {
                    case CPL_TYPE_BOOL:
                        cpl_msg_debug("", "%s: %d", cpl_property_get_name(p),
                                        cpl_property_get_bool(p));
                        break;
                    case CPL_TYPE_INT:
                        cpl_msg_debug("", "%s: %d", cpl_property_get_name(p),
                                        cpl_property_get_int(p));
                        break;
                    case CPL_TYPE_DOUBLE:
                        cpl_msg_debug("", "%s: %12.16g", cpl_property_get_name(p),
                                        cpl_property_get_double(p));
                        break;
                    case CPL_TYPE_FLOAT:
                        cpl_msg_debug("", "%s: %12.16f", cpl_property_get_name(p),
                                        cpl_property_get_float(p));
                        break;
                    case CPL_TYPE_STRING:
                        cpl_msg_debug("", "%s: %s", cpl_property_get_name(p),
                                        cpl_property_get_string(p));
                        break;
                    default:
                        break;
                }
            }
        }
        cpl_msg_debug("", "====== END HEADER ======");
        KMO_TRY_CHECK_ERROR_STATE();
    }
    KMO_CATCH
    {
        KMO_CATCH_MSG();
        ret_error = cpl_error_get_code();
    }

    return ret_error;
}

/**
    @brief
        All frames contained in @c frameset are printed for debugging purposes.

    @param frameset The frameset to print.

    @return
        The function returns CPL_ERROR_NONE on success or a CPL error code
        otherwise.

    Possible cpl_error_code set in this function:

    @li CPL_ERROR_NULL_INPUT if @c frameset is NULL.
*/
cpl_error_code kmo_debug_frameset(const cpl_frameset *frameset)
{
    const cpl_frame *frame      = NULL;   /* must not be deleted at the end */
    cpl_error_code  ret_error   = CPL_ERROR_NONE;

    KMO_TRY
    {
        cpl_msg_debug("", "====== START FRAMESET ======");
        if (frameset == NULL) {
            cpl_msg_warning("", "Empty frameset!");
        } else {
            frame = cpl_frameset_find_const(frameset, NULL);

            if (KMO_TRY_GET_NEW_ERROR(void) != CPL_ERROR_NONE) {
                KMO_TRY_RECOVER();

                cpl_msg_debug("", "====== END FRAMESET ======");

                return CPL_ERROR_NONE;
            }

            while (frame != NULL) {
                kmo_debug_frame(frame);
                KMO_TRY_EXIT_IF_NULL(
                    frame = cpl_frameset_find_const(frameset, NULL));
            }
        }
        cpl_msg_debug("", "====== END FRAMESET ======");
        KMO_TRY_CHECK_ERROR_STATE();
    }
    KMO_CATCH
    {
        KMO_CATCH_MSG();
        ret_error = cpl_error_get_code();
    }

    return ret_error;
}

/**
    @brief
        The CPL_FRAME_TYPE, CPL_FRAME_LEVEL and CPL_FRAME_GROUP of @c frame are
        printed for debugging purposes.

    @param frame The frame to print.

    @return
        The function returns CPL_ERROR_NONE on success or a CPL error code
        otherwise.

    Possible cpl_error_code set in this function:

    @li CPL_ERROR_NULL_INPUT if @c frame is NULL.
*/
cpl_error_code kmo_debug_frame(const cpl_frame *frame)
{
    const char      *tmp        = NULL;
    int             i           = 0;
    cpl_error_code  ret_error   = CPL_ERROR_NONE;

    KMO_TRY
    {
        cpl_msg_debug("", "     ====== START FRAME ======");
        if (frame == NULL) {
            cpl_msg_warning("", "Empty frame!");
        } else {
            tmp = cpl_frame_get_filename(frame);

            if (KMO_TRY_GET_NEW_ERROR(void) != CPL_ERROR_NONE) {

                KMO_TRY_RECOVER();
                cpl_msg_debug("", "     ====== END FRAME ======");
                return CPL_ERROR_NONE;
            }

            cpl_msg_debug("", "filename: %s", tmp);
            cpl_msg_debug("", "tag:      %s", cpl_frame_get_tag(frame));

            i = cpl_frame_get_type(frame);
            KMO_TRY_CHECK_ERROR_STATE();
            switch(i) {
                case CPL_FRAME_TYPE_NONE:
                    cpl_msg_debug("", "type:     CPL_FRAME_TYPE_NONE (%d)", i);
                    break;
                case CPL_FRAME_TYPE_IMAGE:
                    cpl_msg_debug("", "type:     CPL_FRAME_TYPE_IMAGE (%d)", i);
                    break;
                case CPL_FRAME_TYPE_MATRIX:
                    cpl_msg_debug("", "type:     CPL_FRAME_TYPE_MATRIX (%d)", i);
                    break;
                case CPL_FRAME_TYPE_TABLE:
                    cpl_msg_debug("", "type:     CPL_FRAME_TYPE_TABLE (%d)", i);
                    break;
                case CPL_FRAME_TYPE_PAF:
                    cpl_msg_debug("", "type:     CPL_FRAME_TYPE_PAF (%d)", i);
                    break;
                case CPL_FRAME_TYPE_ANY:
                    cpl_msg_debug("", "type:     CPL_FRAME_TYPE_ANY (%d)", i);
                    break;
                default:
                    cpl_msg_debug("", "type:     other ERROR (%d)", i);
            }

            i = cpl_frame_get_group(frame);
            KMO_TRY_CHECK_ERROR_STATE();
            switch(i) {
                case CPL_FRAME_GROUP_NONE:
                    cpl_msg_debug("", "group:    CPL_FRAME_GROUP_NONE (%d)", i);
                    break;
                case CPL_FRAME_GROUP_RAW:
                    cpl_msg_debug("", "group:    CPL_FRAME_GROUP_RAW (%d)", i);
                    break;
                case CPL_FRAME_GROUP_CALIB:
                    cpl_msg_debug("", "group:    CPL_FRAME_GROUP_CALIB (%d)", i);
                    break;
                case CPL_FRAME_GROUP_PRODUCT:
                    cpl_msg_debug("", "group:    CPL_FRAME_GROUP_PRODUCT (%d)", i);
                    break;
                default:
                    cpl_msg_debug("", "group:    other ERROR (%d)", i);
            }

            i = cpl_frame_get_level(frame);
            KMO_TRY_CHECK_ERROR_STATE();
            switch(i) {
                case CPL_FRAME_GROUP_NONE:
                    cpl_msg_debug("", "level:    CPL_FRAME_LEVEL_NONE (%d)", i);
                    break;
                case CPL_FRAME_GROUP_RAW:
                    cpl_msg_debug("", "level:    CPL_FRAME_LEVEL_TEMPORARY (%d)", i);
                    break;
                case CPL_FRAME_GROUP_CALIB:
                    cpl_msg_debug("", "level:    CPL_FRAME_LEVEL_INTERMEDIATE (%d)", i);
                    break;
                case CPL_FRAME_GROUP_PRODUCT:
                    cpl_msg_debug("", "level:    CPL_FRAME_LEVEL_FINAL (%d)", i);
                    break;
                default:
                    cpl_msg_debug("", "level:    other ERROR (%d)", i);
            }
        }
        cpl_msg_debug("", "     ====== END FRAME ======");
        KMO_TRY_CHECK_ERROR_STATE();
    }
    KMO_CATCH
    {
        KMO_CATCH_MSG();
        ret_error = cpl_error_get_code();
    }

    return ret_error;
}

/**
    @brief
        All images contained in @c imglist are printed for debugging purposes.

    @param imglist The imagelist to print.

    @return
        The function returns CPL_ERROR_NONE on success or a CPL error code
        otherwise.

    Possible cpl_error_code set in this function:

    @li CPL_ERROR_NULL_INPUT if @c imglist is NULL.
*/
cpl_error_code kmo_debug_cube(const cpl_imagelist *imglist)
{
    int             i           = 0;
    cpl_error_code  ret_error   = CPL_ERROR_NONE;

    KMO_TRY
    {
        cpl_msg_debug("", "====== START IMAGELIST ======");
        if (imglist == NULL) {
            cpl_msg_warning("", "Empty cube!");
        } else {
            for (i = 0; i < cpl_imagelist_get_size(imglist); i++) {
                KMO_TRY_EXIT_IF_ERROR(
                    kmo_debug_image(cpl_imagelist_get_const(imglist, i)));
            }
        }
        cpl_msg_debug("", "====== END IMAGELIST ======");
        KMO_TRY_CHECK_ERROR_STATE();
    }
    KMO_CATCH
    {
        KMO_CATCH_MSG();
        ret_error = cpl_error_get_code();
    }

    return ret_error;
}

/**
    @brief
        All values contained in @c img are printed for debugging purposes.

    @param img The image to print.

    @return
        The function returns CPL_ERROR_NONE on success or a CPL error code
        otherwise.

    Possible cpl_error_code set in this function:

    @li CPL_ERROR_NULL_INPUT if @c img is NULL.
*/
cpl_error_code kmo_debug_image(const cpl_image *img)
{
    int             x           = 0,
                    y           = 0;
    int             gaga        = 0;
    cpl_error_code  ret_error   = CPL_ERROR_NONE;
    char            line[200000],
                    tmp[2048];

    KMO_TRY
    {
        cpl_msg_debug("", "     ====== START IMAGE ======");
        if (img == NULL) {
            cpl_msg_warning("", "Empty image!");
        } else {
            strcpy(line, " ");
            for (y = 1; y <= cpl_image_get_size_y(img); y++) {
                for (x = 1; x <= cpl_image_get_size_x(img); x++) {
                    sprintf(tmp, "%f   ", cpl_image_get(img, x, y, &gaga));
                    strcat(line, tmp);
                    KMO_TRY_CHECK_ERROR_STATE();
                }
                strcat(line, "");
                cpl_msg_debug("", "%s", line);
            }
        }
        cpl_msg_debug("", "     ====== END IMAGE ======");
        KMO_TRY_CHECK_ERROR_STATE();
    }
    KMO_CATCH
    {
        KMO_CATCH_MSG();
        ret_error = cpl_error_get_code();
    }

    return ret_error;
}

/**
    @brief
        All values contained in @c vec are printed for debugging purposes.

    @param vec The vector to print.

    @return
        The function returns CPL_ERROR_NONE on success or a CPL error code
        otherwise.

    Possible cpl_error_code set in this function:

    @li CPL_ERROR_NULL_INPUT if @c vec is NULL.
*/
cpl_error_code kmo_debug_vector(const cpl_vector *vec)
{
    int             x           = 0,
                    size        = 0;
    cpl_error_code  ret_error   = CPL_ERROR_NONE;
    const double    *pvec       = NULL;

    KMO_TRY
    {
        cpl_msg_debug("", "     ====== START VECTOR ======");
        if (vec == NULL) {
            cpl_msg_warning("", "Empty vector!");
        } else {
            KMO_TRY_EXIT_IF_NULL(
                pvec = cpl_vector_get_data_const(vec));

            size = cpl_vector_get_size(vec);
            for (x = 0; x < size; x++) {
                cpl_msg_debug("", "%12.16g   ", pvec[x]);
            }
        }
        cpl_msg_debug("", "     ====== END VECTOR ======");
        KMO_TRY_CHECK_ERROR_STATE();
    }
    KMO_CATCH
    {
        KMO_CATCH_MSG();
        ret_error = cpl_error_get_code();
    }

    return ret_error;
}


/**
    @brief
        All values contained in @c arr are printed for debugging purposes.

    @param arr The array to print.

    @return
        The function returns CPL_ERROR_NONE on success or a CPL error code
        otherwise.

    Possible cpl_error_code set in this function:

    @li CPL_ERROR_NULL_INPUT if @c arr is NULL.
*/
cpl_error_code kmo_debug_array(const cpl_array *arr)
{
    int             x           = 0,
                    size        = 0;
    const int       *pint       = NULL;
    const double    *pdouble    = NULL;
    cpl_error_code  ret_error   = CPL_ERROR_NONE;
    cpl_type        type;

    KMO_TRY
    {
        if (arr != NULL) {
            type = cpl_array_get_type(arr);
            size = cpl_array_get_size(arr);

            switch (type) {
                case CPL_TYPE_INT:
                    pint = cpl_array_get_data_int_const(arr);
                    cpl_msg_debug("", "     ====== START ARRAY ======");
                    if (arr== NULL) {
                        cpl_msg_warning("", "Empty array!");
                    } else {
                        for (x = 0; x < size; x++) {
                            cpl_msg_debug("", "%i", pint[x]);
                        }
                    }
                    cpl_msg_debug("", "     ====== END ARRAY ======");
                    break;
                case CPL_TYPE_DOUBLE:
                    pdouble = cpl_array_get_data_double_const(arr);
                    cpl_msg_debug("", "     ====== START ARRAY ======");
                    if (arr== NULL) {
                        cpl_msg_warning("", "Empty array!");
                    } else {
                        for (x = 0; x < size; x++) {
                            cpl_msg_debug("", "%12.16g", pdouble[x]);
                        }
                    }
                    cpl_msg_debug("", "     ====== END ARRAY ======");
                    break;
                default:
                    cpl_msg_debug("", ">>> cpl_type (%d) not supported!", type);
                    break;
            }
            KMO_TRY_CHECK_ERROR_STATE();
        } else {
            cpl_msg_debug("", "     ====== START ARRAY ======");
            cpl_msg_debug("", "Empty array!");
            cpl_msg_debug("", "     ====== END ARRAY ======");
        }
    }
    KMO_CATCH
    {
        KMO_CATCH_MSG();
        ret_error = cpl_error_get_code();
    }

    return ret_error;
}
/**
    @brief
        All values contained in @c desc are printed for debugging purposes.

    @param desc The @c main_fits_desc to print.

    @return
        The function returns CPL_ERROR_NONE on success or a CPL error code
        otherwise.
*/
cpl_error_code kmo_debug_desc(const main_fits_desc desc)
{
    int             i           = 0;
    cpl_error_code  ret_error   = CPL_ERROR_NONE;
    char            line[2048],
                    tmp[512];

    KMO_TRY
    {
        cpl_msg_debug("", "====== START MAIN_DESC ======");

        strcpy(line, "fits_type:   ");
        switch(desc.fits_type) {
            case raw_fits:
                sprintf(tmp, "%s   ", "RAW");
                strcat(line, tmp);
                break;
            case f2d_fits:
                sprintf(tmp, "%s   ", "F2D");
                strcat(line, tmp);
                break;
            case b2d_fits:
                sprintf(tmp, "%s   ", "B2D");
                strcat(line, tmp);
                break;
            case f2l_fits:
                sprintf(tmp, "%s   ", "F2L");
                strcat(line, tmp);
                break;
            case f1i_fits:
                sprintf(tmp, "%s   ", "F1I");
                strcat(line, tmp);
                break;
            case f1l_fits:
                sprintf(tmp, "%s   ", "F1L");
                strcat(line, tmp);
                break;
            case f1s_fits:
                sprintf(tmp, "%s   ", "F1S");
                strcat(line, tmp);
                break;
            case f2i_fits:
                sprintf(tmp, "%s   ", "F2I");
                strcat(line, tmp);
                break;
            case f3i_fits:
                sprintf(tmp, "%s   ", "F3I");
                strcat(line, tmp);
                break;
            default:
                sprintf(tmp, "%s   ", "ILLEGAL FITS");
                strcat(line, tmp);
        }
        cpl_msg_debug("", "%s", line);

        strcpy(line, "frame_type:  ");
        switch(desc.frame_type) {
            case detector_frame:
                sprintf(tmp, "%s   ", "DETECTOR");
                strcat(line, tmp);
                break;
            case ifu_frame:
                sprintf(tmp, "%s   ", "IFU");
                strcat(line, tmp);
                break;
            default:
                sprintf(tmp, "%s   ", "ILLEGAL FRAME");
                strcat(line, tmp);
        }
        cpl_msg_debug("", "%s", line);

        cpl_msg_debug("", "naxis:       %d", desc.naxis);
        cpl_msg_debug("", "naxis1:      %d", desc.naxis1);
        cpl_msg_debug("", "naxis2:      %d", desc.naxis2);
        cpl_msg_debug("", "naxis3:      %d", desc.naxis3);
        if (desc.ex_noise == TRUE)
            cpl_msg_debug("", "ex_noise:    TRUE");
        else
            cpl_msg_debug("", "ex_noise:    FALSE");
        if (desc.ex_badpix == TRUE)
            cpl_msg_debug("", "ex_badpix:    TRUE");
        else
            cpl_msg_debug("", "ex_badpix:    FALSE");
        cpl_msg_debug("", "nr_ext:      %d", desc.nr_ext);

        for (i = 0; i < desc.nr_ext; i++) {
            cpl_msg_debug("", "====== SUB_DESC %d ======", i);
            cpl_msg_debug("", "ext_index:   %d", desc.sub_desc[i].ext_nr);
            if (desc.sub_desc[i].valid_data == TRUE)
                cpl_msg_debug("", "valid_data:  TRUE");
            else
                cpl_msg_debug("", "valid_data:  FALSE");
            if (desc.sub_desc[i].is_noise == TRUE)
                cpl_msg_debug("", "is_noise:    TRUE");
            else
                cpl_msg_debug("", "is_noise:    FALSE");
            if (desc.sub_desc[i].is_badpix == TRUE)
                cpl_msg_debug("", "is_badpix:    TRUE");
            else
                cpl_msg_debug("", "is_badpix:    FALSE");
            cpl_msg_debug("", "frame_nr:    %d", desc.sub_desc[i].device_nr);
        }

        cpl_msg_debug("", "====== END MAIN_DESC ======");
        KMO_TRY_CHECK_ERROR_STATE();
    }
    KMO_CATCH
    {
        KMO_CATCH_MSG();
        ret_error = cpl_error_get_code();
    }

    return ret_error;
}

/**
    @brief
        All values contained in @c table are printed for debugging purposes.

    @param table The table to print.

    @return
        The function returns CPL_ERROR_NONE on success or a CPL error code
        otherwise.

    Possible cpl_error_code set in this function:

    @li CPL_ERROR_NULL_INPUT if @c table is NULL.
*/
cpl_error_code kmo_debug_table(const cpl_table *table)
{
    cpl_error_code  ret_error   = CPL_ERROR_NONE;

    KMO_TRY
    {
        cpl_msg_debug("", "     ====== START TABLE ======");
        if (table == NULL) {
            cpl_msg_warning("", "Empty table pointer!");
        } else {
            cpl_table_dump(table, 0, cpl_table_get_nrow(table), NULL);
        }
        cpl_msg_debug("", "     ====== END TABLE ======");
        KMO_TRY_CHECK_ERROR_STATE();
    }
    KMO_CATCH
    {
        KMO_CATCH_MSG();
        ret_error = cpl_error_get_code();
    }

    return ret_error;
}

/**
    @brief
        Plots a vector only if message level is CPL_MSG_DEBUG.

    @param pre      An optional string with pre-plot commands
    @param opt      An optional string with plotting options
    @param vector   The vector to plot.

    @return
        The function returns CPL_ERROR_NONE on success or a CPL error code
        otherwise.

    Possible cpl_error_code set in this function:
    Any possibly set error from cpl_plot_vector()
*/
cpl_error_code kmo_plot_vector(const char *pre, const char *opt,
                               const cpl_vector *vector)
{
    cpl_error_code  ret_error   = CPL_ERROR_NONE;

    char            *ostype     = NULL,
                    pre_final[1024];

    KMO_TRY
    {
        if ((vector != NULL) &&
            (cpl_msg_get_level() == CPL_MSG_DEBUG))
        {
            strcpy(pre_final, "");
            if (pre != NULL) {
                strcat(pre_final, pre);
            }
            ostype = getenv("OSTYPE");
            if(strcmp(ostype, "darwin") == 0) {
                strcat(pre_final, "set term x11;");
            }

            KMO_TRY_EXIT_IF_ERROR(
                cpl_plot_vector(pre_final, opt, NULL, vector));
        }
    }
    KMO_CATCH
    {
        KMO_CATCH_MSG();
        ret_error = cpl_error_get_code();
    }

    return ret_error;
}

/**
    @brief
        Plots vector y against vector x.

    @param pre      An optional string with pre-plot commands
    @param opt      An optional string with plotting options
    @param x The vector to plot.
    @param y The vector to plot.

    @return
        The function returns CPL_ERROR_NONE on success or a CPL error code
        otherwise.

    Possible cpl_error_code set in this function:
    Any possibly set error from cpl_plot_vector()
*/
cpl_error_code kmo_plot_vectors_xy(const char *pre, const char *opt,
                                   cpl_vector *x, cpl_vector *y)
{
    cpl_error_code  ret_error   = CPL_ERROR_NONE;

    cpl_bivector    *bi         = NULL;

    char            *ostype     = NULL,
                    pre_final[1024];

    KMO_TRY
    {
        if ((x != NULL) && (y != NULL) &&
            (cpl_msg_get_level() == CPL_MSG_DEBUG))
        {
            strcpy(pre_final, "");
            if (pre != NULL) {
                strcat(pre_final, pre);
            }
            ostype = getenv("OSTYPE");
            if(strcmp(ostype, "darwin") == 0) {
                strcat(pre_final, "set term x11;");
            }

            KMO_TRY_EXIT_IF_NULL(
                bi = cpl_bivector_wrap_vectors(x, y));

            KMO_TRY_EXIT_IF_ERROR(
                cpl_plot_bivector(pre_final, opt, NULL, bi));

            cpl_bivector_unwrap_vectors(bi);
        }
    }
    KMO_CATCH
    {
        KMO_CATCH_MSG();
        ret_error = cpl_error_get_code();
    }

    return ret_error;
}

/**
    @brief
        Plots 2 vectors against vector x.

    @param pre      An optional string with pre-plot commands
    @param opt      An optional string with plotting options
    @param x  The vector to plot.
    @param y1 The 1st vector to plot.
    @param y2 The 2nd vector to plot.

    @return
        The function returns CPL_ERROR_NONE on success or a CPL error code
        otherwise.

    Possible cpl_error_code set in this function:
    Any possibly set error from cpl_plot_vector()
*/
cpl_error_code     kmo_plot_vectors2(const char *pre, const char **opt,
                                     cpl_vector *x,
                                     cpl_vector *y1,
                                     cpl_vector *y2)
{
    cpl_error_code  ret_error   = CPL_ERROR_NONE;

    int             nr_plots            = 2;
    cpl_bivector    *plots[nr_plots];
    char            *ostype             = NULL,
                    pre_final[1024];

    KMO_TRY
    {
        if ((x != NULL) && (y1 != NULL) && (y2 != NULL) &&
            (cpl_msg_get_level() == CPL_MSG_DEBUG))
        {
            strcpy(pre_final, "");
            if (pre != NULL) {
                strcat(pre_final, pre);
            }
            ostype = getenv("OSTYPE");
            if(strcmp(ostype, "darwin") == 0) {
                strcat(pre_final, "set term x11;");
            }

            KMO_TRY_EXIT_IF_NULL(
                plots[0] = cpl_bivector_wrap_vectors(x, y1));
            KMO_TRY_EXIT_IF_NULL(
                plots[1] = cpl_bivector_wrap_vectors(x, y2));

            CPL_DIAG_PRAGMA_PUSH_IGN(-Wcast-qual);
            cpl_error_code err = cpl_plot_bivectors(pre_final, opt, "",
            		(const cpl_bivector **)plots,
                    nr_plots);
            CPL_DIAG_PRAGMA_POP;

            KMO_TRY_EXIT_IF_ERROR(err);

            int k = 0;
            for (k = 0; k < nr_plots; k++) {
                cpl_bivector_unwrap_vectors(plots[k]);
            }
            KMO_TRY_CHECK_ERROR_STATE();
        }
    }
    KMO_CATCH
    {
        KMO_CATCH_MSG();
        ret_error = cpl_error_get_code();
    }

    return ret_error;
}

/**
    @brief
        Plots an image only if message level is CPL_MSG_DEBUG.

    @param pre      An optional string with pre-plot commands
    @param opt      An optional string with plotting options
    @param img The image to plot.

    @return
        The function returns CPL_ERROR_NONE on success or a CPL error code
        otherwise.

    Possible cpl_error_code set in this function:
    Any possibly set error from cpl_plot_image()
*/
cpl_error_code kmo_plot_image(const char *pre, const char *opt,
                              const cpl_image *img)
{
    cpl_error_code  ret_error   = CPL_ERROR_NONE;

    char            *ostype     = NULL,
                    pre_final[1024];

    KMO_TRY
    {
        if ((img != NULL) &&
            (cpl_msg_get_level() == CPL_MSG_DEBUG))
        {
            strcpy(pre_final, "");
            if (pre != NULL) {
                strcat(pre_final, pre);
            }
            ostype = getenv("OSTYPE");
            if(strcmp(ostype, "darwin") == 0) {
                strcat(pre_final, "set term x11;");
            }

            KMO_TRY_EXIT_IF_ERROR(
                cpl_plot_image(pre_final, opt, NULL, img));
        }
    }
    KMO_CATCH
    {
        KMO_CATCH_MSG();
        ret_error = cpl_error_get_code();
    }

    return ret_error;
}

void kmo_debug_unused_ifus(cpl_array *unused) {
    int     has_inactive_ICS    =   0,
            has_inactive_DRL    =   0,
            *punused            =   NULL;

    char    str[512];

    KMO_TRY
    {
        KMO_TRY_ASSURE(unused != NULL,
                       CPL_ERROR_NULL_INPUT,
                       "Not all input data is provided!");

        KMO_TRY_EXIT_IF_NULL(
            punused = cpl_array_get_data_int(unused));
        for (int j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
            switch (punused[j]) {
            case 0:
                break;
            case 1:
                has_inactive_ICS++;
                break;
            case 2:
                has_inactive_DRL++;
                break;
            default:
                KMO_TRY_ASSURE(1 == 0,
                               CPL_ERROR_ILLEGAL_INPUT,
                               "The unused structure can only contain "
                               "0, 1 or 2!");
            }
        }

        cpl_msg_info("", "*******************************************");

        if ((has_inactive_ICS == 0) && (has_inactive_DRL == 0)) {
            cpl_msg_info("", "   All IFUs are active");
        } else {
            cpl_msg_info("", "   .: IFUs active");
            if (has_inactive_ICS != 0) {
                cpl_msg_info("", "   x: IFUs set inactive by ICS");
            }
            if (has_inactive_DRL != 0) {
                cpl_msg_info("", "   *: IFUs set inactive by KMOS pipeline");
            }
            cpl_msg_info("", "-------------------------------------------");
            cpl_msg_info("", "        1  2  3  4  5  6  7  8");
            cpl_msg_info("", "        9 10 11 12 13 14 15 16");
            cpl_msg_info("", "       17 18 19 20 21 22 23 24");

            sprintf(str, "      ");
            KMO_TRY_EXIT_IF_NULL(
                punused = cpl_array_get_data_int(unused));
            for (int j = 0; j < KMOS_IFUS_PER_DETECTOR; j++) {
                switch (punused[j]) {
                case 0:
                    strcat(str, "  .");
                    break;
                case 1:
                    strcat(str, "  x");
                    break;
                case 2:
                    strcat(str, "  *");
                    break;
                default:
                    ;
                }
            }
            strcat(str, "\0");
            cpl_msg_info("", "%s", str);
        }
        cpl_msg_info("", "*******************************************");
    }
    KMO_CATCH
    {
        KMO_CATCH_MSG();
    }
}

/** @} */
