/**************************************************************

project.h (C-Munipack project)
Table of input frames
Copyright (C) 2008 David Motl, dmotl@volny.cz

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.

**************************************************************/

#ifndef MUNIWIN_PROJECT_H
#define MUNIWIN_PROJECT_H

#include <gtk/gtk.h>

#include "helper_classes.h"
#include "utils.h"
#include "profile.h"

// File state codes (bitmask)
#define	CFILE_CONVERSION	0x0001		// Fetched/converted
#define CFILE_TIMECORR		0x0002 		// Time corrected
#define CFILE_BIASCORR      0x0040		// Bias corrected
#define CFILE_DARKCORR		0x0004 		// Dark corrected
#define CFILE_FLATCORR		0x0008 		// Flat corrected
#define CFILE_PHOTOMETRY	0x0010		// Photometry processed
#define CFILE_MATCHING		0x0020		// Matching processed
#define CFILE_ERROR         0x1000		// Error
#define CFILE_THUMBNAIL		0x2000		// Thumbnail is valid

// Frame list - model columns
enum tFrameListColumns {
	FRAME_ID,			// File id
	FRAME_STATE,		// State bit mask
	FRAME_FLAGS,		// File flags
	FRAME_JULDAT,		// Julian date of observation
	FRAME_REPORT,		// Result of last operation
	FRAME_ORIGFILE,		// Full path of the source file 
	FRAME_TEMPFILE,		// Name of the temporary file (without path)
	FRAME_PHOTFILE,		// Name of the photometry file (without path)
	FRAME_BIASFILE,		// Full path of the bias correction frame
	FRAME_DARKFILE,		// Full path of the dark correction frame
	FRAME_FLATFILE,		// Full path of the flat correction frame
	FRAME_FILTER,		// Filter name
	FRAME_TIMECORR,		// Time correction in seconds
	FRAME_EXPTIME,		// Exposure duration in seconds
	FRAME_CCDTEMP,		// CCD temperature in centigrades
	FRAME_AVGFRAMES,	// Number of frames averaged
	FRAME_SUMFRAMES,	// Number of frames summed
	FRAME_STARS,		// Number of stars found
	FRAME_MSTARS,		// Number of stars matched
	FRAME_STRINGID,		// Frame identifier as a text
	FRAME_THUMBNAIL,	// GdkPixbuf with a thumbnail
	FRAME_OFFSET_X,		// Offset in X axis in pixels
	FRAME_OFFSET_Y,		// Offset in Y axis in pixels
	FRAME_MB_OBJ,		// Minor body object ID (0 = undefined)
	FRAME_MB_KEY,		// Key frame (0 = not a key, 1 = first key frame, 2 = other key frames)
	FRAME_TR_XX,		// Transformation matrix between the frame coordinate system and the reference coordinate system (xx component)
	FRAME_TR_YX,		// Transformation matrix between the frame coordinate system and the reference coordinate system (yx component)
	FRAME_TR_XY,		// Transformation matrix between the frame coordinate system and the reference coordinate system (xy component)
	FRAME_TR_YY,		// Transformation matrix between the frame coordinate system and the reference coordinate system (yy component)
	FRAME_TR_X0,		// Transformation matrix between the frame coordinate system and the reference coordinate system (x0 component)
	FRAME_TR_Y0,		// Transformation matrix between the frame coordinate system and the reference coordinate system (y0 component)
	FRAME_NCOLS
};

// 
// Reference types
//
enum tReferenceType {
	REF_UNDEFINED,
	REF_FRAME,
	REF_CATALOG_FILE,
	REF_TYPE_COUNT
};

//
// Target type
//
enum tTargetType {
	STATIONARY_TARGET,
	MOVING_TARGET,
	TARGET_TYPE_COUNT
};

//
// Project interface
//
class CProject
{
public:
	// Project status descriptor
	struct tStatus
	{
		bool open;			// Project is open
		bool readonly;		// Can't change the project
		int files;			// Total number of files
		int converted;		// Number of converted files
		int photometred;	// Number of photometred files
		int matched;		// Number of matched files
	};

