/* Main RPC function */
function RPC(name,args) {
	function args2Array(args) {
		var ret=Array();
		for (var i=0; i<args.length; i++) ret[i]=args[i];
		return ret;
	}
	function getXMLObject () {
		if (typeof(XMLHttpRequest)!='undefined') return new XMLHttpRequest();
		var ax=['Msxml2.XMLHTTP.6.0', 'Msxml2.XMLHTTP.4.0',
			'Msxml2.XMLHTTP.3.0', 'Msxml2.XMLHTTP',
			'Microsoft.XMLHTTP'];
		for (var i=0; i<ax.length; i++)
			try { return new ActiveXObject(ax[i]); }
			catch (e) {}
		return null;
	}
	function call(fnc,callback,args) {
		var async=(typeof callback=='function');
		var xmlhttp=getXMLObject();
		if (xmlhttp==null) {
			if (!RPC.complainedLoudly)
				alert("Your browser does not support\n"+
					"XMLHttpRequest in any known form");
				RPC.complainedLoudly=true;
				return false;
		}
		
		var content='params='+escape(Object.toPHP(args)).replace(/\//g,'%252F');
		var postdata='';
		var method='POST';
		
		var orst=function () {
			var x;
			if (xmlhttp.readyState==4)
				if (xmlhttp.status==200){
					try {
						eval('x = '+xmlhttp.responseText+';');
					} catch (e) {
						x={
							type:'error',
							message:'Server responded with non-JSON data:\n',
							fnc:fnc,
							args:args,
							response:xmlhttp.responseText
						};
					}
					if (async) {
						callback(x);
						return true;
					} else return x;
				}else{
					x={type:'error',message:xmlhttp.statusText,request:postdata};
					alert(x.toSource());
					if (async) {
						callback(x);
						return true;
					}
					else return x;
				}
		}
		if (async) xmlhttp.onreadystatechange=orst;
		xmlhttp.open(method,'/rpc/'+fnc+'/?'+postdata,async);
		if (method=='POST')
			xmlhttp.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
		xmlhttp.send(content);
		if (async) return true;
		else return orst();
	}
	var callback=null;
	args=args2Array(args);
	if (typeof args[0]=='function') callback=args.shift();
	return call(name,callback,args);	
}
RPC.async = function () {}
RPC.enumerateProcedures = function () {
	var ret=[];
	for (i in RPC) {
		switch (i) {
			case 'async': case 'prototype': case 'enumerateProcedures': case 'toPHP': break;
			default:
				ret.push(i);
			
		}
	}
	return ret;
}
/*
	Serialization functions for PHP-based server
	(we don't provide reverse, because the backend will return JSON objects)
*/
Object.toPHP = function(object) {
	var type = typeof object;
	if (typeof object.nodeName=='string') return 'N;';
	if (object==window) return 'N;';
	switch (type) {
		case 'undefined':
		case 'unknown': 
		case 'function':
			return 'N;';
	}
	if (object === null) return 'N;';
	if (object.toPHP) return object.toPHP();
	if (!!object.getAttribute) return null;
	var ret = [];
	for (var property in object) {
		var value = Object.toPHP(object[property]);
		if (value !== undefined)
			ret.push(Object.toPHP(property.toString())+value);
	}
	var ret='a:'+ret.length+':{'+ ret.join('')+'}';
	return ret;
}
Date.prototype.toPHP = function() {
  return 'i:'+this.getTime()+';';
}
String.prototype.toPHP = function () {
	var s=this.escapeUTF();
	return 's:'+s.length+':"'+s+'";';
};
String.prototype.escapeUTF = function  () {
	var charCode,ret = '';
	for (i=0; i<this.length; i++) {
		charCode = this.charCodeAt(i);
		ret+=((charCode <= 127) && (charCode >=32))?
			this.charAt(i):
			('&#x' + charCode.toString(16).toUpperCase() + ';');
	}
	return ret; 
};
Array.prototype.toPHP = function () {
	var ret=[];
	for (var index=0; index<this.length; index++)
		ret.push(Object.toPHP(index)+Object.toPHP(this[index]));
	return 'a:'+ret.length+':{'+ret.join('')+'}';
};
Number.prototype.toPHP = function () {
	return ((Math.floor(this)==this)?'i':'d')+':'+this.toString()+';';
};
Boolean.prototype.toPHP = function () {
	return 'b:'+(this?'1':'0')+';';
};
Function.prototype.toPHP = function () {
	return 'N;';
};
RPC.getlightdetailfromrandom = function () { return RPC('getlightdetailfromrandom',arguments); }
RPC.addservice = function () { return RPC('addservice',arguments); }
RPC.addindustry = function () { return RPC('addindustry',arguments); }
RPC.removeservice = function () { return RPC('removeservice',arguments); }
RPC.removeindustry = function () { return RPC('removeindustry',arguments); }
RPC.editpsi = function () { return RPC('editpsi',arguments); }
RPC.portfolioupdate = function () { return RPC('portfolioupdate',arguments); }
RPC.deleteclient = function () { return RPC('deleteclient',arguments); }
RPC.describephoto = function () { return RPC('describephoto',arguments); }
RPC.updatevanity = function () { return RPC('updatevanity',arguments); }
RPC.dropvanity = function () { return RPC('dropvanity',arguments); }
