/**
	\file
	\brief Functions for managing a set of frames

	The frameset is a data object, that was designed promarily to hold
	a set of photometry files and make an output listings. 
	It provides an interface for adding and removing frames, retrieving 
	stored data. The data can be saved to a file and loaded back without
	lost of information.

	\author David Motl <dmotl@volny.cz>
	
	\par Copying
	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, version 2.
	
	$Id: cmpack_fset.h,v 1.6 2016/05/19 20:47:18 dmotl Exp $
*/

#ifndef _CMPACK_FRAMESET_H_INCLUDED
#define _CMPACK_FRAMESET_H_INCLUDED

#include "cmpack_console.h"
#include "cmpack_common.h"
#include "cmpack_phtfile.h"
#include "cmpack_catfile.h"
#include "cmpack_table.h"

/******************    Data types and definitions    ****************/

/** 
	\brief Frame set context
	\details This opaque structure holds the entire frame set.
*/
typedef struct _CmpackFrameSet CmpackFrameSet;

/** \brief Julian dates in a frame set */
typedef enum _CmpackJDMode
{
	CMPACK_JD_UNKNOWN,			/**< It is not known */
	CMPACK_JD_GEOCENTRIC,		/**< Julian date is geocentric */
	CMPACK_JD_HELIOCENTRIC		/**< Julian date is heliocentric */
} CmpackJDMode;	

/** \brief Frame set parameters */
typedef struct _CmpackFrameSetInfo
{
	int		frame_width;		/**< Reference frame width in pixels */
	int		frame_height;		/**< Reference frame height in pixels */
	CmpackObjCoords	objcoords;	/**< Object's designation and coordinates */
	CmpackLocation	location;	/**< Observer's designation and coordinates */
	CmpackJDMode jd_mode;		/**< Julian date mode */
	int		jd_prec;			/**< Number of decimal places used to print JD */
} CmpackFrameSetInfo;

/** \brief Frame set parameters flags */
typedef enum _CmpackFrameSetInfoFlags
{
	CMPACK_FS_FRAME_SIZE	= (1<<0),	/**< Fields: frame_width, frame_height */
	CMPACK_FS_OBJECT		= (1<<1),	/**< Fields: objcoords.* */
	CMPACK_FS_LOCATION		= (1<<2),	/**< Fields: location.* */
	CMPACK_FS_JD_MODE		= (1<<3),	/**< Fields: jd_mode */
	CMPACK_FS_JD_PREC		= (1<<4),	/**< Fields: jd_prec */
	CMPACK_FS_OBJ_RA		= (1<<5),	/**< Fields: objcoords.ra */
	CMPACK_FS_OBJ_DEC		= (1<<6),	/**< Fields: objcoords.dec */
	CMPACK_FS_LONGITUDE		= (1<<7),	/**< Fields: location.longitude */
	CMPACK_FS_LATITUDE		= (1<<8)	/**< Fields: location.latitude */
} CmpackFrameSetInfoFlags;	
		
/** \brief Frame parameters */
typedef struct _CmpackFrameInfo
{
	int		frame_id;			/**< Frame identifier */
	double	juldat;				/**< Julian date */
	int		valid_helcor;		/**< Valid heliocentric correction */
	double	helcor;				/**< Heliocentric correction [days] */
	double	airmass;			/**< Air mass coefficient */
	double	altitude;			/**< Altitude in degrees */
	char	*filter;			/**< Color filter name */
	char	*filename;			/**< File name */
	double	exptime;			/**< Exposure duration in seconds */
	double	ccdtemp;			/**< CCD temperature */
	int     valid_offset;		/**< Are offsets valid? */
	double	offset[2];			/**< Offset in pixels */
} CmpackFrameInfo;