	// Open modes
	enum tOpenMode 
	{
		OPEN_READWRITE,		// Open project in read-write mode
		OPEN_READONLY,		// Open project in read-only mode
		OPEN_CREATE			// Create a new project
	};

	// Constructor
	CProject();

	// Destructor
	virtual ~CProject(void);

	// Open existing project
	bool Open(const gchar *fpath, tOpenMode mode, GError **error, GtkWindow *parent);

	// Save project to file
	void Save(void) const;

	// Close current project
	void Close(void);
	
	// Rename project
	bool Rename(const gchar *newname, GError **error);

	// Import data from old C-Munipack
	bool Import(const gchar *srcdir, GError **error);

	// Make copy of a project to specified location
	bool Export(const gchar *dstpath, GError **error);

	// Is project opened?
	bool isOpen(void) const
	{ return m_Path!=NULL; }

	// Is project opened?
	bool isReadOnly(void) const
	{ return m_ReadOnly; }

	// Is given file a project file?
	static bool isProjectFile(const gchar *fpath);

	// Get project name (file name without extension)
	const gchar *Name(void) const
	{ return m_Name; }

	// Get project's file name
	const gchar *Path(void) const
	{ return m_Path; }

	// Get project's data directory
	const gchar *DataDir(void) const
	{ return m_DataDir; }

	// Enter critical section
	void Lock(void) const;

	// Leave critical section
	void Unlock(void) const;

	// Block updates
	// If the flag is set to true, updates to frame properties that sorting on the main window
	// and queued, until the flag is cleared or applyPendingUpdates method is called. If the
	// flag is set to false, the updates are written directly do the model and the changes
	// are immediately visible to the user. Resetting the flag makes all queued changes to be 
	// applied.
	void blockUpdates(bool enable);

	// Apply pending updates
	void applyPendingUpdates(void);

	// Get project type
	tProjectType ProjectType(void) const;

	// Get project status
	void GetStatus(tStatus *stat) const;

	// Get list of frames
	GtkTreeModel *FileList(void)
	{ return GTK_TREE_MODEL(m_Frames); }

	// Configuration parameters
	const CProfile *Profile(void) const
	{ return &m_Profile; }

	// Change configration parameters
	void SetProfile(const CProfile &profile);

	// Get number of files
	int GetFileCount(void);

	// Remove all frames from the project
	void RemoveAllFrames(void);

	// Delete all temporary files
	void ClearTempFiles(void);

	// Clear thumbnails
	void ClearThumbnails(void);

	// Clear information about reference frame
	void ClearReference(void);

	// Clear information about correction frames
	void ClearCorrections(void);

	// Clear information about observed object
	void ClearObject(void);

	// Remove all key frames (set all FRAME_MB_KEY to null)
	void ClearKeyFrames(void);

	// Add single file to the project
	// Return path (caller is responsible to free it)
	GtkTreePath *AddFile(const CFrameInfo &info);

	// Returns true if the file is already in the project
	bool FileInProject(const gchar *filepath);

	// Remove single file
	void RemovePath(GtkTreePath *pPath);
	void RemoveFrame(int frame_id);

	// Remove selected files
	void RemoveFiles(GList *pPaths);

	// Set path to the original bias file
	void SetOrigBiasFile(const CFileInfo &info);

	// Get path to the original bias file
	const CFileInfo *GetOrigBiasFile(void) const
	{ return &m_OrigBiasFile; }

	// Set path to the temporary bias file
	void SetTempBiasFile(const CFileInfo &info);

	// Get path to the temporary bias file
	const CFileInfo *GetTempBiasFile(void) const
	{ return &m_TempBiasFile; }

	// Set path to the original dark file
	void SetOrigDarkFile(const CFileInfo &info);

	// Get path to the original dark file
	const CFileInfo *GetOrigDarkFile(void) const
	{ return &m_OrigDarkFile; }

	// Set path to the temporary dark file
	void SetTempDarkFile(const CFileInfo &temp_file);

