#include <CtrlLib/CtrlLib.h>
using namespace Upp;

class BackgroundTask{
	typedef BackgroundTask CLASSNAME;
	#ifdef _MULTITHREADED
	Thread t;
	#endif
	bool running;
	const int id;
	static Index<int> list;

	void Watch(Callback task);
	static int AssignId();

	friend bool ProcessForeground(int);
public:
	void Start(Callback task);
	void Stop()                                      {int n=list.Find(id); if(n>=0) list.Remove(id);}
	int GetId()                                      {return id;}
	bool IsRunning()                                 {return running;}
	BackgroundTask():running(false),id(AssignId())   {}
	BackgroundTask(Callback task):id(AssignId())     {Start(task);}
};
Index<int> BackgroundTask::list;

void BackgroundTask::Watch(Callback task){
	running=true;
	task();
	Stop();
	running=false;
}

int BackgroundTask::AssignId(){
	static int sid=0;
	return sid++;
}

void BackgroundTask::Start(Callback task){
	if(IsRunning()) Stop();
	list.Add(id);
	#ifdef _MULTITHREADED
	t.Run(THISBACK1(Watch,task));
	#else
	PostCallback(THISBACK1(Watch,task));
	#endif
}

bool ProcessForeground(int id){
#ifndef _MULTITHREADED
	Ctrl::ProcessEvents();
#endif
	return BackgroundTask::list.Find(id)>=0;
}

class App:public TopWindow {
	typedef App CLASSNAME;
	BackgroundTask b;
	TimeStop t;
public:
	void DoSomethingSlow(){
		for(int i=0;i<500;i++){
			Sleep(10);
			if(!ProcessForeground(b.GetId()))
				return;
		}
	}
	void Check(){
		if(b.IsRunning())
			Title("Doing something slow ("+AsString(t.Elapsed()/1000.0)+" seconds)");
		else
			Title("Finished");
	}
	virtual void Close(){
		b.Stop();
		TopWindow::Close();
	}
	App(){
		Title("Started");
		t.Reset();
		SetTimeCallback(-250,THISBACK(Check));
		b.Start(THISBACK(DoSomethingSlow));
	}
};

GUI_APP_MAIN{
	App().Sizeable().Run();
}
