void VJSTimer::_SetTimer (VJSParms_callStaticFunction &ioParms, VJSWorker *inWorker, bool inIsInterval) 
{
	xbox_assert(inWorker != NULL);

	if (!ioParms.CountParams())
		
		return;

	XBOX::VJSContext	context(ioParms.GetContext());
	XBOX::VJSObject		functionObject(context);

	ioParms.GetParamObject(1, functionObject);
	if (!functionObject.IsFunction())

		return;

	functionObject.Protect();

	Real	duration;

	duration = 0.0;
	if (ioParms.CountParams() >= 2) {

		if (ioParms.IsNumberParam(2)) {
			
			if (!ioParms.GetRealParam(2, &duration))
			
				duration = 0.0;

		} else {

			// According to specification, if timeout is an object, call its toString() method if any. 
			// Then apply ToNumber() on the string to obtain duration.
			
			XBOX::VJSObject	timeOutObject(context);

			if (ioParms.GetParamObject(2, timeOutObject)) {

				timeOutObject.SetContext(context);
				if (timeOutObject.HasProperty("toString")) {

					XBOX::VJSObject	toStringObject = timeOutObject.GetPropertyAsObject("toString");

					if (toStringObject.IsFunction()) {

						std::vector<XBOX::VJSValue>	values;
						XBOX::VJSValue				string(context);

						toStringObject.SetContext(context);
						timeOutObject.CallFunction(toStringObject, &values, &string, NULL);

						if (string.IsString()) {

							// If Number() is called as a function (and not as a constructor), it acts as ToNumber().
							// See section 15.7.1 of ECMA-262 specification.

							XBOX::VJSObject	toNumberObject = context.GetGlobalObject().GetPropertyAsObject("Number");

							if (toNumberObject.IsFunction()) {

								XBOX::VJSValue	number(context);

								values.clear();
								values.push_back(string);
								toNumberObject.SetContext(context);
								context.GetGlobalObject().CallFunction(toNumberObject, &values, &number, NULL);

								if (number.IsNumber() && !number.GetReal(&duration))

									duration = 0.0;

							}

						}

					}

				}

			}
		
		}

		// (value != value) is true if value is a NaN.

		if (duration < 0.0 || duration > XBOX::kMAX_Real || duration != duration)
		
			duration = 0.0;

	}	
	
	std::vector<XBOX::VJSValue> *arguments;

	arguments = new std::vector<XBOX::VJSValue>;
	for (sLONG i = 3; i <= ioParms.CountParams(); i++) 

		arguments->push_back(ioParms.GetParamValue(i));

	sLONG		period, id;
	VJSTimer	*timer;

	period = (sLONG) duration;
	if (inIsInterval) {

		if (period < VJSTimer::kMinimumInterval)

			period = VJSTimer::kMinimumInterval;

	} else {

		if (period < VJSTimer::kMinimumTimeout)

			period = VJSTimer::kMinimumTimeout;

	}		 
	timer = new VJSTimer(functionObject, inIsInterval ? period : VJSTimer::kTimeOut);
	if ((id = inWorker->GetTimerContext()->InsertTimer(timer)) < 0) {

		// Too many timers (should never happen). Silently ignore. 
		// Returned ID (-1) isn't valid and a clear on it, will do nothing.

		timer->Release();
		delete arguments;
	
	} else {

		XBOX::VTime	triggerTime;
	
		triggerTime.FromSystemTime();
		triggerTime.AddMilliseconds(period);

		inWorker->QueueEvent(VJSTimerEvent::Create(timer, triggerTime, arguments));

	}

	ioParms.ReturnNumber(id);
}
void VJSStream::_PutBinary (VJSParms_callStaticFunction &ioParms, XBOX::VStream *inStream)
{
	xbox_assert(inStream != NULL);

	XBOX::VJSObject	binaryObject(ioParms.GetContext());
		
	if (!ioParms.GetParamObject(1, binaryObject)) {
	
		XBOX::vThrowError(XBOX::VE_JVSC_WRONG_PARAMETER, "1");
		return;

	} 

	bool			isBuffer;
	VJSBufferObject	*buffer;
	VJSDataSlice	*dataSlice;
	const void		*data;
	VSize			size;

	if (binaryObject.IsOfClass(VJSBufferClass::Class())) {
		
		isBuffer = true;

		buffer = binaryObject.GetPrivateData<VJSBufferClass>();
		xbox_assert(buffer != NULL);

		buffer->Retain();

		data = buffer->GetDataPtr();
		size = buffer->GetDataSize();

	} else if (binaryObject.IsOfClass(VJSBlob::Class())) {

		VJSBlobValue	*blob;

		isBuffer = false;

		blob = binaryObject.GetPrivateData<VJSBlob>();
		xbox_assert(blob != NULL);

		dataSlice = blob->RetainDataSlice();
		xbox_assert(dataSlice != NULL);
		
		data = dataSlice->GetDataPtr();
		size = dataSlice->GetDataSize();

	} else {

		XBOX::vThrowError(XBOX::VE_JVSC_WRONG_PARAMETER, "1");
		return;

	}

	bool	isOk;
	sLONG	index, length;

	isOk = true;	
		
	if (ioParms.CountParams() >= 2) {
		
		if (!ioParms.GetLongParam(2, &index)) {

			XBOX::vThrowError(XBOX::VE_JVSC_WRONG_PARAMETER_TYPE_NUMBER, "2");
			isOk = false;

		} 

	} else

		index = 0;

	if (isOk && ioParms.CountParams() >= 3) {
		
		if (!ioParms.GetLongParam(3, &length)) {

			XBOX::vThrowError(XBOX::VE_JVSC_WRONG_PARAMETER_TYPE_NUMBER, "3");
			isOk = false;

		} 

	} else {

		length = (sLONG) size;
		if (index > 0)

			length -= index;

	}

	// Silently ignore if out of bound.

	if (isOk && index >= 0 && length > 0 && index + length <= size) {

		XBOX::VError	error;

		if ((error = inStream->PutData((uBYTE *) data + index, length)) != XBOX::VE_OK)

			XBOX::vThrowError(error);

	}

	if (isBuffer)

		buffer->Release();

	else

		dataSlice->Release();

}
void VJSRequireClass::_evaluate (VJSParms_callStaticFunction &ioParms, void *)
{
	XBOX::VJSContext	context(ioParms.GetContext());
	XBOX::VString		fullPath;
	XBOX::VJSObject		exportsObject(context), moduleObject(context);

	if (!ioParms.GetStringParam(1, fullPath)) {
		
		XBOX::vThrowError(XBOX::VE_JVSC_WRONG_PARAMETER_TYPE_STRING, "1");
		return;

	}

	if (!ioParms.GetParamObject(2, exportsObject)) {

		XBOX::vThrowError(XBOX::VE_JVSC_WRONG_PARAMETER_TYPE_OBJECT, "2");
		return;

	}

	if (!ioParms.GetParamObject(3, moduleObject)) {

		XBOX::vThrowError(XBOX::VE_JVSC_WRONG_PARAMETER_TYPE_OBJECT, "3");
		return;

	}

	XBOX::VError	error;
	XBOX::VURL		url;
	XBOX::VString	script;
		
	if ((error = VJSModuleState::LoadScript(fullPath, &url, &script)) != XBOX::VE_OK) {

		if (error == XBOX::VE_JVSC_SCRIPT_NOT_FOUND) {

			// Should not happen as require() does already check for existence.

			XBOX::vThrowError(XBOX::VE_JVSC_SCRIPT_NOT_FOUND, fullPath);

		} else

			XBOX::vThrowError(error);
			
	} else {

		XBOX::VFilePath	path(fullPath, FPS_POSIX);
		XBOX::VFile		*file;
			
		if ((file = new XBOX::VFile(path)) == NULL) {

			XBOX::vThrowError(XBOX::VE_MEMORY_FULL);
			
		} else {

			context.GetGlobalObjectPrivateInstance()->RegisterIncludedFile(file);

			XBOX::VString				functionScript;
			XBOX::VJSValue				functionResult(context);
			XBOX::JS4D::ExceptionRef	exception;			

			// Make a function of the module script, then call it.
			
			functionScript.AppendString("(function (exports, module) {");
			functionScript.AppendString(script);
			functionScript.AppendString("})");

			if (!context.EvaluateScript(functionScript, &url, &functionResult, &exception)) {
						
				ioParms.SetException(exception);	// Syntax error.

			} else {

				xbox_assert(functionResult.IsFunction());

				XBOX::VJSObject				functionObject(context);
				std::vector<XBOX::VJSValue>	arguments;
				XBOX::VJSValue				result(context);

				functionObject.SetObjectRef((XBOX::JS4D::ObjectRef) functionResult.GetValueRef());
	
				arguments.push_back(exportsObject);
				arguments.push_back(moduleObject);

				if (!context.GetGlobalObject().CallFunction(functionObject, &arguments, &result, &exception, &path)) 

					ioParms.SetException(exception);

				else 

					ioParms.ReturnValue(result);

			}

			XBOX::ReleaseRefCountable<XBOX::VFile>(&file);

		}

	}	
}