/* -*- 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) 2005-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.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

/*---------------------------------------------------------------------------*
 *                             Includes                                      *
 *---------------------------------------------------------------------------*/
#include <string.h>

#include <muse.h>
#include "muse_exp_combine_z.h"

/*---------------------------------------------------------------------------*
 *                             Functions code                                *
 *---------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------*/
/**
  @brief    Combine several exposures
  @param    aProcessing  the processing structure
  @param    aParams      the parameters list
  @return   0 if everything is ok, -1 something went wrong

  @see muse_scipost_compute()
 */
/*----------------------------------------------------------------------------*/
int
muse_exp_combine_compute(muse_processing *aProcessing,
                         muse_exp_combine_params_t *aParams)
{
  /* sort input pixel tables into different exposures */
  cpl_table *exposures = muse_processing_sort_exposures(aProcessing);
  int nexposures = cpl_table_get_nrow(exposures);
  if (nexposures < 2) {
    cpl_msg_error(__func__, "This recipe only makes sense with multiple "
                  "exposures!");
    cpl_table_delete(exposures);
    return -1;
  }
  const char *savevalid = "cube,combined";
  if (!muse_postproc_check_save_param(aParams->save, savevalid)) {
    return -1;
  }
  /* load the optional offsets table */
  cpl_table *offsets = muse_processing_load_ctable(aProcessing, MUSE_TAG_OFFSET_LIST, 0);
  if (offsets && muse_cpltable_check(offsets, muse_offset_list_def) != CPL_ERROR_NONE) {
    cpl_msg_warning(__func__, "Input %s has unexpected format, proceeding "
                    "without offset and flux scales!", MUSE_TAG_OFFSET_LIST);
    cpl_table_delete(offsets);
    offsets = NULL;
  } /* if offsets have wrong format */

  /* now process all the pixel tables, do it separately for each exposure */
  /* allocate one additional element for NULL termination */
  muse_pixtable **pixtables = cpl_calloc(nexposures + 1, sizeof(muse_pixtable *));
  int i;
  for (i = 0; i < nexposures; i++) {
    cpl_table *thisexp = cpl_table_extract(exposures, i, 1);
    pixtables[i] = muse_pixtable_load_merge_channels(thisexp,
                                                     aParams->lambdamin,
                                                     aParams->lambdamax);
    cpl_table_delete(thisexp);
    if (pixtables[i]) {
      /* erase pre-existing QC parameters */
      cpl_propertylist_erase_regexp(pixtables[i]->header, "ESO QC ", 0);
    } /* if */
  } /* for i (exposures) */
  cpl_table_delete(exposures);

  do { /* loop to break out of in case of error */
    /* now combine the exposures */
    muse_xcombine_types weight = muse_postproc_get_weight_type(aParams->weight_s);
    cpl_error_code rc = muse_xcombine_weights(pixtables, weight);
    if (rc != CPL_ERROR_NONE) {
      cpl_msg_error(__func__, "weighting the pixel tables didn't work: %s",
                    cpl_error_get_message());
      break;
    }
    /* combine individual pixel tables and delete them */
    muse_pixtable *bigpixtable = muse_xcombine_tables(pixtables, offsets);
    if (!bigpixtable) {
      cpl_msg_error(__func__, "combining the pixel tables didn't work: %s",
                    cpl_error_get_message());
      break;
    }
    cpl_free(pixtables);

    if (strstr(aParams->save, "cube")) {
      muse_resampling_type resample
        = muse_postproc_get_resampling_type(aParams->resample_s);
      muse_resampling_params *rp = muse_resampling_params_new(resample);
      rp->dx = aParams->dx;
      rp->dy = aParams->dy;
      rp->dlambda = aParams->dlambda;
      rp->crtype = muse_postproc_get_cr_type(aParams->crtype_s);
      rp->crsigma = aParams->crsigma;
      rp->ld = aParams->ld;
      rp->rc = aParams->rc;
      muse_resampling_params_set_pixfrac(rp, aParams->pixfrac);
      cpl_propertylist *outwcs = muse_postproc_cube_load_output_wcs(aProcessing);
      muse_resampling_params_set_wcs(rp, outwcs);
      cpl_propertylist_delete(outwcs);
      muse_cube_type format = muse_postproc_get_cube_format(aParams->format_s);
      rc = muse_postproc_cube_resample_and_collapse(aProcessing, bigpixtable,
                                                    format, rp, aParams->filter);
      muse_resampling_params_delete(rp);
    } /* if save contains cube */
    if (strstr(aParams->save, "combined")) {
      muse_processing_save_table(aProcessing, -1, bigpixtable, NULL,
                                 MUSE_TAG_PIXTABLE_COMBINED,
                                 MUSE_TABLE_TYPE_PIXTABLE);
    }
    muse_pixtable_delete(bigpixtable);
    cpl_table_delete(offsets);
    return rc == CPL_ERROR_NONE ? 0 : -1;
  } while (0); /* end of "error-free" loop, error handling follows */
  for (i = 0; i < nexposures; i++) {
    muse_pixtable_delete(pixtables[i]);
  } /* for i (exposures) */
  cpl_free(pixtables);
  cpl_table_delete(offsets);
  return -1;
} /* muse_exp_combine_compute() */