	// Get path to the temporary dark file
	const CFileInfo *GetTempDarkFile(void) const
	{ return &m_TempDarkFile; }
	
	// Set path to the original flat file
	void SetOrigFlatFile(const CFileInfo &orig_file);

	// Get path to the original flat file
	const CFileInfo *GetOrigFlatFile(void) const
	{ return &m_OrigFlatFile; }
	
	// Set path to the temporary flat file
	void SetTempFlatFile(const CFileInfo &temp_file);

	// Get path to the temporary flat file
	const CFileInfo *GetTempFlatFile(void) const
	{ return &m_TempFlatFile; }

	// Selected stars stored in the catalogue file
	CSelectionList *SelectionList(void) { return &m_SelectionList; }
	const CSelectionList *SelectionList(void) const { return &m_SelectionList; }

	// Last selected stars
	void SetLastSelection(const CSelection &sel);
	const CSelection *LastSelection(void) const { return &m_Selection; }

	// Actual list of tags
	void SetTags(const CTags &tags);
	CTags *Tags(void) { return &m_Tags; }
	const CTags *Tags(void) const { return &m_Tags; }

	// List of manually defined objects 
	void SetObjectList(const CObjectList &objs);
	CObjectList *objectList(void) { return &m_Objects; }
	const CObjectList *objectList(void) const { return &m_Objects; }

	// Actual object coordinates
	void SetObjectCoords(const CObjectCoords &obj);
	const CObjectCoords *ObjectCoords(void) const { return &m_Coords; }

	// Set target type
	void SetTargetType(tTargetType type);

	// Set reference frame
	void SetReferenceFrame(GtkTreePath *frame_path, int moving_target = 0);
	void SetReferenceFile(const gchar *cat_file);

	// Get reference frame
	tReferenceType GetReferenceType(void) const
	{ return m_RefType; }

	// Get target type
	tTargetType GetTargetType(void) const
	{ return m_TargetType; }
	
	// Get object ID of the moving target on the reference frame
	int GetReferenceTarget(void) const
	{ return m_RefMBObjID; }

	// Get reference frame
	GtkTreePath *GetReferencePath(void);

	// Get reference frame
	int GetReferenceFrame(void) const
	{ return m_RefFrameID; }

	// Get path to the temporary catalog file
	const CFileInfo *GetReferenceCatalog(void) const
	{ return &m_OrigCatFile; }
	
	// Tracking data
	void SetTrackingData(const CTrackingData &data);
	const CTrackingData *GetTrackingData() const { return &m_TrackingData; }

	// Actual list of aperture
	void SetApertures(const CApertures &aper);
	const CApertures *Apertures(void) const { return &m_Apertures; }

	// Observer's name
	void SetObserver(const gchar *name);
	const gchar *Observer(void) const { return m_Observer; }

	// Acquisition telescope designation
	void SetTelescope(const gchar *name);
	const gchar *Telescope(void) const { return m_Telescope; }

	// Acquisition instrument designation
	void SetInstrument(const gchar *name);
	const gchar *Instrument(void) const { return m_Instrument; }

	// Observer's coordinates in the reference file
	void SetLocation(const CLocation &loc);
	const CLocation *Location(void) const { return &m_Location; }

	// Returns true if the given frame is a reference frame
	bool IsReferenceFrame(GtkTreePath *path);

	// Returns true if the given list of tree paths
	// contains a reference frame
	bool ContainsReferenceFrame(GList *list);

	// Set path to the temporary catalog file
	void SetTempCatFile(const CFileInfo &info);

	// Get path to the temporary catalog file
	const CFileInfo *GetTempCatFile(void) const
	{ return &m_TempCatFile; }

	// Get tree path to the file
	GtkTreePath *GetPath(int frame_id);

	// Get frame id from the tree path
	int GetFrameID(GtkTreePath *pPath);

	// Get state
	unsigned GetState(GtkTreePath *pPath);

	// Get flags
	unsigned GetFlags(GtkTreePath *pPath);

	// Get date of observation
	double GetJulDate(GtkTreePath *pPath);

