/* -*- 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>

/*----------------------------------------------------------------------------*/
/**
 * @defgroup tools_musepixtablecrop         Tool muse_pixtable_crop
 *
 * <b>muse_pixtable_crop</b>: Crop a MUSE pixel table in one or more dimensions.
 *
 * This restricts (crops) the contents of a MUSE pixel table depending on the
 * coordinates it contains, so that it afterwards only contains pixels within
 * the given range of coordinates.
 *
 * <b>Command line arguments:</b>
 *   - <tt>-x1 xpos1</tt> (optional, default is no lower boundary)\n
 *     start x coordinate in "native" coordinates
 *   - <tt>-x2 xpos2</tt> (optional, default is no upper boundary)\n
 *     end x coordinate in "native" coordinates
 *   - <tt>-y1 ypos1</tt> (optional, default is no lower boundary)\n
 *     start y coordinate in "native" coordinates
 *   - <tt>-y2 ypos2</tt> (optional, default is no upper boundary)\n
 *     end y coordinate in "native" coordinates
 *   - <tt>-l1 lambda1</tt> (optional, default is no lower boundary)\n
 *     start wavelength in Angstrom
 *   - <tt>-l2 lambda2</tt> (optional, default is no upper boundary)\n
 *     end wavelength in Angstrom
 *   - <tt>-i ifu</tt> (optional, default is no IFU-selection)\n
 *     IFU number to select
 *   - <tt>-s slice</tt> (optional, default is no slice-selection)\n
 *     slice number to select
 *   - <tt><b>PIXTABLE_IN</b></tt>\n
 *     the filename of the pixel table to crop
 *   - <tt><b>PIXTABLE_OUT</b></tt>\n
 *     the filename of the output pixel table to write; can be the same as
 *     PIXTABLE_IN which causes the input table to be overwritten
 *
 * <b>Return values:</b>
 *   - <tt> 0</tt>\n   Success
 *   - <tt> 1</tt>\n   no input or output filename given
 *   - <tt> 2</tt>\n   argument <tt>-x1</tt> or <tt>-x2</tt> without any number
 *   - <tt> 3</tt>\n   argument <tt>-y1</tt> or <tt>-y2</tt> without any number
 *   - <tt> 4</tt>\n   argument <tt>-l1</tt> or <tt>-l2</tt> without any number
 *   - <tt> 5</tt>\n   argument <tt>-i</tt> without any number
 *   - <tt> 6</tt>\n   argument <tt>-s</tt> without any number
 *   - <tt> 9</tt>\n   unknown option given
 *   - <tt>10</tt>\n   pixel table could not be loaded from file
 *   - <tt>11</tt>\n   File does not seem to contain a MUSE pixel table
 *   - <tt>50</tt>\n   unknown error
 */
/*----------------------------------------------------------------------------*/

/**@{*/

