/**
	\file
	\brief Functions for reading CCD frames

	Set of function defined in this module allows user to
	read CCD frame files in various formats by means of
	single interface. Writing files is not supported, use
	the cfitsio library directly.

	\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_ccdfile.h,v 1.2 2015/07/12 08:11:54 dmotl Exp $
*/

#ifndef _CMPACK_CCDFILE_H_INCLUDED
#define _CMPACK_CCDFILE_H_INCLUDED

#include "cmpack_common.h"
#include "cmpack_console.h"
#include "cmpack_image.h"
#include "cmpack_wcs.h"

/********************   Public constants   ********************************/

/** \brief Image format identifiers */
typedef enum _CmpackFormat
{
	CMPACK_FORMAT_UNKNOWN = 0,		/**< Unknown format */
	CMPACK_FORMAT_FITS,				/**< FITS format */
	CMPACK_FORMAT_SBIG,				/**< SBIG format */
	CMPACK_FORMAT_OES,				/**< OES Astro format */
	CMPACK_FORMAT_CRW,				/**< Canon raw format */
	CMPACK_FORMAT_NEF,				/**< Nikon raw format */
	CMPACK_FORMAT_MRW,				/**< Minolta raw format */
	CMPACK_FORMAT_CR3,				/**< Canon CR3 format */
} CmpackFormat;

/** \brief Color channel identifiers (for RAW images) */
typedef enum _CmpackChannel
{
	CMPACK_CHANNEL_SUM = 0,			/**< R+G+G+B */
	CMPACK_CHANNEL_RED,				/**< Red channel */
	CMPACK_CHANNEL_GREEN,			/**< Green channel */
	CMPACK_CHANNEL_BLUE,			/**< Blue channel */
	CMPACK_CHANNEL_0,				/**< First channel */
	CMPACK_CHANNEL_1,				/**< Second channel */
	CMPACK_CHANNEL_2,				/**< Third channel */
	CMPACK_CHANNEL_3,				/**< Fourth channel */
	CMPACK_CHANNEL_RGG				/**< R+G+G */
} CmpackChannel;

#define CMPACK_CHANNEL_DEFAULT CMPACK_CHANNEL_SUM

/********************   Public data types   ********************************/

/**
	\brief CCD frame file context 
	\details This private structure is used to access CCD frame file
*/
typedef struct _CmpackCcdFile CmpackCcdFile;

/**
	\brief CCD frame parameters 
	\details This structure is used to retrieve and update the 
	parameters in the CCD file.
*/
typedef struct _CmpackCcdParams
{
	CmpackFormat format_id;			/**< Format identifier */
	char *format_name;					/**< Format name */
	int image_width;					/**< Number of columns */
	int image_height;					/**< Number of rows */
	CmpackBitpix image_format;			/**< Image data format */
	CmpackDateTime date_time;			/**< Date and time of observation */
	double jd;							/**< Julian date of observation */
	double exposure;					/**< Exposure duration in seconds */
	double ccdtemp;						/**< CCD temperature in deg. C */
	char *filter;						/**< Color filter designation */
	char *observer;						/**< Observer's name */
	char *telescope;					/**< Name of the data acqusition telescope */
	char *instrument;					/**< name of the data acqusition instrument (camera) */
	CmpackObjCoords object;				/**< Object designation and coordinates */
	CmpackLocation location;			/**< Location designation and coordinates */
	int subframes_sum;					/**< Number of subframes summed */
	int subframes_avg;					/**< Number of subframes averaged */
	int working_format;					/**< Nonzero if the file is standard FITS file */
} CmpackCcdParams;

