function _rpcShift(a) // not native in iemac)
{
	if (a.length)
	{
		var r = a[0];
		for (var n = 1;n < a.length; n++)
			a[n - 1] = a[n];
		a.length = a.length - 1;
		return r;
	}
	else return null;
}

function _rpcJsLit(s)
{
  s = s.replace(/\\/g, "\\\\");
  s = s.replace(/\"/g, "\\\"");
  s = s.replace(/\r/g, "\\r");
  s = s.replace(/\n/g, "\\n");
  
  return "\"" + s + "\"";
}

function _rpcFnName(fn)
{
	var s = fn.toString();
	var x = s.indexOf("function");
	if (x < 0) return null;
	x += 9;
	return s.substr(x, s.indexOf("(", x) - x);
}

function _rpcObjToString(o)
{
  var s = "null";
  var typ = o == null ? "null" : typeof o;
  
  if (typ == "object")
		if (o.constructor)
		{
			var con = _rpcFnName(o.constructor);
			switch (con)
			{
				case "Number":
					typ = "number";
					break;
	        
				case "String":
					typ = "string"
					break;
	        
				case "Boolean":
					typ = "boolean"
					break;
	        
				case "Array":
				case "Date":
				case "RegExp":
					typ = con;
					break;
			}
		}
		else
			typ = "undefined";
  
  switch (typ)
  {
    case "number":
    case "boolean":
      s = o.toString();
      break;
      
    case "string":
      s = _rpcJsLit(o);
      break;
      
    case "Array":
      s = "[";
      for (var n = 0; n < o.length; n++)
      {
        if (n != 0)
          s += ",";
        s += _rpcObjToString(o[n]);
      }
      s += "]";
      break;
      
    case "object":
      s = "{";
      var bFirst = true;
      for (var p in o)
      {
        if (bFirst)
          bFirst = false;
        else
          s += ",";
        s += p;
        s += ":";
        s += _rpcObjToString(o[p]);
      }
      s += "}";
      break;
  }
  
  return s;
}

function _rpcEscape(s)
{
	var p1 = 0;
	var p2 = 0;
	var s2 = "";
	while (p2 < s.length)
	{
		var esc = null;
		var ch = s.charCodeAt(p2);
		if (ch == 43) esc = String.fromCharCode(127, 90); //+
		else if (ch >= 126)
		  if (ch <= 209) esc = String.fromCharCode(126, ch - 82);
		  else esc = String.fromCharCode(127, ch - 166);
		if (esc)
		{
			s2 += s.substr(p1, p2 - p1) + esc;
			p1 = p2 + 1;
		}
		p2++;
	}
	if (p1 != 0) s = s2 + s.substr(p1, p2 - p1);
	return s;
}

function _rpcTimeout()
{
	if (!_rpc.current) return;
	var rpcObj = _rpc.current;
	rpcObj.inTimeout = true;
	if (!rpcObj.silentTimeout && confirm("There is a delay in contacting our server. Click OK to continue trying."))
	{
		rpcObj.inTimeout = false;
		if (rpcObj.completed)
			_rpcSuccess(rpcObj);
		else
			rpcObj.timeoutId = setTimeout("_rpcTimeout()", rpcObj.timeout);
	}
	else
	{
		rpcObj.inTimeout = false;
		_rpc.current = null;
		if (rpcObj.onCompletion)
		{
			var obj = new Object();
			obj.timeout = true;
			rpcObj.onCompletion(obj, rpcObj.passthru);
		}
		_rpc.busy = false;
		_rpcStart();
	}
}

function _rpcSend(ticket)
{
	if (!_rpc.current) return;
	var first = ticket == null;
	var rpcObj = _rpc.current;
	if (ticket)
	{
		if (ticket.ticket != rpcObj.ticket) return; // a stray onLoad?
		if (ticket.error)
		{
			if (rpcObj.onCompletion)
				rpcObj.onCompletion(ticket, rpcObj.passthru);
			_rpc.current = null;
			_rpc.busy = false;
			_rpcStart();
			return
		}
		else ticket = ticket.ticket;
	}
	else ticket = rpcObj.ticket;
	var svr = rpcObj.svr + '?';
	var maxlen;
	if (_rpc.Post)
		maxlen = rpcObj.sObj.length;
	else
	{
		maxlen = _rpc.MaxUrl || 1900;
		if (ticket) maxlen -= ticket.length + 1;
		if (maxlen < 5) maxlen = 5;
		if (rpcObj.sObj.length > maxlen) 
		{
			// if there is a percent in the last 3 places, we back off a bit
			var pct = rpcObj.sObj.lastIndexOf('%', maxlen - 1);
			if (pct >= maxlen - 3) 
				maxlen = pct;
		}
	}
	var data;
	if (rpcObj.sObj.length <= maxlen) // can send all
	{
		data = rpcObj.sObj;
		rpcObj.sObj = null;
	}
	else
	{
		data = rpcObj.sObj.substr(0, maxlen);
		rpcObj.sObj = rpcObj.sObj.substr(maxlen);
	}
	var tag;
	if (first)
		tag = rpcObj.sObj ? 'B' : 'A';
	else
		tag = rpcObj.sObj ? 'C' : 'D';
	data = tag + ticket + '.' + data;
	if (_rpc.Post)
	{
		var html = "<form name=rpc method=post action=" + rpcObj.svr + ">";
		for (var inx = 0; inx * 100000 < data.length; inx++)
		  html += "<input type=hidden name=rpc" + inx.toString() + ">";
		html += "</form>";
		_rpc.IFrameDoc.body.innerHTML = html;
		for (var inx = 0; inx * 100000 < data.length; inx++)
			_rpc.IFrameDoc.rpc["rpc" + inx.toString()].value = data.substr(inx * 100000, 100000);
		_rpc.IFrameDoc.rpc.submit();
	}
	else
	{
		url = svr + data;
		_rpc();
		_rpc.IFrameDoc.location.replace(url);
	}
	if (rpcObj.timeout)
		rpcObj.timeoutId = setTimeout("_rpcTimeout()", rpcObj.timeout);
}

