/* $Id: amber_raw_to_fitsimage.c,v 1.16 2011/09/26 12:54:06 agabasch Exp $
 *
 * 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
 */

/*
 * $Author: agabasch $
 * $Date: 2011/09/26 12:54:06 $
 * $Revision: 1.16 $
 * $Name: amber-4_2_2 $
 */

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

/* AMDLIB usage switch */
#define USE_AMDLIB YES

/*-----------------------------------------------------------------------------
                                Includes
 -----------------------------------------------------------------------------*/

#include <math.h>
#include <cpl.h>
#include <string.h>
#include "amdrs.h"

#ifdef USE_AMDLIB	

/* amdlib structures */
amdlibERROR_MSG       errMsg;
amdlibBAD_PIXEL_MAP   badPixels;
amdlibFLAT_FIELD_MAP  flatField;
static  amdlibRAW_DATA        rawData;
amdlibP2VM_INPUT_DATA p2vmData;
amdlibP2VM_MATRIX     p2vm;

#endif

/*-----------------------------------------------------------------------------
                            Functions prototypes
 -----------------------------------------------------------------------------*/

static int amber_raw_to_fitsimage_create(cpl_plugin *) ;
static int amber_raw_to_fitsimage_exec(cpl_plugin *) ;
static int amber_raw_to_fitsimage_destroy(cpl_plugin *) ;
static int amber_raw_to_fitsimage(cpl_parameterlist *, cpl_frameset *) ;


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

/*
static struct {
	 Inputs
	int         bool_option ;
	char        str_option[512] ;

	 Outputs
	double      qc_param ;
} amber_raw_to_fitsimage_config ;
 */

static char amber_raw_to_fitsimage_man[] =
		"This recipe creates a fits file including a primary image showing "
		"the 5 \n"
		"channels of AMBER\n"
		"\n";

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


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

  This function is exported.
 */
/*----------------------------------------------------------------------------*/
int cpl_plugin_get_info(cpl_pluginlist * list)
{
	cpl_recipe  *   recipe = cpl_calloc(1, sizeof(*recipe)) ;
	cpl_plugin  *   plugin = &recipe->interface ;

	cpl_plugin_init(plugin,
			CPL_PLUGIN_API,
			AMBER_BINARY_VERSION,
			CPL_PLUGIN_TYPE_RECIPE,
			"amber_raw_to_fitsimage",
			"AMBER raw data display",
			amber_raw_to_fitsimage_man,
			"Tom Licha",
			PACKAGE_BUGREPORT,
			"GP",
			amber_raw_to_fitsimage_create,
			amber_raw_to_fitsimage_exec,
			amber_raw_to_fitsimage_destroy) ;

	cpl_pluginlist_append(list, plugin) ;

	return 0;
}

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

  Create the recipe instance and make it available to the application using the 
  interface. 
 */
/*----------------------------------------------------------------------------*/
static int amber_raw_to_fitsimage_create(cpl_plugin * plugin)
{
	cpl_recipe * recipe = (cpl_recipe *)plugin ;
	cpl_parameter * p ;

	/* Create the parameters list in the cpl_recipe object */
	recipe->parameters = cpl_parameterlist_new() ;

	/* Fill the parameters list */
	/* --stropt */
	p = cpl_parameter_new_value("amber.amber_raw_to_fitsimage.str_option",
			CPL_TYPE_STRING, "the string option", "amber.amber_raw_to_fitsimage"
			,NULL);
	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "stropt") ;
	cpl_parameterlist_append(recipe->parameters, p) ;
#ifdef USE_PARAMETERS_HERE

	/* binning int */
	p = cpl_parameter_new_value("amber.amber_disply.int_binning",
			CPL_TYPE_INT, "Number of Frames to be averaged per Visibility",
			"amber.amber_raw_to_fitsimage", 1 ) ;
	cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "binning") ;
	cpl_parameterlist_append(recipe->parameters, p) ;
#endif 
	/* Return */
	return 0;
}

/*----------------------------------------------------------------------------*/
/**
  @brief    Execute the plugin instance given by the interface
  @param    plugin  the plugin
  @return   0 if everything is ok
 */
/*----------------------------------------------------------------------------*/
static int amber_raw_to_fitsimage_exec(cpl_plugin * plugin)
{
	cpl_recipe * recipe = (cpl_recipe *)plugin ;
	return amber_raw_to_fitsimage(recipe->parameters, recipe->frames) ;
}

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

