/* -*- 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) 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>
#include <string.h>

/*----------------------------------------------------------------------------*/
/**
 * @defgroup tools_museoffsetlist           Tool muse_offset_list_create
 *
 * @brief <b>muse_offset_list_create</b>: Create (empty) OFFSET_LIST file.
 *
 * Create a table in the format of an OFFSET_LIST, optionally filling in
 * DATE-OBS and MJD-OBS from a list of files, either given as .sof file (where
 * all pixel tables are used), or given directly on the command line.
 *
 * This program sets the offset and flux scaling columns to NAN.
 *
 * <b>Command line arguments:</b>
 *   - <tt>-f</tt> (optional)\n
 *     Force overwriting of existing file.
 *   - <tt>-s SOFFILE</tt> (optional)\n
 *     <tt>.sof</tt> file to load filenames from; only the files tagged
 *     PIXTABLE_* are used here
 *   - <tt><b>OFFSET_LIST</b></tt>\n
 *     the mandatory output filename of the new OFFSET_LIST
 *   - <tt><b>OFFSET_LIST</b></tt>\n
 *     the mandatory output filename of the new OFFSET_LIST
 *   - <tt>FILE(S)</tt>\n
 *     the filename(s) of the MUSE exposures to use to fill the data columns
 *
 * <b>Return values:</b>
 *   - <tt> 0</tt>\n   Success
 *   - <tt> 1</tt>\n   less than one filename given
 *   - <tt> 2</tt>\n   argument <tt>-s</tt> without any filename
 *   - <tt> 3</tt>\n   filename given with argument <tt>-s</tt> cannot be opened
 *   - <tt> 9</tt>\n   unknown option given
 *   - <tt>10</tt>\n   OFFSET_LIST output filename not given
 *   - <tt>11</tt>\n   could not create output file with given name
 *   - <tt>12</tt>\n   could not create output file with given name
 *   - <tt>50</tt>\n   unknown error
 */
/*----------------------------------------------------------------------------*/

/**@{*/

#define PRINT_USAGE(rc)                                                        \
  fprintf(stderr, "Usage: %s [ -f ] [ -s SOFFILE ] OFFSET_LIST "               \
          "[ FILE [ FILE [ ... ] ] ] \n", argv[0]);                            \
  cpl_end(); return (rc);

