<?php

//*****************************************************************
// function Return(x)
//	This function is used to translate the data in given variable x,
//	into a string for transport to the client.  If the variable
//	is an object, then the type is set to EVAL_OBJECT to indicate 
//	to the client that this is an object being marshalled and it 
//	should be "evaluated".  
//*****************************************************************
function ReturnX($x)
{
	$returnType = gettype($x);
	if ($returnType == 'object' || $returnType == 'array')
		return '<RETURN_VALUE TYPE=EVAL_OBJECT>' . rawurlencode(uneval($x)) . '</RETURN_VALUE>';
	else
		return '<RETURN_VALUE TYPE=SIMPLE>' . rawurlencode($x) . '</RETURN_VALUE>';
}

//*****************************************************************
// function RSDispatch()
//	This function is used to dispatch to the proper server
//	function in the public_description object based on the
//	Request.QueryString("_method") parameter passed in.
//
//*****************************************************************
function RSDispatch($vtable = "", $methodname= "")
{
	global $_mtype, $_method, $pcount, $public_description;

	if ((gettype($methodname) != "string") || ($methodname == "")) {
		$methodtype = $_mtype;
		if ($methodtype != "execute")
			return false;
		$methodname = $_method;
		if ($methodname == "" || $methodname == "undefined")
			return false;
	}

	$dispatchVTbl = "";
	if (gettype($vtable) == "object")
		$dispatchVTbl = $vtable;
	else if (gettype($public_description) == "object")
		$dispatchVTbl = $public_description;
	if ($dispatchVTbl == "")
		return false;

	$strResponse = "<METHOD VERSION='1.0.8044'>";
	if ($methodname == "GetServerProxy") {
//	$strResponse .= ReturnX(GetServerProxy($dispatchVTbl));
		$strResponse .= ReturnX($dispatchVTbl);
	} else {
##!!!if (gettype($dispatchVTbl->$methodname) == "user function") {
		if (method_exists($dispatchVTbl,$methodname)) {
//echo "METHOD EXISTS <br>\n";
			// validate function is in dispatchVTbl
			$params = "";
			for ($i=0; $i < $pcount; $i++) {
				// extract parameter values
				$param = $GLOBALS['p' . $i];
				$params .= '"' . $param . '"';
				if ($i < $pcount - 1)
					$params .= ',';
			}

			$dispatch = '$dispatchVTbl->' . $methodname . '(' . $params . ');';		
			// Response.write(dispatch);	// USED FOR DEBUG
			// validated against dispatchVTbl, safe to eval on the server
			eval("\$r = ".$dispatch);
			$strResponse .= ReturnX($r);
		}
		else
		{
			$strError = '<RETURN_VALUE TYPE=ERROR>';
			$strError .= rawurlencode($methodname) . ' : not a public function';
			$strError .= '</RETURN_VALUE>';
			$strResponse .= $strError;
		}
	}
	$strResponse .= '</METHOD>';
	
	print($strResponse);
	return true;
}

//*****************************************************************
// function uneval(obj) 
//	This function takes a given jscript object and creates a 
//	string representing the object instance in its current state, 
//	such that when the string is "evaluated" with the "eval" 
//	function, the object will be recreated. This function is used 
//	to to "marshall" jscript objects across the client/server
//	boundary.
//
//*****************************************************************
$unevalNextID = 0;

function unevalGetNextID() {
	global $unevalNextID;
	return '_o' . $unevalNextID++;
}

function uneval($obj) {
	global $unevalNextID;
	$unevalNextID = 0;
	$s = 'var undefined;' . unevalDecl(&$obj) . unevalInst(&$obj);
	unevalClear(&$obj);
	return $s;
}

function isPublic($member) {
	return (substr($member, 0, 2) != "__");
}

function unevalDecl($obj) {
	$s = '';
//echo "OBJECT $obj TYPE". gettype($obj);

	switch (gettype($obj)) {
	
	case 'boolean':   ###!!!added for PHP4
	case 'integer':
	case 'double':
	case 'string':
		break;

	case 'array':
// echo "in the array loop\n";
		$s = array_unevalDecl($obj);
		break;
		
	case 'object':
		if ($obj->__mark){ 
			$s = '"ERROR: Cycle in uneval graph."';
			}
		else {
			$obj->__mark = true;
			$obj->__decl = unevalGetNextID();
			$s = obj_unevalDecl($obj);
			unset($obj->__mark);
		}
		break;
	default:
		die("Decl: OBJ $obj is of Unknown type :". gettype($obj));
	}
	return $s;
}

function unevalInst($obj) {
	switch (gettype($obj)) {

	case 'integer':
	case 'boolean': ###!!! php4     
	case 'double':
		$s = $obj;
		break;
		
	case 'string':
		$s = unevalString($obj);
		break;

	case 'object':
		$s = $obj->__decl;
		break;
		
	case 'array':
		break;
		
	default:
		die("Inst: Unknown type");
	}
	return $s;
}

function unevalClear($obj)
{
	switch (gettype($obj)) {
	
	case 'boolean': ##!!! php4
	case 'double':
	case 'integer':
	case 'string':
	case 'array':
		break;

	case 'object':
		obj_unevalClear($obj);
		break;
		
	default:
		die("Clear: Unknown type");
	}
	return ;
}

function unevalDoNothing() {
}

function unevalConvertToString($obj) {
	return String($obj);		
}

function unevalString($str) {
	return '"' . addslashes($str) . '"'; 	
//return '"' . str.replace(/([^\\])'/g,'$1\\"') . '"'; 	
}

function obj_unevalDecl($obj) {
	$retval = array( "otherDecl" => '', "myDecl" => '' );
	
	reset($obj);
	while( list($key, $val) = each($obj)) {
		if (isPublic($key)) {
## !!!if (gettype($val) == 'user function') {
			if (method_exists($obj,$val)) {
				$retval["otherDecl"] .= "function ". $obj->__decl . "_". $key . "() { return 0; }";
				$retval["myDecl"] .= $obj->__decl . '[' . unevalString($key) . ']=' . $obj->__decl . "_". $key . ';';
			} else {
				$retval["otherDecl"] .= unevalDecl(&$obj->$key);
				$retval["myDecl"] .= $obj->__decl . '[' . unevalString($key) . ']=' . unevalInst(&$obj->$key) . ';';
			}
		}
	}
	return $retval[otherDecl] . 'var ' . $obj->__decl . '= new Object;' . $retval[myDecl];
}

function obj_unevalClear($obj) {
	unset($obj->__decl);
	reset($obj);
	while( list($key, $val) = each($obj)) {
		if (gettype($val) == 'object')
			obj_unevalClear($obj->$val);
	}
}

function array_unevalDecl($obj) {
	$__decl = unevalGetNextID();
	$r = '';
	$s = 'var ' . $__decl . '= new Array(' . count($obj) . ');';
	for ($i = 0; $i < count($obj); $i++) {
##!!!!!!
		$r .= unevalDecl($obj[$i]);
		$s .= $__decl . '[' . $i . ']=' . unevalInst($obj[$i]) . ';';
	}
	return $r . $s . $__decl . ';';
}

?>