typedef enum _CmpackFrameInfoFlags
{
	CMPACK_FI_ID			= (1<<0),	/**< Fields: frame_id */ 
	CMPACK_FI_JULDAT		= (1<<1),	/**< Fields: juldat */
	CMPACK_FI_HELCOR		= (1<<2),	/**< Fields: valid_helcor, helcor */
	CMPACK_FI_AIRMASS_ALT	= (1<<3),	/**< Fields: airmass, altitude */
	CMPACK_FI_FILTER		= (1<<4),	/**< Fields: filter */
	CMPACK_FI_EXPTIME		= (1<<5),	/**< Fields: exptime */
	CMPACK_FI_CCDTEMP		= (1<<6),	/**< Fields: ccdtemp */
	CMPACK_FI_OFFSET		= (1<<7),	/**< Fields: valid_offset, offset */
	CMPACK_FI_FILENAME      = (1<<8)	/**< Fields: filename */
} CmpackFrameInfoFlags;

typedef enum _CmpackFSetColumns
{
	/* Frame properties */
	CMPACK_FC_FRAME			= (1<<0),	/**< Frame ID */ 
	CMPACK_FC_JULDAT		= (1<<1),	/**< Julian date (geocentric) */
	CMPACK_FC_HJD			= (1<<2),	/**< Julian date (heliocentric) */
	CMPACK_FC_HELCOR		= (1<<3),	/**< Heliocentric correction */
	CMPACK_FC_AIRMASS		= (1<<4),	/**< Air mass */
	CMPACK_FC_ALTITUDE		= (1<<5),	/**< Altitude */
	CMPACK_FC_FILTER		= (1<<6),	/**< Filter designation */
	CMPACK_FC_EXPTIME		= (1<<7),	/**< Exposure time */
	CMPACK_FC_CCDTEMP		= (1<<8),	/**< CCD temperature */
	CMPACK_FC_OFFSET		= (1<<9),	/**< Relative offset X, offset Y w.r.t. reference frame */
	CMPACK_FC_FILENAME      = (1<<10),	/**< Filename */

	/* Object properties */
	CMPACK_FC_CENTER		= (1<<11),	/**< X and Y coordinate in pixels */
	CMPACK_FC_SKY			= (1<<12),	/**< Background mean level and noise in ADU */
	CMPACK_FC_FWHM			= (1<<13),	/**< Full width at half maximum in pixels */
	
	/* Magnitude */
	CMPACK_FC_MAG			= (1<<14)	/**< Instrumental magnitude + error */
} CmpackFSetColumns;

/***********************   Public functions   *****************************/

