/* -*- 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-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_musecubeconcatenate      Tool muse_cube_concatenate
 *
 * <b>muse_cube_concatenate</b>: Concatenate multiple fully reduced MUSE cubes.
 *
 * Concatenate cubes that were resampled onto the same output grid but using
 * different, adjacent wavelength ranges into a single output cube.
 *
 * <b>Command line arguments:</b>
 *   - <tt><b>CUBE_OUT</b></tt>\n
 *     the filename of output cube
 *   - <tt><b>CUBE_IN_1</b></tt>\n
 *     the filename of the 1st input cube to use for concatenation
 *   - <tt><b>CUBE_IN_2</b></tt>\n
 *     the filename of the 2nd input cube to use for concatenation
 *   - <tt>CUBE_IN_3 ...</tt> (optional)\n
 *     the filename(s) of the 3rd and following inputs cubes to use for
 *     concatenation; the number of total cubes is not limited, but at least
 *     two input cubes need to be given for this tool to make sense
 *
 * <b>Return values:</b>
 *   - <tt> 0</tt>\n   Success
 *   - <tt> 1</tt>\n   less than three filenames given
 *   - <tt> 9</tt>\n   unknown option given
 *   - <tt>10</tt>\n   no output cube name found
 *   - <tt>11</tt>\n   cube with given output filename already exists
 *   - <tt>12</tt>\n   less than 2 valid cubes found in input
 *   - <tt>20</tt>\n   error when saving the output cube
 *   - <tt>50</tt>\n   unknown error
 */
/*----------------------------------------------------------------------------*/

/**@{*/

#define PRINT_USAGE(rc)                                                        \
  fprintf(stderr, "Usage: %s CUBE_OUT CUBE_IN_1 CUBE_IN_2 [ CUBE_IN_3 ... ]\n",\
          argv[0]);                                                            \
  cpl_end(); return (rc);

int main(int argc, char **argv)
{
  const char *idstring = "muse_cube_concatenate";
  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();

  if (argc < 4) {
    /* three filenames are needed at least */
    PRINT_USAGE(1);
  }

  char *oname = NULL; /* output cube */
  /* argument processing */
  int i;
  for (i = 1; i < argc; i++) {
    if (strncmp(argv[i], "-", 1) == 0) { /* unallowed options */
      PRINT_USAGE(9);
    } else {
      if (oname) {
        break; /* we have the required name, skip the rest */
      }
      oname = argv[i];
    }
  } /* for i (all arguments) */
  if (!oname) {
    PRINT_USAGE(10);
  }
  FILE *fp = fopen(oname, "r");
  if (fp) {
    cpl_msg_error(idstring, "Output cube \"%s\" is already present!", oname);
    cpl_msg_error(idstring, "Please specify another output name or rename the "
                  "existing file with this name.");
    fclose(fp);
    PRINT_USAGE(11);
  }

  int ncubes = argc - i;
  cpl_msg_info(idstring, "Will write concatenation of %d cubes to \"%s\".",
               ncubes, oname);

  cpl_errorstate state = cpl_errorstate_get();

  /* now start the processing by loading the first cube *
   * and then appending the other one(s) in turn        */
  cpl_msg_info(idstring, "Loading cube 1 from \"%s\"", argv[2]);
  muse_datacube *cube1 = muse_datacube_load(argv[2]);
  int icube = 3; /* index of cube in the argv[] array */
  for (icube = 3; icube < ncubes + 2; icube++) {
    cpl_msg_info(idstring, "Loading cube %d from \"%s\"", icube - 1, argv[icube]);
    muse_datacube *cube2 = muse_datacube_load(argv[icube]);
    if (!cube2) {
      cpl_msg_warning(idstring, "Could not load MUSE cube from \"%s\": %s",
                      argv[icube], cpl_error_get_message());
      continue;
    }
    cpl_error_code rc = muse_datacube_concat(cube1, cube2);
    if (rc != CPL_ERROR_NONE) {
      cpl_msg_warning(idstring, "Error while concatenating \"%s\": %s",
                      argv[icube], cpl_error_get_message());
    }
    muse_datacube_delete(cube2);
  } /* for icube */

  int rc = 0;
  if (!cpl_errorstate_is_equal(state)) {
    cpl_msg_error(idstring, "Some errors occurred while concatenating the "
                  "cubes (not saving an output cube):");
    cpl_errorstate_dump(state, CPL_FALSE, muse_cplerrorstate_dump_some);
    rc = 50;
  } else {
    cpl_msg_info(idstring, "Saving concatenated cube as \"%s\".", oname);
    muse_datacube_save(cube1, oname);
    cpl_msg_info(idstring, "...done");
  }
  muse_datacube_delete(cube1);

  cpl_memory_dump(); /* only active when CPL_MEMORY_MODE != 0 */
  cpl_end();
  return rc;
}

/**@}*/
