/* -*- 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-2015 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>

/* structure for the expected arc line detections */
typedef struct {
  int no;
  float pos;
  float flux;
} expected;

void
test_line_locations(cpl_table *aLines, expected aPositions[], int aNLines)
{
  cpl_test_nonnull(aLines);
  if (aLines) {
    int nlines = cpl_table_get_nrow(aLines);
    cpl_test(nlines == aNLines);
    if (nlines != aNLines) {
      cpl_msg_error(__func__, "nlines=%d != aNLines=%d", nlines, aNLines);
      cpl_table_dump(aLines, 0, nlines, stdout);
      fflush(stdout);
    }

    /* test for expected positions of all lines with a tolerance of +/-0.5 pix */
    int i;
    for (i = 0; aPositions[i].pos > 0. && aPositions[i].no < nlines; i++) {
      double detpos = cpl_table_get(aLines, "center", aPositions[i].no, NULL);
      int doesmatch = (detpos > aPositions[i].pos - 0.5)
                   && (detpos < aPositions[i].pos + 0.5);
      cpl_test(doesmatch);
      if (!doesmatch) {
        cpl_msg_error(__func__, "position[%d][] = %d %f %f does not match %f",
                      i, aPositions[i].no, aPositions[i].pos, aPositions[i].flux,
                      detpos);
        cpl_table_dump(aLines, 0, nlines, stdout);
        fflush(stdout);
        break;
      }
#if 0
      else {
        cpl_msg_debug(__func__, "position[%d][] = %d %f %f does match %f",
                      i, aPositions[i].no, aPositions[i].pos, aPositions[i].flux,
                      detpos);
      }
#endif
    }
  }
  cpl_table_delete(aLines);
} /* test_line_locations() */

/*----------------------------------------------------------------------------*/
/**
  @brief    test program to check that muse_wave_lines_search() does what it
            should when called on a column taken from a real and an
            INM-simulated arc exposure
 */
