#include "holder.h"
#include "environment.h"
#include "util.h"
#include <atomic>

using std::shared_ptr;
using std::unique_ptr;

namespace catbox {

IsolateHolder::IsolateHolder(shared_ptr<IsolateEnvironment> isolate) : isolate(std::move(isolate)) {}

void IsolateHolder::Dispose() {
	shared_ptr<IsolateEnvironment> tmp = std::atomic_exchange(&isolate, shared_ptr<IsolateEnvironment>());
	if (tmp) {
		tmp->Terminate();
		tmp.reset();
	} else {
		throw js_generic_error("Isolate is already disposed");
	}
}

shared_ptr<IsolateEnvironment> IsolateHolder::GetIsolate() {
	return std::atomic_load(&isolate);
}

void IsolateHolder::ScheduleTask(unique_ptr<Runnable> task, bool run_inline, bool wake_isolate, bool handle_task) {
	shared_ptr<IsolateEnvironment> ref = std::atomic_load(&isolate);
	if (ref) {
		if (run_inline && IsolateEnvironment::GetCurrent() == ref.get()) {
			task->Run();
			return;
		}
		IsolateEnvironment::Scheduler::Lock lock(ref->scheduler);
		if (handle_task) {
			lock.PushHandleTask(std::move(task));
		} else {
			lock.PushTask(std::move(task));
		}
		if (wake_isolate) {
			lock.WakeIsolate(std::move(ref));
		}
	}
}

} // namespace catbox