	// Get color filter
	gchar *GetColorFilter(GtkTreePath *pPath);

	// Get exposure duration 
	double GetExposure(GtkTreePath *pPath);

	// Get CCD temperature in C 
	// Returns -999.99 to indicate an invalid value
	double GetCCDTemperature(GtkTreePath *pPath);

	// Get number of averaged frames (for master frames)
	int GetAveragedFrames(GtkTreePath *pPath);

	// Get number of accumulated frames (for master frames)
	int GetAccumulatedFrames(GtkTreePath *pPath);

	// Get time correction in seconds
	double GetTimeCorrection(GtkTreePath *pPath);

	// Get source CCD image (full path)
	gchar *GetSourceFile(GtkTreePath *pPath);

	// Get image file (full path)
	gchar *GetImageFile(GtkTreePath *pPath);

	// Get image file base name (without path)
	gchar *GetImageFileName(GtkTreePath *pPath);

	// Get photometry file (full path)
	gchar *GetPhotFile(GtkTreePath *pPath);

	// Get photometry file base name (without path)
	gchar *GetPhotFileName(GtkTreePath *pPath);

	// Get bias-frame file (full path)
	gchar *GetBiasFrameFile(GtkTreePath *pPath);

	// Get dark-frame file (full path)
	gchar *GetDarkFrameFile(GtkTreePath *pPath);

	// Get flat-frame file (full path)
	gchar *GetFlatFrameFile(GtkTreePath *pPath);

	// Get number of detected stars (from photometry)
	int GetStars(GtkTreePath *pPath);

	// Get number of matched stars (from matching)
	int GetMatchedStars(GtkTreePath *pPath);

	// Set error flag and set the report string
	void SetError(GtkTreePath *pPath, const gchar *message, int state_mask, ...);
	void SetError(GtkTreePath *pPath, int errcode, int state_mask, ...);

	void SetErrorCode(GtkTreePath *pPath, int errcode);
	void SetErrorMessage(GtkTreePath *pPath, const gchar *message);

	// Reset frame properties
	void resetFields(GtkTreePath *pPath, ...);

	// Set field value later
	void setField(GtkTreePath *pPath, ...);

	// Set error flag and set the report string
	void SetResult(GtkTreePath *pPath, const gchar *message, int state_mask, int state_value, ...);
	
	// Set thumbnail image (makes own reference)
	void SetThumbnail(GtkTreePath *pPath, GdkPixbuf *pImage);

	// Set pixel offset
	void SetOffset(GtkTreePath *pPath, double offset_x, double offset_y);
	double GetOffsetX(GtkTreePath *pPath);
	double GetOffsetY(GtkTreePath *pPath);

	// Get transformation matrix from reference coordinates to frame coordinates
	void SetTrafo(GtkTreePath *pPath, const CmpackMatrix &pMatrix);
	bool GetTrafo(GtkTreePath *pPath, CmpackMatrix &pMatrix);

	// Get Julian date range of frames
	bool GetRange(gdouble &jdmin, gdouble &jdmax);

	// Returns object ID of moving target
	int GetMBObject(GtkTreePath *pPath);

	// Return status of frame when tracking a moving target
	int GetMBKey(GtkTreePath *pPath);

	// Get last message. The caller is responsible for
	// releasing memory using g_free function.
	gchar *GetLastMessage(GtkTreePath *pPath);

	// Get tree path to the first file
	GtkTreePath *GetFirstFile(void);

	// Get tree path to the last file
	GtkTreePath *GetLastFile(void);

	// Get tree path to the next file
	GtkTreePath *GetNextFile(GtkTreePath *path);

	// Get tree path to the previous file
	GtkTreePath *GetPreviousFile(GtkTreePath *path);

	// Update dialog settings
	void SetStr(const char *group, const char *key, const char *val);
	void SetDbl(const char *group, const char *key, const double val);
	void SetInt(const char *group, const char *key, const int val);
	void SetBool(const char *group, const char *key, bool val);

