/*
 * This file is part of the ESO SINFONI Pipeline
 * Copyright (C) 2004,2005 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, 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA
 */
/************************************************************************
* E.S.O. - VLT project
*
* who       when      what
* --------  --------  ----------------------------------------------
* schreib  30/08/00  created
*/

/************************************************************************
*   NAME
*        sinfo_cube_construct.c -
*------------------------------------------------------------------------
*/

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif
#define POSIX_SOURCE 1
#include "sinfo_vltPort.h"

/*
 * System Headers
 */

/*
 * Local Headers
 */
#include "sinfo_function_1d.h"
#include "sinfo_cube_construct.h"
#include "sinfo_spectrum_ops.h"
#include "sinfo_wave_calibration.h"
#include "sinfo_utilities.h"
#include "sinfo_utils_wrappers.h"
#include "sinfo_local_types.h"
#include "sinfo_fft_base.h"

static int
sinfo_sort_slitlets(const int kslit);


static int
sinfo_sort_slitlets_array(const int slit, int* row_index);

/**@{*/
/**
 * @defgroup sinfo_cube_construct Cube generation functions
 *
 * some procedures to construct a data cube
 */

/*----------------------------------------------------------------------------
 *                            Function codes
 *--------------------------------------------------------------------------*/
/**
   @name   sinfo_new_convolve_ns_image_by_gauss()
   @memo convolves a north-south-test image with a Gaussian
                        with user given integer half width by using the
                        routine sinfo_function1d_filter_lowpass().

   @param lineImage  North-south-test image
   @param hw          kernel half width of the Gaussian response function

   @return  north-south-test image convolved with a Gaussian


 */

cpl_image * 
sinfo_new_convolve_ns_image_by_gauss( cpl_image * lineImage,
                                   int        hw )
{
    cpl_image * returnImage ;
    float* row_buffer=NULL ;
    float * filter ;
    int col, row ;
    int ilx=0;
    int ily=0;
 
    float* pidata=NULL;
    float* podata=NULL;

    if ( lineImage == NULL )
    {
        sinfo_msg_error("no input image given!\n") ;
        return NULL ;
    }
    ilx=cpl_image_get_size_x(lineImage);
    ily=cpl_image_get_size_y(lineImage);
    pidata=cpl_image_get_data_float(lineImage);
    if ( hw < 1 )
    {
        sinfo_msg_error(" wrong half width given!\n") ;
        return NULL ;
    }

    /* allocate memory for returned image */
    if ( NULL == ( returnImage = cpl_image_new(ilx,ily,CPL_TYPE_FLOAT ) ))
    {
        sinfo_msg_error("cannot allocate a new image\n");
        return NULL ;
    }
    podata=cpl_image_get_data_float(returnImage);

    /* go through the image rows and save them in a buffer */
    row_buffer=cpl_calloc(ily,sizeof(float)) ;

    for ( row = 0 ; row < ily ; row++ )
    {
        for ( col = 0 ; col < ilx ; col++ )
        {
            if ( isnan(pidata[col+row*ilx]) )
            {
                row_buffer[col] = 0. ;
            }
            else
            {
                row_buffer[col] = pidata[col + row*ilx] ;
            }
        }

        /*--------------------------------------------------------------------
         * now low pass filter the rows by the gaussian and fill the return
         * image.
         */
        filter = sinfo_function1d_filter_lowpass( row_buffer,
                                            ilx,
                                            LOW_PASS_GAUSSIAN,
                                            hw ) ;
        for ( col = 0 ; col < ily ; col++ )
        {
            podata[col + row*ilx] = filter[col] ;
        }
        /* deallocate memory */
        sinfo_function1d_del (filter) ;
    }
    cpl_free(row_buffer);    
    return returnImage ;
}

/**
   @name  sinfo_north_south_test()

   @memo determines the distances of the slitlets

   @param ns_image   north-south image
   @param n_slitlets number of slitlets
   @param halfWidth  half width of the box in which the lines
                                    are fit by a sinfo_gaussian
   @param fwhm       first guess of the full width at half maximum
   @param minDiff    amplitude threshold for Gaussian: 
                    below this intensity the fit will not 
                    be carried through
   @param estimated_dist estimated average distance of spectra
   @param devtol     maximal pixel deviation of slitlet distances
   @param bottom     bottom image row
   @param top        top image row
   @return            array of the distances of the slitlets from each other
*/