/** \brief Parameter flags */
typedef enum _CmpackCcdParamMask
{
	CMPACK_CM_FORMAT		= (1<<0),	/**< Fields: format_id, format_name */
	CMPACK_CM_IMAGE			= (1<<1),	/**< Fields: image_width, image_height, image_format */
	CMPACK_CM_DATETIME		= (1<<2),	/**< Fields: date_time */
	CMPACK_CM_JD			= (1<<3),	/**< Fields: jd */
	CMPACK_CM_EXPOSURE		= (1<<4),	/**< Fields: exposure */
	CMPACK_CM_CCDTEMP		= (1<<5),	/**< Fields: ccdtemp */
	CMPACK_CM_FILTER		= (1<<6),	/**< Fields: filter  */
	CMPACK_CM_OBJECT		= (1<<7),	/**< Fields: object.* */
	CMPACK_CM_OBSERVER		= (1<<8),	/**< Fields: observer */
	CMPACK_CM_LOCATION		= (1<<9),	/**< Fields: location.* */
	CMPACK_CM_SUBFRAMES		= (1<<10),	/**< Fields: subframes */
	CMPACK_CM_WORKFORMAT	= (1<<11),	/**< Fields: working_format */
	CMPACK_CM_TELESCOPE		= (1<<12),	/**< Fields: telescope */
	CMPACK_CM_INSTRUMENT	= (1<<13)	/**< Fields: instrument */
} CmpackCcdParamMask;

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

