/*********************************************************\
         __      __           __  __
        / /     / / _____    / / / / ______   __     __
       / /     / / /___  \  / / / / / ___  | / /    / /
      / /_____/ / _____| / / / / / / /__/ / / /    / /
     / ______  / / ___  / / / / / / _____/ / /    / /
    / /     / / / /__/ / / / / / / |____  / |____/ /
   /_/     /_/ |______/ /_/ /_/  \_____/  \_____  /
                                         ______/ /
            High Level Game Framework   /_______/

  ------------------------------------------------------

  Copyright (c) 2009 - Rodrigo Braz Monteiro.
  This file is subject to the terms of license.txt.

\*********************************************************/

#include "thread.h"
#include "SDL.h"
#include "SDL_thread.h"
#include "exception.h"
using namespace Halley;


Thread::Thread(bool _detached)
	: running(false)
	, detached(_detached)
	, thread(NULL)
{
}

Thread::~Thread()
{
	if (detached && thread) {
		// WARNING:
		// Catastrophe!
		// This can result in the application aborting its execution, but there's no better way to handle it
		throw Exception("Attempting to delete a detached thread");
	}
}

void Thread::Start()
{
	running = true;
	thread = SDL_CreateThread(RunThread, this);
}

int Thread::Wait()
{
	if (detached) {
		throw Exception("You can only wait on non-detached threads.");
	}

	assert (thread);
	int status;
	SDL_WaitThread(thread, &status);
	return status;
}

bool Thread::IsDone()
{
	if (detached) {
		throw Exception("You can only wait on non-detached threads.");
	}

	return !running;
}

int Thread::RunThread(void *data)
{
	Thread *thread = (Thread*) data;
	int status = thread->Run();
	thread->running = false;
	thread->thread = nullptr;
	if (thread->detached) delete thread;
	return status;
}

void Thread::async(std::function<void()> function)
{
	auto t = new FunctionVoidThread(function, true);
	t->Start();
}