#ifdef __cplusplus
extern "C" {
#endif

/**
	\brief Create a new frame set
	\details The function creates a new frame set and returns a reference to it. 
	The reference counter is set to one. The caller is responsible to call 
	cmpack_fset_destroy() when it is no longer needed.
	\return pointer to a new reference
*/
	CMPACK_EXPORT(CmpackFrameSet*, cmpack_fset_init, (void));

/**
	\brief Make a new reference to the existing frame set
	\details The function makes a new reference to the frame set and returns 
	a pointer to it. The reference counter is incremented by one. The caller 
	is responsible to call cmpack_fset_destroy() when the reference is 
	no longer needed.
	\return pointer a new reference
*/
	CMPACK_EXPORT(CmpackFrameSet*, cmpack_fset_reference, (CmpackFrameSet* fset));

/**
	\brief Release a reference to the frame set
	\details The function releases a reference to the frame set. The reference 
	counter is decreased by one and when it was the last reference to the 
	file, the frame set is released from the memory.
*/
	CMPACK_EXPORT(void, cmpack_fset_destroy, (CmpackFrameSet* fset));

/**
	\brief Load frame set from a file
	\details The function reads frames set data from a specified file. 
	At present, only readall format is supported.
	\param[in]	fset			frame set
	\param[in] 	filename		path to the source file
	\param[in]	flags			bitmask of CMPACK_LOAD_xxx flags
	\return zero on success, error code on failure
*/
	CMPACK_EXPORT(int, cmpack_fset_load, (CmpackFrameSet** fset, const char* filename, int flags));

/**
	\brief Export frame set to the file
	\details The function exports the frame set data in readall format.
	\param[in]	fset			frame set
	\param[in] 	filename		path to the target file
	\param[in]	aperture		aperture index
	\return zero on success, error code on failure
*/
	CMPACK_EXPORT(int, cmpack_fset_export, (CmpackFrameSet* fset, const char* filename, int aperture));

/**
	\brief Make copy of the frame set
	\details The function makes deep copy of the given frame set. All data
	in target frame set are overwritten.
	\param[in]	dst				target frame set
	\param[in] 	src				source frame set
	\return zero on success, error code on failure
*/
	CMPACK_EXPORT(int, cmpack_fset_copy, (CmpackFrameSet* dst, const CmpackFrameSet* src));

/**
	\brief Clear the frame set
	\details The function deletes all frames that are stored in the frame set
	and clears all parameters from the header.
	\param[in]	fset			frame set
*/
	CMPACK_EXPORT(void, cmpack_fset_clear, (CmpackFrameSet* fset));

/** 
	\brief Test if given file seems to be a readall file
	\details The function reads the beginning of the file and
	examines them to check if the file is a valid readall file or not.
	This function is used for file format autodetection.
	\param[in] 	filename		path + file name
	\return nonzero if the file is a valid readall file, zero otherwise
*/
	CMPACK_EXPORT(int, cmpack_fset_test, (const char* filename));

/** 
	\brief Test memory buffer if it seems to be a valid readall file
	\details The function examines the given memory buffer to check
	if the buffer contains a beginning of a valid readall file or not.
	This function is used for file format autodetection.
	\param[in] 	buffer			data to be examined
	\param[in]	buflen			number of bytes in the buffer
	\param[in]	filesize		real size of the complete file in bytes
	\return nonzero if the file is a valid readall file, zero otherwise
*/
	CMPACK_EXPORT(int, cmpack_fset_test_buffer, (const char* buffer, int buflen, int filesize));

/****************************   File header   *******************************/

/**
	\brief Set frame set parameters
	\details The function changes the global frame set parameters
	\param[in] fset				frame set
	\param[in] mask				which fields shall be modified?
	\param[in] info				frame set parameters
	\return zero on success, error code on failure
*/
	CMPACK_EXPORT(int, cmpack_fset_set_info, (CmpackFrameSet* fset, unsigned mask,
		const CmpackFrameSetInfo* info));

/**
	\brief Read frame set parameters
	\details The function retrieves frame set global parameters
	\param[in] fset				frame set
	\param[in] mask				which fields shall be retrieved?
	\param[out] info			frame set parameters
	\return zero on success, error code on failure
*/
	CMPACK_EXPORT(int, cmpack_fset_get_info, (CmpackFrameSet* fset, unsigned mask,
		CmpackFrameSetInfo* info));

/****************************   Apertures   *******************************/

/**
	\brief Get number of apertures stored in a frame set
	\details The function returns number of apertures that are defined
	in the frame set.
	\param[in] fset				frame set
	\return number of apertures or zero on failure
*/
	CMPACK_EXPORT(int, cmpack_fset_aperture_count, (CmpackFrameSet* fset));

/**
	\brief Get number of apertures stored in a frame set
	\details The function adds a new aperture to the frame set. The
	aperture is appended to the end of the table.
	\param[in] fset				frame set
	\param[in] mask				which fields shall be initialized?
	\param[in] info				initial values
	\return aperture index on success or negative value on failure
*/
	CMPACK_EXPORT(int, cmpack_fset_add_aperture, (CmpackFrameSet* fset, unsigned mask,
		const CmpackPhtAperture* info));

/**
	\brief Find aperture in the frame set by its identifier
	\details The function searches for an aperture in the frame set
	which has specified identifier. The function returns an index
	to the table of apertures or -1 if the aperture does not exist.
	\param[in] fset				frame set
	\param[in] aper_id			aperture identifier
	\return aperture index or negative value on failure
*/
	CMPACK_EXPORT(int, cmpack_fset_find_aperture, (CmpackFrameSet* fset, int aper_id));

/**
	\brief Get aperture parameters from the frame set
	\details The function retrieves parameters of the aperture
	from the table of apertures. The item is specified by an index
	to the table.
	\param[in] fset				frame set
	\param[in] index			aperture index (starting by 0)
	\param[in] mask				which fields shall be retrieved?
	\param[out] info			aperture parameters
	\return zero on success or negative error code on failure.
*/
	CMPACK_EXPORT(int, cmpack_fset_get_aperture, (CmpackFrameSet* fset, int index, unsigned mask,
		CmpackPhtAperture* info));

/**
	\brief Change aperture parameters in the frame set
	\details The function sets parameters of the aperture
	in the table of apertures.The item is specified by an index
	to the table.
	\param[in] fset				frame set
	\param[in] index			aperture index (starting by 0)
	\param[in] mask				which fields shall be modified?
	\param[in] info				aperture parameters
	\return aperture identifier or negative value on failure
*/
	CMPACK_EXPORT(int, cmpack_fset_set_aperture, (CmpackFrameSet* fset, int index, unsigned mask,
		const CmpackPhtAperture* info));

/*************************  Objects   *****************************/

/**
	\brief Get number of objects 
	\details The function returns a number of objects that are
	defined in the frame set.
	\param[in] fset				frame set
	\return number of objects or zero on failure
*/
	CMPACK_EXPORT(int, cmpack_fset_object_count, (CmpackFrameSet* fset));

/**
	\brief Add object to chart
	\details The function inserts a new object to the frame set. The
	object is appended to the end of the table.
	\param[in] fset				frame set
	\param[in] mask				which fields shall be initialized?
	\param[out] info			initial object parameters
	\return object index on success or negative error code on failure.
*/
	CMPACK_EXPORT(int, cmpack_fset_add_object, (CmpackFrameSet* fset, unsigned mask,
		const CmpackCatObject* info));

/**
	\brief Find object in the frame set by its identifier
	\details The function searches for an object in the frame set
	which has specified identifier. The function returns an index
	to the table of objects or -1 if the object does not exist.
	\param[in] fset				frame set
	\param[in] object_id		object identifier
	\return record index or negative value on failure.
*/
	CMPACK_EXPORT(int, cmpack_fset_find_object, (CmpackFrameSet* fset, int object_id));

/**
	\brief Get object parameters from the frame set
	\details The function retrieves parameters of the object
	from the table of objects. The item is specified by an index
	to the table.
	\param[in] fset				frame set
	\param[in] index			record index
	\param[in] mask				which fields shall be retrieved?
	\param[out] info			object parameters
	\return zero on failure or negative error code on failure.
*/
	CMPACK_EXPORT(int, cmpack_fset_get_object, (CmpackFrameSet* fset, int index, unsigned mask,
		CmpackCatObject* info));

/**
	\brief Get object identifier from the frame set
	\details The function returns identifier of the object
	from the table of objects. The item is specified by an index
	to the table.
	\param[in] fset				frame set
	\param[in] index			record index
	\param[in] mask				which fields shall be retrieved?
	\param[in] info				object parameters
	\return zero on failure or negative error code on failure.
*/
	CMPACK_EXPORT(int, cmpack_fset_set_object, (CmpackFrameSet* fset, int index, unsigned mask,
		const CmpackCatObject* info));

/**
	\brief Remove object from the frame set
	\details The function removes an object from the frame set. The objects
	beyond the removed item are moved to fill the gap.
	\param[in] fset				frame set
	\param[in] index			record index
*/
	CMPACK_EXPORT(void, cmpack_fset_remove_object, (CmpackFrameSet* fset, int index));

/*************************   Frame management   *******************************/

/**
	\brief Get number of frames stored in the frame set
	\details The function returns number of frames that are stored
	in the frame set.
	\param[in] fset				frame set
	\return number of frames or zero on failure.
*/
	CMPACK_EXPORT(int, cmpack_fset_frame_count, (CmpackFrameSet* fset));

/**
	\brief Set actual frame to the first frame in the frame set
	\details The function sets the frame pointer in the frame set
	to the first frame. If the frame set is empty it returns 
	CMPACK_ERR_OUT_OF_RANGE value, on success it returns zero.
	\param[in] fset				frame set
	\return zero on success, error code on failure
*/
	CMPACK_EXPORT(int, cmpack_fset_rewind, (CmpackFrameSet* fset));

/**
	\brief Move to the next frame in the frame set
	\details The function sets the frame pointer in the frame set
	to the next frame. If the last frame was active, the function
	returns CMPACK_ERR_OUT_OF_RANGE value, on success it returns zero.
	\param[in] fset				frame set
	\return zero on success, error code on failure
*/
	CMPACK_EXPORT(int, cmpack_fset_next, (CmpackFrameSet* fset));

/**
	\brief Move frame pointer to a n-th frame in the frame set
	\details The function sets the frame pointer to a frame indicated
	by its index, starting from zero. If such frame does not exist,
	the function returns CMPACK_ERR_OUT_OF_RANGE value, on success 
	it returns zero.
	\param[in] fset				frame set
	\param[in] index			record index
	\return zero on success, error code on failure
*/
	CMPACK_EXPORT(int, cmpack_fset_setpos, (CmpackFrameSet* fset, int index));

/**
	\brief Is the active frame valid?
	\details The function returns nonzero value if the active
	frame in the frame set refers to the valid frame. The
	function is used in conjuction with cmpack_fset_first()
	and cmpack_fset_next() to iterate over frames in the set.
	\param[in] fset				frame set
	\return nonzero if the active frame is a valid frame, zero otherwise
*/
	CMPACK_EXPORT(int, cmpack_fset_eof, (CmpackFrameSet* fset));

/**
	\brief Add new empty frame to the frame set
	\details The function inserts a new frame into the frame set. The
	new frame becomes an active frame.
	\param[in] fset				frame set
	\param[in] mask				which fields shall be initialized?
	\param[in] info				frame parameters 
	\return zero on success or negative error code on failure.
*/
	CMPACK_EXPORT(int, cmpack_fset_append, (CmpackFrameSet* fset, unsigned mask,
		const CmpackFrameInfo* info));

/**
	\brief Add new frame to the frame set from the photometry file
	\details The function creates a new frame in the frame set and fill
	the measurements for all objects defined in the table of objects and
	all apertures defined in the table of apertures.
	\param[in] fset				frame set
	\param[in] file				photometry file
	\param[in] frame_id			frame identifier
	\param[in] filename			file name displayed in error reporting (optional)
	\return zero on success or negative error code on failure.
*/
	CMPACK_EXPORT(int, cmpack_fset_append_frame, (CmpackFrameSet* fset, CmpackPhtFile* file,
		int frame_id, const char* filename));

/**
	\brief Add new frame to the frame set from the photometry file
	\details The function creates a new frame in the frame set and fill
	the measurements for all objects defined in the table of objects and
	all apertures defined in the table of apertures.
	\param[in] fset				frame set
	\param[in] filepath			path to the photometry file
	\param[in] frame_id			frame identifier
	\return zero on success or negative error code on failure.
*/
	CMPACK_EXPORT(int, cmpack_fset_append_file, (CmpackFrameSet* fset, const char* filepath,
		int frame_id));

/**
	\brief Set information about a frame in the frame set
	\details The function sets the parameters of the active frame 
	stored in the frame set.
	\param[in] fset				frame set
	\param[in] mask				which fields shall be modified?
	\param[in] info				frame parameters 
	\return zero on success or negative error code on failure.
*/
	CMPACK_EXPORT(int, cmpack_fset_set_frame, (CmpackFrameSet* fset, unsigned mask,
		const CmpackFrameInfo* info));

/**
	\brief Get information about a frame in the frame set
	\details The function retrieves the parameters from the active frame
	stored in the frame set.
	\param[in] fset				frame set
	\param[in] mask				which fields shall be retrieved?
	\param[out] info			frame parameters 
	\return zero on success or negative error code on failure.
*/
	CMPACK_EXPORT(int, cmpack_fset_get_frame, (CmpackFrameSet* fset, unsigned mask,
		CmpackFrameInfo* info));

/**
	\brief Find frame in the frame set by its identifier
	\details The function searches for a frame in the frame set
	which has specified identifier. If the frame exists, it becames
	the active frame. Otherwise, the frame pointer is set beyond the
	last item and the function returns an error code.
	\param[in] fset				frame set
	\param[in] frame_id			frame identifier
	\return nonzero on success or zero if the frame was not found
*/
	CMPACK_EXPORT(int, cmpack_fset_find_frame, (CmpackFrameSet* fset, int frame_id));

/**
	\brief Remove a frame from the set
	\details The function deletes the active frame and sets the
	frame pointer to the next frame, if possible
	\param[in] fset				frame set
*/
	CMPACK_EXPORT(void, cmpack_fset_delete_frame, (CmpackFrameSet* fset));

/*********************  Low-level data access   ************************/

/**
	\brief Read measurement from active frame
	\details The function reads a single measurement from the active frame 
	in the frame set. The caller must specify the index of the object
	and the index of the aperture.
	\param[in] fset				frame set
	\param[in] object_index		object index
	\param[in] aperture_index	aperture index
	\param[out] data			brightness and error estimation
	\return zero on success or negative error code on failure.
*/
	CMPACK_EXPORT(int, cmpack_fset_get_data, (CmpackFrameSet* fset, int object_index,
		int aperture_index, CmpackPhtData* data));

/**
	\brief Set measurement to active frame
	\details The function sets a single measurement in the active frame 
	in the frame set. The caller must specify the index of the object
	and the index of the aperture.
	\param[in] fset				frame set
	\param[in] object_index		object index
	\param[in] aperture_index	aperture index
	\param[in] data				brightness and error estimation
	\return zero on success or negative error code on failure.
*/
	CMPACK_EXPORT(int, cmpack_fset_set_data, (CmpackFrameSet* fset, int object_index,
		int aperture_index, const CmpackPhtData* data));

/**
	\brief Get object properties from a frame in the frame set
	\details The function retrieves parameters of the object
	from the table of frames. The item is specified by an index
	to the table.
	\param[in] fset				frame set
	\param[in] index			record index
	\param[in] mask				which fields shall be retrieved?
	\param[out] info			object parameters
	\return zero on failure or negative error code on failure.
*/
	CMPACK_EXPORT(int, cmpack_fset_get_frame_object, (CmpackFrameSet* fset, int index, unsigned mask,
		CmpackPhtObject* info));

/*********************    REPORTING   *******************************/

/*
	\brief Generate a table 
	\details The function creates a table, each row corresponds to
	one frame. The table columns are specified using a packed bitmask
	\param[in] fset				frame set
	\param[out] table			created table
	\param[in] type				table type
	\param[in] object_index		object index
	\param[in] aperture_index	aperture index
	\param[in] cols				packed bitmask of columns to be included
	\param[in] objname			object designation (can be NULL)
	\param[in] ra				right ascension of object in hours
	\param[in] declination		declination of object in degrees
	\param[in] location			location name (can be NULL)
	\param[in] longitude		longitude of observer in degrees
	\param[in] latitude			latitude of observer in degrees
	\param[in] console			used to print debug outputs (can be NULL)
	\return zero on success or negative error code on failure.
*/
	CMPACK_EXPORT(int, cmpack_fset_plot, (CmpackFrameSet* fset, CmpackTable** table, CmpackTableType type, CmpackFSetColumns cols,
		int object_index, int aperture_index, const char* objname, double ra, double declination,
		const char* location, double longitude, double latitude, CmpackConsole* console));

#ifdef __cplusplus
}
#endif

#endif
