/* $Id: kmo_priv_fits_check.c,v 1.6 2013-08-02 08:11:37 aagudo Exp $
 *
 * This file is part of the KMOS Library
 * Copyright (C) 2007-2008 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 */

/*
 * $Author: aagudo $
 * $Date: 2013-08-02 08:11:37 $
 * $Revision: 1.6 $
 * $Name: not supported by cvs2svn $
 */

#include <string.h>

#include <cpl.h>

#include "kmclipm_constants.h"
#include "kmclipm_functions.h"

#include "kmo_error.h"
#include "kmo_debug.h"
#include "kmo_dfs.h"
#include "kmo_priv_fits_check.h"

/*----------------------------------------------------------------------------*/
/**
    @defgroup kmos_priv_fits_check     Helper functions for recipe kmo_fits_check.

    @{
 */
/*----------------------------------------------------------------------------*/

/**
    @brief
        Prints a propertylist.

    @param pl   The header to print.

    @return
        The function returns CPL_ERROR_NONE on success or a CPL error code
        otherwise.
*/
cpl_error_code kmo_fits_check_print_header(const cpl_propertylist *pl)
{
    int                 i       = 0;
    const cpl_property  *p      = NULL;
    cpl_type            t;

    cpl_error_code  ret_error   = CPL_ERROR_NONE;

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

        for (i = 0; i < cpl_propertylist_get_size(pl); i++) {
            KMO_TRY_EXIT_IF_NULL(
                p = cpl_propertylist_get_const(pl, i));

            t = cpl_property_get_type (p);
            KMO_TRY_CHECK_ERROR_STATE();

            switch (t) {
                case CPL_TYPE_BOOL:
                    if (cpl_property_get_bool(p) == TRUE) {
                        printf("%s: TRUE    | %s\n", cpl_property_get_name(p),
                                                     cpl_property_get_comment(p));
                    } else {
                        printf("%s: FALSE   | %s\n", cpl_property_get_name(p),
                                                     cpl_property_get_comment(p));
                    }
                    break;
                case CPL_TYPE_CHAR:
                    printf("%s: %c    | %s\n", cpl_property_get_name(p),
                                               cpl_property_get_char(p),
                                               cpl_property_get_comment(p));
                    break;
                case CPL_TYPE_DOUBLE:
                    printf("%s: %12.16g    | %s\n", cpl_property_get_name(p),
                                               cpl_property_get_double(p),
                                               cpl_property_get_comment(p));
                    break;
                case CPL_TYPE_FLOAT:
                    printf("%s: %12.16f    | %s\n", cpl_property_get_name(p),
                                               cpl_property_get_float(p),
                                               cpl_property_get_comment(p));
                    break;
                case CPL_TYPE_INT:
                    printf("%s: %d    | %s\n", cpl_property_get_name(p),
                                               cpl_property_get_int(p),
                                               cpl_property_get_comment(p));
                    break;
                case CPL_TYPE_LONG:
                    printf("%s: %ld    | %s\n", cpl_property_get_name(p),
                                                cpl_property_get_long(p),
                                                cpl_property_get_comment(p));
                    break;
                case CPL_TYPE_STRING:
                    printf("%s: %s    | %s\n", cpl_property_get_name(p),
                                               cpl_property_get_string(p),
                                               cpl_property_get_comment(p));
                    break;
                default:
                    break;
            }
        }
        KMO_TRY_CHECK_ERROR_STATE();
    }
    KMO_CATCH
    {
        KMO_CATCH_MSG();
        ret_error = cpl_error_get_code();
    }

    return ret_error;
}

/**
    @brief
        Prints a vector.

    @param vec   The vector to print.

    @return
        The function returns CPL_ERROR_NONE on success or a CPL error code
        otherwise.
*/
cpl_error_code kmo_fits_check_print_vector(const kmclipm_vector *vec)
{
    int             x           = 0,
                    size        = 0;

    const double    *pvec       = NULL;

    cpl_error_code  ret_error   = CPL_ERROR_NONE;

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

        printf("     ====== START VECTOR ======\n");

        KMO_TRY_EXIT_IF_NULL(
            pvec = cpl_vector_get_data_const(vec->data));

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

    return ret_error;
}