function _rpcSuccess(o)
{
	if (o.onCompletion)
		o.onCompletion(o.parm, _rpc.current.passthru);
	_rpc.current = null;
	_rpc.busy = false;
	_rpcStart();
}

//function _rpcDeferredSend(ticket)
//{
//	var fn = "_rpcSend(" + _rpcObjToString(ticket) + ")";
//	setTimeout(fn, 1);
//}

function _rpcOnLoad(parm)
{
	var rpcObj = _rpc.current;
	if (rpcObj)
	{
		if (parm.ticket != rpcObj.ticket) return;
		if (rpcObj.timeoutId) 
		{
			clearTimeout(rpcObj.timeoutId);
			rpcObj.timeoutId = null;
		}
		if (rpcObj.sObj == null) // finished
		{
			rpcObj.parm = parm;
			if (rpcObj.inTimeout)
				rpcObj.completed = true;
			else
				_rpcSuccess(rpcObj);
		}
		else // more to send
			_rpcSend(parm);
			//_rpcDeferredSend(parm);
	}
	else
		_rpcStart();
}

function _rpc()
{ // return of false indicates success
	if (document.frames)
 		_rpc.IFrameObj = document.frames['_RpcFrame']; //iemac
	else 
		_rpc.IFrameObj = document.getElementById('_RpcFrame')
  if (_rpc.IFrameObj.contentDocument) // For NS6
    _rpc.IFrameDoc = _rpc.IFrameObj.contentDocument; 
  else if (_rpc.IFrameObj.contentWindow) // For IE5.5 and IE6
    _rpc.IFrameDoc = _rpc.IFrameObj.contentWindow.document;
  else if (_rpc.IFrameObj.document) // For IE5
    _rpc.IFrameDoc = _rpc.IFrameObj.document;
  else 
    return true;
    
  return false;
}

function _rpcAbsUrl(url)
{
	if (url.indexOf("://") < 0) // not absolute
	{
		if (url.charAt(0) == '/') // prepend protocol and server name only
		{
			var pos = document.URL.indexOf("://");
			if (pos >= 0)
			{
				pos = document.URL.indexOf('/', pos + 3);
				if (pos >= 0)
					url = document.URL.substr(0, pos) + url;
			}
		}
		else // prepend entire path
		{
			var spos = document.URL.lastIndexOf('/');
			if (spos >= 0)
			{
				var dpos = document.URL.indexOf('.', spos);
				if (dpos > 0) // page
					url = document.URL.substr(0, spos + 1) + url;
				else if (spos == document.URL.length - 1)
					url = document.URL + url;
				else url = document.URL + '/' + url;
			}
		}
	}
	return url;
}

function _rpcStart()
{
	if (!_rpc.busy && _rpc.queue && _rpc.queue.length)
	{ 
		_rpc.busy = true;
		//rpcObj = _rpc.queue.shift();
		rpcObj = _rpcShift(_rpc.queue);
		_rpc.current = rpcObj;
		//_rpc(); // setup // for the sake of IE XP sp2, we need to do this before every send
		_rpcSend();
	}
}

function _rpcSetMaxPacket(max)
{
	_rpc.MaxUrl = max;
}

function _rpcSetPost(val)
{
	_rpc.Post = val;
}

function RPC(svr, fn, obj, onCompletion, timeout, passthru)
{
	if (obj) obj._referrer = document.location.href;
	if (!_rpc.nextTicket) _rpc.nextTicket = 1;
	var rpcObj = new Object();
	if (timeout == null) timeout = 5000;
	if (timeout < 0) // no error report
	{
		timeout = -timeout;
		rpcObj.silentTimeout = true;
	}
	if (_rpc.queue == null) _rpc.queue = [];
	rpcObj.sObj = fn + ':' + _rpcObjToString(obj);
	if (!_rpc.Post)
		rpcObj.sObj = escape(_rpcEscape(rpcObj.sObj));
	rpcObj.onCompletion = onCompletion;
	rpcObj.svr = _rpcAbsUrl(svr);
	rpcObj.timeout = timeout;
	rpcObj.passthru = passthru;
	rpcObj.ticket = (_rpc.nextTicket++).toString();
	_rpc.queue[_rpc.queue.length] = rpcObj; // no push on IE mac
	_rpcStart();
}

function CheckRPC(obj, fullinfo)
{
  if (obj && obj.error == 0)
    if (obj.ok) return true;
    else alert(obj.msg);
  else if (!obj.timeout)
  {
		var msg = "A server error occurred. Please try again later.";
		if (fullinfo && obj.errmsg) msg += "\r\n\r\n[" + obj.errmsg + "]";
		alert(msg);
	}
}