// +---------------------------------+
// | RPC client                      |
// | Copyright (C) 2007 Craig Manley |
// +---------------------------------+
// $Id: RpcClient.js,v 1.6 2011-12-18 14:13:03 cmanley Exp $

// Make sure the required jsolait scripts are loaded.
// /js/jsolait/init.js
// /js/jsolait/lib/urllib.js
// /js/jsolait/lib/xml.js
// /js/jsolait/lib/xmlrpc.js


// Initialize xmlrpc module and set xmlrpc global.
var xmlrpc = null;
try {
	xmlrpc = importModule('xmlrpc');
}
catch(e) {
	try { reportException(e); } catch(e) {}
	throw "Importing of xmlrpc module failed.";
}



/***
 * RpcClient class.
 */
var RpcClient = new (function() {

	/*** Protected properties ***/
	this._service = (function() {
		var loc = window.document.location;
		var url = '/xmlrpc-server.php';
		if (loc.pathname.match(/^(\/[a-z]{2})\//)) {
			url = RegExp.$1 + url;
		}
		//var url = loc.protocol + '//' + loc.host + url;
		var methods = [
			'user.cart.addItem',
			'user.cart.addItemsFromOrder',
			'user.content.get',
			'user.login',
			'user.order.post',
			'user.product.getInfo'
		];
		return new xmlrpc.ServiceProxy(url, methods);
	})();

	/*** Protected methods ***/
	this._handleXmlRpcException = function(e) {
		var arr = e.constructor.toString().match(/^\[class (\S+)\]$/);
		var classname = arr && arr.length == 2 ? arr[1] : undefined;
		if (classname == 'Fault') {
			if (e.faultCode >= 800) { // user error
				alert(e.faultString);
			}
			else {
				throw("An XML-RPC server fault occurred:\n\n" + e.faultString);
			}
		}
		else {
			var em;
			if (e.toTraceString) {
				em = e.toTraceString();
			}
			else {
				em = e.message;
			}
			throw("Communication with the XML-RPC server failed:\n\nError trace:\n\n" + em);
		}
	}

	/*** Public methods ***/
	// Returns a boolean.
	this.login = function(email, password, autologin) {
		email = new String(email);
		password = new String(password);
		autologin = new Boolean(autologin);
		var result = false;
		try {
			result = this._service.user.login(email, password, autologin);
		}
		catch(e) {
			this._handleXmlRpcException(e);
		}
		return result;
	};

	/*** Public object properties ***/
	this.Cart = new (function(owner) {
		/*** Private properties ***/
		var _owner = owner;

		/*** Public methods ***/
		// Returns a hash with keys 'count' and 'value' on success, else false.
		this.addItemsFromOrder = function(order_id) {
			order_id = parseInt(order_id);
			var result = null;
			try {
				result = _owner._service.user.cart.addItemsFromOrder(order_id);
			}
			catch(e) {
				_owner._handleXmlRpcException(e);
			}
			return result;
		};

		// Returns a hash with keys 'count' and 'value' on success, else false.
		this.addItem = function(code, amount) {
			if (amount) {
				amount = parseInt(amount);
			}
			else {
				amount = 1;
			}
			var result = null;
			try {
				result = _owner._service.user.cart.addItem(code, amount);
			}
			catch(e) {
				_owner._handleXmlRpcException(e);
			}
			return result;
		};
	})(this);

	this.Content = new (function(owner) {
		/*** Private properties ***/
		var _owner = owner;
		var _cache = {};  // hash of key => {'title' => ..., 'body' => ...} pairs

		/*** Public methods ***/
		// Returns an array with keys 'caption' and 'body' if match found, else false.
		this.get = function(key) {
			key = new String(key);
			if (typeof(_cache[key]) == 'object') {
				return _cache[key];
			}
			var result = false;
			try {
				result = _owner._service.user.content.get(key);
				if (result) {
					_cache[key] = result;
				}
			}
			catch(e) {
				_owner._handleXmlRpcException(e);
			}
			return result;
		};
	})(this);

	this.Order = new (function(owner) {
		/*** Private properties ***/
		var _owner = owner;
		var _order_struct = null;	// cached result of last post() to prevent multiple submits.

		/*** Public methods ***/
		// Returns the order_id on success, else null.
		this.post = function(checksum, comment, bankaccnum) {
			checksum = new String(checksum);
			comment = new String(comment);
			bankaccnum = new String(bankaccnum);
			var result = _order_struct;
			if (result == null) {
				try {
					result = _owner._service.user.order.post(checksum, comment, bankaccnum);
					_order_struct = result;
				}
				catch(e) {
					var arr = e.constructor.toString().match(/^\[class (\S+)\]$/);
					var classname = arr && arr.length == 2 ? arr[1] : undefined;
					if ((classname == 'Fault') && (e.faultCode >= 800)) { // user error
						if (e.faultCode == 801) { // redirect
							document.location.href = e.faultString;
						}
						else if (e.faultCode > 801) {
							alert(e.faultString);
						}
						else { // whatever.
							_owner._handleXmlRpcException(e);
						}
					}
					else {
						_owner._handleXmlRpcException(e);
					}
				}
			}
			return result;
		};
	})(this);

	this.Product = new (function(owner) {
		/*** Private properties ***/
		var _owner = owner;
		var _cache = {};  // hash of product_code => xhtml pairs

		/*** Public methods ***/
		// Returns an xhtml string if match found, else false.
		this.getInfo = function(code) {
			code = new String(code);
			if (typeof(_cache[code]) == 'string') {
				return _cache[code];
			}
			var result = false;
			try {
				result = _owner._service.user.product.getInfo(code);
				if (typeof(result) == 'string') { // success
					_cache[code] = result;
				}
			}
			catch(e) {
				_owner._handleXmlRpcException(e);
			}
			return result;
		};
	})(this);



})();

