//
// Object_Semaphore
//

#include "ascript/Object_Semaphore.h"

namespace AScript {

//-----------------------------------------------------------------------------
// Object_Semaphore
//-----------------------------------------------------------------------------
Object_Semaphore::~Object_Semaphore()
{
}

Object *Object_Semaphore::Clone() const
{
	return new Object_Semaphore(*this);
}

String Object_Semaphore::ToString(Signal sig, bool exprFlag)
{
	String str;
	str += "<semaphore:";
	str += ">";
	return str;
}

//-----------------------------------------------------------------------------
// AScript interfaces for Object_Semaphore
//-----------------------------------------------------------------------------
// semaphore#wait()
AScript_DeclareMethod(Semaphore, wait)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	SetHelp(
	"Watis for the semaphore being released by other threads, and ghen grabs\n"
	"that ownership.");
}

AScript_ImplementMethod(Semaphore, wait)
{
	Object_Semaphore *pSelf = Object_Semaphore::GetSelfObj(args);
	pSelf->GetSemaphore().Wait();
	return Value::Null;
}

// semaphore#release()
AScript_DeclareMethod(Semaphore, release)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	SetHelp("Releases the owership of the semaphore that is grabbed by semaphore#wait().");
}

AScript_ImplementMethod(Semaphore, release)
{
	Object_Semaphore *pSelf = Object_Semaphore::GetSelfObj(args);
	pSelf->GetSemaphore().Release();
	return Value::Null;
}

// semaphore#session()
AScript_DeclareMethod(Semaphore, session)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareBlock(OCCUR_Once);
	SetHelp(
	"Forms a critical session by grabbing the semaphore's ownership, executing\n"
	"the block and releasing that ownership. It internally proccesses the same\n"
	"job as semaphore#wait() and semaphore#release() before and after the block\n"
	"execution");
}

AScript_ImplementMethod(Semaphore, session)
{
	Object_Semaphore *pSelf = Object_Semaphore::GetSelfObj(args);
	const Function *pFuncBlock =
						args.GetBlockFunc(env, sig, GetSymbolForBlock());
	if (sig.IsSignalled()) return Value::Null;
	pSelf->GetSemaphore().Wait();
	Environment envBlock(&env, ENVTYPE_Block);
	Args argsSub(ValueList::Null);
	Value result = pFuncBlock->Eval(envBlock, sig, argsSub);
	pSelf->GetSemaphore().Release();
	return result;
}

// assignment
Class_Semaphore::Class_Semaphore(Environment *pEnvOuter) : Class(pEnvOuter)
{
	AScript_AssignMethod(Semaphore, wait);
	AScript_AssignMethod(Semaphore, release);
	AScript_AssignMethod(Semaphore, session);
}

Object *Class_Semaphore::CreateDescendant(Environment &env, Signal sig, Class *pClass)
{
	ERROREND(env, "this function must not be called");
	return NULL;
}

}