#ifdef __cplusplus
extern "C" {
#endif

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

/**
	\brief Check if the content in buffer is a beginning of a CCD frame
	\details The function examines the given memory buffer to check
	if the buffer contains a beginning of a valid CCD frame or not.
	This function is used for file format autodetection.
	\param[in] buffer			beginning of the file
	\param[in] buflen			number of bytes stored in the buffer
	\param[in] filesize			size of file in bytes
	\returns nonzero if the file is a CCD frame, zero otherwise
*/
	CMPACK_EXPORT(int, cmpack_ccd_test_buffer, (const char* buffer, int buflen, int filesize));

/**
	\brief Create a memory-only CCD frame
	\details The function creates a new CCD frame and returns a new 
	reference to it. This file is designed to store data temporarily
	in the memory. To open a file from the disk or create a permanent
	file, use cmpack_ccd_open() function instead. The reference counter 
	is set to one. The caller is responsible to call cmpack_ccd_close() 
	or cmpack_ccd_destroy() when it is no longer needed.
	\return pointer to new reference or zero on failure
*/
	CMPACK_EXPORT(CmpackCcdFile*, cmpack_ccd_new, (void));

/**
	\brief Make a new reference to the CCD frame
	\details The function makes a new reference to the file and returns a 
	pointer to it. The reference counter is incremented by one. The caller 
	is responsible to call cmpack_ccd_destroy() when the reference is 
	no longer needed.
	\param[in]	file			file context
	\return pointer to a new reference
*/
	CMPACK_EXPORT(CmpackCcdFile*, cmpack_ccd_reference, (CmpackCcdFile* file));

/**
	\brief Release a reference to the CCD frame
	\details The function releases a reference to the file. The reference 
	counter is decreased by one and when it was the last reference to the 
	file, the content of the disk file is updated and it is closed. The data
	are freed from the memory.
	\param[in]	file			file context
*/
	CMPACK_EXPORT(void, cmpack_ccd_destroy, (CmpackCcdFile* file));

/**
	\brief Open or create a CCD frame stored on the disk.
	\details The function opens an existing CCD frame stored on the
	disk or creates a new one.
	\param[out]	file			new file context
	\param[in] 	filename		path + file name
	\param[in]	mode			opening mode (see CMPACK_OPEN_xxx constants)
	\param[in] 	flags 			not used, should be 0
	\return zero on success, error code on failure
*/
	CMPACK_EXPORT(int, cmpack_ccd_open, (CmpackCcdFile** file, const char* filename,
		CmpackOpenMode mode, unsigned flags));

/**
	\brief Select a color channel for DSLR images
	\details The function selects a color channel. It has effect on subsequent
	calls of other function. For example, the cmpack_ccd_copy will copy the
	selected channel, cmpack_ccd_to_image will return image data for selected
	channel. It does no effect on SBIG, FITS or OES files.
	\param[in]	file			file context
	\param[in] 	channel 		new channel (CMPACK_CHANNEL_xxx)
*/
	CMPACK_EXPORT(void, cmpack_ccd_set_channel, (CmpackCcdFile* file, CmpackChannel channel));

/**
	\brief Close catalog file and release the reference
	\details The function updates the content of the disk file and 
	closes the file. The context is then switched to the read-only
	mode, so it is possible in some cases to retrieve the information, 
	but the file cannot be modified. The function also decrements the 
	reference counter and when it was the last reference, the memory 
	is freed. In that case, the context is no longer valid and it is 
	not possible to retrieve the information from it.
	\param[in]	file			file context
	\return zero on success, error code on failure
*/
	CMPACK_EXPORT(int, cmpack_ccd_close, (CmpackCcdFile* file));

/**
	\brief Copy content of the CCD frame
	\details The function makes copy of the source catalog file
	and to the target catalog file. If the target file contains
	any information, it is overwritten.
	\param[in] dstfile			source frame context
	\param[in] srcfile			target frame context
	\param[in] con				console where messages are printed to
	\return zero on success, error code on failure
*/
	CMPACK_EXPORT(int, cmpack_ccd_copy, (CmpackCcdFile* dstfile, CmpackCcdFile* srcfile, CmpackConsole* con));

/**
	\brief Get CCD frame parameters
	\param[in]	file			file context
	\param[in]	mask			which fields shall be retrieved
	\param[out]	params			where the values shall be stored to
	\return file format descriptor or NULL on failure
*/
	CMPACK_EXPORT(int, cmpack_ccd_get_params, (CmpackCcdFile* file, unsigned mask, CmpackCcdParams* params));

/**
	\brief Set CCD frame parameters
	\param[in]	file			file context
	\param[in]	mask			which fields shall be modified
	\param[in]	params			new values for fields to be changed
	\return file format descriptor or NULL on failure
*/
	CMPACK_EXPORT(int, cmpack_ccd_set_params, (CmpackCcdFile* file, unsigned mask, const CmpackCcdParams* params));

/**
	\brief Enumeration of parameters in the CCD frame header
	\details The function retrieves a record from the CCD frame header
	that is indicated by its index. The index of the first parameter is 
	zero. The output parameters receive the pointers to newly allocated 
	memory buffers, the caller is responsible to free it by calling of 
	cmpack_free() function. You can set the value of output parameter 
	to NULL if you do not need any of them.
	\param[in] fc				file context
	\param[in] index			parameter index (starting by 0)
	\param[out] key				parameter name
	\param[out] val				parameter value
	\param[out] com				comment text
	\return zero on success, error code on failure
*/
	CMPACK_EXPORT(int, cmpack_ccd_get_param, (CmpackCcdFile* fc, int index, char** key, char** val, char** com));

/**
	\brief Get a string value from a file header
	\details The function finds a record in the file header
	and returns its value as a string. The function returns 
	newly allocated string, the caller is responsible to free it
	by calling of cmpack_free() function. You can set the output
	parameter to NULL to check whether a field exists or not.
	Keys are case sensitive.
	\param[in] fc				file context
	\param[in] key				parameter name (key)
	\param[out] val				parameter value
	\return zero on success, error code on failure
*/
	CMPACK_EXPORT(int, cmpack_ccd_gkys, (CmpackCcdFile* fc, const char* key, char** val));

/**
	\brief Get a integer value from a file header
	\details The function finds a record in the file header, and retrieves
	its value as an integer number through the 'value' parameter.
	If the record doesn't exist or its value cannot be converted
	into an integer number, an error code is returned.
	Keys are case sensitive.
	\param[in] fc				file context
	\param[in] key				parameter name (key)
	\param[out] val				parameter value
	\return zero on success, error code on failure
*/
	CMPACK_EXPORT(int, cmpack_ccd_gkyi, (CmpackCcdFile* fc, const char* key, int* val));

/**
	\brief Get a boolean value from a file header
	\details The function finds a record in the file header, and retrieves
	its value as a boolean value through the 'value' parameter.
	If the record doesn't exist or its value cannot be converted
	into a boolean value, an error code is returned.
	Keys are case sensitive.
	\param[in] fc				file context
	\param[in] key				parameter name (key)
	\param[out] val				parameter value (zero=false, nonzero=true)
	\return zero on success, error code on failure
*/
	CMPACK_EXPORT(int, cmpack_ccd_gkyl, (CmpackCcdFile* fc, const char* key, int* val));

/**
	\brief Get a real value from a file header
	\details The function finds a record in the file header, and retrieves
	its value as a real number through the 'value' parameter.
	If the record doesn't exist or its value cannot be converted
	into a real number, an error code is returned.
	Keys are case sensitive.
	\param[in] fc				file context
	\param[in] key				parameter name (key)
	\param[out] val				parameter value
	\return zero on success, error code on failure
*/
	CMPACK_EXPORT(int, cmpack_ccd_gkyd, (CmpackCcdFile* fc, const char* key, double* val));

/**
	\brief Get image width
	\details The function returns width of an image associated with given file handle
	\param[in] fc				file context
	\return image width in pixels or zero if there is no image data
	associated with given file handle.
*/
	CMPACK_EXPORT(int, cmpack_ccd_width, (CmpackCcdFile* fc));

/**
	\brief Get image height
	\details The function returns height of an image associated with given file handle
	\param[in] fc				file context
	\return image width in pixels or zero if there is no image data
	associated with given file handle.
*/
	CMPACK_EXPORT(int, cmpack_ccd_height, (CmpackCcdFile* fc));

/**
	\brief Get image format
	\details The function returns a value that identifies format 
	used for encoding image data in a file.
	\param[in] fc				file context
	\return image depth or CMPACK_BITPIX_UNKNOWN if there is no image data
	associated with given file handle.
*/
	CMPACK_EXPORT(CmpackBitpix, cmpack_ccd_bitpix, (CmpackCcdFile* fc));

/**
	\brief Get image data from a file
	\details The function reads image data from a file and returns
	them as a new CmpackImage object. Use the cmpack_ccd_set_channel 
	function to select a color channel. If the bitpix value is CMPACK_BITPIX_AUTO,
	the image data are retrieved in the original format. Otherwise, the image
	data are converted to the specified depth.
	\param[in] fc				file context
	\param[in] bitpix			image depth (CMPACK_BITPIX_AUTO = original format)
	\param[out] image			new CmpackImage object
	\returns zero on success, error code on failure
*/
	CMPACK_EXPORT(int, cmpack_ccd_to_image, (CmpackCcdFile* fc, CmpackBitpix bitpix, CmpackImage** image));

/**
	\brief Set image data from a file
	\details The function sets the image data in a file.
	\param[in] fc				file context
	\param[in] image			image data
	\returns zero on success, error code on failure
*/
	CMPACK_EXPORT(int, cmpack_ccd_set_image, (CmpackCcdFile* fc, const CmpackImage* image));

/*************************** World Coordinate System **********************************/

/**
	\brief Read World Coordinate System (WCS) data from the file
	\details The function retrieves WCS data stored in the file. The data
	are returned as a new CmpackWcs object. If the file contains several 
	WCS data sets, all of them are retrieved. The returned object is a pointer
	to internal data, the caller should not modify or free it.
	\param[in] fc				file context
	\param[out] wcs				WCS data retrieved from the file
	\returns zero on success, error code on failure
*/
	CMPACK_EXPORT(int, cmpack_ccd_get_wcs, (CmpackCcdFile* fc, CmpackWcs** wcs));

#ifdef __cplusplus
}
#endif

#endif
