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

/*----------------------------------------------------------------------------*/
/**
 * @defgroup tools_museproductsign          Tool muse_product_sign
 *
 * <b>muse_product_sign</b>: Sign a product, i.e. update checksum headers.
 *
 * This simply calls the CPL function cpl_dfs_sign_products() for a given file.
 *
 * To not touch the PIPELINE keyword in the header, the input filename should
 * correspond to the one given in that entry.
 *
 * <b>Command line arguments:</b>
 *   - <tt>-s</tt> (optional, only when compiled with MUSE_EXPERT=1)\n
 *     sign a MUSE static calibration
 *   - <tt><b>FILENAME</b></tt>\n
 *     the filename of the MUSE pipeline product
 *   - <tt><b>TAG</b></tt>\n
 *     the tag of the MUSE pipeline product
 *
 * <b>Return values:</b>
 *   - <tt> 0</tt>\n   Success
 *   - <tt> 1</tt>\n   no input filename or tag given
 *   - <tt> 9</tt>\n   unknown option given
 *   - <tt>50</tt>\n   unknown error
 */
/*----------------------------------------------------------------------------*/

/**@{*/

#ifdef MUSE_EXPERT /* extra -s and -C flag for the maintainer! */
  #define PRINT_USAGE(rc)                                                      \
    fprintf(stderr, "Usage: %s [ -s ] [ -C ] FILENAME TAG\n", argv[0]);        \
    cpl_end(); return (rc);
#else /* normal compilation, when not maintainer */
  #define PRINT_USAGE(rc)                                                      \
    fprintf(stderr, "Usage: %s FILENAME TAG\n", argv[0]);                      \
     cpl_end(); return (rc);
#endif

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

  if (argc <= 2) {
    /* filename and tag are needed */
    PRINT_USAGE(1);
  }

  /* argument processing */
  char *iname = NULL, /* filename */
       *tag = NULL; /* tag */
  cpl_boolean statcal = CPL_FALSE;
  cpl_boolean checksum = CPL_FALSE;
  int i;
  for (i = 1; i < argc; i++) {
#ifdef MUSE_EXPERT /* extra -s and -C  flag for the maintainer! */
    if (strncmp(argv[i], "-s", 3) == 0) {
      statcal = CPL_TRUE;
    } else if (strncmp(argv[i], "-C", 3) == 0) {
      checksum = CPL_TRUE;
    } else /* if follows below*/
#endif
    if (strncmp(argv[i], "-", 1) == 0) { /* unallowed options */
      PRINT_USAGE(9);
    } else {
      if (iname && tag) {
        break; /* we have the required name, skip the rest */
      }
      if (!iname) {
        iname = argv[i]; /* set the filename */
      } else {
        tag = argv[i]; /* set the tag */
      }
    }
  } /* for i (all arguments) */

  cpl_errorstate state = cpl_errorstate_get();

  cpl_frameset *fset = cpl_frameset_new();
  cpl_frame *frame = cpl_frame_new();
  cpl_frame_set_filename(frame, iname);
  cpl_frame_set_tag(frame, tag);
  cpl_frame_set_type(frame, CPL_FRAME_TYPE_TABLE);
  cpl_frame_set_group(frame, CPL_FRAME_GROUP_PRODUCT);
  cpl_frame_set_level(frame, CPL_FRAME_LEVEL_FINAL);
  printf("Working on \"%s\" (tag %s).\n", iname, tag);
#if 0
  printf("frame!\n");
  cpl_frame_dump(frame, stdout);
  fflush(stdout);
#endif
  cpl_frameset_insert(fset, frame);
#if 0
  printf("fset unsigned!\n");
  cpl_frameset_dump(fset, stdout);
  fflush(stdout);
#endif
  unsigned int flags = CPL_DFS_SIGNATURE_DATAMD5;
  if (!statcal || checksum) {
    flags |= CPL_DFS_SIGNATURE_CHECKSUM;
  }
  cpl_dfs_sign_products(fset, flags);
#if 0
  printf("fset signed!\n");
  cpl_frameset_dump(fset, stdout);
  fflush(stdout);
#endif
  cpl_frameset_delete(fset);

#ifdef MUSE_EXPERT /* special compilation for the maintainer! */
  #include <fitsio.h>
  /* special handling for static calibrations, since these cannot contain *
   * PIPEFILE keywords which the CPL function above adds unconditionally; *
   * since there is no way in CPL to rewrite the header with the correct  *
   * CHECKSUM keyword but without changing the DATE, do it with CFITSIO   *
   * directly                                                             */
  if (statcal) {
    printf("Handling \"%s\" as STATIC calibration!\n", iname);
    int status;
    fitsfile *fptr;
    fits_open_file(&fptr, iname, READWRITE, &status);
    if (status) {
      fits_report_error(stderr, status);
    }
    /* primary HDU, no need to call fits_movabs_hdu() */
    fits_delete_key(fptr, "PIPEFILE", &status);
    if (status) {
      fits_report_error(stderr, status);
    }
    /* add/overwrite key ESO.OBS.NAME */
    fits_update_key_str(fptr, "HIERARCH ESO OBS NAME", "STATIC",
                        "Static calibration for the MUSE pipeline.", &status);
    // really insert at position before PRO.CATG, i.e. using
    //   fits_insert_record(unit,key_no,card, &status);
    // but this needs the position of PRO.CATG first
    if (status) {
      fits_report_error(stderr, status);
    }
    /* now finally recompute the CHECKSUM */
    fits_write_chksum(fptr, &status);
    if (status) {
      fits_report_error(stderr, status);
    }
    fits_close_file(fptr, &status);
    if (status) {
      fits_report_error(stderr, status);
    }
  } /* if static calibration */
#endif /* end of maintainer-only section */

  int rc = 0;
  if (!cpl_errorstate_is_equal(state)) {
    cpl_errorstate_dump(state, CPL_FALSE, muse_cplerrorstate_dump_some);
    rc = 50;
  }
#if 0
  cpl_memory_dump();
#endif
  cpl_end();
  return rc;
}

/**@}*/