float * 
sinfo_north_south_test( cpl_image * ns_image,
                          int        n_slitlets,
                          int        halfWidth,
                          float      fwhm,
                          float      minDiff,
                          float      estimated_dist,
                          float      devtol,
              int         bottom,
              int         top )
{
    int i, j, k, m, row, col, n, ni, na ;
    int position, counter;
    int xdim, ndat, its, numpar ;
    pixelvalue row_buf[cpl_image_get_size_x(ns_image)] ;
    float sum, mean, maxval ;
    float tol, lab ;
    float * distances ;
    float distances_buf[cpl_image_get_size_y(ns_image)][n_slitlets-1] ;
    float x_position[n_slitlets] ;
    float * xdat, * wdat ;
    int * mpar ;
    int found[3*n_slitlets], found_clean[3*n_slitlets] ;
    int found_cleanit[3*n_slitlets] ;
    Vector * line ;
    FitParams ** par ;
    int foundit, begin, end ;
    int ilx=0;
    //int ily=0;
 
    float* pidata=NULL;
 
    if ( ns_image == NULL )
    {
        sinfo_msg_error("sorry, no image given\n") ;
        return NULL ;
    }
    ilx=cpl_image_get_size_x(ns_image);
    //ily=cpl_image_get_size_y(ns_image);
    pidata=cpl_image_get_data_float(ns_image);


    if ( n_slitlets < 1 )
    {
        sinfo_msg_error("wrong number of slitlets given\n") ;
        return NULL ;
    }
    if ( halfWidth < 0 || halfWidth >= estimated_dist )
    {
        sinfo_msg_error("wrong half width given\n") ;
        return NULL ;
    }
    if ( fwhm <= 0. )
    {
        sinfo_msg_error("wrong fwhm given\n") ;
        return NULL ;
    }
    if ( minDiff < 1. )
    {
        sinfo_msg_error("wrong minDiff given\n") ;
        return NULL ;
    }

    /* allocate memory for output array */
    if (NULL == (distances = (float *) cpl_calloc ( n_slitlets - 1 , 
                                                    sizeof (float) ))) 
    {
        sinfo_msg_error("could not allocate memory\n") ;
        return NULL ;
    }

    /* go through the image rows */
    for ( row = bottom ; row < top ; row++ )
    {
        int zeroindicator = 0 ;

        /* initialize the distance buffer */
        for ( i = 0 ; i < n_slitlets-1 ; i++ )
        {
            distances_buf[row][i] = ZERO ;
        }

        /* fill the row buffer array with image data */
        for ( col = 0 ; col < ilx ; col++ )
        {
            row_buf[col] = pidata[col + row*ilx] ;
        }

        /* determine the mean of the row data */
        sum = 0. ;
        n = 0 ;
        for ( i = 0 ; i < ilx ; i++ )
        {
            if ( isnan(row_buf[i]) )
            {
                continue ;
            }
            sum += row_buf[i] ;
            n++ ;
        }
        mean = sum / (float)n ;


        /* store the positions of image values greater than the mean */
        n = 0 ;
        for ( i = 0 ; i < ilx ; i++ )
        {
            if (isnan(row_buf[i]))
            {
                continue ;
            }
            if ( row_buf[i] >  sqrt(mean*mean*9) )
            {
                found[n] = i ;
                n++ ;
            } 
        }
       
        if ( n < n_slitlets )
        {
            sinfo_msg_warning("t1 wrong number of intensity columns found "
                              "in row: %d, found number: %d, mean: %g",
                              row, n, mean) ;
            continue ;
        }
        else
        { 
            /* find the maximum value position around the found columns */
            na = 0 ;
            for ( i = 1 ; i < n ; i ++ )
            {
                if ( found[i] - found[i-1] < halfWidth )
                {
                    begin = found[i] - halfWidth ;
                    if ( begin < 0 )
                    {
                        begin = 0 ;
                    }
                    end = found[i] + halfWidth ;
                    if ( end >= ilx )
                    {
                        end = ilx - 1 ;
                    }
                    /* find the maximum value inside the box 
                       around the found positions*/
                    maxval = -FLT_MAX ;
                    foundit = 0 ;
                    for ( j = begin ; j <= end ; j++ )
                    {
                        /* do not consider boxes that contain bad pixels */
                        if (isnan(row_buf[j]))
                        {
                            continue ;
                        }
                        if (row_buf[j] >= maxval )
                        {
                            maxval = row_buf[j] ;
                            foundit = j ;
                        }
                    }
                    if (maxval == -FLT_MAX)
                    {
                        continue ;
                    }
                    for ( k = 0 ; k < na ; k++ )
                    {
                        if ( found_cleanit[k] >= begin && 
                             found_cleanit[k] < foundit )
                        {
                            na-- ;
                        }
                    }
                    for ( k = 0 ; k < n ; k++ )
                    {
                        if ( found[k] == foundit)
                        {
                 if (na>0){
                            if ( found_cleanit[na-1] != found[k] )
                            {
                                found_cleanit[na] = found[k] ;
                                na++ ;
                            }
             }
             else{
                found_cleanit[na] = found[k] ;  
                            na++ ;
             } 
                      }
                    }
                }
                else
                {
                    if ( i == 1 )
                    {
                        found_cleanit[na] = found[0] ;
                        na++ ;
                        found_cleanit[na] = found[1] ;
                        na++ ;
                    }
                    else
                    {   
                if (na>0){
                            if ( found_cleanit[na-1] != found[i-1])
                            {
                                found_cleanit[na] = found[i-1] ;
                                na++ ;
                            }
                            if ( found_cleanit[na-1] != found[i])
                            {
                                found_cleanit[na] = found[i] ;
                                na++ ;
                            }
                        }
            else
                        {
                            found_cleanit[na] = found[i] ;
                            na++ ;
                        }
            }  
                }
            }
            /* determine only one pixel position for each slitlet intensity */
            j = 1 ;
            for ( i = 1 ; i < na ; i++ )
            {
                if ( (float)(found_cleanit[i] - found_cleanit[i-1]) < 
                            (estimated_dist - devtol) ||
                     (float)(found_cleanit[i] - found_cleanit[i-1]) > 
                            (estimated_dist + devtol) )
                {
                    continue ;
                }
                else
                {
                    found_clean[j-1] = found_cleanit[i-1] ;
                    found_clean[j]   = found_cleanit[i] ;
                    j++ ;
                }
            }
        }
        if ( j > n_slitlets )
        {
            /* check the distance again */
            ni = 1 ;
            for ( i = 1 ; i < j ; i++ )
            {
                if ( (float)(found_clean[i] - found_clean[i-1]) < 
                            (estimated_dist - devtol ) ||
                     (float)(found_clean[i] - found_clean[i-1]) > 
                            (estimated_dist + devtol ) )
                { 
                    continue ;
                }
                else
                {

                    found_clean[ni-1] = found_clean[i-1] ;
                    found_clean[ni]   = found_clean[i] ;
                    ni++ ;
                }
            }
            if ( ni != n_slitlets )
            {
                sinfo_msg_warning("t2 wrong number of intensity columns"
                                  " found in row: %d,  found number: %d",
                                  row, ni) ;
                continue ;
            }
            else 
            {
                j = ni ;
            }
        }
        else if ( j < n_slitlets )
        {
            cpl_msg_debug ("north_south_test3:",
                            "t3 wrong number of intensity columns "
                            "found in row: %d , found number: %d, mean: %g\n", 
                            row, j, mean) ;
            continue ;
        }
        counter = 0 ;
        /* go through the found intensity pixels in one row */
        for ( i = 0 ; i < j ; i++ )
        {
            /* allocate memory for the array where the line is fitted in */
            if ( NULL == (line = sinfo_new_vector (2*halfWidth + 1)) )
            {
                sinfo_msg_error ("cannot allocate new Vector \n") ;
                cpl_free(distances) ;
                return NULL ;
            }

            /* allocate memory */
            xdat = (float *) cpl_calloc( line -> n_elements, sizeof (float) ) ;
            wdat = (float *) cpl_calloc( line -> n_elements, sizeof (float) ) ;
            mpar = (int *)   cpl_calloc( MAXPAR, sizeof (int) ) ;
            par = sinfo_new_fit_params(1) ;

            m = 0 ;
            for ( k = found_clean[i]-halfWidth ; 
                  k <= found_clean[i]+halfWidth ; k++ )
            {
                if ( k < 0 )
                {
                    k = 0. ;
                }
                else if ( k >= ilx )
                {
                    k = ilx - 1 ;
                }
                else if ( isnan(row_buf[k]) )
                {
                    zeroindicator = 1 ;
                    break ;
                }
                else
                {
                    line -> data[m] = row_buf[k] ;
                    m++ ;
                }
            }
            if ( zeroindicator == 1 )
            {
                sinfo_new_destroy_vector(line) ;
                cpl_free(xdat) ;
                cpl_free(wdat) ;
                cpl_free(mpar) ;
                sinfo_new_destroy_fit_params(&par) ;
                break ;
            }

            /*----------------------------------------------------------------
             * go through the spectral sinfo_vector
             * determine the maximum pixel value in the spectral sinfo_vector
             */
            maxval = -FLT_MAX ;
            position = -INT32_MAX ;
            for ( k = 0 ; k < m ; k++ )
            {
                xdat[k] = k ;
                wdat[k] = 1.0 ;
                if ( line -> data[k] >= maxval )
                {
                    maxval = line -> data[k] ;
                    position = k ;
                }
            }

            /* set initial values for the fitting routine */
            xdim     = XDIM ;
            ndat     = line -> n_elements ;
            numpar   = MAXPAR ;
            tol      = TOL ;
            lab      = LAB ;
            its      = ITS ;
            (*par) -> fit_par[1] = fwhm ;
            (*par) -> fit_par[2] = (float) position ;
            (*par) -> fit_par[3] = (float) (line -> data[0] + 
                                   line -> data[line->n_elements - 1]) / 2.0 ;
            (*par) -> fit_par[0]  = maxval - ((*par) -> fit_par[3]) ;


            /* exclude negative peaks and low signal cases */
            if ( (*par) -> fit_par[0] < minDiff )
            {
                sinfo_msg_warning ("sorry, signal of line too low to fit "
                                   "in row: %d in slitlet %d\n", row, i) ;
                sinfo_new_destroy_vector(line) ;
                cpl_free(xdat) ;
                cpl_free(wdat) ;
                cpl_free(mpar) ;
                sinfo_new_destroy_fit_params(&par) ;
                continue ;
            }

            for ( k = 0 ; k < MAXPAR ; k++ )
            {
                (*par) -> derv_par[k] = 0.0 ;
                mpar[k] = 1 ;
            }
            /* finally, do the least square fit using a Gaussian */
            int iters;
            if ( 0 > ( iters = sinfo_new_lsqfit_c( xdat, &xdim, 
                                                   line -> data, wdat, &ndat, 
                                                   (*par) -> fit_par,
                                                   (*par) -> derv_par, mpar, 
                                                   &numpar, &tol, &its, &lab)) )
            {
          /*
                cpl_msg_debug ("north_south_test:",
                               "sinfo_lsqfit_c: least squares fit failed,"
                               " error no.: %d in row: %d in slitlet %d\n",
                                iters, row, i) ;
          */
                sinfo_new_destroy_vector(line) ;
                cpl_free(xdat) ;
                cpl_free(wdat) ;
                cpl_free(mpar) ;
                sinfo_new_destroy_fit_params(&par) ;
                continue ;
            }

            /* check for negative fit results */
            if ( (*par) -> fit_par[0] <= 0. || 
                 (*par) -> fit_par[1] <= 0. ||
                 (*par) -> fit_par[2] < 0. )
            {
                sinfo_msg_warning ("negative parameters as fit result, "
                                   "not used! in row %d in slitlet %d", 
                                   row, i) ;
                sinfo_new_destroy_vector(line) ;
                cpl_free(xdat) ;
                cpl_free(wdat) ;
                cpl_free(mpar) ;
                sinfo_new_destroy_fit_params(&par) ;
                continue ;
            }

            /* correct the fitted position for the given row of the line 
               in image coordinates */
            (*par) -> fit_par[2] =  (float) (found_clean[i] - halfWidth) + 
                                            (*par) -> fit_par[2] ;
            x_position[counter] = (*par) -> fit_par[2] ;
            counter ++ ;

            /* free memory */
            sinfo_new_destroy_fit_params(&par) ;
            sinfo_new_destroy_vector ( line ) ;
            cpl_free ( xdat ) ;
            cpl_free ( wdat ) ;
            cpl_free ( mpar ) ;
        }
        if (zeroindicator == 1)
        {
            sinfo_msg_debug ("bad pixel in fitting box in row: %d\n", row) ;
            continue ;
        }

        if ( counter != n_slitlets )
        {
            continue ;
            sinfo_msg_warning("wrong number of slitlets found in row: %d",row);
        }
        /* store the distances between the sources in a buffer */
        for ( i = 1 ; i < n_slitlets ; i++ )
        {
            distances_buf[row][i-1] = x_position[i] - x_position[i-1] ;
        }
    }

    /* ----------------------------------------------------------------
     * go through the rows again and take the mean of the distances, 
     * throw away the runaways 
     */
    for ( i = 0 ; i < n_slitlets-1 ; i++ )
    {
        n   = 0 ;
        sum = 0. ;
        for ( row = bottom ; row < top ; row++ )
        {
            if ( fabs( distances_buf[row][i] - estimated_dist ) > devtol || 
                 isnan(distances_buf[row][i]) )
            {
            /*
          sinfo_msg("dist=%g devtol=%g isan=%d", 
            distances_buf[row][i],
            devtol,
            isnan(distances_buf[row][i]));
            */
                continue ;
            }
            sum += distances_buf[row][i] ;
            n++ ;
        }
        if ( n < 2 )
        {
            sinfo_msg_error("distances array could not be determined "
                            "completely!, deviations of distances from number "
                            "of slitlets too big\n" ) ;
            cpl_free(distances) ;
            return NULL ;
        }
        else
        {
            distances[i] = sum / (float)n ;
        }
    }
    return distances ; 
}


