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

newfiles_dlg.h (C-Munipack project)
The 'Process new frames' dialog
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 CMPACK_NEWFILES_DLG_H
#define CMPACK_NEWFILES_DLG_H

#include "infobox.h"
#include "proc_classes.h"

class CMainWindow;

class CNewFilesDlg
{
public:
	CNewFilesDlg(GtkWindow *pParent);
	~CNewFilesDlg();

	bool Execute(void);

private:
	GtkWindow	*m_pParent;
	GtkWidget	*m_pDlg, *m_AllBtn, *m_FilesBtn, *m_DirEdit, *m_DirBtn;
	GtkWidget	*m_FilterCheck, *m_FilterEdit, *m_NameCheck, *m_NameEdit;
	GtkWidget	*m_ObjectCheck, *m_ObjectEdit, *m_ProcLabel, *m_OptLabel, *m_OptLabel2;
	GtkWidget	*m_SubDirs, *m_BgCheck;
	int			m_InFiles, m_OutFiles;
	GList		*m_FrameList;

	void UpdateControls(void);
	void EditDirPath(void);
	int ProcessFiles(class CProgressDlg *sender);
	int ProcessFrames(class CProgressDlg *sender);

	void OnButtonClicked(GtkButton *widget);
	void OnButtonToggled(GtkToggleButton *widget);
	bool OnResponseDialog(gint response_id);

	static void response_dialog(GtkDialog *pDlg, gint response_id, CNewFilesDlg *pMe);
	static void button_clicked(GtkButton *widget, CNewFilesDlg *user_data);
	static void button_toggled(GtkToggleButton *widget, CNewFilesDlg *user_data);
	static int FramesProc(class CProgressDlg *sender, void *user_data);
	static int FilesProc(class CProgressDlg *sender, void *user_data);
	static bool NewFileCB(const CFrameInfo &frame, gpointer data, bool *try_again);
};

//
// Object that detects new files
//
class CNewFilesChecker
{
public:
	// Prototype for a function that receives a notification about new frames
	// It is called whenever a checker encouters a new frame that meets the 
	// conditions specified in the configuration. When it returns FALSE, you
	// will receive a notification about this frame next time, when you return
	// TRUE, the file is put on the list of existing frames and the notification
	// won't be sent unless you call the Init or Clear function.
	typedef bool NewFrameProc(const CFrameInfo &frame, gpointer data, bool *try_again);

	// Constructor
	CNewFilesChecker(void);

	// Destructor
	virtual ~CNewFilesChecker();

	// Read configuration, returns true if the base directory exists
	bool Init(void);

	// Check for new files
	// Returns a list of CFrameInfo objects
	bool Check(NewFrameProc *cb_proc, gpointer cb_data);

	// Clear all stored information
	void Clear(void);

	// Get path to the base directory
	const gchar *DirPath(void) const
	{ return m_DirPath; }

private:
	class CDirEntry	*m_Dir;
	gchar			*m_DirPath, *m_Prefix, *m_Filter, *m_Object;
	bool			m_Recursive;
	NewFrameProc	*m_CBProc;
	gpointer		m_CBData;

	// Check new files in given directory, updates the entry. 
	// Calls CheckNewFile for new files. Calls recursively itself 
	// for subdirectories. Returns TRUE to continue the process or
	// FALSE to abort it.
	bool FindNewFiles(const gchar *dirpath, CDirEntry *entry);

	// Check a single file. If the is a valid CCD frame, creates a CFrameInfo 
	// instance and check its properties. If it meets the conditions, it 
	// issues a notification. Depending on its result, it puts the file to 
	// the list of visited entries. Returns TRUE to continue the process 
	// or FALSE to abort it.
	bool CheckNewFile(const gchar *filepath, bool *try_again);

	// Test filename filter
	static bool CheckFileName(const gchar *filepath, const gchar *prefix);

private:
	// Disable copy constructor and assignment operator
	CNewFilesChecker(const CNewFilesChecker&);
	CNewFilesChecker &operator=(const CNewFilesChecker&);
};

//
// This box is included in the main window and it is visible
// when 'Process new frames' runs on background
//
class CNewFilesBox:public CInfoBox
{
public:
	// Constructor
	CNewFilesBox(CMainWindow *pMainWnd);

	// Destructor
	virtual ~CNewFilesBox();

	// Process is running
	bool IsRunning(void);

	// Print a message (can be called from any thread)
	void Print(const gchar *message);

protected:
	// Initialization before the tool is shown
	virtual void OnShow(void);

	// Clean up after the tool is hidden
	virtual void OnHide(void);

private:
	// Status codes
	enum tStateCode
	{
		STATE_WAIT,			// Waiting for files
		STATE_WORK,			// Processing new files
		STATE_SUSPENDED,	// Process is suspended
		STATE_STOP			// Stopped
	};
	
	// Queue event codes
	enum tEventCode
	{
		EVENT_UPDATE,		// Update GUI
		EVENT_MESSAGE,		// Put message to log
		APPLY_CHANGES		// Apply pending changes (project)
	};

	// Queue items
	struct tMessage
	{
		tEventCode	event;	// Event code
		gchar		*text;	// Message text
	};
	
	GtkWidget		*m_Line1, *m_Line2;
	GtkWidget		*m_CancelBtn, *m_PauseBtn;
	GThread			*m_Thread;
	GAsyncQueue		*m_Queue;
	GMutex			*m_DataMutex;
	GCond			*m_Cond;
	bool			m_StopThread, m_SuspendRq, m_Delay;
	int				m_OutFiles;
	tStateCode		m_State;
	class CNFConsole *m_Con;
	CNewFilesChecker	m_Checker;
	CUpdateProc		*m_Proc;
	CMainWindow		*m_pMainWnd;
	
	// Clear all messages
	void Clear(void);

	// Check the process
	bool Cancelled(void);

	// Notification about new frames
	bool OnNewFrame(const CFrameInfo &frame, bool *try_again);

	// Update state
	void OnUpdate(void);

	// Cancel button clicked
	void OnCancelClicked(void);

	// Pause/resume button clicked
	void OnPauseClicked(void);

	// Thread procedure
	void OnThreadProc(void);

	// Push a message to the queue
	void PushMessage(tEventCode event, gchar *text);

	// Pop single message from the queue
	tMessage *PopMessage(void);

	// Process all message in queue
	void PurgeQueue(void);

	// Calls OnThreadProc
	static void thread_proc(CNewFilesBox *pMe);

	// Process messages from the queue
	static gboolean idle_func(CNewFilesBox *pMe);

	// Cancel button clicked
	static void cancel_clicked(GtkButton *button, CNewFilesBox *pMe);

	// Pause/resume button clicked
	static void pause_clicked(GtkButton *button, CNewFilesBox *pMe);

	// Notification about new frames
	static bool NewFrameCB(const CFrameInfo &frame, gpointer data, bool *try_again);
};

#endif