	// Retrieve dialog settings, returns default value if the parameter is not defined)
	char *GetStr(const char *group, const char *key, const char *defval = "") const;
	double GetDbl(const char *group, const char *key, double defval = 0.0) const;
	int GetInt(const char *group, const char *key, int defval = 0) const;
	int GetInt(const char *group, const char *key, int defval, int minval, int maxval) const;
	bool GetBool(const char *group, const char *key, bool defval = false) const;

private:
	// Project path and name
	gchar			*m_Name;			// Project name (file name without extension)
	gchar			*m_Path;			// Project's file name
	gchar			*m_DataDir;			// Project's data directory
	FileLock		*m_FileLock;		// Handle of the lock file
	bool			m_ReadOnly;			// Open in read-only mode

	// List of source frames
	GtkListStore	*m_Frames;			// List of input files
	int				m_FreeID;			// Next free id

	// Calibration
	CFileInfo		m_OrigBiasFile;		// Original bias file
	CFileInfo		m_TempBiasFile;		// Temporary bias file
	CFileInfo		m_OrigDarkFile;		// Original dark file
	CFileInfo		m_TempDarkFile;		// Temporary dark file
	CFileInfo		m_OrigFlatFile;		// Original flat file
	CFileInfo		m_TempFlatFile;		// Temporary flat file

	// Reference frame
	tTargetType		m_TargetType;		// Target type (variable star, minor body, ...)
	tReferenceType	m_RefType;			// Reference type
	int				m_RefFrameID;		// Reference frame id
	GtkTreeRowReference *m_Ref;			// Reference frame
	CFileInfo		m_OrigCatFile;		// Original catalog file
	CFileInfo		m_TempCatFile;		// Temporary catalog file
	int				m_RefMBObjID;		// Minor body - object ID
	CTrackingData	m_TrackingData;		// Minor body - tracking data

	// Selection of stars + tags
	CSelection		m_Selection;		// Last object selection
	CSelectionList	m_SelectionList;	// Object selections
	CTags			m_Tags;				// Object tags
	CObjectList		m_Objects;			// List of manually defined objects

	// Configuration parameters
	CApertures		m_Apertures;		// List of apertures
	gchar			*m_Observer;		// Observer's name
	gchar			*m_Telescope;		// Acquisition telescope designation
	gchar			*m_Instrument;		// Acquisition instrument designation
	CLocation		m_Location;			// Observer's coordinates
	CObjectCoords	m_Coords;			// Object coordinates
	CProfile		m_Profile;			// Project properties
	GKeyFile		*m_Params;			// Dialog settings

	// Pending updates
	bool			m_blockUpdates;		// False = apply changes immediately, true = enqueue changes and apply updates later
	GQueue			*m_updateQueue;		// List of pending updates

	// Disable copy constructor
	CProject(const CProject&);

	// Reset all internal parameters
	void reset(void);

	// Load project from file
	bool read(const gchar *fpath, bool import, GError **error);
	
	// Save project to file
	bool write(const gchar *fpath, GError **error) const;

	// Copy data files to given folder
	bool CopyFiles(const gchar *datadir, GError **error);

	// Remove and delete all items from the update queue
	void ClearUpdateQueue(void);

	// Remove orphaned update items from the queue
	void PruneUpdateItems(void);

	// Enqueue an update request
	void PushToQueueText(GtkTreePath *pPath, tFrameListColumns fieldId, const gchar *value);

	// Get value from the queue
	bool GetValueUInt(GtkTreePath *pPath, tFrameListColumns fieldId, unsigned *value);
	bool GetValueInt(GtkTreePath *pPath, tFrameListColumns fieldId, int *value);
	bool GetValueDouble(GtkTreePath *pPath, tFrameListColumns fieldId, double *value);
	bool GetValueText(GtkTreePath *pPath, tFrameListColumns fieldId, gchar **value);

	// Reset field value
	static void resetField(GtkListStore *model, GtkTreeIter *iter, tFrameListColumns fieldId);

	// Get default value
	static double getDefaultValue(tFrameListColumns fieldId);

};

#endif
