#include "ThreadedImageLoader.h"

#define LLOG(x) TLOG(x)

String LogTime()
{
	String out;
	out << GetSysTime() << " % " << (dword)msecs() % 10000;
	return out;
}

String LogContext()
{
	String out = LogTime();
	out << ", t=" << (int)GetCurrentThreadId() << ": ";
	return out;
}

#define TLOG(x) RLOG(LogContext() << x);

ImageLoader::ImageLoader() :
ready_to_load_(false),
time_to_die_(false),
new_image_ready_(false),
status_("Thread not started") {
	LLOG("LoadingThread> "+status_);
}

void ImageLoader::LoadingThreadFunction()
{
	// Repeat until time_to_die, then exit
	ready_to_load_ = true;
	while (!time_to_die_) {
		status_ = "Waiting for job";
		LLOG("Wait");
		job_ready_.Wait();
		LLOG("//Wait");
		if (time_to_die_)
			break;

		status_ = "Loading";
		LLOG("StdLoadImage");
		loading_info_.image = StdLoadArrayFile(loading_info_.filepath).pixel;
		LLOG("//StdLoadImage");
		//------------------------------------------------------
		Size cachesize = GetFitSize(loading_info_.image.GetSize(), ScreenInfo().GetClip().Size());
		LLOG("Image ctr");
//		Image cacheimage(cachesize);
		LLOG("//Image ctr");
		LLOG("srcim");
		const PixelArray& srcim = loading_info_.image;
//		PixelArray srcim(ImageToPixelArray(loading_info_.image));
		LLOG("dstim");
		PixelArray dstim(cachesize, -3);
//		PixelArray dstim(ImageToPixelArray(cacheimage));
		//-- Either just resize or resize with anti-aliasing
		//PixelCopy(dstim,cacheimage.GetSize(),srcim,loading_info_.image.GetSize());
		TLOG("PixelCopyAntiAlias");
		PixelCopyAntiAlias(dstim,dstim.GetSize(),srcim,srcim.GetSize());
		TLOG("//PixelCopyAntiAlias");
		loading_info_.image = dstim; //PixelArrayToImage(dstim);
		TLOG("//PixelArrayToImage");
		//------------------------------------------------------
		loading_info_.valid = true;
		status_ = "Image ready";
		LLOG("LoadingThread> "+status_);
		new_image_ready_ = true;
		ready_to_load_ = true;
		PostCallback(WhenImageReady);
	}
	status_ = "Finished";
	//LLOG("LoadingThread> "+status_);
//	Thread::Exit(0);
}
void ImageLoader::LoadNextImage(const ThreadedImageLoadInfo& info)
{
	Reset();
	ready_to_load_ = false;

	ThreadedImageLoadInfo& blah = loading_info_;
	blah = info;
	loading_info_.image = PixelArray();
	loading_info_.valid = false;

	TLOG("LoadNextImage / Set");
	job_ready_.Set();
	TLOG("//LoadNextImage / Set");
}
void ImageLoader::Die()
{
	WhenImageReady = Callback::Empty();
	new_image_ready_ = false;
	time_to_die_ = true;
	ready_to_load_ = false;
	status_ = "Terminating";
	job_ready_.Set();
}

ThreadedImageLoader::ThreadedImageLoader()
{
	CtrlLayout(*this, "Threaded Image Loader");
	AddFrame(menus);
	menus.Set(THISBACK(SetupMainMenu));
	loader.WhenImageReady = THISBACK(OnImageLoaded);
	loader_thread.Run(callback(&loader,ImageLoader::LoadingThreadFunction));
	loader_thread.Priority(0);
	Zoomable().Sizeable();
	SetTimeCallback(-200, THISBACK(SyncTime));
}
ThreadedImageLoader::~ThreadedImageLoader()
{
	loader.Die();
	loader_thread.Wait();
}
void ThreadedImageLoader::SyncTime()
{
	time <<= LogTime();
}
void ThreadedImageLoader::OnImageLoaded() {
	TLOG("OnImageLoaded, display.SetImage");
	display.SetImage(PixelArrayToImage(loader.Result().image));
	TLOG("//display.SetImage");
	TLOG("Loaded Image: "+loader.Result().filepath);
	if (!remaining.IsEmpty()) {
		TLOG(" - next is: "+remaining.Top());
		loader.LoadNextImage(remaining.Pop());
	}
}
void ThreadedImageLoader::OnSelectDir() {
	FileSel filesel;
	filesel.Type("All Images","*.jpg;*.png;*.bmp;*.jpeg");
	filesel.Type("All files","*.*");
	if (!filesel.ExecuteSelectDir("Select directory")) {
		return;
	}
	remaining.Clear();
	String dirname = filesel;
	FindFile ff(dirname + "\\*.jpg");
	while (ff.Next()) {
		remaining.Insert(0,dirname+"\\"+ff.GetName());
	}
	LLOG("Adding files to load list from directory: "+dirname);
	for (int i = 0; i < remaining.GetCount(); ++i)
		LLOG(" "+remaining[i]);

	if (!remaining.IsEmpty())
		loader.LoadNextImage(remaining.Pop());
}
void ThreadedImageLoader::SetupMainMenu(Bar& bar)
{
	bar.Add("[E&xit]",THISBACK(Close)).Key(K_CTRL_E);
	bar.Add("[Select &Directory]",THISBACK(OnSelectDir)).Key(K_CTRL_D);
}

GUI_APP_MAIN
{
	JpgEncoder::Register();
	ThreadedImageLoader().Run();
}