/**
   @name sinfo_sort_slitlets()

   @brief sort the slitlets in the right spiffi specific way

   @param kslit slit number

   @return spiffi slit index or -1
*/

static int
sinfo_sort_slitlets(const int kslit)
{
  int slit_index=0;

  switch (kslit)
    {
    case 0:
      slit_index = 8 ;
      break ;
    case 1:
      slit_index = 7 ;
      break ;
    case 2:
      slit_index = 9 ;
      break ;
    case 3:
      slit_index = 6 ;
      break ;
    case 4:
      slit_index = 10 ;
      break ;
    case 5:
      slit_index = 5 ;
      break ;
    case 6:
      slit_index = 11 ;
      break ;
    case 7:
      slit_index = 4 ;
      break ;
    case 8:
      slit_index = 12 ;
      break ;
    case 9:
      slit_index = 3 ;
      break ;
    case 10:
      slit_index = 13 ;
      break ;
    case 11:
      slit_index = 2 ;
      break ;
    case 12:
      slit_index = 14 ;
      break ;
    case 13:
      slit_index = 1 ;
      break ;
    case 14:
      slit_index = 15 ;
      break ;
    case 15:
      slit_index = 0 ;
      break ;
    case 16:
      slit_index = 31 ;
      break ;
    case 17:
      slit_index = 16 ;
      break ;
    case 18:
      slit_index = 30 ;
      break ;
    case 19:
      slit_index = 17 ;
      break ;
    case 20:
      slit_index = 29 ;
      break ;
    case 21:
      slit_index = 18 ;
      break ;
    case 22:
      slit_index = 28 ;
      break ;
    case 23:
      slit_index = 19 ;
      break ;
    case 24:
      slit_index = 27 ;
      break ;
    case 25:
      slit_index = 20 ;
      break ;
    case 26:
      slit_index = 26 ;
      break ;
    case 27:
      slit_index = 21 ;
      break ;
    case 28:
      slit_index = 25 ;
      break ;
    case 29:
      slit_index = 22 ;
      break ;
    case 30:
      slit_index = 24 ;
      break ;
    case 31:
      slit_index = 23 ;
      break ;
    default:
      sinfo_msg_error("wrong slitlet index: couldn't be a "
                      "spiffi image,  there must be 32 slitlets!") ;
      return -1 ;

                
   }
   return slit_index;

}