/*----------------------------------------------------------------------------*/
/**
  @brief    Get the command line options and execute the data reduction
  @param    parlist     the parameters list
  @param    frameset   the frames list
  @return   0 if everything is ok
 */
/*----------------------------------------------------------------------------*/
static int amber_raw_to_fitsimage(
		cpl_parameterlist     *   parlist,
		cpl_frameset    *   frameset)
{

	/* CPL structures */
	/*	cpl_frameset * cur_set=NULL;*/
	cpl_frame    * cur_frame=NULL;

	/*
	cpl_frameset * frameSetTmp;
	cpl_frame    * frameTmp;
	 */

	cpl_frame  * pFrameProduct = NULL;

	cpl_imagelist  * pImagelist        = NULL;

	char   szMessage[1024];
	/*
	char   szFilnameP2VM[1024];
	char * pszFilename=NULL;
	char * pszFileTag=NULL;
	 */

	cpl_frame        *  pFrame;
	cpl_propertylist *  pHeader;

	int  iStatus           = 0;
	/*
	int  iFrameCount       = 0;
	int  iLoadedFrameCount = 0;
	 */

	/*
	cur_set     = NULL;
	cur_frame   = NULL;
	pszFilename = NULL;
	pszFileTag  = NULL;
	 */


	const char * fctid = "amber_raw_to_fitsimage";



	int iNumbExt     = 0;  /* Number of extensions in FITS file */
	int iTelescopes  = 0;  /* Number of Telescopes used to produce raw data */
	/*
	int iXWidth      = 0;   Total X Pixels for all SubWindows
	int iXSubWindow  = 0;   Width of a Channel (SubWindow)
	int iYSubWindow  = 0;   Height of a Channel (SubWindow)
	 */
	amdlibERROR_MSG  errMsg;
	/*  amdlibRAW_DATA   rawData; */

	/*	FILE         *  fp;*/

	int    pszTemp;
	/*	char   szTemp[128];*/

	char * pszInfile;
	char   szProduct[512];

	cpl_propertylist  *  pHeader_tmp = NULL;


	cpl_msg_info( fctid, "Start of DataReduction");

	/* For DFS fill Header function later */;
	/* pHeader = cpl_propertylist_new();   IMPLICIT to load later */
	pFrame  = cpl_frame_new();

	/* Outfile goes to temp */
	strcpy( szProduct, "/tmp/amber_display.fits" );

	/* Just use the first frame */
	cur_frame = cpl_frameset_get_first( frameset );
	cpl_frame_set_group(cur_frame, CPL_FRAME_GROUP_RAW);
	pszInfile = (char *)cpl_frame_get_filename( cur_frame );


	{


		/* read the number of extensions from the file */
		iNumbExt = cpl_fits_count_extensions(pszInfile);
		/*      cpl_msg_info(cpl_func,"iNumbExt: %d", iNumbExt); */


		if( iNumbExt < 3 )
		{
			/* Necessary extension 2 and 3 is not existing! */
			iStatus = 2;
		}
		else
		{
			/* Decide 2 or 3 telescope case by number of subwindows */


			pHeader_tmp = cpl_propertylist_load(pszInfile,2);

			pszTemp=cpl_propertylist_get_int(pHeader_tmp,"NREGION");
			cpl_msg_info(cpl_func,"NREGION: %d", pszTemp);

			cpl_propertylist_delete(pHeader_tmp);

			if(pszTemp == 4){
				iTelescopes = 2;
			}
			else if( pszTemp == 5){
				iTelescopes = 3;
			}
			else if(pszTemp == 1){
				iTelescopes = 1;
			}
			if(iTelescopes != 1 && iTelescopes != 2 && iTelescopes != 3 )
			{
				iStatus = 3;
			}
			else
			{
				/* Load raw frame and store it as an image */
				if (amdlibLoadRawData(pszInfile, &rawData, errMsg) !=
						amdlibSUCCESS)
				{
#ifdef TL_DEBUG	    	
					printf ("Could not load raw data file '%s'\n", pszInfile);
					printf ("%s\n", errMsg);
#endif      
					iStatus = 20;
				}

				if( amdlibSaveRawDataToFits( szProduct, &rawData, errMsg) !=
						amdlibSUCCESS )
				{
#ifdef TL_DEBUG	      	
					printf ("Could not write image file '%s'\n", szProduct);
					printf ("%s\n", errMsg);
#endif      
					iStatus = 21;
				}
				else
				{
					/* OK */
					iStatus = 0;
					amdlibReleaseRawData(&rawData);
				}
			} /* wrong region count */
		} /* ext 2 not present */
	}



	/* Create the Product file, start with filling the header */

	/*
	 * Workaround for cpl_dfs_setup_product_header picking the wrong Header in
	 * this CPL release and
	 * also might pick the wrong in the future! It uses the first RAW frame,
	 * but this recipe can handle
	 * many raw frames. Hence:
	 *
	 * Read the Header of the RAW file to be written as a product and send it to
	 *  the function
	 */

	sprintf( szMessage, "Extracted Header from file %s.", pszInfile );
	cpl_msg_info( fctid, szMessage );

	/* Create a set of frames with just this frame, so header will be correct */
	/*   frameSetTmp = cpl_frameset_new(); */
	/*   frameTmp    = cpl_frame_new(); */

	pImagelist = cpl_imagelist_load(szProduct, CPL_TYPE_FLOAT, 0 );

	pHeader = cpl_propertylist_load( pszInfile, 0 );

	pFrameProduct = cpl_frame_new();
	cpl_frame_set_filename( pFrameProduct, szProduct );
	cpl_frame_set_type    ( pFrameProduct, CPL_FRAME_TYPE_IMAGE );
	cpl_frame_set_tag     ( pFrameProduct, "AMBER_RAW_IMAGE" );
	cpl_frame_set_group   ( pFrameProduct, CPL_FRAME_GROUP_PRODUCT );
	cpl_frame_set_level   ( pFrameProduct, CPL_FRAME_LEVEL_FINAL );





	/*   cpl_frame_set_filename( frameTmp, pszInfile );  */
	/*   cpl_frame_set_type( frameTmp, CPL_FRAME_TYPE_IMAGE ); */
	/*   cpl_frame_set_tag( frameTmp, "AMBER_RAW_IMAGE" ); */
	/*   cpl_frame_set_group( frameTmp, CPL_FRAME_GROUP_RAW );  */
	/*   cpl_frame_set_level( frameTmp, CPL_FRAME_LEVEL_NONE );  */
	/*   cpl_frameset_insert( frameSetTmp, frameTmp );  */



	/* Add the necessary DFS fits header information to the product */
#if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 8, 0)
	if( cpl_dfs_setup_product_header(  pHeader,
			pFrameProduct,
			frameset,
			parlist,
			"amber_raw_to_fitsimage", /* const char *  recid,  */
			"AMBER", /* const char *  pipeline_id,  */
			"AMBER",  /* const char *  dictionary_id */
			NULL
	)  != CPL_ERROR_NONE )
	{
		/* Error */
		sprintf( szMessage, "Warning: problem with product header. [%s]",
				cpl_error_get_where() );

		cpl_msg_info( fctid, szMessage );
		/*     cpl_msg_info(cpl_func, cpl_error_get_message()); */
		iStatus = 16;
	}
#else 
	if( cpl_dfs_setup_product_header(  pHeader,
			pFrame,
			frameSetTmp,
			parlist,
			"amber_raw_to_fitsimage", /* const char *  recid,  */
			"AMBER", /* const char *  pipeline_id,  */
			"AMBER"  /* const char *  dictionary_id */
	)  != CPL_ERROR_NONE )
	{
		/* Error */
		sprintf( szMessage, "Warning: problem with product header. [%s]",
				cpl_error_get_where() );
		cpl_msg_info( fctid, szMessage );
		iStatus = 16;
	}
#endif   

	if (CPL_ERROR_NONE != cpl_imagelist_save(pImagelist, szProduct,
			CPL_BPP_IEEE_FLOAT, pHeader, CPL_IO_DEFAULT ))
	{
		cpl_msg_error(cpl_func,"Error in cpl_imagelist_save");
	}

	/*   cpl_frameset_delete(frameSetTmp); */
	cpl_frame_delete(pFrame);
	cpl_frame_delete(pFrameProduct);
	cpl_propertylist_delete(pHeader);

	cpl_imagelist_delete(pImagelist);

	/* FREE CPL STUFF !!! */

	/* ---------
  0  = OK
  1  = not a FITS file
  2  = Ext 2 or 3 not present
  3  = Wrong number of Regions in Extension 2 
  4  = No new FITS Header available
  5  = Cannot create outfile 

  11 = no memory for buffer
  12 = cannot open table with IMAGING_DATA

  20 = amdlib error
  ----------- */

	sprintf ( szMessage, "Status: %d for %s", iStatus, szProduct );
	cpl_msg_info( fctid, szMessage );

	cpl_msg_info( fctid, "End of DataReduction");

	cpl_error_reset();


	return iStatus;
}