/**
    @brief
        Prints an image.

    @param img   The image to print.

    @return
        The function returns CPL_ERROR_NONE on success or a CPL error code
        otherwise.
*/
cpl_error_code kmo_fits_check_print_image(const cpl_image *img)
{
    int             x           = 0,
                    y           = 0,
                    t           = 0;

    cpl_error_code  ret_error   = CPL_ERROR_NONE;

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

        printf("     ====== START IMAGE ======\n");
        for (y = 1; y <= cpl_image_get_size_y(img); y++) {
            for (x = 1; x <= cpl_image_get_size_x(img); x++) {
                printf("%f   ", cpl_image_get(img, x, y, &t));
            }
            printf("\n");
        }
        printf("     ====== END IMAGE ======\n");
        KMO_TRY_CHECK_ERROR_STATE();
    }
    KMO_CATCH
    {
        KMO_CATCH_MSG();
        ret_error = cpl_error_get_code();
    }

    return ret_error;
}

/**
    @brief
        Prints an imagelist.

    @param imglist   The imagelist to print.

    @return
        The function returns CPL_ERROR_NONE on success or a CPL error code
        otherwise.
*/
cpl_error_code kmo_fits_check_print_imagelist(const cpl_imagelist *imglist)
{
    int             i           = 0;

    cpl_error_code  ret_error   = CPL_ERROR_NONE;

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

        printf("====== START IMAGELIST ======\n");
        for (i = 0; i < cpl_imagelist_get_size(imglist); i++) {
            KMO_TRY_EXIT_IF_ERROR(
                kmo_fits_check_print_image(cpl_imagelist_get_const(imglist, i)));
        }
        printf("====== END IMAGELIST ======\n");
        KMO_TRY_CHECK_ERROR_STATE();
    }
    KMO_CATCH
    {
        KMO_CATCH_MSG();
        ret_error = cpl_error_get_code();
    }

    return ret_error;
}

/**
    @brief
        Prints a table.

    @param table   The table to print.

    @return
        The function returns CPL_ERROR_NONE on success or a CPL error code
        otherwise.
*/
cpl_error_code kmo_fits_check_print_table(const cpl_table *table)
{
    cpl_error_code  ret_error   = CPL_ERROR_NONE;

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

        printf("====== START TABLE ======\n");
        cpl_table_dump(table, 0, cpl_table_get_nrow(table), NULL);
        printf("====== END TABLE ======\n");
        KMO_TRY_CHECK_ERROR_STATE();
    }
    KMO_CATCH
    {
        KMO_CATCH_MSG();
        ret_error = cpl_error_get_code();
    }

    return ret_error;
}