/**
   @name sinfo_sord_slitlets_array()

   @short sort spiffi slitlets

   @param  slit slit id
   @param  row_index array with sorted indexes

   @doc sort the slitlets in the right spiffi specific way
        the row_index describes the row index of the current slitlet 
        in the resulting cube images.





*/

static int
sinfo_sort_slitlets_array(const int slit, int* row_index)
{

  switch (slit)
    {
    case 0:
      row_index[0] = 8 ;
      break ;
    case 1:
      row_index[1] = 7 ;
      break ;
    case 2:
      row_index[2] = 9 ;
      break ;
    case 3:
      row_index[3] = 6 ;
      break ;
    case 4:
      row_index[4] = 10 ;
      break ;
    case 5:
      row_index[5] = 5 ;
      break ;
    case 6:
      row_index[6] = 11 ;
      break ;
    case 7:
      row_index[7] = 4 ;
      break ;
    case 8:
      row_index[8] = 12 ;
      break ;
    case 9:
      row_index[9] = 3 ;
      break ;
    case 10:
      row_index[10] = 13 ;
      break ;
    case 11:
      row_index[11] = 2 ;
      break ;
    case 12:
      row_index[12] = 14 ;
      break ;
    case 13:
      row_index[13] = 1 ;
      break ;
    case 14:
      row_index[14] = 15 ;
      break ;
    case 15:
      row_index[15] = 0 ;
      break ;
    case 16:
      row_index[16] = 31 ;
      break ;
    case 17:
      row_index[17] = 16 ;
      break ;
    case 18:
      row_index[18] = 30 ;
      break ;
    case 19:
      row_index[19] = 17 ;
      break ;
    case 20:
      row_index[20] = 29 ;
      break ;
    case 21:
      row_index[21] = 18 ;
      break ;
    case 22:
      row_index[22] = 28 ;
      break ;
    case 23:
      row_index[23] = 19 ;
      break ;
    case 24:
      row_index[24] = 27 ;
      break ;
    case 25:
      row_index[25] = 20 ;
      break ;
    case 26:
      row_index[26] = 26 ;
      break ;
    case 27:
      row_index[27] = 21 ;
      break ;
    case 28:
      row_index[28] = 25 ;
      break ;
    case 29:
      row_index[29] = 22 ;
      break ;
    case 30:
      row_index[30] = 24 ;
      break ;
    case 31:
      row_index[31] = 23 ;
      break ;
    default:
      sinfo_msg_error("wrong slitlet index: couldn't be a spiffi "
                      "image,  there must be 32 slitlets!\n") ;
      return -1 ;
    }

  return 0;

}



/**
   @name sinfo_new_make_cube_spi()

   @param  calibImage  re-sampled source image
   @param  slit_edges  absolute beginning and ending positions of
                                     slitlet, output of sinfo_fitSlits().
   @param  shift       sub_pixel shifts referred to the reference slit
                                     sinfo_edge

   @return  resulting source data cube

   @doc     makes a data cube out of a re-sampled source image
            this SPIFFI specific routine takes into account the
            Spiffi slitlet order on the detector.
            This routine takes fitted slitlet positions into account.
            Can do the same with the bad pixel map image to generate a
            bad pixel mask cube.


*/

cpl_imagelist * 
sinfo_new_make_cube_spi ( cpl_image *  calibImage,
                        float    ** slit_edges,
                        float    *  shift )
{
    cpl_imagelist * returnCube ;

    float * center ;
    int * row_index ;
    int slit ;
    int col, z ;
    int imsize ;
    int * beginCol ;
    int col_counter ;
    int ilx=0;
    int ily=0;


    float* pidata=NULL;


    if ( NULL == calibImage )
    {
        sinfo_msg_error("no resampled image given!\n") ;
        return NULL ;
    }
    ilx=cpl_image_get_size_x(calibImage);
    ily=cpl_image_get_size_y(calibImage);
    pidata=cpl_image_get_data_float(calibImage);

    if ( NULL == slit_edges )
    {
        sinfo_msg_error("no slit_edges array given from sinfo_fitSlits()!/n") ;
        return NULL ;
    }

    if ( N_SLITLETS != 32 )
    {
        sinfo_msg_error ("wrong number of slitlets given \n" ) ;
        return NULL ;
    }
    imsize = ilx / N_SLITLETS ;

    /* allocate memory */  
    if ( NULL == (row_index = (int*) cpl_calloc(N_SLITLETS, sizeof(int)) ) )
    {
        sinfo_msg_error ("cannot allocate memory \n" ) ;
        return NULL ;
    }
    if ( NULL == (beginCol = (int*) cpl_calloc(N_SLITLETS, sizeof(int)) ) )
    {
        sinfo_msg_error ("cannot allocate memory \n" ) ;
        cpl_free(row_index) ;
        return NULL ;
    }
    if ( NULL == (center = (float*) cpl_calloc(N_SLITLETS, sizeof(float)) ) )
    {
        sinfo_msg_error ("cannot allocate memory \n" ) ;
        cpl_free (row_index) ;
        cpl_free (beginCol) ;
        return NULL ;
    }
    if ( NULL == (returnCube = cpl_imagelist_new()) )
    {
        sinfo_msg_error ("cannot allocate new cube \n" ) ;
        cpl_free (row_index) ;
        cpl_free (beginCol) ;
        cpl_free (center) ;
        return NULL ;
    }
    /* determine the absolute center of the slitlets and the distances 
       inside the image*/
    for ( slit = 0 ; slit < N_SLITLETS ; slit++ ) 
    /* go through the slitlets of each row of the resampled image */
    {
        center[slit] = (slit_edges[slit][1] + slit_edges[slit][0]) / 2. ;
        /* -------------------------------------------------------------
         * sort the slitlets in the right spiffi specific way
         * the row_index describes the row index of the current slitlet 
         * in the resulting cube images.
         */
        if(-1 == sinfo_sort_slitlets_array(slit,row_index)) {
	  cpl_imagelist_delete(returnCube) ;
	  cpl_free (row_index) ;
          cpl_free (beginCol) ;
          cpl_free (center) ;
          return NULL ;
        }
        /* determine the integer column on which the slitlet starts, center the
           slitlet on the image row */
        float start = center[slit] - (float) (imsize - 1)/2. ;
        beginCol[slit] = sinfo_new_nint (start) ;
        /* determine the error of using integer pixels */
        float diff = start - (float)beginCol[slit] ;

        /*-------------------------------------------------------------------- 
         * determine the output shift values by which the rows are finally 
           shifted, consider the integer pixel errors  
         * resort shift array to get the row index 
         */
        shift[row_index[slit]] = diff ;
    }   

    /* now build the data cube out of the resampled image */
    for ( z = 0 ; z < ily ; z++ ) /* go through the z-axis */
    {
      cpl_image* o_img=cpl_image_new(imsize,N_SLITLETS,CPL_TYPE_FLOAT);
      float* podata=cpl_image_get_data_float(o_img);
      for ( slit = 0 ; slit < N_SLITLETS ; slit++ )
        {
      col_counter = beginCol[slit] ;
      /* each slitlet is centered on the final image row */
      for ( col = 0 ; col < imsize ; col++ )
            {
          if ( col_counter > ilx-1 )
                {
          col_counter-- ;
                }
          if ( col_counter + z*ilx < 0 )
                {
          podata[col+row_index[slit]*imsize] = pidata[0] ;
                }
              else
                {   
                  podata[col+row_index[slit]*imsize]=pidata[col_counter+z*ilx];
                }

                col_counter++ ;
            }
        }
      cpl_imagelist_set(returnCube,o_img,z);    
    }
    cpl_free (row_index) ;
    cpl_free (beginCol) ;
    cpl_free (center) ;

    return returnCube ;
}
/**
   @name   sinfo_new_make_cube_dist()

   @memo   makes a data cube out of a re-sampled source image

   @param  calibImage  re-sampled source image
   @param  firstCol    floating point value of the first column of
                                     the first slitlet in the re-sampled image,
                                     determined "by hand"
   @param  distances   distances of the slitlets from each other
                                     output of function ns_test
   @param  shift       dummy array with 32 elements

   @return              resulting source data cube

   @note       shift differences of the slitlets from
                               distance 32 given in the correct
                               Spiffi row sequence. The first slitlet
                               is the reference, therefore element
                               23 is set 0.

   @doc        makes a data cube out of a re-sampled source image
                        this SPIFFI specific routine takes into account the
                        Spiffi slitlet order on the detector.
                        Also shifts the resulting image rows by one pixel if
                        necessary according to the distances array gained from
                        the north-south test routine.
                Can do the same with the bad pixel map image to generate a
                bad pixel mask cube.

*/

