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

progress_dlg.h (C-Munipack project)
Progress 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_PROGRESS_DLG_H
#define CMPACK_PROGRESS_DLG_H

#include <gtk/gtk.h>

#include "helper_classes.h"

class CProgressDlg:public CConsole
{
public:
	// Procedure (called in a worker thread)
	typedef int ExecProc(class CProgressDlg *sender, void *user_data);

	// Constructor
	CProgressDlg(GtkWindow *pParent, const char *Title);

	// Destructor
	virtual ~CProgressDlg();

	// Run the procedure in a worker thread
	// params:
	//	pExecFn			- [in] procedure to execute 
	//	user_data		- [in] custom data passed to the procedure
	//	error			- [out] error object
	// The function returns a return value of the given procedure
	int Execute(ExecProc *pExecFn, void *user_data, GError **error = NULL);

	// Set title of the dialog (first line, highlighted text)
	void SetTitle(const char *title);

	// Set displayed file name (second line of the dialog)
	void SetFileName(const char *filename);

	// Set progress range
	void SetMinMax(double min, double max);

	// Set progress position
	void SetProgress(double val);

	// Set error object. The error is passed out of the Execute method.
	// You must not free the error object after calling this function.
	void SetError(GError *error);

	// Returns true if the user hit the "Cancel" button
	bool Cancelled(void);

protected:
	virtual void OnPrint(const char *text);

private:
	enum tEventCode
	{
		EVENT_MESSAGE,
		EVENT_TITLE,
		EVENT_FILENAME,
		EVENT_PROGRESS,
		EVENT_SUSPEND,
		EVENT_FINISHED
	};

	struct tMessage
	{
		tEventCode	event;
		gchar		*text;
		gint		int_val;
		gdouble		dbl_val;
	};

	GtkWidget	*m_pDlg, *m_Caption, *m_FileName, *m_TextView;
	GtkWidget	*m_Progress, *m_CancelBtn, *m_SuspendBtn;
	GThread		*m_Thread;
	GMutex		*m_DataMutex;
	GCond		*m_Resume;
	GAsyncQueue	*m_Queue;
	ExecProc	*m_ExecFn;
	gpointer	m_UserData;
	int			m_Result;
	double		m_Min, m_Max;
	GMainLoop	*m_Loop;
	bool		m_StopRq, m_Suspend, m_Waiting;
	GError		**m_pError;

	static void thread_proc(CProgressDlg *pMe);
	static void show_dialog(GtkWidget *widget, CProgressDlg *pDlg);
	static gboolean delete_event(GtkWidget *pWnd, GdkEvent *event, CProgressDlg *pDlg);
	static gboolean idle_func(CProgressDlg *pDlg);
	static void cancel_clicked(GtkButton *button, CProgressDlg *pDlg);
	static void suspend_clicked(GtkButton *button, CProgressDlg *pDlg);

	void InternalAddMessage(const char *text);
	void InternalSetTitle(const char *text);
	void InternalSetFileName(const char *text);
	void InternalSetProgress(double val);

	void PushMessage(tEventCode event, gint intval=0, gdouble dblval=0.0, gchar *text=NULL);
	tMessage *PopMessage(void);
	static void FreeMessage(tMessage *msg);
};

#endif
