/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set sw=2 sts=2 et cin: */
/*
 * This file is part of the MUSE Instrument Pipeline
 * Copyright (C) 2007-2017 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.
 */

#include <muse.h>
#include <string.h>

/*----------------------------------------------------------------------------*/
/**
  @brief    short test program to check that muse_wave_map() does what it
            should when called for a correct set of data
 */
/*----------------------------------------------------------------------------*/
int main(int argc, char **argv)
{
  UNUSED_ARGUMENTS(argc, argv);
  cpl_test_init(PACKAGE_BUGREPORT, CPL_MSG_DEBUG);

  cpl_table *wavecaltable = NULL, *tracetable = NULL;
  if (argc >= 3) {
    char *wcal = NULL,
         *trace = NULL;
    unsigned char nifu = 0; /* IFU number to load */
    /* argument processing */
    int i;
    for (i = 1; i < argc; i++) {
      if (strncmp(argv[i], "-n", 3) == 0) {
        /* skip to next arg to get extension name */
        i++;
        if (i < argc) {
          nifu = atoi(argv[i]); /* check below */
        }
      } else if (strncmp(argv[i], "-", 1) == 0) { /* unallowed options */
        /* nothing... */
      } else {
        if (wcal && trace) {
          break /* we have the required name, skip the rest */;
        }
        if (!wcal) {
          wcal = argv[i];
        } else {
          trace = argv[i];
        }
      }
    }
    cpl_msg_info(__func__, "command line arguments detected, will try to load "
                 "IFU %hhu from %s (as WAVECAL_TABLE) and %s (as TRACE_TABLE)",
                 nifu, wcal, trace);
    int ext1 = 1,
        ext2 = 1;
    if (nifu > 0 && nifu <= kMuseNumIFUs) {
      ext1 = muse_utils_get_extension_for_ifu(wcal, nifu);
      ext2 = muse_utils_get_extension_for_ifu(trace, nifu);
    }
    wavecaltable = cpl_table_load(wcal, ext1, 1);
    tracetable = cpl_table_load(trace, ext2, 1);
  } else {
    wavecaltable = cpl_table_load(BASEFILENAME"_wavecal_in.fits", 1, 1);
    tracetable = cpl_table_load(BASEFILENAME"_trace_in.fits", 1, 1);
  }
  if (!tracetable || !wavecaltable) {
    cpl_msg_error(__func__, "Could not load trace or wavecal table: %s",
                  cpl_error_get_message());
    cpl_table_delete(wavecaltable);
    cpl_table_delete(tracetable);
    return cpl_test_end(2);
  }
  cpl_error_reset();

  /* just create any image into which the normal MUSE pattern fits */
  muse_image *inimage = muse_image_new();
  inimage->data = cpl_image_new(4096, 4112, CPL_TYPE_FLOAT);
  inimage->dq = NULL;
  inimage->stat = NULL;
  cpl_image *outimage = muse_wave_map(inimage, wavecaltable, tracetable);
  cpl_test(outimage != NULL);
  if (outimage) {
    double mean = cpl_image_get_mean(outimage),
           stdev = cpl_image_get_stdev(outimage),
           median = cpl_image_get_median(outimage);
    /* mean and median should be within the MUSE wavelength range */
    cpl_test(mean > 4650. && mean < 9300.);
    cpl_test(median > 4650. && median < 9300.);
    cpl_msg_info(__func__, "successfully created wavelength map (stats: %f(%f)+/-%f)",
                 mean, median, stdev);

    /* loop through all pixels and compute dlambda */
    int nx = cpl_image_get_size_x(outimage),
        ny = cpl_image_get_size_y(outimage);
    const float *data = cpl_image_get_data_float_const(outimage);
    cpl_vector *lambda = cpl_vector_new(nx * ny),
               *dlambda = cpl_vector_new(nx * ny);
    cpl_size n = 0;
    int i;
    for (i = 0; i < nx; i++) {
      int j;
      for (j = 1; j < ny; j++) {
        double d = data[i + j*nx] - data[i + (j-1)*nx];
        if (d > 1. && d < 2.) { /* exclude empty image parts and slice edges */
          cpl_vector_set(lambda, n, data[i + j*nx]);
          cpl_vector_set(dlambda, n++, d);
        }
      }
    }
    cpl_vector_set_size(lambda, n);
    cpl_vector_set_size(dlambda, n);
    mean = cpl_vector_get_mean(dlambda);
    median = cpl_vector_get_median_const(dlambda);
    stdev = cpl_vector_get_stdev(dlambda);
    double min = cpl_vector_get_min(dlambda),
           max = cpl_vector_get_max(dlambda);
#if 0
    cpl_bivector *biv = cpl_bivector_wrap_vectors(lambda, dlambda);
    cpl_bivector_dump(biv, stderr);
    cpl_bivector_unwrap_vectors(biv);
#endif
    cpl_vector_delete(dlambda);
    cpl_vector_delete(lambda);
    cpl_msg_debug(__func__, "delta lambda statistics: %f(%f)+/-%f %f...%f",
                  mean, median, stdev, min, max);
    cpl_test(mean > 1.245 && mean < 1.26);
    cpl_test(median > 1.245 && median < 1.26);
    cpl_test(stdev < 0.02);
    cpl_test(min > 1.2);
    cpl_test(max < 1.3);

    cpl_image_save(outimage, "wavecal_map.fits", CPL_TYPE_FLOAT, NULL,
                   CPL_IO_CREATE);
    cpl_image_delete(outimage);
  }
  cpl_table_delete(wavecaltable);
  cpl_table_delete(tracetable);
  muse_image_delete(inimage);

  return cpl_test_end(0);
}