cpl_imagelist * 
sinfo_new_make_cube_dist ( cpl_image * calibImage,
                         float      firstCol,
                         float    * distances,
                         float    * shift )
{
    cpl_imagelist * returnCube ;
    float di ;
    float start ;
    int * row_index ;
    int slit ;
    int col, z ;
    int imsize ;
    int * beginCol ;
    int col_counter ;
    int ilx=0;
    int ily=0;

    float* podata=NULL;
    float* pidata=NULL;

    if ( NULL == calibImage )
    {
        sinfo_msg_error(" no resampled image given!\n") ;
        return NULL ;
    }
    ilx=cpl_image_get_size_x(calibImage);
    ily=cpl_image_get_size_y(calibImage);
    pidata=cpl_image_get_data_float(calibImage);

    if ( NULL == distances )
    {
        sinfo_msg_error("no distances array given from north_south_test()!") ;
        return NULL ;
    }

    if ( N_SLITLETS != 32 )
    {
        sinfo_msg_error ("wrong number of slitlets given \n" ) ;
        return NULL ;
    }
    imsize = ilx / N_SLITLETS ;

    /* allocate memory */  
    if ( NULL == (row_index = (int*) cpl_calloc(N_SLITLETS, sizeof(int)) ) )
    {
        sinfo_msg_error ("cannot allocate memory \n" ) ;
        return NULL ;
    }
    if ( NULL == (beginCol = (int*) cpl_calloc(N_SLITLETS, sizeof(int)) ) )
    {
        sinfo_msg_error ("cannot allocate memory \n" ) ;
        cpl_free(row_index) ;
        return NULL ;
    }
    if ( NULL == (returnCube = cpl_imagelist_new()) )
    {
        sinfo_msg_error ("cannot allocate new cube \n" ) ;
        cpl_free(row_index) ;
        cpl_free(beginCol) ;
        return NULL ;
    }

    di = 0. ;
    /* determine the absolute beginning of the slitlets and the distances 
       inside the image*/
    for ( slit = 0 ; slit < N_SLITLETS ; slit++ ) 
    /* go through the slitlets of each row of the resampled image */
    {

        /* -------------------------------------------------------------
         * sort the slitlets in the right spiffi specific way
         * the row_index describes the row index of the current slitlet 
         * in the resulting cube images.
         */
        if(-1 == sinfo_sort_slitlets_array(slit,row_index)) {
	  cpl_imagelist_delete(returnCube) ;
	  cpl_free(row_index) ;
	  cpl_free(beginCol) ;
	  return NULL ;
        }

        /* determine the integer column on which the slitlet starts */
        if ( slit == 0 )
        {
            start = firstCol ;
        }
        else
        {
            di += distances[slit-1] ;
            start = firstCol + di ;
        }
        beginCol[slit] = sinfo_new_nint(start) ;

        /* determine the error of using integer pixels, its always smaller 
           than 1 */
        float diff = start - (float)beginCol[slit] ;

        /*---------------------------------------------------------------- 
         * determine the output shift values by which the rows are finally 
         * shifted, consider the integer pixel errors and resort shift array 
         * to get the row index 
         */
        shift[row_index[slit]] = diff ;
    }   

    /* now build the data cube out of the resampled image */
    for ( z = 0 ; z < ily ; z++ ) /* go through the z-axis */
    {
      cpl_image* o_img=cpl_image_new(imsize,N_SLITLETS,CPL_TYPE_FLOAT);
      podata=cpl_image_get_data_float(o_img);
      for ( slit = 0 ; slit < N_SLITLETS ; slit++ )
        {
      col_counter = beginCol[slit] ;
      /* each slitlet is centered on the final image row */
      for ( col = 0 ; col < imsize ; col++ )
            {
          if ( col_counter > ilx-1 )
                {
          col_counter-- ;
                }
                if ( col_counter + z*ilx < 0 )
                {
          podata[col+row_index[slit]*imsize] = podata[0] ;
                }
                else
                {   
                  podata[col+row_index[slit]*imsize]=pidata[col_counter+z*ilx];
                }

                col_counter++ ;
            }
        }  
      cpl_imagelist_set(returnCube,o_img,z);  
    }
    cpl_free (row_index) ;
    cpl_free (beginCol) ;

    return returnCube ;
}