/**
    @brief
        Prints a short description of a FITS file.

    @param valid    TRUE if creating the desc-parameter didn't fail, FALSE
                    otherwise.
    @param desc     The descriptor of the file to examine (in case it is a KMOS
                    FITS file).
    @param frame    The frame of the FITS file to examine.

    @return
        The function returns CPL_ERROR_NONE on success or a CPL error code
        otherwise.
*/
cpl_error_code kmo_fits_check_print_info(int valid,
                                         const main_fits_desc *desc,
                                         const cpl_frame *frame)
{
    char            reason[256],
                    *tmp        = NULL;

    const char      *xtension   = NULL,
                    *extname    = NULL;

    int             i           = 0,
                    is_bin      = FALSE;

    cpl_error_code  ret_error   = CPL_ERROR_NONE;

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

        KMO_TRY_ASSURE((valid == TRUE) ||
                       (valid == FALSE),
                       CPL_ERROR_ILLEGAL_INPUT,
                       "valid must be 0 or 1!");

        printf("++++++++++++++++++++++++++++++++++++++++"
               "++++++++++++++++++++++++++++++++++++++++\n");

        if (valid) {
            char format[256];

            // according to desc, the frame should be valid. Let's see...
            if (desc->fits_type == raw_fits) {
                printf("FORMAT:        RAW\n");
//            } else if (desc->fits_type == f1d_fits) {
//                printf("FORMAT:        F1D\n");
            } else if (desc->fits_type == f2d_fits) {
                printf("FORMAT:        F2D\n");
            } else if (desc->fits_type == b2d_fits) {
                printf("FORMAT:        B2D\n");
            } else if (desc->fits_type == f1i_fits) {
                printf("FORMAT:        F1I\n");
            } else if (desc->fits_type == f2i_fits) {
                printf("FORMAT:        F2I\n");
            } else if (desc->fits_type == f3i_fits) {
                printf("FORMAT:        F3I\n");
            } else if (desc->fits_type == f1l_fits) {
                printf("FORMAT:        F1L\n");
            } else if (desc->fits_type == f2l_fits) {
                printf("FORMAT:        F2L\n");
            } else if (desc->fits_type == f1s_fits) {
                printf("FORMAT:        F1S\n");
            } else {
                valid = FALSE;
                strcpy(reason, ">>> UNEXPECTED ERROR (1) !!!\n");
            }

            if (valid) {
                int nr_noise = 0,
                    nr_data = 0,
                    nr_badpix = 0,
                    nr_empty = 0;
// checks in following bracket should only be for RAW, F1I, F2I, F3I, F1D, F2D
// and B2D (not F1L, F2L, F1S --> add other checks for these!)
                {
                    // print number of axes
                    if ((desc->fits_type != f1l_fits) &&
                        (desc->fits_type != f2l_fits))
                    {
                        printf("NAXIS:         %d\n", desc->naxis);
                    }

                    if (desc->naxis > 0) {
                        if ((desc->fits_type == f1l_fits) ||
                            (desc->fits_type == f2l_fits))
                        {
                            printf("NR.COLUMNS:    %d\n", desc->naxis1);
                        } else {
                            printf("NAXIS1:        %d\n", desc->naxis1);
                        }

                        if (desc->naxis > 1) {
                            if ((desc->fits_type == f1l_fits) ||
                                (desc->fits_type == f2l_fits))
                            {
                                printf("NR.ROWS:       %d\n", desc->naxis2);
                            } else {
                                printf("NAXIS2:        %d\n", desc->naxis2);
                            }

                            if (desc->naxis > 2) {
                                printf("NAXIS3:        %d\n", desc->naxis3);
                            }
                        }
                    }

                    // print if noise exists
                    if (desc->ex_noise == TRUE) {
                        printf("NOISE:         TRUE\n");
                    } else {
                        printf("NOISE:         FALSE\n");
                    }

                    // print if badpix exists
                    if (desc->ex_badpix == TRUE) {
                        printf("BADPIX:        TRUE\n");
                    } else {
                        printf("BADPIX:        FALSE\n");
                    }

                    // print number of extensions
                    printf("NR. EXT:       %d (excluding primary header)\n",
                           desc->nr_ext);

                    // print number of data and noise frames
                    for (i = 0; i < desc->nr_ext; i++) {
                        if (desc->sub_desc[i].valid_data == FALSE) {
                            nr_empty++;
                        } else {
                            if ((desc->sub_desc[i].is_noise == FALSE) &&
                                (desc->sub_desc[i].is_badpix == FALSE))
                            {
                                nr_data++;
                            } else if ((desc->sub_desc[i].is_noise == TRUE) &&
                                       (desc->sub_desc[i].is_badpix == FALSE)) {
                                nr_noise++;
                            } else if ((desc->sub_desc[i].is_noise == FALSE) &&
                                       (desc->sub_desc[i].is_badpix == TRUE)) {
                                nr_badpix++;
                            } else {
                                valid = FALSE;
                                strcpy(reason, ">> badpix & noise not allowed");
                            }
                        }
                    }
                    printf("   NR. DATA:   %d\n", nr_data);
                    printf("   NR. NOISE:  %d\n", nr_noise);
                    printf("   NR. BADPIX: %d\n", nr_badpix);
                    printf("   NR. EMPTY:  %d\n", nr_empty);
                }

                if (valid) {
                    // check numbers of data, noise & badpixel frames and if they
                    // conform to the KMOS FITS standard
                    if (desc->fits_type == raw_fits) {
                        if ((desc->nr_ext == 3) &&
                            (nr_data == 3) &&
                            (nr_noise == 0))
                        {
                            strcpy(format, RAW);
                        } else {
                            valid = FALSE;
                            strcpy(reason, "RAW frame needs exactly 3 data "
                                           "frames (no noise and no badpix "
                                           "frames)!");
                        }
//                    } else if (desc->fits_type == f1d_fits) {
//                        if (((nr_data == desc->nr_ext) &&
//                             (desc->nr_ext <= 3) &&
//                             (nr_noise == 0) &&
//                             (nr_badpix == 0)) ||
//                            ((nr_data == desc->nr_ext / 2) &&
//                             (nr_noise == desc->nr_ext / 2) &&
//                             (desc->nr_ext / 2 <= 3) &&
//                             (nr_badpix == 0)))
//                        {
//                            strcpy(format, F1D);
//                        } else {
//                            valid = FALSE;
//                            strcpy(reason, "F1D frame needs either 3 data "
//                                           "frames or 3 data and 3 noise "
//                                           "frames (and no badpix frames)!");
//                            strcpy(reason, "F1D can contain up to 3 data "
//                                           "frames or up to 3 pairs "
//                                           "of alternating data and noise "
//                                           "frames. But it can't contain "
//                                           "badpixel frames!");
//                        }
                    } else if (desc->fits_type == f2d_fits) {
                        if ((desc->nr_ext % 3 == 0) &&
                            (nr_badpix == 0) &&
                            ((nr_data % 3 == 0) ||
                             (nr_noise % 3 == 0)))
                        {
                            strcpy(format, F2D);
                        } else {
                            valid = FALSE;
                            strcpy(reason, "F2D frame needs modulo 3 data "
                                           "frames (optionally modulo 3 noise "
                                           "frames (and no badpix frames)!");
                        }
                    } else if (desc->fits_type == b2d_fits) {
                        if ((desc->nr_ext % 3 == 0) &&
                            (nr_data == 0) &&
                            (nr_noise == 0) &&
                            (nr_badpix % 3 == 0))
                        {
                            strcpy(format, B2D);
                        } else {
                            valid = FALSE;
                            strcpy(reason, "B2D frame needs exactly modulo 3 bad "
                                           "pixel frames and no noise frames!");
                        }
                    } else if (desc->fits_type == f1i_fits) {
//                        if (((nr_data == desc->nr_ext) &&
//                             (nr_noise == 0) &&
//                             (nr_badpix == 0)) ||
//                            ((nr_data == desc->nr_ext / 2) &&
//                             (nr_noise == desc->nr_ext / 2) &&
//                             (nr_badpix == 0)))
//                        {
                            strcpy(format, F1I);
//                        } else {
//                            valid = FALSE;
//                            strcpy(reason, "F1I can contain as many data "
//                                           "frames as wanted or as many pairs "
//                                           "of alternating data and noise "
//                                           "frames. But it can't contain "
//                                           "badpixel frames!");
//                        }
                    } else if (desc->fits_type == f2i_fits) {
//                        if (((nr_data == desc->nr_ext) &&
//                             (nr_noise == 0) &&
//                             (nr_badpix == 0)) ||
//                            ((nr_data == desc->nr_ext / 2) &&
//                             (nr_noise == desc->nr_ext / 2) &&
//                             (nr_badpix == 0)))
//                        {
                            strcpy(format, F2I);
//                        } else {
//                            valid = FALSE;
//                            strcpy(reason, "F2I can contain as many data "
//                                           "frames as wanted or as many pairs "
//                                           "of alternating data and noise "
//                                           "frames. But it can't contain "
//                                           "badpixel frames!");
//                        }
                    } else if (desc->fits_type == f3i_fits) {
//                        if (((nr_data == desc->nr_ext) &&
//                             (nr_noise == 0) &&
//                             (nr_badpix == 0)) ||
//                            ((nr_data == desc->nr_ext / 2) &&
//                             (nr_noise == desc->nr_ext / 2) &&
//                             (nr_badpix == 0)))
//                        {
                            strcpy(format, F3I);
//                        } else {
//                            valid = FALSE;
//                            strcpy(reason, "F3I can contain as many data "
//                                           "frames as wanted or as many pairs "
//                                           "of alternating data and noise "
//                                           "frames. But it can't contain "
//                                           "badpixel frames!");
//                        }
                    } else if (desc->fits_type == f1l_fits) {
                        if ((nr_data == desc->nr_ext) &&
                             (nr_noise == 0) &&
                             (nr_badpix == 0))
                        {
                            strcpy(format, F1L);
                        } else {
                            valid = FALSE;
                            strcpy(reason, "F1L can contain just one binary "
                                           "table and no noise and badpix "
                                           "frames!");
                        }
                    } else if (desc->fits_type == f2l_fits) {
                        if ((nr_data == desc->nr_ext) &&
                             (nr_noise == 0) &&
                             (nr_badpix == 0))
                        {
                            strcpy(format, F2L);
                        } else {
                            valid = FALSE;
                            strcpy(reason, "F1L can contain just one binary "
                                           "table and no noise and badpix "
                                           "frames!");
                        }
                    } else if (desc->fits_type == f1s_fits) {
                        if ((nr_data == desc->nr_ext) &&
                             (nr_noise == 0) &&
                             (nr_badpix == 0))
                        {
                            strcpy(format, F1S);
                        } else {
                            valid = FALSE;
                            strcpy(reason, "F1S can contain just one data "
                                           "vector and no noise and badpix "
                                           "frames!");
                        }
                    } else {
                        valid = FALSE;
                        strcpy(reason, ">>> UNEXPECTED ERROR (2) !!!\n");
                    }
                }
            }

            if (valid) {
                printf("\nVALID %s FILE!\n", format);
            } else {
                printf("\n>>> INVALID FILE! (%s)\n", reason);
            }
        } else {
            printf("This is not a valid KMOS FITS file!\n\n");

            valid = TRUE;
            strcpy(reason, "");

            // according to desc, the frame isn't a valid KMOS FITS file
            // Let's extract as many information as possible...
            cpl_propertylist *pl = NULL;
            int nr_frames   = cpl_frame_get_nextensions(frame) + 1,
                start       = 0,
                val         = 0,
                val1        = 0,
                val2        = 0,
                val3        = 0,
                *naxis      = NULL,
                *naxis1     = NULL,
                *naxis2     = NULL,
                *naxis3     = NULL;

            KMO_TRY_EXIT_IF_NULL(
                naxis      = (int*)cpl_calloc(nr_frames, sizeof(int)));
            KMO_TRY_EXIT_IF_NULL(
                naxis1     = (int*)cpl_calloc(nr_frames, sizeof(int)));
            KMO_TRY_EXIT_IF_NULL(
                naxis2     = (int*)cpl_calloc(nr_frames, sizeof(int)));
            KMO_TRY_EXIT_IF_NULL(
                naxis3     = (int*)cpl_calloc(nr_frames, sizeof(int)));
            KMO_TRY_CHECK_ERROR_STATE();

            printf("NR. FRAMES:    %d\n", nr_frames);

            for (i = 0; i < nr_frames; i++) {
                KMO_TRY_EXIT_IF_NULL(
                    pl = kmclipm_propertylist_load(cpl_frame_get_filename(frame),
                                               i));

                naxis[i] = cpl_propertylist_get_int(pl, NAXIS);
                KMO_TRY_CHECK_ERROR_STATE();

                if (naxis[i] > 0) {
                    naxis1[i] = cpl_propertylist_get_int(pl, NAXIS1);
                    KMO_TRY_CHECK_ERROR_STATE();
                    if (naxis[i] > 1) {
                        naxis2[i] = cpl_propertylist_get_int(pl, NAXIS2);
                        KMO_TRY_CHECK_ERROR_STATE();
                        if (naxis[i] > 2) {
                            naxis3[i] = cpl_propertylist_get_int(pl, NAXIS3);
                            KMO_TRY_CHECK_ERROR_STATE();
                        }
                    }
                }

                cpl_propertylist_delete(pl); pl = NULL;
            }

            if (naxis[0] == 0) {
                printf("Extension Nr.: 0, (empty)\n");
                start = 1;
            } else {
                printf("Doesn't have an empty primary extension\n\n");
                start = 0;
            }

            for (i = 0; i < nr_frames; i++) {
                KMO_TRY_EXIT_IF_NULL(
                    pl = kmclipm_propertylist_load(cpl_frame_get_filename(frame),
                                               i));

                if (cpl_propertylist_has(pl, XTENSION)) {
                    printf("Extension Nr.: %d, ", i);
                    xtension = cpl_propertylist_get_string(pl, XTENSION);
                    printf("XTENSION: %s, ", xtension);
                    if (strcmp(xtension, BINTABLE) == 0) {
                        is_bin = TRUE;
                    }
                    printf("NAXIS1/2/3: %d, %d, %d, ", naxis1[i], naxis2[i], naxis3[i]);
                    extname = cpl_propertylist_get_string(pl, EXTNAME);
                    printf("EXTNAME: %s\n", extname);
                }

                cpl_propertylist_delete(pl); pl = NULL;
            }

            printf("\n");

            val  = naxis[start];
            val1 = naxis1[start];
            val2 = naxis2[start];
            val3 = naxis3[start];

            for (i = start + 1; i < nr_frames; i++) {
                if (val != naxis[i]) {
                    KMO_TRY_EXIT_IF_NULL(
                        tmp = cpl_sprintf("    NAXIS of extension %d and %d differ "
                                          "(%d and %d)!\n", start, i, val, naxis[i]));
                    strcat(reason, tmp);
                    cpl_free(tmp); tmp = NULL;
                    valid = FALSE;
                }
                if (val1 != naxis1[i]) {
                    KMO_TRY_EXIT_IF_NULL(
                        tmp = cpl_sprintf("    NAXIS1 of extension %d and %d differ "
                                          "(%d and %d)!\n", start, i, val1, naxis1[i]));
                    strcat(reason, tmp);
                    cpl_free(tmp); tmp = NULL;
                    valid = FALSE;
                }
                if (val2 != naxis2[i]) {
                    KMO_TRY_EXIT_IF_NULL(
                        tmp = cpl_sprintf("    NAXIS2 of extension %d and %d differ "
                                          "(%d and %d)!\n", start, i, val2, naxis2[i]));
                    strcat(reason, tmp);
                    cpl_free(tmp); tmp = NULL;
                    valid = FALSE;
                }
                if (val3 != naxis3[i]) {
                    KMO_TRY_EXIT_IF_NULL(
                        tmp = cpl_sprintf("    NAXIS3 of extension %d and %d differ "
                                          "(%d and %d)!\n", start, i, val3, naxis3[i]));
                    strcat(reason, tmp);
                    cpl_free(tmp); tmp = NULL;
                    valid = FALSE;
                }

                if (!valid) {
                    break;
                }
            }

            if (valid) {
                if (val1 != 0) {
                    printf("NAXIS:   %d", val);
                    if (is_bin)
                    {
                        printf(" (NR. COLUMNS)");
                    }
                    printf("\n");
                }
                if (val1 != 0) {
                    printf("NAXIS1:  %d\n", val1);
                }
                if (val2 != 0) {
                    printf("NAXIS2:  %d", val2);
                    if (is_bin)
                    {
                        printf(" (NR. ROWS)");
                    }
                    printf("\n");
                }
                if (val3 != 0) {
                    printf("NAXIS3:  %d\n", val3);
                }
            } else {
                printf(">>> Problematic file!\n%s", reason);
            }

        }

        printf("++++++++++++++++++++++++++++++++++++++++"
               "++++++++++++++++++++++++++++++++++++++++\n");
    }
    KMO_CATCH
    {
        KMO_CATCH_MSG();
        ret_error = cpl_error_get_code();
    }

    return ret_error;
}

/** @{ */
