//-----------------------------------------------------------------------------
// AScript win32dll module
//-----------------------------------------------------------------------------
#include "Module_win32dll.h"

AScript_BeginModule(win32dll)

//-----------------------------------------------------------------------------
// Object_Dll implementation
//-----------------------------------------------------------------------------
Object_Dll::~Object_Dll()
{
	Close();
}

Object *Object_Dll::Clone() const
{
	return NULL;
}

String Object_Dll::ToString(Signal sig, bool exprFlag)
{
	String str;
	str = "<win32dll.dll:";
	str += _fileName;
	str += ">";
	return str;
}

bool Object_Dll::Open(Signal sig, const char *fileName)
{
	_hModule = ::LoadLibrary(fileName);
	if (_hModule == NULL) {
		sig.SetError(ERR_IOError, "failed to open dll file %s", fileName);
		return false;
	}
	_fileName = fileName;
	return true;
}

void Object_Dll::Close()
{
	if (_hModule != NULL) {
		::FreeLibrary(_hModule);
		_hModule = NULL;
	}
}

//-----------------------------------------------------------------------------
// AScript interfaces for Object_Dll
//-----------------------------------------------------------------------------
// sample.Dll#close()
AScript_DeclareMethod(Dll, close)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
}

AScript_ImplementMethod(Dll, close)
{
	Object_Dll *pSelf = Object_Dll::GetSelfObj(args);
	pSelf->Close();
	return args.GetSelf();
}

// sample.Dll#proc(procname:string)
AScript_DeclareMethod(Dll, proc)
{
	SetMode(RSLTMODE_Normal, FLAG_None);
	DeclareArg(env, "procname", VTYPE_String);
}

AScript_ImplementMethod(Dll, proc)
{
	Object_Dll *pObjDll = Object_Dll::GetSelfObj(args);
	HMODULE hModule = pObjDll->GetModuleHandle();
	const char *procName = args.GetString(0);
	FARPROC proc = ::GetProcAddress(hModule, procName);
	Function_Proc *pFunc =  new Function_Proc(env, Symbol::Add(procName),
										Object_Dll::Reference(pObjDll), proc);
	Object_Function *pObjFunc = new Object_Function(env, pFunc, Value::Null);
	return Value(pObjFunc);
}

// implementation of class Dll
AScript_ImplementPrivClass(Dll)
{
	AScript_AssignMethod(Dll, close);
	AScript_AssignMethod(Dll, proc);
}

//-----------------------------------------------------------------------------
// Function_Proc implementation
//-----------------------------------------------------------------------------
Function_Proc::~Function_Proc()
{
	Object::Delete(_pObjDll);
}

Value Function_Proc::DoEval(Environment &env, Signal sig, Args &args) const
{
	_proc();
	return Value::Null;
}

//-----------------------------------------------------------------------------
// AScript module functions: win32dll
//-----------------------------------------------------------------------------
// obj = win32dll.open(filename:string):map
AScript_DeclareFunction(open)
{
	SetMode(RSLTMODE_Normal, FLAG_Map);
	DeclareArg(env, "filename", VTYPE_String);
}

AScript_ImplementFunction(open)
{
	Object_Dll *pObj = new Object_Dll();
	if (!pObj->Open(sig, args.GetString(0))) {
		Object::Delete(pObj);
		return Value::Null;
	}
	return Value(pObj);
}

// Module entry
AScript_ModuleEntry()
{
	// class realization
	AScript_RealizePrivClass(Dll, "dll", env.LookupClass(VTYPE_Object));
	// function assignment
	AScript_AssignFunction(open);
}

AScript_ModuleTerminate()
{
}

AScript_EndModule(win32dll, win32dll)

AScript_RegisterModule(win32dll)