/**
   @name     sinfo_new_fine_tune_cube()

   @param    cube  cube, output of sinfo_makeCube
   @param  correct_diff_dist  differences of the slitlets from
                              distance 32 given in the correct
                              Spiffi row sequence. The first slitlet
                              is the reference, therefore element
                              23 is set 0.
                              Output of sinfo_makeCube!
   @param n_order interpolating polynomial order

   @return resulting data cube having the exact row positions

   @doc    fine tunes each row in the right position according
           to the distances of the slitlets to each other
           (output of the north-south test).
           This means that the rows must be realigned by a
           fraction of a pixel to accomodate non-integer slit
           length. The fractional realignment is done by using
           tanh interpolation.
           Each row is rescaled so that the total flux is conserved.


*/
 
cpl_imagelist * 
sinfo_new_fine_tune_cube( cpl_imagelist * cube,
                                     float   * correct_diff_dist,
                                     int       n_order )
{
    cpl_imagelist * returnCube ;
    float* row_data=NULL ;
    float* corrected_row_data=NULL ;
    float* xnum=NULL ;
    float sum, new_sum ;
    float eval/*, dy*/ ;
    float * imageptr ;
    int row, col ;
    int i, z ;
    int imsize, n_points ;
    int firstpos ;
    int  flag;
    int ilx=0;
    int ily=0;
    int inp=0;

    if ( NULL == cube )
    {
        sinfo_msg_error("no input cube given!\n") ;
        return NULL ;
    }
    ilx=cpl_image_get_size_x(cpl_imagelist_get(cube,0));
    ily=cpl_image_get_size_y(cpl_imagelist_get(cube,0));
    inp=cpl_imagelist_get_size(cube);

    if ( NULL == correct_diff_dist )
    {
        sinfo_msg_error("no distances array from ns_test given!n") ;
        return NULL ;
    }
  
    if ( n_order <= 0 )
    {
        sinfo_msg_error("wrong order of interpolation polynom given!") ;
    returnCube = cpl_imagelist_duplicate(cube);
        return returnCube ;
    }

    returnCube = cpl_imagelist_duplicate(cube);
    
    imsize = ily ;
    if ( imsize != N_SLITLETS )
    {
        sinfo_msg_error ("wrong image size\n" ) ;
        sinfo_free_imagelist(&returnCube);
        return NULL ;
    }

    n_points = n_order + 1 ;
    if ( n_points % 2 == 0 )
    {
        firstpos = (int)(n_points/2) - 1 ;
    }
    else
    {
        firstpos = (int)(n_points/2) ;
    }
    xnum=cpl_calloc(n_order+1,sizeof(float)) ;

    for ( i = 0 ; i < n_points ; i++ )
    {
        xnum[i] = i ;
    }    

    row_data=cpl_calloc(ilx,sizeof(float)) ;
    corrected_row_data=cpl_calloc(ilx,sizeof(float)) ;

    for ( z = 0 ; z < inp ; z++ )
    {
      cpl_image* i_img=cpl_imagelist_get(cube,z);
      float* pidata=cpl_image_get_data_float(i_img);
      cpl_image* o_img=cpl_imagelist_get(returnCube,z);
      float* podata=cpl_image_get_data_float(o_img);


        for ( row = 0 ; row < imsize ; row++ )
        {
            for ( col = 0 ; col < ilx ; col++ )
            {
                corrected_row_data[col] = 0. ;
            }
            sum = 0. ; 
            for ( col = 0 ; col < ilx ; col++ )
            {
                row_data[col] = pidata[col+row*ilx] ;
                if ( isnan(row_data[col]) )
                {
                    row_data[col] = 0. ;
                    for ( i = col - firstpos ; 
                          i < col -firstpos+n_points ; i++ )
                    {
                        if ( i < 0 ) continue ;
                        if ( i >= ilx) continue ; 
                        corrected_row_data[i] = ZERO ;
                    }
                }
                if ( col != 0 && col != ilx - 1 )
                {
                    sum += row_data[col] ;
                }
            }

           
            new_sum = 0. ;
            for ( col = 0 ; col < ilx ; col++ )
            {
                
                if ( isnan(corrected_row_data[col]) )
                {
                    continue ;
                }
                if ( col - firstpos < 0 )
                {
                    imageptr = &row_data[0] ;
                    eval     = correct_diff_dist[row] + col ;
                }
                else if ( col - firstpos + n_points >= ilx )
                {
                    imageptr = &row_data[ilx - n_points] ;
                    eval     = correct_diff_dist[row] + col + n_points - ilx ;
                }
                else
                {
                    imageptr = &row_data[col-firstpos] ;
                    eval     = correct_diff_dist[row] + firstpos ;
                }

        
        flag = 0;
        corrected_row_data[col]=sinfo_new_nev_ille(xnum, imageptr, 
                                                       n_order, eval, &flag);

               
                if ( col != 0 && col != ilx - 1 )
                {
                    new_sum += corrected_row_data[col] ;
                }
            }
            for ( col = 0 ; col < ilx ; col++ )
            {
                
                if ( col == 0 )
                {
                    podata[col+row*ilx] = ZERO ;
                }
                else if ( col == ilx - 1 )
                {
                    podata[col+row*ilx] = ZERO ;
                }
                else
                {
                    if ( isnan(corrected_row_data[col]) ) 
                    {
                        podata[col+row*ilx] = ZERO ;
                    }
                    else
                    {
                        if ( new_sum == 0. ) new_sum = 1. ;
                     
                        podata[col+row*ilx] = corrected_row_data[col] ;
                    }
                }
            }
        }
    }       

    cpl_free(xnum) ;
    cpl_free(row_data) ;
    cpl_free(corrected_row_data) ;

    return returnCube ;
}

/**
   @name   sinfo_new_fine_tune_cube_by_FFT()

   @param  cube:  cube, output of sinfo_makeCube
   @param  correct_diff_dist: differences of the slitlets from
                  distance 32 given in the correct
                  Spiffi row sequence. The first slitlet
                  is the reference, therefore element
                  23 is set 0.
                  Output of sinfo_makeCube!

   @return  resulting data cube having the exact row positions

   @doc    fine tunes each row in the right position according
                        to the distances of the slitlets to each other
                        (output of the north-south test).
                        This means that the rows must be realigned by a
                        fraction of a pixel to accomodate non-integer slit
                        length. The fractional realignment is done by using
                        the FFT algorithm four1() of N.R.


*/

