/* This file is part of the AMBER Pipeline
 * Copyright (C) 2002,2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */


/*
 * amber_calibrate.c
 *
 *  Created on: Nov 6, 2009
 *      Author: agabasch
 */

/*-----------------------------------------------------------------------------
                                Includes
 -----------------------------------------------------------------------------*/
#include <config.h>
#include <cpl.h>
#include "amber_dfs.h"
#include "string.h"
#include "esolibCalibVis.h"
/*-----------------------------------------------------------------------------
                            Private function prototypes
 -----------------------------------------------------------------------------*/
static int amber_calibrate_create(cpl_plugin *);
static int amber_calibrate_exec(cpl_plugin *);
static int amber_calibrate_destroy(cpl_plugin *);
static int amber_calibrate(cpl_frameset *, cpl_parameterlist *);

/*-----------------------------------------------------------------------------
                            Static variables
 -----------------------------------------------------------------------------*/

static char amber_calibrate_man[] =
		"This recipe calculates calibrated squared visibilities and closure "
		"phases                                                              \n"
		"\n"
		"Input files:\n\n"
		"  DO category:               Type:      Explanation:      Required: \n"
		"  SCIENCE_REDUCED            Products   Science frame               \n"
		"  or                                                               Y\n"
		"  SCIENCE_REDUCED_FILTERED   Products   Science    frame          \n\n"
		"  AMBER_TRF_J     Calib      J-Band transfer function               \n"
		"  and/or                                                            \n"
		"  AMBER_TRF_H     Calib      H-Band transfer function              Y\n"
		"  and/or                                                            \n"
		"  AMBER_TRF_K     Calib      K-Band transfer function               \n"
		"Output files:\n\n"
		"  DO category:               Data type: Explanation:\n"
		"  SCIENCE_CALIBRATED         calibrated (vis2) OI-fits file \n\n";

/*-----------------------------------------------------------------------------
                                Function code
 -----------------------------------------------------------------------------*/


/*----------------------------------------------------------------------------*/
/**
  @brief    Build the list of available plugins, for this module.
  @param    list    the plugin list
  @return   0 if everything is ok, 1 otherwise
  @note     Only this function is exported

  Create the recipe instance and make it available to the application using the
  interface.
 */
/*----------------------------------------------------------------------------*/
int cpl_plugin_get_info(cpl_pluginlist * list)
{
	cpl_recipe  *   recipe = cpl_calloc(1, sizeof *recipe );
	cpl_plugin  *   plugin = &recipe->interface;

	if (cpl_plugin_init(plugin,
			CPL_PLUGIN_API,
			AMBER_BINARY_VERSION,
			CPL_PLUGIN_TYPE_RECIPE,
			"amber_calibrate",
			"AMBER Derives calibrated visibilities",
			amber_calibrate_man,
			"Armin Gabasch",
			PACKAGE_BUGREPORT,
			"GPL",
			amber_calibrate_create,
			amber_calibrate_exec,
			amber_calibrate_destroy)) {
		cpl_msg_error(cpl_func, "Plugin initialization failed");
		(void)cpl_error_set_where(cpl_func);
		return 1;
	}

	if (cpl_pluginlist_append(list, plugin)) {
		cpl_msg_error(cpl_func, "Error adding plugin to list");
		(void)cpl_error_set_where(cpl_func);
		return 1;
	}

	return 0;
}
/*----------------------------------------------------------------------------*/
/**
  @brief    Setup the recipe options
  @param    plugin  the plugin
  @return   0 if everything is ok

  Defining the command-line/configuration parameters for the recipe.
 */
/*----------------------------------------------------------------------------*/
static int amber_calibrate_create(cpl_plugin * plugin)
{
	cpl_recipe    * recipe;
	/*cpl_parameter * p;*/

	/* Do not create the recipe if an error code is already set */
	if (cpl_error_get_code() != CPL_ERROR_NONE) {
		cpl_msg_error(cpl_func, "%s():%d: An error is already set: %s",
				cpl_func, __LINE__, cpl_error_get_where());
		return (int)cpl_error_get_code();
	}

	if (plugin == NULL) {
		cpl_msg_error(cpl_func, "Null plugin");
		cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
	}

	/* Verify plugin type */
	if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
		cpl_msg_error(cpl_func, "Plugin is not a recipe");
		cpl_ensure_code(0, (int)CPL_ERROR_TYPE_MISMATCH);
	}

	/* Get the recipe */
	recipe = (cpl_recipe *)plugin;

	/* Create the parameters list in the cpl_recipe object */
	recipe->parameters = cpl_parameterlist_new();
	if (recipe->parameters == NULL) {
		cpl_msg_error(cpl_func, "Parameter list allocation failed");
		cpl_ensure_code(0, (int)CPL_ERROR_ILLEGAL_OUTPUT);
	}

	/* Fill the parameters list */


	return 0;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Execute the plugin instance given by the interface
  @param    plugin  the plugin
  @return   0 if everything is ok
 */