int main(int argc, char **argv)
{
  const char *idstring = "muse_offset_list_create";
  cpl_init(CPL_INIT_DEFAULT);
  cpl_msg_set_time_on();
  muse_processing_recipeinfo(NULL);
  cpl_msg_set_level(CPL_MSG_DEBUG);
  cpl_msg_set_component_on();
  cpl_errorstate state = cpl_errorstate_get();

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

  char *oname = NULL; /* output filename */
  cpl_array *files = NULL, /* file names */
            *soffiles = NULL; /* file names from .sof */
  cpl_boolean overwrite = CPL_FALSE;
  int i;

  /* argument processing */
  for (i = 1; i < argc; i++) {
    if (strncmp(argv[i], "-s", 3) == 0) {
      /* skip to next arg to name of the .sof file */
      i++;
      if (i < argc) {
        FILE *fp = fopen(argv[i], "r");
        if (!fp) {
          PRINT_USAGE(3);
        }
        if (!soffiles) {
          soffiles = cpl_array_new(0, CPL_TYPE_STRING);
        }
        char fn[4096],
             tag[50];
        while (fscanf(fp, "%4095s %49s", fn, tag) != EOF) {
          if (!strncmp(tag, "PIXTABLE_", 9)) {
#if 0 /* DEBUG */
            cpl_msg_debug(idstring, "IS a pixel table: \"%s\" is %s", fn, tag);
#endif
            /* seems to be a pixel table, use this filename */
            cpl_array_set_size(soffiles, cpl_array_get_size(soffiles) + 1);
            /* set the name for this one input file */
            cpl_array_set_string(soffiles, cpl_array_get_size(soffiles) - 1, fn);
          } else {
#if 0 /* DEBUG */
            cpl_msg_debug(idstring, "not a pixel table: \"%s\" is %s", fn, tag);
#endif
          }
        } /* while */
        fclose(fp);
      } else {
        PRINT_USAGE(2);
      }
    } else if (strncmp(argv[i], "-f", 3) == 0) {
      overwrite = CPL_TRUE;
    } else if (strncmp(argv[i], "-", 1) == 0) { /* unallowed options */
      PRINT_USAGE(9);
    } else {
      if (!oname) {
        oname = argv[i];
      } else if (!files) {
        files = cpl_array_new(1, CPL_TYPE_STRING);
        /* set the name for this one input file */
        cpl_array_set_string(files, 0, argv[i]);
      } else {
        cpl_array_set_size(files, cpl_array_get_size(files) + 1);
        /* set the name for this one input file */
        cpl_array_set_string(files, cpl_array_get_size(files) - 1, argv[i]);
      }
    }
  } /* for i (all arguments) */

#if 0 /* DEBUG */
  printf("files:\n");
  cpl_array_dump(files, 0, cpl_array_get_size(files), stdout);
  printf("from .sof:\n");
  cpl_array_dump(soffiles, 0, cpl_array_get_size(soffiles), stdout);
  fflush(stdout);
#endif

  /* merge both lists of filenames, if necessary */
  if (!files) {
    files = soffiles;
  } else {
    if (cpl_array_get_size(soffiles) > 0) {
      cpl_array_insert(files, soffiles, cpl_array_get_size(files));
    }
    cpl_array_delete(soffiles);
    soffiles = NULL;
  }

  /* check that there _is_ and output filename and ensure its *
   * non-existance (unless we force overwriting it)           */
  if (!oname) {
    cpl_array_delete(files);
    PRINT_USAGE(10);
  }
  if (!access(oname, F_OK) && !overwrite) {
    cpl_array_delete(files);
    PRINT_USAGE(11);
  }

  /* create primary header and the table */
  cpl_propertylist *pheader = cpl_propertylist_new();
  cpl_propertylist_append_string(pheader, "INSTRUME", "MUSE");
  cpl_propertylist_append_string(pheader, "ESO PRO CATG", MUSE_TAG_OFFSET_LIST);
  cpl_table *olist = NULL;
  int nfiles = 0;
  if (!files) {
    cpl_msg_debug(idstring, "No MUSE exposures given on input, creating empty "
                  "table with 10 rows");
    olist = muse_cpltable_new(muse_offset_list_def, 10);
    cpl_propertylist_append_string(pheader, "FILES", "no files given");
  } else {
    nfiles = cpl_array_get_size(files);
    cpl_msg_debug(idstring, "%d MUSE exposures given on input, creating table "
                  "for these", nfiles);
    olist = muse_cpltable_new(muse_offset_list_def, nfiles);
  }

#if 0
  /* this doesn't work, because we cannot easily construct a cpl_recipe *
   * that is valid enough for muse_processing_new() to work             */
  cpl_recipe *recipe = NULL;
  muse_processing *proc = muse_processing_new("muse_offset_list_create", recipe);
  muse_processing_sort_exposures(proc);
  muse_processing_delete(proc);
#endif

  /* fill the DATE-OBS and MJD-OBS columns in the table */
  for (i = 0; i < nfiles; i++) {
    const char *fn = cpl_array_get_string(files, i);
    cpl_propertylist *header = cpl_propertylist_load(fn, 0);
    if (!header) {
      cpl_msg_warning(idstring, "Could not load primary header from \"%s\"!",
                      fn);
      continue;
    }
    cpl_table_set_string(olist, MUSE_OFFSETS_DATEOBS, i,
                         muse_pfits_get_dateobs(header));
    cpl_table_set_double(olist, MUSE_OFFSETS_MJDOBS, i,
                         muse_pfits_get_mjdobs(header));
    cpl_propertylist_delete(header);
    char *kw = cpl_sprintf("FILE%d", i+1),
         *p = strrchr(fn, '/');
    if (p) {
      p++;
    } else {
      p = (char *)fn;
    }
    cpl_propertylist_append_string(pheader, kw, p);
    cpl_free(kw);
  } /* for i (all files) */

  /* save the table and clean up */
  cpl_error_code rc = cpl_table_save(olist, pheader, NULL, oname, CPL_IO_CREATE);
  cpl_array_delete(files);
  cpl_table_delete(olist);
  cpl_propertylist_delete(pheader);
  switch (rc) {
  case CPL_ERROR_NONE:
    rc = 0;
    cpl_msg_info(idstring, "Saved %s as \"%s\"", MUSE_TAG_OFFSET_LIST, oname);
    break;
  case CPL_ERROR_FILE_NOT_CREATED:
    cpl_msg_error(idstring, "Could not create output file \"%s\"", oname);
    rc = 12;
    break;
  default:
    rc = 50;
    cpl_msg_error(idstring, "An unknown error occurred: %s",
                  cpl_error_get_message());
  } /* switch */

  if (!cpl_errorstate_is_equal(state)) {
    cpl_errorstate_dump(state, CPL_FALSE, muse_cplerrorstate_dump_some);
  }
  cpl_memory_dump();
  cpl_end();
  return rc;
}

/**@}*/
