/* -*- 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-2014 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>
#include <strings.h>

/*----------------------------------------------------------------------------*/
/**
 * @defgroup tools_muselsffwhm              Tool muse_lsf_fwhm
 *
 * <b>muse_lsf_fwhm</b>: Determine FWHM of a line from given LSF.
 *
 * This small program takes an LSF_PROFILE, constructs spectra of an emission
 * line at different wavelengths using muse_lsf_spectrum_get_lines(). To compute
 * the FWHM it searches the maximum position in this spectrum, then searches the
 * half-maximum on each side. The FWHM is then difference in positions within
 * the spectrum divided by the spectral sampling.
 *
 * This is mainly for AIT and PAE.
 *
 * <b>Command line arguments:</b>
 *   - <tt>-v</tt> (optional)\n
 *     be verbose, output detailed parameters for each wavelength and slice,
 *     mainly for debugging
 *   - <tt>-c IFUNUM</tt> (needed in case of multi-IFU files)\n
 *     the IFU number to read, i.e. a number between 1 and 24
 *   - <tt>-l LAMBDA</tt> (optional)
 *     the wavelength at which to evaluate the LSF
 *   - <tt><b>LSF_PROFILE</b></tt>\n
 *     the filename of the LSF profile to use
 *
 * <b>Return values:</b>
 *   - <tt> 0</tt>\n   Success
 *   - <tt> 1</tt>\n   no filename given
 *   - <tt> 2</tt>\n   -c without number
 *   - <tt> 3</tt>\n   -l without number
 *   - <tt> 9</tt>\n   unknown option given
 *   - <tt>10</tt>\n   profile could not be loaded from file
 *   - <tt>50</tt>\n   unknown error
 */
/*----------------------------------------------------------------------------*/

/**@{*/

#define PRINT_USAGE(rc)                                                        \
  fprintf(stderr, "Usage: %s [ -v ] [ -c IFUNUM ] [ -l LAMBDA ] LSF_PROFILE\n",\
          argv[0]);                                                            \
  cpl_end(); return (rc);

int main(int argc, char **argv)
{
  cpl_init(CPL_INIT_DEFAULT);

  if (argc <= 1) {
    /* filename is needed at least */
    PRINT_USAGE(1);
  }

  cpl_boolean verbose = CPL_FALSE;
  char *iname = NULL; /* table name */
  unsigned char nifu = 0;
  double lambda = -1.;

  /* argument processing */
  int i;
  for (i = 1; i < argc; i++) {
    if (strncmp(argv[i], "-v", 3) == 0) { /* verbose */
      verbose = CPL_TRUE;
    } else if (strncmp(argv[i], "-c", 3) == 0) { /* channel */
      /* skip to next arg to last slice number */
      i++;
      if (i < argc) {
        nifu = atoi(argv[i]);
      } else {
        PRINT_USAGE(2);
      }
    } else if (strncmp(argv[i], "-l", 3) == 0) { /* channel */
      /* skip to next arg to last slice number */
      i++;
      if (i < argc) {
        lambda = atof(argv[i]);
      } else {
        PRINT_USAGE(3);
      }
    } else if (strncmp(argv[i], "-", 1) == 0) { /* unallowed options */
      PRINT_USAGE(9);
    } else {
      if (iname) {
        break; /* we have the possible names, skip the rest */
      }
      iname = argv[i] /* set the name for the table */;
    }
  } /* for i (all arguments) */

  muse_lsf_params **detpars = muse_lsf_params_load(iname, NULL, nifu);
  if (!detpars) {
    PRINT_USAGE(10);
  }

#define SPEC_LENGTH 1000 /* [pix] */
#define SPEC_SAMPLING 0.01 /* [Angstrom] */
#define LINE_FLUX 10000 /* [counts] */
  /* output a kind of header */
  printf("# FWHM computed from LSF profile function for several wavelengths "
         "as mean +/- stdev median\n""# conversion to value in pixels and "
         "spectral resolution R using %.3f Angstrom/pix\n",
         kMuseSpectralSamplingA);
  if (verbose) {
    printf("%soutput of detailed parameters and results for each slice; "
           "columns:\n%slambda: ifu.slice\tref_lambda slitwidth binwidth\t  "
           "specmean  +/- specstdev   (specmedian)    specmin..specmax   "
           "(maxidx)\tleftvalue  (lidx)  rightvalue  (ridx) ==> FWHM\n",
           verbose ? "# " : "", verbose ? "# " : "");
  }
  /* line wavelengths for which we want the LSF width */
  double lpos[] = { 4650., 5000., 6000., 7000., 8000., 9000., 9300., -1. };
  if (lambda > 0) { /* replace with input wavelength */
    lpos[0] = lambda;
    lpos[1] = -1.;
  }
  int ilpos = -1;
  while (lpos[++ilpos] > 0) {
    cpl_vector *vfwhm = cpl_vector_new(50); /* result for this wavelength */
    int ifwhm = 0;
    for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
      int nslice;
      for (nslice = 1; nslice <= kMuseSlicesPerCCD; nslice++) {
        muse_lsf_params *dp = muse_lsf_params_get(detpars, nifu, nslice);
        if (!dp) {
          continue;
        }
        cpl_errorstate es = cpl_errorstate_get();
        double fwhm = muse_lsf_fwhm_lambda(dp, lpos[ilpos], LINE_FLUX,
                                           SPEC_SAMPLING, SPEC_LENGTH,
                                           verbose ? stdout : NULL);
        if (!cpl_errorstate_is_equal(es)) {
          continue;
        }
        cpl_vector_set(vfwhm, ifwhm++, fwhm);
        fflush(stdout);
      } /* for nslice */
    } /* for nifu */
    cpl_vector_set_size(vfwhm, ifwhm);
    double mean = cpl_vector_get_mean(vfwhm),
           stdev = cpl_vector_get_stdev(vfwhm),
           median = cpl_vector_get_median(vfwhm);
    printf("%sFWHM at %.3f Angstrom is %.3f +/- %.3f %.2f [Angstrom], ~%.3f "
           "[pix], R is %.1f\n", verbose ? "# " : "", lpos[ilpos], mean, stdev,
           median, mean / kMuseSpectralSamplingA, lpos[ilpos] / mean);
    cpl_vector_delete(vfwhm);
  } /* while lpos > 0 */
  muse_lsf_params_delete(detpars);

  cpl_end();
  return 0;
}

/**@}*/
