/* 
 * This file is part of the HAWKI 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

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

/*-----------------------------------------------------------------------------
   								Includes
 -----------------------------------------------------------------------------*/

#include <string.h>
#include <locale.h>
#include <cpl.h>

#include "hawki_load.h"
#include "hawki_pfits_legacy.h"
#include "hawki_utils_legacy.h"
#include "hawki_dfs_legacy.h"

/*----------------------------------------------------------------------------*/
/**
 * @defgroup hawki_load    Loading related functions
 *
 */
/*----------------------------------------------------------------------------*/

/**@{*/

/*----------------------------------------------------------------------------*/
/**
   @brief   Extract the frames with the given tag from a frameset
   @param   in      A non-empty frameset
   @param   tag     The tag of the requested frames
   @return  The newly created frameset or NULL on error

   The returned frameset must be de allocated with cpl_frameset_delete()
 */
/*----------------------------------------------------------------------------*/
cpl_frameset * hawki_extract_frameset(
        const cpl_frameset  *   in,
        const char          *   tag)
{
    cpl_frameset    *   out ;
    const cpl_frame *   cur_frame ;
    cpl_frame       *   loc_frame ;
    int                 nbframes, nbext ;
    int                 i ;

    /* Test entries */
    if (in == NULL) return NULL ;
    if (tag == NULL) return NULL ;

    /* Initialise */
    nbframes = cpl_frameset_get_size(in) ;

    /* Count the frames with the tag */
    if ((nbext = cpl_frameset_count_tags(in, tag)) == 0) return NULL ;

    /* Create the output frameset */
    out = cpl_frameset_new() ;

    /* Loop on the requested frames and store them in out */
    nbext = 0 ;
    for (i=0 ; i<nbframes ; i++) {
        cur_frame = cpl_frameset_get_position_const(in, i);
        if (!strcmp(cpl_frame_get_tag(cur_frame), tag)) {
            loc_frame = cpl_frame_duplicate(cur_frame) ;
            cpl_frameset_insert(out, loc_frame) ;
            nbext ++ ;
        }
    }
    return out ;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Load the quarter of a chip from a frameset in an image
  @param    fset        the input set of frames
  @param    fnum        the frame to load from (start from 0)
  @param    chip        the chip to load (1 to HAWKI_NB_DETECTORS)
  @param    quad        the quadrant to load (1 to 4)
  @param    ptype       the pixel type
  @return   the image list or NULL in error case
 */
/*----------------------------------------------------------------------------*/
cpl_image * hawki_load_quadrant(
        const cpl_frameset  *   fset,
        int                     fnum,
        int                     chip,
        int                     quad,
        cpl_type                ptype)
{
    const cpl_frame     *   frame ;
    const char          *   fname ;
    cpl_image           *   ima ;

    /* Test entries */
    if (fset == NULL) return NULL ;
    if (chip < 1 || chip > HAWKI_NB_DETECTORS) return NULL ;
    if (quad < 1 || quad > 4) return NULL ;

    /* Load the fnum frame */
    frame = cpl_frameset_get_position_const(fset, fnum) ;
    fname = cpl_frame_get_filename(frame) ;

    /* Load */
    if ((ima=hawki_load_quadrant_from_file(fname, chip, quad, ptype)) == NULL) {
        cpl_msg_error(__func__, "Cannot load %dth frame (chip %d quarter %d)",
                fnum+1, chip, quad) ;
        return NULL ;
    }
    return ima ;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Load the quarter of a chip from a file in an image
  @param    fname       the input file name
  @param    chip        the chip to load (1 to HAWKI_NB_DETECTORS)
  @param    quad        the quadrant to load (1 to 4)
  @param    ptype       the pixel type
  @return   the image list or NULL in error case
 */
/*----------------------------------------------------------------------------*/
cpl_image * hawki_load_quadrant_from_file(
        const char  *   fname,
        int             chip,
        int             quad,
        cpl_type        ptype)
{
    cpl_image           *   ima ;
    int                     ext_nb ;
    int                     llx, lly, urx, ury ;

    /* Test entries */
    if (fname == NULL) return NULL ;
    if (chip < 1 || chip > HAWKI_NB_DETECTORS) return NULL ;
    if (quad < 1 || quad > 4) return NULL ;

    /* Define the window */
    if (quad == 1) {
        llx = lly = 1 ;
        urx = ury = 1024 ;
    } else if (quad == 2) {
        llx = 1025 ;
        lly = 1 ;
        urx = 2048 ;
        ury = 1024 ;
    } else if (quad == 3) {
        llx = 1 ;
        lly = 1025 ;
        urx = 1024 ;
        ury = 2048 ;
    } else if (quad == 4) {
        llx = lly = 1025 ;
        urx = ury = 2048 ;
    } else return NULL ;

    /* Get the extension with the wished chip */
    if ((ext_nb = hawki_get_ext_from_detector(fname, chip)) == -1) {
        cpl_msg_error(__func__, "Cannot get the extension with chip %d",
                chip+1) ;
        return NULL ;
    }

    /* Load */
    if ((ima=cpl_image_load_window(fname, ptype, 0, ext_nb, llx, lly, urx,
                    ury)) == NULL) {
        cpl_msg_error(__func__, "Cannot load chip %d quarter %d from %s",
                chip, quad, fname) ;
        return NULL ;
    }
    return ima ;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Load the chips of HAWKI frameset in an image list
  @param    fset        the input set of frames
  @param    chip        the chip to load (1 to HAWKI_NB_DETECTORS)
  @param    ptype       the pixel type
  @return   the image list or NULL in error case
 */
/*----------------------------------------------------------------------------*/
cpl_imagelist * hawki_load_detector(
        const cpl_frameset  *   fset,
        int                     chip,
        cpl_type                ptype)
{
    int                     nframes ;
    cpl_imagelist       *   out ;
    const cpl_frame     *   frame ;
    const char          *   fname ;
    cpl_image           *   ima ;
    int                     ext_nb ;
    int                     i ;

    /* Test entries */
    if (fset == NULL) return NULL ;
    if (chip < 1 || chip > HAWKI_NB_DETECTORS) return NULL ;
    nframes = cpl_frameset_get_size(fset) ;

    /* Create the output list */
    out = cpl_imagelist_new() ;

    /* Loop on the frames */
    for (i=0 ; i<nframes ; i++) {

        /* Load the ith frame */
        frame = cpl_frameset_get_position_const(fset, i) ;
        fname = cpl_frame_get_filename(frame) ;

        /* Get the extension with the wished chip */
        if ((ext_nb = hawki_get_ext_from_detector(fname, chip)) == -1) {
            cpl_msg_error(__func__, "Cannot get the extension with chip %d",
                    chip) ;
            cpl_imagelist_delete(out);
            return NULL ;
        }
        /* Load */
        if ((ima=cpl_image_load(fname, ptype, 0, ext_nb)) == NULL) {
            cpl_msg_error(__func__, "Cannot load %dth frame (chip %d)",
                    i+1, chip) ;
            cpl_imagelist_delete(out) ;
            return NULL ;
        }
        cpl_imagelist_set(out, ima, i) ;
    }
    return out ;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Loads a given extension from a HAWKI frameset in an image list
  @param    fset        the input set of frames
  @param    ext         the chip to load (1 to HAWKI_NB_DETECTORS)
  @param    ptype       the pixel type
  @return   the image list or NULL in error case
 */
/*----------------------------------------------------------------------------*/
cpl_imagelist * hawki_load_extensions
(const cpl_frameset  *   fset,
 int                     extension,
 cpl_type                ptype)
{
    int                     nframes ;
    cpl_imagelist       *   out ;
    const cpl_frame     *   frame ;
    const char          *   fname ;
    cpl_image           *   ima ;
    int                     iframe;

    /* Test entries */
    if (fset == NULL) return NULL ;
    nframes = cpl_frameset_get_size(fset) ;

    /* Create the output list */
    out = cpl_imagelist_new() ;

    /* Loop on the frames */
    for (iframe=0 ; iframe<nframes ; iframe++) {

        /* Load the ith frame */
        frame = cpl_frameset_get_position_const(fset, iframe) ;
        fname = cpl_frame_get_filename(frame) ;

        /* Load */
        if ((ima=cpl_image_load(fname, ptype, 0, extension)) == NULL) {
            cpl_msg_error(__func__, "Cannot load %dth frame (extension %d)",
                    iframe+1, extension) ;
            cpl_imagelist_delete(out) ;
            return NULL ;
        }
        cpl_imagelist_set(out, ima, iframe) ;
    }
    return out ;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Load the chip of HAWKI image from a frameset in an image
  @param    fset        the input set of frames
  @param    fnum        the frame to load from (start from 0)
  @param    chip        the chip to load (1 to HAWKI_NB_DETECTORS)
  @param    ptype       the pixel type
  @return   the image list or NULL in error case
 */
/*----------------------------------------------------------------------------*/
cpl_image * hawki_load_image(
        const cpl_frameset  *   fset,
        int                     fnum,
        int                     chip,
        cpl_type                ptype)
{
    const cpl_frame     *   frame ;
    const char          *   fname ;
    cpl_image           *   ima ;
    int                     ext_nb ;

    /* Test entries */
    if (fset == NULL) return NULL ;
    if (chip < 1 || chip > HAWKI_NB_DETECTORS) return NULL ;

    /* Load the fnum frame */
    frame = cpl_frameset_get_position_const(fset, fnum) ;
    fname = cpl_frame_get_filename(frame) ;

    /* Check that the frame has the right number of extension */
    if(cpl_frame_get_nextensions(frame) != HAWKI_NB_DETECTORS)
    {
        cpl_msg_error(__func__, "File %s contains less than %d extensions",
                      fname, HAWKI_NB_DETECTORS);
        return NULL ;
    }

    /* Get the extension with the wished chip */
    if ((ext_nb = hawki_get_ext_from_detector(fname, chip)) == -1) {
        cpl_msg_error(__func__, "Cannot get the extension with chip %d",
                chip+1) ;
        return NULL ;
    }
    /* Load */
    if ((ima=cpl_image_load(fname, ptype, 0, ext_nb)) == NULL) {
        cpl_msg_error(__func__, "Cannot load %dth frame (chip %d)",
                fnum+1, chip) ;
        return NULL ;
    }
    return ima ;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Load the quarter of a chip from a frameset in an image list
  @param    fset        the input set of frames
  @param    chip        the chip to load (1 to HAWKI_NB_DETECTORS)
  @param    quad        the quadrant to load (1 to 4)
  @param    ptype       the pixel type
  @return   the image list or NULL in error case
 */
/*----------------------------------------------------------------------------*/
cpl_imagelist * hawki_load_quadrants(
        const cpl_frameset  *   fset,
        int                     chip,
        int                     quad,
        cpl_type                ptype)
{
    cpl_imagelist       *   out ;
    cpl_image           *   ima ;
    int                     i ;

    /* Test entries */
    if (fset == NULL) return NULL ;
    if (chip < 1 || chip > HAWKI_NB_DETECTORS) return NULL ;
    if (quad < 1 || quad > 4) return NULL ;

    /* Create the output imagelist */
    out = cpl_imagelist_new() ;

    /* Loop on the frames */
    for (i=0 ; i<cpl_frameset_get_size(fset) ; i++) {
        ima = hawki_load_quadrant(fset, i, chip, quad, ptype) ;
        if (ima == NULL) {
            cpl_msg_error(__func__, "Cannot load %dth frame (chip %d, quad %d)",
                    i+1, chip, quad) ;
            cpl_imagelist_delete(out) ;
            return NULL ;
        }
        cpl_imagelist_set(out, ima, i) ;
    }
    return out ;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Load the chip of HAWKI images from a frameset in an image list
  @param    fset        the input set of frames
  @param    chip        the chip to load (1 to HAWKI_NB_DETECTORS)
  @param    ptype       the pixel type
  @return   the image list (image chip 1 to chip HAWKI_NB_DETECTORS) or NULL
  in error case
 */
/*----------------------------------------------------------------------------*/
cpl_imagelist * hawki_load_frameset(
        const cpl_frameset  *   fset,
        int                     chip,
        cpl_type                ptype)
{
    cpl_imagelist       *   out ;
    cpl_image           *   ima ;
    int                     i ;

    /* Test entries */
    if (fset == NULL) return NULL ;
    if (chip < 1 || chip > HAWKI_NB_DETECTORS) return NULL ;

    /* Create the output imagelist */
    out = cpl_imagelist_new() ;

    /* Loop on the frames */
    for (i=0 ; i<cpl_frameset_get_size(fset) ; i++) {
        ima = hawki_load_image(fset, i, chip, ptype) ;
        if (ima == NULL) {
            cpl_msg_error(__func__, "Cannot load %dth frame (chip %d)",
                    i+1, chip) ;
            cpl_imagelist_delete(out) ;
            return NULL ;
        }
        cpl_imagelist_set(out, ima, i) ;
    }
    return out ;
}

/**
  @brief    Load all the chips of HAWKI images from a frame into an image list
  @param    frame       the input set of frames
  @param    ptype       the pixel type
  @return   the image list (image chip 1 to chip HAWKI_NB_DETECTORS) or NULL
  in error case
 */
/*----------------------------------------------------------------------------*/
cpl_imagelist * hawki_load_frame(
        const cpl_frame  *   frame,
        cpl_type             ptype)
{
    cpl_imagelist       *   out;
    cpl_image           *   ima;
    const char          *   fname;
    int                     idet;
    int                     ext_nb;
    int                 *   ext_chip_mapping;

    /* Test entries */
    if (frame == NULL) return NULL ;

    /* Create the output imagelist */
    out = cpl_imagelist_new() ;

    /* Get the filename */
    fname = cpl_frame_get_filename(frame);

    /* Check that the frame has the right number of extension */
    if(cpl_frame_get_nextensions(frame) != HAWKI_NB_DETECTORS)
    {
        cpl_msg_error(__func__, "File %s contains less than %d extensions",
                      fname, HAWKI_NB_DETECTORS);
        cpl_imagelist_delete(out);
        return NULL ;
    }

    /* Get the extension-chip mapping */
    ext_chip_mapping = hawki_get_ext_detector_mapping(fname);
    if (ext_chip_mapping == NULL)
    {
        cpl_msg_error(__func__,"Cannot get mapping between extension and chip");
        cpl_imagelist_delete(out);
        return NULL;
    }
    
    /* Loop on the chips */
    for (idet=0 ; idet< HAWKI_NB_DETECTORS ; idet++)
    {
        /* Get the extension */
        ext_nb = ext_chip_mapping[idet];
        
        /* Load */
        if ((ima=cpl_image_load(fname, ptype, 0, ext_nb)) == NULL)
        {
            cpl_msg_error(__func__, "Cannot load frame (detector %d)",
                          idet);
            cpl_imagelist_delete(out);
            return NULL;
        }
        cpl_imagelist_set(out, ima, idet);
    }
    
    /* Free */
    cpl_free(ext_chip_mapping);
    return out;
}

/**
  @brief    Load one the extensions of HAWKI images from a frame into an image
  @param    frame       the input frame
  @param    extension   the extension to load (1 to HAWKI_NB_DETECTORS)
  @param    ptype       the pixel type
  @return   the image or NULL in error case
 */
/*----------------------------------------------------------------------------*/
cpl_image * hawki_load_frame_extension(
        const cpl_frame  *   frame,
        int                  iextension,
        cpl_type             ptype)
{
    cpl_image        *   ima;
    const char       *   fname;

    /* Test entries */
    if (frame == NULL) return NULL ;

    /* Get filename */
    fname = cpl_frame_get_filename(frame);

    /* Load */
    if ((ima=cpl_image_load(fname, ptype, 0, iextension)) == NULL)
    {
        cpl_msg_error(__func__, "Cannot load frame (extension %d)",
                      iextension) ;
        return NULL ;
    }

    /* Return */
    return ima;
}

/**
  @brief    Load one the chips of HAWKI images from a frame into an image
  @param    frame       the input frame
  @param    idet        the detector to load (1 to HAWKI_NB_DETECTORS)
  @param    ptype       the pixel type
  @return   the image or NULL in error case
 */
/*----------------------------------------------------------------------------*/
cpl_image * hawki_load_frame_detector(
        const cpl_frame  *   frame,
        int                  idet,
        cpl_type             ptype)
{
    cpl_image        *   ima;
    const char       *   fname;
    int                  ext_nb;

    /* Test entries */
    if (frame == NULL) return NULL ;

    /* Get filename */
    fname = cpl_frame_get_filename(frame);

    /* Get the extension with the wished chip */
    if ((ext_nb = hawki_get_ext_from_detector(fname, idet)) == -1)
    {
        cpl_msg_error(__func__, "Cannot get the extension with chip %d",
                      idet) ;
        return NULL ;
    }
    /* Load */
    if ((ima=cpl_image_load(fname, ptype, 0, ext_nb)) == NULL)
    {
        cpl_msg_error(__func__, "Cannot load frame (chip %d)",
                      idet) ;
        return NULL ;
    }

    /* Return */
    return ima;
}

/**
  @brief    Load a table with four extensions, one for each chip
  @param    frame       the input set of frames
  @param    ptype       the pixel type
  @return   the image list (image chip 1 to chip HAWKI_NB_DETECTORS) or NULL
  in error case
 */
/*----------------------------------------------------------------------------*/
cpl_table  ** hawki_load_tables(const cpl_frame * frame)
{
    cpl_table  ** tables;
    const char *  filename;
    int           idet;
    int           j;
    int           ext_nb;

    /* Allocate the set of tables */
    tables = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_table *));

    /* Get the filename */
    filename = cpl_frame_get_filename(frame);
    for (idet=0 ; idet< HAWKI_NB_DETECTORS ; idet++)
    {
        /* Get the extension with the wished chip */
        if ((ext_nb = hawki_get_ext_from_detector(filename, idet+1)) == -1)
        {
            cpl_msg_error(__func__, "Cannot get the extension with detector %d",
                          idet+1) ;
            cpl_free(tables);
            return NULL ;
        }
        /* Load the table */
        if((tables[idet] = cpl_table_load(filename, ext_nb, 0) ) == NULL)
        {
            for (j=0 ; j< idet ; j++)
            {
                cpl_table_delete(tables[j]);
            }
            cpl_free(tables);
            return NULL;
        }
    }

    return  tables;
}

/**
  @brief    Load a table containing refined offsets
  @param    offsets_frame   the frame containing the offests.
  @return   the offsets bivector. It must be deallocated afterwards. NULL if
  in error case
 */
/*----------------------------------------------------------------------------*/
cpl_bivector  ** hawki_load_refined_offsets(const cpl_frame * offsets_frame)
{
    cpl_errorstate    previous_state;
    cpl_table      ** offsets_tables;
    cpl_bivector   ** offsets;
    int               idet;

    /* Get the error state */
    previous_state = cpl_errorstate_get();

    /* Read the offsets table */
    if((offsets_tables = hawki_load_tables(offsets_frame)) == NULL)
        return NULL;

    /* Convert the table to offsets bivectors */
    offsets = cpl_malloc(HAWKI_NB_DETECTORS * sizeof(cpl_bivector *));
    if(offsets == NULL)
    {
        for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
            cpl_table_delete(offsets_tables[idet]);
        return NULL;
    }
    for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
    {
        cpl_vector * off_x;
        cpl_vector * off_y;
        int          noff;
        int          ioff;
        int          jdet;

        noff = cpl_table_get_nrow(offsets_tables[idet]);
        offsets[idet] = cpl_bivector_new(noff);
        if(offsets[idet] == NULL)
        {
            for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
                cpl_table_delete(offsets_tables[idet]);
            for(jdet = 0; jdet < idet; ++jdet)
                cpl_bivector_delete(offsets[jdet]);
            cpl_free(offsets[jdet]);
            return NULL;
        }
        off_x = cpl_bivector_get_x(offsets[idet]);
        off_y = cpl_bivector_get_y(offsets[idet]);
        for(ioff = 0; ioff < noff; ++ioff)
        {
            double xoffset, yoffset;
            xoffset = cpl_table_get
                (offsets_tables[idet], HAWKI_COL_OFFSET_X, ioff, NULL);
            yoffset = cpl_table_get
                (offsets_tables[idet], HAWKI_COL_OFFSET_Y, ioff, NULL);
            cpl_vector_set(off_x, ioff, xoffset);
            cpl_vector_set(off_y, ioff, yoffset);
        }
    }

    /* Check error state */
    if(cpl_errorstate_get() != previous_state)
    {
        for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
        {
            cpl_table_delete(offsets_tables[idet]);
            cpl_bivector_delete(offsets[idet]);
        }
        cpl_free(offsets);
        return NULL;
    }

    /* Free and exit */
    for(idet = 0; idet < HAWKI_NB_DETECTORS; ++idet)
        cpl_table_delete(offsets_tables[idet]);
    cpl_free(offsets_tables);

    return offsets;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Rebuild the 4 chips
  @param    ima1    the first chip
  @param    ima2    the second chip
  @param    ima3    the third chip
  @param    ima4    the fourth chip
  @return   the image or NULL in error case
 */
/*----------------------------------------------------------------------------*/
cpl_image * hawki_rebuild_detectors(
        const cpl_image *   ima1,
        const cpl_image *   ima2,
        const cpl_image *   ima3,
        const cpl_image *   ima4)
{
    cpl_image           *   ima ;

    /* Test entries */
    if (ima1 == NULL) return NULL ;
    if (ima2 == NULL) return NULL ;
    if (ima3 == NULL) return NULL ;
    if (ima4 == NULL) return NULL ;
    if (cpl_image_get_type(ima1)!=cpl_image_get_type(ima2)) return NULL ;
    if (cpl_image_get_type(ima1)!=cpl_image_get_type(ima3)) return NULL ;
    if (cpl_image_get_type(ima1)!=cpl_image_get_type(ima4)) return NULL ;

    /* Create the image */
    ima = cpl_image_new(4096, 4096, cpl_image_get_type(ima1)) ;

    /* Paste the input images */
    if (cpl_image_copy(ima, ima1, 1, 1) != CPL_ERROR_NONE) {
        cpl_image_delete(ima) ;
        return NULL ;
    }
    if (cpl_image_copy(ima, ima2, 2049, 1) != CPL_ERROR_NONE) {
        cpl_image_delete(ima) ;
        return NULL ;
    }
    if (cpl_image_copy(ima, ima3, 2049, 2049) != CPL_ERROR_NONE) {
        cpl_image_delete(ima) ;
        return NULL ;
    }
    if (cpl_image_copy(ima, ima4, 1, 2049) != CPL_ERROR_NONE) {
        cpl_image_delete(ima) ;
        return NULL ;
    }
    return ima ;
}


/*----------------------------------------------------------------------------*/
/**
  @brief    Rebuild the 4 quadrants
  @param    ima1    the first quadrant
  @param    ima2    the second quadrant
  @param    ima3    the third quadrant
  @param    ima4    the fourth quadrant
  @return   the image or NULL in error case
 */
/*----------------------------------------------------------------------------*/
cpl_image * hawki_rebuild_quadrants(
        const cpl_image *   ima1,
        const cpl_image *   ima2,
        const cpl_image *   ima3,
        const cpl_image *   ima4)
{
    cpl_image           *   ima ;

    /* Test entries */
    if (ima1 == NULL) return NULL ;
    if (ima2 == NULL) return NULL ;
    if (ima3 == NULL) return NULL ;
    if (ima4 == NULL) return NULL ;
    if (cpl_image_get_type(ima1)!=cpl_image_get_type(ima2)) return NULL ;
    if (cpl_image_get_type(ima1)!=cpl_image_get_type(ima3)) return NULL ;
    if (cpl_image_get_type(ima1)!=cpl_image_get_type(ima4)) return NULL ;

    /* Create the image */
    ima = cpl_image_new(2048, 2048, cpl_image_get_type(ima1)) ;

    /* Paste the input images */
    if (cpl_image_copy(ima, ima1, 1, 1) != CPL_ERROR_NONE) {
        cpl_image_delete(ima) ;
        return NULL ;
    }
    if (cpl_image_copy(ima, ima2, 1025, 1) != CPL_ERROR_NONE) {
        cpl_image_delete(ima) ;
        return NULL ;
    }
    if (cpl_image_copy(ima, ima3, 1, 1025) != CPL_ERROR_NONE) {
        cpl_image_delete(ima) ;
        return NULL ;
    }
    if (cpl_image_copy(ima, ima4, 1025, 1025) != CPL_ERROR_NONE) {
        cpl_image_delete(ima) ;
        return NULL ;
    }
    return ima ;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Get the chip to store in the wished extension
  @param    fname       The input frame name
  @param    ext     the extension number (1 to HAWKI_NB_DETECTORS)
  @return   The chip number (1 to HAWKI_NB_DETECTORS) or -1 in error case
 */
/*----------------------------------------------------------------------------*/
int hawki_get_detector_from_ext(
        const char  *   fname,
        int             ext)
{
    cpl_propertylist    *   plist ;
    const char          *   sval ;
    int                     chip ;

    /* Test entries */
    if (ext <= 0 || ext > HAWKI_NB_DETECTORS) return -1 ;

    /* Load the extension  */
    plist=cpl_propertylist_load(fname, ext) ;
    if (plist == NULL) return -1 ;
    sval = hawki_pfits_get_extname(plist) ;
    setlocale(LC_NUMERIC, "C"); // Behaviour of sscanf depends on the locale
    if (sscanf(sval, "CHIP%d.INT1", &chip) != 1) chip = -1 ;
    cpl_propertylist_delete(plist) ;

    return chip ;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Get the extension corresponding to the wished chip
  @param    fname       The input frame name
  @param    chip        The chip number (1 to HAWKI_NB_DETECTORS)
  @return   the extension number (1 to HAWKI_NB_DETECTORS)
 */
/*----------------------------------------------------------------------------*/
int hawki_get_ext_from_detector(
        const char  *   fname,
        int             chip)
{
    cpl_propertylist    *   plist ;
    const char          *   sval ;
    char                    chipval[512] ;
    int                     ext_nb ;
    int                     iext;

    /* Test entries */
    if (fname == NULL) return -1;
    if (chip <= 0 || chip > HAWKI_NB_DETECTORS) return -1 ;

    /* Initialise */
    ext_nb = -1 ;

    /* Create  the wished chipval */
    snprintf(chipval, 512, "CHIP%d.INT1", chip) ;

    /* Loop on the HAWKI_NB_DETECTORS extensions */
    for (iext=0 ; iext<HAWKI_NB_DETECTORS ; iext++) {
        /* Load the propertylist of the current extension */
        if ((plist = cpl_propertylist_load(fname, iext+1)) == NULL) {
            cpl_msg_error(__func__, "Cannot read the Extname keyword") ;
            return -1 ;
        }
        if ((sval = hawki_pfits_get_extname(plist)) == NULL) {
            cpl_msg_error(__func__, "Cannot read the Extname keyword") ;
            cpl_propertylist_delete(plist) ;
            return -1 ;
        }
        /* Check if the chip is found */
        if (!strcmp(chipval, sval)) {
            ext_nb = iext+1 ;
            cpl_propertylist_delete(plist) ;
            break;
        }
        cpl_propertylist_delete(plist) ;
    }
    return ext_nb ;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Get the mapping between extensions and detectors
  @param    fname       The input frame name
  @return   the mapping if everything goes well, NULL otherwise
 */
/*----------------------------------------------------------------------------*/
int * hawki_get_ext_detector_mapping
(const char  *  fname)
{
    int           iext;
    int         * ext_chip_mapping;   
    

    /* Test entries */
    if (fname == NULL) return NULL;
    
    /* Initialise */
    ext_chip_mapping = cpl_malloc(sizeof(int) * HAWKI_NB_DETECTORS);

    /* Loop on the HAWKI_NB_DETECTORS extensions */
    for (iext=0 ; iext<HAWKI_NB_DETECTORS ; iext++) {
        int ichip = hawki_get_detector_from_ext(fname, iext + 1);
        ext_chip_mapping[ichip-1] = iext + 1; 
    }
    return ext_chip_mapping;
}
/**@}*/