/*----------------------------------------------------------------------------*/
static int amber_calibrate_exec(cpl_plugin * plugin)
{

	cpl_recipe * recipe;
	int recipe_status;
	cpl_errorstate initial_errorstate = cpl_errorstate_get();

	/* Return immediately if an error code is already set */
	if (cpl_error_get_code() != CPL_ERROR_NONE) {
		cpl_msg_error(cpl_func, "%s():%d: An error is already set: %s",
				cpl_func, __LINE__, cpl_error_get_where());
		return (int)cpl_error_get_code();
	}

	if (plugin == NULL) {
		cpl_msg_error(cpl_func, "Null plugin");
		cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
	}

	/* Verify plugin type */
	if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
		cpl_msg_error(cpl_func, "Plugin is not a recipe");
		cpl_ensure_code(0, (int)CPL_ERROR_TYPE_MISMATCH);
	}

	/* Get the recipe */
	recipe = (cpl_recipe *)plugin;

	/* Verify parameter and frame lists */
	if (recipe->parameters == NULL) {
		cpl_msg_error(cpl_func, "Recipe invoked with NULL parameter list");
		cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
	}
	if (recipe->frames == NULL) {
		cpl_msg_error(cpl_func, "Recipe invoked with NULL frame set");
		cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
	}

	/* Invoke the recipe */
	recipe_status = amber_calibrate(recipe->frames, recipe->parameters);

	/* Ensure DFS-compliance of the products */
	if (cpl_dfs_update_product_header(recipe->frames)) {
		if (!recipe_status) recipe_status = (int)cpl_error_get_code();
	}

	if (!cpl_errorstate_is_equal(initial_errorstate)) {
		/* Dump the error history since recipe execution start.
           At this point the recipe cannot recover from the error */
		cpl_errorstate_dump(initial_errorstate, CPL_FALSE, NULL);
	}

	return recipe_status;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Destroy what has been created by the 'create' function
  @param    plugin  the plugin
  @return   0 if everything is ok
 */
/*----------------------------------------------------------------------------*/
static int amber_calibrate_destroy(cpl_plugin * plugin)
{
	cpl_recipe * recipe;

	if (plugin == NULL) {
		cpl_msg_error(cpl_func, "Null plugin");
		cpl_ensure_code(0, (int)CPL_ERROR_NULL_INPUT);
	}

	/* Verify plugin type */
	if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
		cpl_msg_error(cpl_func, "Plugin is not a recipe");
		cpl_ensure_code(0, (int)CPL_ERROR_TYPE_MISMATCH);
	}

	/* Get the recipe */
	recipe = (cpl_recipe *)plugin;

	cpl_parameterlist_delete(recipe->parameters);

	return 0;
}
/*----------------------------------------------------------------------------*/
/**
  @brief    Interpret the command line options and execute the data processing
  @param    frameset   the frames list
  @param    parlist    the parameters list
  @return   0 if everything is ok
 */
/*----------------------------------------------------------------------------*/
static int amber_calibrate(cpl_frameset * frameset, cpl_parameterlist * parlist)
{
	cpl_errorstate    prestate=0;
	cpl_frame         * cur_frame=NULL;
	int               frameset_orig_length=0;
	int               i=0;
	prestate = cpl_errorstate_get();

	amber_dfs_set_groups(frameset);

	frameset_orig_length=cpl_frameset_get_size(frameset);


	if (!frameset_orig_length)
	{
		cpl_msg_error(cpl_func,"No file found in the SOF!!");
		return -1;
	}

	if(cpl_frameset_find( frameset, "SCIENCE_REDUCED" )==NULL &&
			cpl_frameset_find( frameset, "SCIENCE_REDUCED_FILTERED")==NULL )
	{
		cpl_msg_error(cpl_func,"No file tagged SCIENCE_REDUCED or "
				"SCIENCE_REDUCED_FILTERED found in the SOF!!");
		return -1;
	}

	for(i=0; i<frameset_orig_length; i++){
		cur_frame=cpl_frameset_get_position(frameset,i);
		if (!strcmp(cpl_frame_get_tag(cur_frame), "SCIENCE_REDUCED"))
		{
			amber_CalibVis("amber_calibrate",
					cpl_frame_get_filename(cur_frame), parlist, frameset);
		}

		else if (!strcmp(cpl_frame_get_tag(cur_frame),
				"SCIENCE_REDUCED_FILTERED"))
		{
			amber_CalibVis("amber_calibrate",
					cpl_frame_get_filename(cur_frame), parlist, frameset);
		}

	}

	/*

	 Get first valid frame
	cur_frame = cpl_frameset_find( frameset, "SCIENCE_REDUCED" );
	if (cur_frame==NULL)
	{
		cur_frame = cpl_frameset_find( frameset, "SCIENCE_REDUCED_FILTERED" );
	}



	amber_TransferFunction("amber_calibrate",cpl_frame_get_filename(cur_frame),
			parlist, frameset);
	 */

	if (!cpl_errorstate_is_equal(prestate)){
		/*cpl_errorstate_dump(prestate, CPL_FALSE, NULL);*/
		return cpl_error_set_message(cpl_func, cpl_error_get_code(),
				"Recipe failed");


	}
	return 0;

}
