/* ImLib3D
 * Copyright (c) 2001, ULP-IPB Strasbourg.
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/*! \file TaskProgressManager.hpp */

#ifndef _TaskProgressManager_hpp
#define _TaskProgressManager_hpp

#include<imlib3dconfig.h>
#ifdef    HAVE_LIBPTHREAD
#include<pthread.h>
#else  // HAVE_LIBPTHREAD
typedef int pthread_t;
typedef int pthread_mutex_t;
#endif // HAVE_LIBPTHREAD

#include<ImLib3D/CppTools.hpp>
#include<algorithm>

void ttprintf(const char *fmt, ...);


class TaskProgressManager;
extern TaskProgressManager *defaultTaskProgressManager;

//! Base class for tasks. The user creates a task object each time he wants to track the progress of some action
/*! On creation the task is automatically registered to th TaskProgressManager. On destruction
the task is automatically deleted from the TaskProgressManager. This means it's use is very simple (1-line)
 */
class TaskInProgress
{
	friend class TaskProgressManager;
protected:
	TaskProgressManager *manager;

	double refTime;
	string name;
	double startTime;
	double lastReport;
	void AutoKill();
public:
	virtual double Progress(){return DTime(refTime)-startTime;}
	virtual string ProgressLabel(){return SPrintf("%2.1fs",Progress());}
	virtual ~TaskInProgress(){AutoKill();}
	TaskInProgress(const string &_name,TaskProgressManager *_manager=defaultTaskProgressManager);
};

//! Track the progress for an object that has a "Progress" fct
template<class TType>
class ProgressTracker : public TaskInProgress
{
	TType *progressAwareObj;
public:
	virtual double Progress(){return progressAwareObj->Progress();}
	virtual string ProgressLabel(){return SPrintf("%2.1f%%",100*Progress());}
	ProgressTracker(const string &_name,TType *_progressAwareObj,TaskProgressManager *_manager=defaultTaskProgressManager):
		TaskInProgress(_name,_manager),
		progressAwareObj(_progressAwareObj)
	{		
	}
};

//! Tracks the progress of some variable 
/*! the variable's type should be ultimately transformable to "float" */
template<class TType>
class TaskTracker : public TaskInProgress
{
	TType startValue;
	TType endValue;
	TType *currentValue;
public:
	virtual double Progress(){return (*currentValue-startValue)/(float)(endValue-startValue);}
	virtual string ProgressLabel(){return SPrintf("%2.1f%%",100*Progress());}
	
	TaskTracker(const string &_name,TType _startValue,TType _endValue,TType *_currentValue,TaskProgressManager *_manager=defaultTaskProgressManager):
		TaskInProgress(_name,_manager),
		startValue(_startValue),endValue(_endValue),currentValue(_currentValue)
	{

	}
};
//! Main progress tracking class
/*! It creates a thread that periodically checks if there are tasks that need reporting.
It keeps a list of nested tasks.
*/
class TaskProgressManager
{
	typedef TaskInProgress Task;
	pthread_t thread;
	pthread_mutex_t mutex;
	double refTime;
	double sampleDelay;
	double reportDelay;
	bool running;
protected:
	int dirtyLine;
	vector<Task *> tasks;
	void Report(int taskNum);
public:
	void CleanLine();
protected:
	void Lock();
	void UnLock();
	void CheckTasks();
public:
	void NewTask(Task *task);
	void EndTask(const Task *task);
protected:
	void Run();// never should exit
	static void *EntryPoint(void *arg);
public:
	void Start();
	void Stop();
	TaskProgressManager(double sampleDelay,double reportDelay);
	~TaskProgressManager();
};

#endif // _TaskProgressManager_hpp