/*----------------------------------------------------------------------------*/
int main(int argc, char **argv)
{
  UNUSED_ARGUMENTS(argc, argv);
  cpl_test_init(PACKAGE_BUGREPORT, CPL_MSG_DEBUG);

  cpl_error_reset();

  cpl_msg_info(__func__, "===== Data from real exposure (not flat-fielded) =====");
  expected positions1[] = { /* list of {no, pos, flux} for each expected arc line */
    /* {  108.8068  87.8679 }. not detected, too faint */
    { 0,  120.2017, 3518.22 },
    { 1,  214.8117, 11558.4 },
    { 2,  305.4193, 208.807 },
    { 3,  438.1213, 24984.0 },
    { 4,  492.0264, 129.439 },
    { 5,  732.8964, 99274.6 },
    /* {  902.3192  39.8464 }, not detected, too faint */
    { 6,  976.9777, 18461.0 },
    { 7,  993.6136, 18575.8 },
    /* {  1345.762, 50.1498 }, not detected, too faint */
    /* {  1417.484, 37.8722 }, not detected, too faint */
    { 8,  1508.089, 10287.0 },
    /* {  1729.771, 44.8923 }, not detected, too faint */
    { 9,  1882.141, 481.420 },
    { 10, 2021.659, 124.865 },
    /* {  2029.547, 51.6413 }, not detected, too faint */
    { 11, 2232.977, 104.027 },
    /* {  2261.895, 69.4551 }, not detected, too faint */
    /* {  2272.911  25.9585 }, not detected, too faint */
    /* {  2464.896, 39.1081 }, not detected, too faint */
    { 12,  2540.088, 86.9954 },
    { 13,  2851.337, 81.1261 },
    /* {  2919.494  80.5648 }, not detected, too faint */
    /* {  3087.383, 46.9465 }, not detected, too faint */
    { 0,  -1.,     -1.      } /* end "tag" with negative position */
  };
  muse_image *arc = muse_image_load(BASEFILENAME"_real.fits");
  if (!arc || !arc->data) {
    cpl_msg_error(__func__, "Could not load test image: %s", cpl_error_get_message());
    muse_image_delete(arc);
    return cpl_test_end(1);
  }
  /* add keyword not present in that old test data */
  cpl_propertylist_append_string(arc->header, "BUNIT", "count");
  test_line_locations(muse_wave_lines_search(arc, 1.0, 24, 10), positions1, 14);
  muse_image_delete(arc);

  cpl_msg_info(__func__, "===== Data from real exposure (flat-fielded) =====");
  expected positions2[] = { /* list of {no, pos, flux} for each expected arc line */
    /* {  108.3552, 541.482 }, not detected, too faint */
    { 0,  120.1869, 42553.2 },
    { 1,  214.8108, 88305.5 },
    { 2,  305.4236, 1190.07 },
    { 3,  438.1479, 94265.4 },
    { 4,  492.0470, 417.331 },
    { 5,  732.9244, 212000. },
    { 6,  976.9833, 27728.1 },
    { 7,  993.6230, 27242.3 },
    /* {  1345.801, 58.0849 }, not detected, too faint */
    { 8,  1508.106, 9084.03 },
    /* {  1729.733, 47.2774 }, not detected, too faint */
    { 9,  1882.136, 330.631 },
    { 10, 2021.659, 74.5212 },
    /* {  2029.588, 29.0155 }, not detected, too faint */
    { 11, 2232.979, 57.3139 },
    /* {  2261.933, 35.5726 }, not detected, too faint */
    /* {  2272.913, 14.0534 }, not detected, too faint */
    /* {  2464.890, 29.5937 }, not detected, too faint */
    /* {  2540.115, 50.3002 }, not detected, too faint */
    /* {  2851.316, 48.4706 }, not detected, too faint */
    { 0,  -1.,      -1.     } /* end "tag" with negative position */
  };
  arc = muse_image_load(BASEFILENAME"_realflat.fits");
  if (!arc || !arc->data) {
    cpl_msg_error(__func__, "Could not load test image: %s", cpl_error_get_message());
    muse_image_delete(arc);
    return cpl_test_end(1);
  }
  /* add keyword not present in that old test data */
  cpl_propertylist_append_string(arc->header, "BUNIT", "count");
  test_line_locations(muse_wave_lines_search(arc, 1.0, 24, 10), positions2, 12);
  muse_image_delete(arc);

  cpl_msg_info(__func__, "===== Data from INM exposure (not flat-fielded) =====");
  expected positions3[] = { /* list of {no, pos, flux} for each expected arc line */
    /* {  109.639, 28.1381 }, not detected, too faint */
    { 0,  121.964, 4504.78 },
    { 1,  216.983, 31689.7 },
    { 2,  308.003, 312.151 },
    { 3,  440.911, 60906.6 },
    { 4,  494.925, 293.064 },
    { 5,  734.845, 111166. },
    { 6,  978.879, 23999.8 },
    { 7,  994.857, 24438.3 },
    { 8,  1345.56, 78.8044 },
    { 9,  1417.82, 144.573 },
    { 10, 1507.95, 29936.9 },
    { 11, 1559.85, 75.9608 },
    { 12, 1573.98, 501.176 },
    { 13, 1702.09, 177.416 },
    { 14, 1729.02, 89.1105 },
    { 15, 1800.95, 805.578 },
    { 16, 1880.99, 741.682 },
    { 17, 1901.63, 2730.02 },
    { 18, 2020.84, 205.277 },
    { 19, 2029.20, 102.573 },
    { 20, 2087.97, 342.069 },
    { 21, 2132.20, 5578.56 },
    { 22, 2194.98, 6051.73 },
    { 23, 2202.02, 2255.08 }, /* sometimes not detected, too close to brighter line?! */
    { 24, 2215.97, 1409.06 },
    { 25, 2232.02, 314.620 },
    { 26, 2263.85, 138.113 },
    { 27, 2830.89, 13079.6 },
    { 28, 2881.89, 868.914 },
    { 29, 3303.91, 63.3318 },
    { 30, 3316.95, 211.574 },
    { 31, 3334.95, 12801.4 },
    { 32, 3852.90, 1404.62 },
    { 33, 4051.76, 2010.92 },
    { 0,  -1.,     -1.     } /* end "tag" with negative position */
  };
  arc = muse_image_load(BASEFILENAME"_inm.fits");
  if (!arc || !arc->data) {
    cpl_msg_error(__func__, "Could not load test image: %s", cpl_error_get_message());
    muse_image_delete(arc);
    return cpl_test_end(3);
  }
  /* add keyword not present in that old test data */
  cpl_propertylist_append_string(arc->header, "BUNIT", "count");
  test_line_locations(muse_wave_lines_search(arc, 1.0, 24, 10), positions3, 34);
  muse_image_delete(arc);

  /* special testcase of 2-pixel high line detection below zero, that was *
   * found through unexpected and cryptic error messages (MPDAF #405)     */
  muse_image *column = muse_image_new();
  /* make the test image large enough for the filtering to work */
  column->data = cpl_image_new(1, 52, CPL_TYPE_FLOAT);
  column->dq = cpl_image_new(1, 52, CPL_TYPE_INT);
  column->stat = cpl_image_new(1, 52, CPL_TYPE_FLOAT);
  column->header = cpl_propertylist_new();
  cpl_propertylist_append_string(column->header, "BUNIT", "count");
  cpl_image_set(column->data, 1, 1, -6.850474); /* fill the data */
  cpl_image_set(column->data, 1, 2, -4.942625);
  cpl_image_set(column->data, 1, 3, -6.670065);
  cpl_image_set(column->data, 1, 4, -7.312554);
  cpl_image_set(column->data, 1, 5, -5.229778);
  cpl_image_set(column->data, 1, 6, -5.679062);
  cpl_image_set(column->data, 1, 7, -6.393769);
  cpl_image_set(column->data, 1, 8, -5.958076);
  cpl_image_set(column->data, 1, 9, -7.086233);
  cpl_image_set(column->data, 1, 10, -3.73726);
  cpl_image_set(column->data, 1, 11, -6.42865);
  cpl_image_set(column->data, 1, 12, -5.448522);
  cpl_image_set(column->data, 1, 13, -6.609288);
  cpl_image_set(column->data, 1, 14, -4.332588);
  cpl_image_set(column->data, 1, 15, -6.736575);
  cpl_image_set(column->data, 1, 16, -5.269438);
  cpl_image_set(column->data, 1, 17, -4.907901);
  cpl_image_set(column->data, 1, 18, -4.24011);
  cpl_image_set(column->data, 1, 19, -5.5755);
  cpl_image_set(column->data, 1, 20, -4.500716);
  cpl_image_set(column->data, 1, 21, -4.992565);
  cpl_image_set(column->data, 1, 22, -7.182353);
  cpl_image_set(column->data, 1, 23, -5.253579);
  cpl_image_set(column->data, 1, 24, -5.06588);
  cpl_image_set(column->data, 1, 25, -5.823569);
  cpl_image_set(column->data, 1, 26, -5.688051);
  cpl_image_set(column->data, 1, 27, -6.150259);
  cpl_image_set(column->data, 1, 28, -6.12965);
  cpl_image_set(column->data, 1, 29, -4.174939);   /* this is the critical peak */
  cpl_image_set(column->data, 1, 30, -4.105794);   /* this is the critical peak */
  cpl_image_set(column->data, 1, 31, -5.082292);
  cpl_image_set(column->data, 1, 32, -8.070259);
  cpl_image_set(column->data, 1, 33, -7.053874);
  cpl_image_set(column->data, 1, 34, -6.481008);
  cpl_image_set(column->data, 1, 35, -5.327928);
  cpl_image_set(column->data, 1, 36, -5.742697);
  cpl_image_set(column->data, 1, 37, -4.856237);
  cpl_image_set(column->data, 1, 38, -3.869008);
  cpl_image_set(column->data, 1, 39, -5.214671);
  cpl_image_set(column->data, 1, 40, -6.591152);
  cpl_image_set(column->data, 1, 41, -6.716819);
  cpl_image_set(column->data, 1, 42, -4.854933);
  cpl_image_set(column->data, 1, 43, -4.74163);
  cpl_image_set(column->data, 1, 44, -6.210804);
  cpl_image_set(column->data, 1, 45, -5.822922);
  cpl_image_set(column->data, 1, 46, -5.862777);
  cpl_image_set(column->data, 1, 47, -5.399067);
  cpl_image_set(column->data, 1, 48, -4.147552);
  cpl_image_set(column->data, 1, 49, -4.751756);
  cpl_image_set(column->data, 1, 50, -5.090693);
  cpl_image_set(column->data, 1, 51, -5.830265);
  cpl_image_set(column->data, 1, 52, -5.181813);
  cpl_image_set(column->stat, 1, 1, 0.2623871); /* also fill the variance */
  cpl_image_set(column->stat, 1, 2, 0.2755064);
  cpl_image_set(column->stat, 1, 3, 0.3115847);
  cpl_image_set(column->stat, 1, 4, 0.2623871);
  cpl_image_set(column->stat, 1, 5, 0.2755064);
  cpl_image_set(column->stat, 1, 6, 0.2623871);
  cpl_image_set(column->stat, 1, 7, 0.3115847);
  cpl_image_set(column->stat, 1, 8, 0.3279838);
  cpl_image_set(column->stat, 1, 9, 0.2623871);
  cpl_image_set(column->stat, 1, 10, 0.3128215);
  cpl_image_set(column->stat, 1, 11, 0.2623871);
  cpl_image_set(column->stat, 1, 12, 0.2755064);
  cpl_image_set(column->stat, 1, 13, 0.3279838);
  cpl_image_set(column->stat, 1, 14, 0.3824989);
  cpl_image_set(column->stat, 1, 15, 0.2623871);
  cpl_image_set(column->stat, 1, 16, 0.2951854);
  cpl_image_set(column->stat, 1, 17, 0.2623871);
  cpl_image_set(column->stat, 1, 18, 0.2623871);
  cpl_image_set(column->stat, 1, 19, 0.2623871);
  cpl_image_set(column->stat, 1, 20, 0.3214268);
  cpl_image_set(column->stat, 1, 21, 0.2886258);
  cpl_image_set(column->stat, 1, 22, 0.2951854);
  cpl_image_set(column->stat, 1, 23, 0.3374177);
  cpl_image_set(column->stat, 1, 24, 0.3115847);
  cpl_image_set(column->stat, 1, 25, 0.2951854);
  cpl_image_set(column->stat, 1, 26, 0.2768476);
  cpl_image_set(column->stat, 1, 27, 0.3046242);
  cpl_image_set(column->stat, 1, 28, 0.2623871);
  cpl_image_set(column->stat, 1, 29, 0.3279838);
  cpl_image_set(column->stat, 1, 30, 0.2623871);
  cpl_image_set(column->stat, 1, 31, 0.3083048);
  cpl_image_set(column->stat, 1, 32, 0.2951854);
  cpl_image_set(column->stat, 1, 33, 0.2623871);
  cpl_image_set(column->stat, 1, 34, 0.2951854);
  cpl_image_set(column->stat, 1, 35, 0.2990736);
  cpl_image_set(column->stat, 1, 36, 0.2755064);
  cpl_image_set(column->stat, 1, 37, 0.2755064);
  cpl_image_set(column->stat, 1, 38, 0.3292923);
  cpl_image_set(column->stat, 1, 39, 0.2623871);
  cpl_image_set(column->stat, 1, 40, 0.2623871);
  cpl_image_set(column->stat, 1, 41, 0.2951854);
  cpl_image_set(column->stat, 1, 42, 0.2623871);
  cpl_image_set(column->stat, 1, 43, 0.3209687);
  cpl_image_set(column->stat, 1, 44, 0.2623871);
  cpl_image_set(column->stat, 1, 45, 0.2951854);
  cpl_image_set(column->stat, 1, 46, 0.2755064);
  cpl_image_set(column->stat, 1, 47, 0.2623871);
  cpl_image_set(column->stat, 1, 48, 0.3291436);
  cpl_image_set(column->stat, 1, 49, 0.2734365);
  cpl_image_set(column->stat, 1, 50, 0.2623871);
  cpl_image_set(column->stat, 1, 51, 0.2623871);
  cpl_image_set(column->stat, 1, 52, 0.2755064);
  /* now do the test call */
  cpl_errorstate state = cpl_errorstate_get();
  cpl_table *detlines = muse_wave_lines_search(column, 1.0, 17, 21);
  cpl_test(cpl_errorstate_is_equal(state));
  cpl_test_nonnull(detlines);
  cpl_table_delete(detlines);
  muse_image_delete(column);

  return cpl_test_end(0);
}