#define PRINT_USAGE(rc)                                                        \
  fprintf(stderr, "Usage: %s [ -l1 lambda1 ] [ -l2 lambda2 ] [ -x1 xpos1 ] "   \
          "[ -x2 xpos2 ] [ -y1 ypos1 ] [ -y2 ypos2 ] [ -i IFU ] [ -s slice ] " \
          "PIXTABLE_IN PIXTABLE_OUT\n", argv[0]);                              \
  cpl_end(); return (rc);

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

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

  char *tiname = NULL, /* input table */
       *toname = NULL; /* output table */
  /* default to low and high values that mean to not crop anything */
  double x1 = -FLT_MAX, x2 = FLT_MAX,
         y1 = -FLT_MAX, y2 = FLT_MAX,
         l1 = -FLT_MAX, l2 = FLT_MAX;
  unsigned char ifu = 0;
  unsigned short slice = 0;
  int i;

  /* argument processing */
  for (i = 1; i < argc; i++) {
    if (strncmp(argv[i], "-x1", 4) == 0) {
      /* skip to next arg to get start value */
      i++;
      if (i < argc) {
        x1 = atof(argv[i]);
      } else {
        PRINT_USAGE(2);
      }
    } else if (strncmp(argv[i], "-x2", 4) == 0) {
      i++;
      if (i < argc) {
        x2 = atof(argv[i]);
      } else {
        PRINT_USAGE(2);
      }
    } else if (strncmp(argv[i], "-y1", 4) == 0) {
      i++;
      if (i < argc) {
        y1 = atof(argv[i]);
      } else {
        PRINT_USAGE(3);
      }
    } else if (strncmp(argv[i], "-y2", 4) == 0) {
      i++;
      if (i < argc) {
        y2 = atof(argv[i]);
      } else {
        PRINT_USAGE(3);
      }
    } else if (strncmp(argv[i], "-l1", 4) == 0) {
      /* skip to next arg to get start value */
      i++;
      if (i < argc) {
        l1 = atof(argv[i]);
      } else {
        PRINT_USAGE(4);
      }
    } else if (strncmp(argv[i], "-l2", 4) == 0) {
      i++;
      if (i < argc) {
        l2 = atof(argv[i]);
      } else {
        PRINT_USAGE(4);
      }
    } else if (strncmp(argv[i], "-i", 3) == 0) {
      i++;
      if (i < argc) {
        ifu = atoi(argv[i]);
      } else {
        PRINT_USAGE(5);
      }
    } else if (strncmp(argv[i], "-s", 3) == 0) {
      i++;
      if (i < argc) {
        slice = atoi(argv[i]);
      } else {
        PRINT_USAGE(6);
      }
    } else if (strncmp(argv[i], "-", 1) == 0) { /* unallowed options */
      PRINT_USAGE(9);
    } else {
      if (tiname && toname) {
        break; /* we have the required name, skip the rest */
      }
      if (!tiname) {
        tiname = argv[i]; /* set the name for the input table */
      } else {
        toname = argv[i]; /* set the name for the output table */
      }
    }
  } /* for i (all arguments) */
  if (!tiname || !toname) {
    PRINT_USAGE(1);
  }

  cpl_msg_set_level(CPL_MSG_WARNING); /* swallow INFO output */
  muse_pixtable *table = muse_pixtable_load(tiname);
  if (!table) {
    PRINT_USAGE(10);
  }

  /* Limit crop ranges to what's in the pixel table, but do this for display *
   * only. Otherwise it might cause the muse_pixtable_restrict_*() functions *
   * to do more work than necessary, because float/double conversions may    *
   * the less/greater comparisons in those functionts to be false.           */
  double ll = fmax(l1, cpl_propertylist_get_float(table->header, MUSE_HDR_PT_LLO)),
         lu = fmin(l2, cpl_propertylist_get_float(table->header, MUSE_HDR_PT_LHI)),
         xl = fmax(x1, cpl_propertylist_get_float(table->header, MUSE_HDR_PT_XLO)),
         xu = fmin(x2, cpl_propertylist_get_float(table->header, MUSE_HDR_PT_XHI)),
         yl = fmax(y1, cpl_propertylist_get_float(table->header, MUSE_HDR_PT_YLO)),
         yu = fmin(y2, cpl_propertylist_get_float(table->header, MUSE_HDR_PT_YHI));

  printf("MUSE pixel table \"%s\" (%"CPL_SIZE_FORMAT" rows)\n"
         "  cropping to lambda = %.2f..%.2f Angstrom\n"
         "                xpos = %.3e..%.3e %s\n"
         "                ypos = %.3e..%.3e %s\n",
         tiname, muse_pixtable_get_nrow(table), ll, lu,
         xl, xu, cpl_table_get_column_unit(table->table, MUSE_PIXTABLE_XPOS),
         yl, yu, cpl_table_get_column_unit(table->table, MUSE_PIXTABLE_YPOS));
  /* ignore the returns of these functions, they only test for NULL input */
  muse_pixtable_restrict_wavelength(table, l1, l2);
  muse_pixtable_restrict_xpos(table, x1, x2);
  muse_pixtable_restrict_ypos(table, y1, y2);

  /* possibly select by IFU and/or slice */
  if (ifu >= 1 && ifu <= kMuseNumIFUs) {
    printf("  selecting pixels from IFU %02hhu ", ifu);
    cpl_table_unselect_all(table->table);
    const int *origin = cpl_table_get_data_int_const(table->table,
                                                     MUSE_PIXTABLE_ORIGIN);
    cpl_size irow, nrow = muse_pixtable_get_nrow(table);
    for (irow = 0; irow < nrow; irow++) {
      if (muse_pixtable_origin_get_ifu(origin[irow]) != ifu) {
        cpl_table_select_row(table->table, irow);
      } /* if */
    } /* for irow */
    printf("(%d of %d)\n", (int)cpl_table_count_selected(table->table), (int)nrow);
    cpl_table_erase_selected(table->table);
  } /* if ifu */
  if (slice >= 1 && slice <= kMuseSlicesPerCCD) {
    printf("  selecting pixels from slice %02hu ", slice);
    cpl_table_unselect_all(table->table);
    const int *origin = cpl_table_get_data_int_const(table->table,
                                                     MUSE_PIXTABLE_ORIGIN);
    cpl_size irow, nrow = muse_pixtable_get_nrow(table);
    for (irow = 0; irow < nrow; irow++) {
      if (muse_pixtable_origin_get_slice(origin[irow]) != slice) {
        cpl_table_select_row(table->table, irow);
      } /* if */
    } /* for irow */
    printf("(%d of %d)\n", (int)cpl_table_count_selected(table->table), (int)nrow);
    cpl_table_erase_selected(table->table);
  } /* if slice */

  /* all selection done, save and clean up */
  cpl_error_code rc = muse_pixtable_save(table, toname);
  switch (rc) {
  case CPL_ERROR_NONE:
    rc = 0;
    break;
  default:
    rc = 50;
  } /* switch */
  printf("MUSE pixel table \"%s\" (%"CPL_SIZE_FORMAT" rows) saved\n",
         toname, muse_pixtable_get_nrow(table));

  muse_pixtable_delete(table);
  cpl_end();
  return rc;
}

/**@}*/