cpl_imagelist * 
sinfo_new_fine_tune_cube_by_FFT( cpl_imagelist * cube,
                                           float   * correct_diff_dist )
{
    cpl_imagelist * returnCube ;

    float* row_data=NULL ;
    dcomplex* data=NULL ;
    dcomplex* corrected_data=NULL ;

    unsigned nn[2];
    /*float corrected_row_data[cube->lx] ;*/
    float phi, pphi ;
    float coph, siph ;
    int row, col ;
    int i, z ;
    int imsize ;
    int blank_indicator ;


    int ilx=0;
    int ily=0;
    int inp=0;
   





    if ( NULL == cube )
    {
        sinfo_msg_error(" no input cube given!\n") ;
        return NULL ;
    }
    ilx=cpl_image_get_size_x(cpl_imagelist_get(cube,0));
    ily=cpl_image_get_size_y(cpl_imagelist_get(cube,0));
    inp=cpl_imagelist_get_size(cube);

    nn[1] = ilx ;
    if ( NULL == correct_diff_dist )
    {
        sinfo_msg_error("no distances array from ns_test given!") ;
        return NULL ;
    }

    returnCube = cpl_imagelist_duplicate( cube ) ;

    imsize = ily ;
    if ( imsize != N_SLITLETS )
    {
        sinfo_msg_error ("wrong image size\n" ) ;
        sinfo_free_imagelist(&returnCube);
        return NULL ;
    }

    data=cpl_calloc(ilx,sizeof(dcomplex)) ;
    corrected_data=cpl_calloc(ilx,sizeof(dcomplex)) ;

    row_data=cpl_calloc(ilx,sizeof(float)) ;
    /* loop over the image planes */
    for ( z = 0 ; z < inp ; z++ )
    {
      cpl_image* i_img=cpl_imagelist_get(cube,z);
      float* pidata=cpl_image_get_data_float(i_img);
      cpl_image* o_img=cpl_imagelist_get(returnCube,z);
      float* podata=cpl_image_get_data_float(o_img);
        /* consider one row at a time */
        for ( row = 0 ; row < imsize ; row++ )
        {
            blank_indicator = 1 ;
            for ( col = 0 ; col < ilx ; col++ )
            {
                /* transfer the row data to a double sized array */
                row_data[col] = pidata[col+row*ilx] ;
        data[col].x = row_data[col] ;
        data[col].y = 0. ;
                /* if row contains a blank pixel proceed */
                if ( isnan(row_data[col]) )
                {
                    blank_indicator = 0 ; 
                }
            }

            /* if row contains a blank don't apply FFT but proceed */
            if ( blank_indicator == 0 )
            {
                for ( col = 0 ; col < ilx ; col++ )
                {
                    podata[col+row*ilx] = ZERO ;
                }
                continue ;
            }
           
            /* FFT algorithm of eclipse */
            sinfo_fftn( data, nn, 1, 1 ) ;
 
            /* calculate the corrected phase shift for each frequency */
            phi = 2*PI_NUMB/(float)ilx * correct_diff_dist[row] ;
            for ( i = 0 ; i < ilx ; i++ )
            {
                /* positive frequencies */
                if ( i <= ilx/2 )
                {
                    /* phase shift */
                    pphi = phi * (float)(i) ;
                    /* Euler factor */
                    coph = cos ( pphi ) ;
                    siph = sin ( pphi ) ;
                }
                else /* negative frequencies */
                {
                    /* phase shift */
                    pphi = phi * (float)(i - ilx/2) ;
                    /* Euler factor */
                    coph = cos ( pphi ) ;
                    siph = sin ( pphi ) ;
                }

                /* ------------------------------------------------------------
                 * now calculate the shift in the pixel space by multiplying
                 * the fourier transform by the Euler factor of the phase shift
                 * and inverse fourier transforming.
                 * used Fourier pair: h(x-x0) <==> H(k)*exp(2*pi*i*k*x0) 
                 */
                /* calculate real part */
                corrected_data[i].x   = data[i].x * coph - data[i].y * siph ; 
                /* calculate imaginary part */
                corrected_data[i].y = data[i].x * siph + data[i].y * coph ;
            }
 
            /* transform back: inverse FFT */
            sinfo_fftn( corrected_data, nn, 1, -1 ) ;

            /* normalize */ 
            for ( i = 0 ; i < ilx ; i++ )
            {
                corrected_data[i].x /= ilx ;
        corrected_data[i].y /= ilx ;
            } 

            /* now transfer row to output, leave the left-most 
               and right-most pixel column */
            for ( col = 0 ; col < ilx ; col++ )
            {
                if ( col == 0 )
                {
                    podata[col+row*ilx] = ZERO ;
                }
                else if ( col == ilx - 1 )
                {
                    podata[col+row*ilx] = ZERO ;
                }
                else
                {
                    podata[col+row*ilx] = corrected_data[col].x ; 
                }
            }
        }
    }

    cpl_free(data) ;
    cpl_free(corrected_data) ;


    cpl_free(row_data);
    return returnCube ;
}
/**
   @name    sinfo_new_fine_tune_cube_by_spline()
   @param   cube:  cube, output of sinfo_makeCube
   @param   correct_diff_dist: differences of the slitlets from
                        distance 32 given in the correct
                        Spiffi row sequence. The first slitlet
                        is the reference, therefore element
                        23 is set 0.
                        Output of sinfo_makeCube!
   @return  resulting data cube having the exact row positions


   @doc     fine tunes each row in the right position according
                        to the distances of the slitlets to each other
                        (output of the north-south test).
                        This means that the rows must be realigned by a
                        fraction of a pixel to accomodate non-integer slit
                        length. The fractional realignment is done by using
                        the spline interpolation algorithm splint in connection
                        with the algorithm spline of N.R.
                        This algorithms assume that each row is a tabulated
                        function. The first derivatives of the interpolating
                        function at the first and last point must be given.
                        These are set higher than 1xe^30, so the routine
                        sets the corresponding boundary condition for a natural
                        spline, with zero second derivative on that boundary.
                        Each row is rescaled so that the total flux is
                        conserved.

 */
cpl_imagelist * sinfo_new_fine_tune_cube_by_spline ( cpl_imagelist * cube,
                                               float   * correct_diff_dist )
{
    cpl_imagelist * returnCube ;

    float* row_data=NULL ;
    float* corrected_row_data=NULL ;
    float* xnum=NULL ;
    float* eval=NULL ;

    float sum, new_sum ;
    int row, col ;
    int i, z ;
    int imsize ;
    int ilx=0;
    int ily=0;
    int inp=0;
 
    if ( NULL == cube )
    {
        sinfo_msg_error("no input cube given!\n") ;
        return NULL ;
    }
    ilx=cpl_image_get_size_x(cpl_imagelist_get(cube,0));
    ily=cpl_image_get_size_y(cpl_imagelist_get(cube,0));
    inp=cpl_imagelist_get_size(cube);

    if ( NULL == correct_diff_dist )
    {
        sinfo_msg_error("no distances array from ns_test given!/n") ;
        return NULL ;
    }
  
    imsize = ily ;
    if ( imsize != N_SLITLETS )
    {
        sinfo_msg_error ("wrong image size\n" ) ;
        return NULL ;
    }
  
    returnCube = cpl_imagelist_duplicate( cube ) ;

    row_data=cpl_calloc(ilx,sizeof(float)) ;
    corrected_row_data=cpl_calloc(ilx,sizeof(float)) ;
    xnum=cpl_calloc(ilx,sizeof(float)) ;
    eval=cpl_calloc(ilx,sizeof(float)) ;
  
    /* fill the xa[] array for a polynomial interpolation */
    for ( i = 0 ; i < ilx ; i++ )
    {
        xnum[i] = i ;
    }    

    /* loop over the image planes */
    for ( z = 0 ; z < inp ; z++ )
    {
      cpl_image* i_img=cpl_imagelist_get(cube,z);
      float* pidata=cpl_image_get_data_float(i_img);
      cpl_image* o_img=cpl_imagelist_get(returnCube,z);
      float* podata=cpl_image_get_data_float(o_img);
        /* consider 1 row at a time */
        for ( row = 0 ; row < imsize ; row++ )
        {
            for ( col = 0 ; col < ilx ; col++ )
            {
                corrected_row_data[col] = 0. ;
            }
        sum = 0. ; /* initialize flux for later rescaling */
            /* go through the columns and compute the flux for each 
               row (leave the sinfo_edge points) */
            for ( col = 0 ; col < ilx ; col++ )
            {   
            eval[col] = correct_diff_dist[row] + (float)col ;
                row_data[col] = pidata[col+row*ilx] ;
                if (col != 0 && col != ilx - 1 && !isnan(row_data[col]) )
                {
                    sum += row_data[col] ;
                }
                if (isnan(row_data[col]) )
                {
                    for ( i = col -1 ; i <= col+1 ; i++ ) 
                    {
                        if ( i < 0 ) continue ;
                        if ( i >= ilx ) continue ;
                        corrected_row_data[i] = ZERO ; 
                    }
                    row_data[col] = 0. ;
                }
        }


            /* ---------------------------------------------------------------
             * now we do the cubic spline interpolation to achieve the 
               fractional (see eclipse).
             */
            if ( -1 == sinfo_function1d_natural_spline(xnum,row_data, ilx, 
                                                       eval,corrected_row_data,
                                                       ilx ) )
        {
            sinfo_msg_error("error in spline interpolation\n") ;
        cpl_imagelist_delete(returnCube) ;
        return NULL ;
        }    

            new_sum = 0. ;
            for ( col = 0 ; col < ilx ; col++ )
            {
                if (isnan(corrected_row_data[col])) continue ;
                /* don't take the sinfo_edge points to calculate 
                   the scaling factor */
                if ( col != 0 && col != ilx - 1 )
                {
                    new_sum += corrected_row_data[col] ;
                }
            }
            for ( col = 0 ; col < ilx ; col++ )
            {
                /* ----------------------------------------------------------
                 * rescale the row data and fill the returned cube, 
                 * leave the left-most and right-most
                 * pixel column 
                 */
                if ( col == 0 )
                {
                    podata[col+row*ilx] = ZERO ;
                }
                else if ( col == ilx - 1 )
                {
                    podata[col+row*ilx] = ZERO ;
                }
                else
                {
                    if ( isnan(corrected_row_data[col]) ) 
                    {
                        podata[col+row*ilx] = ZERO ;
                    }
                    else
                    {
                        if (new_sum == 0.) new_sum = 1. ;
                     /* rescaling is commented out because it delivers 
                        wrong results
                        in case of appearance of blanks or bad pixels */
                  /*       corrected_row_data[col] *= sum / new_sum ; */
                        podata[col+row*ilx] = corrected_row_data[col] ;
                    }
                }
            }
        }
    }       

    cpl_free(row_data) ;
    cpl_free(corrected_row_data) ;
    cpl_free(xnum) ;
    cpl_free(eval) ;

    return returnCube ;
}

/*The old slitlet order*/
/*switch (kslit)
                {
                    case 0:
                        slit_index = 23 ;
                        break ;
                    case 1:
                        slit_index = 24 ;
                        break ;
                    case 2:
                        slit_index = 22 ;
                        break ;
                    case 3:
                        slit_index = 25 ;
                        break ;
                    case 4:
                        slit_index = 21 ;
                        break ;
                    case 5:
                        slit_index = 26 ;
                        break ;
                    case 6:
                        slit_index = 20 ;
                        break ;
                    case 7:
                        slit_index = 27 ;
                        break ;
                    case 8:
                        slit_index = 19 ;
                        break ;
                    case 9:
                        slit_index = 28 ;
                        break ;
                    case 10:
                        slit_index = 18 ;
                        break ;
                    case 11:
                        slit_index = 29 ;
                        break ;
                    case 12:
                        slit_index = 17 ;
                        break ;
                    case 13:
                        slit_index = 30 ;
                        break ;
                    case 14:
                        slit_index = 16 ;
                        break ;
                    case 15:
                        slit_index = 31 ;
                        break ;
                    case 16:
                        slit_index = 0 ;
                        break ;
                    case 17:
                        slit_index = 15 ;
                        break ;
                    case 18:
                        slit_index = 1 ;
                        break ;
                    case 19:
                        slit_index = 14 ;
                        break ;
                    case 20:
                        slit_index = 2 ;
                        break ;
                    case 21:
                        slit_index = 13 ;
                        break ;
                    case 22:
                        slit_index = 3 ;
                        break ;
                    case 23:
                        slit_index = 12 ;
                        break ;
                    case 24:
                        slit_index = 4 ;
                        break ;
                    case 25:
                        slit_index = 11 ;
                        break ;
                    case 26:
                        slit_index = 5 ;
                        break ;
                    case 27:
                        slit_index = 10 ;
                        break ;
                    case 28:
                        slit_index = 6 ;
                        break ;
                    case 29:
                        slit_index = 9 ;
                        break ;
                    case 30:
                        slit_index = 7 ;
                        break ;
                    case 31:
                        slit_index = 8 ;
                        break ;
                    default:
                        sinfo_msg_error("wrong slitlet index: couldn't "
                                        "be a spiffi image,  \
                                 there must be 32 slitlets!\n") ;
                        cpl_imagelist_delete(returnCube) ;
                        return NULL ;
                        break ;
                }*/


/*--------------------------------------------------------------------------*/
/**@}*/
