/*
 * Aplix BONDI loader
 */

if (typeof bondi == 'undefined') { (function() {

		var defaults = {
			pluginParams: {},
			instanceParams: {},
			mimetype: 'application/x-vnd-aplix-webvm'
		};

		var root = {};
		root.ob = addPlugin(defaults.pluginParams);
		if (!root.ob) {
			return;
		}

		window.bondi = {};
		bondi.ext = {};

		bondi.DeviceAPIError = {};
		bondi.DeviceAPIError.UNKNOWN_ERROR = 10000;
		bondi.DeviceAPIError.INVALID_ARGUMENT_ERROR = 10001;
		bondi.DeviceAPIError.NOT_FOUND_ERROR = 10002;
		bondi.DeviceAPIError.PENDING_OPERATION_ERROR = 10003;
		bondi.DeviceAPIError.IO_ERROR = 10004;
		bondi.DeviceAPIError.NOT_SUPPORTED_ERROR = 10005;
		bondi.SecurityError = {};
		bondi.SecurityError.PERMISSION_DENIED_ERROR = 20000;

		/* define enums */
		bondi.defs = {
			state: {
				created: 0,
				initialised: 1,
				loading: 2,
				loaded: 3,
				starting: 4,
				started: 5,
				exited: 6,
				aborted: 7,
				failed: 8,
				denied: 9
			},
			status: {
				ok: 0,
				inuse: - 78
			}
		};

		/*
		 * add any private variables used by global exported functions
		 * as children of root
		 */
		root.queue = {
			documentLoad: {
				queue: [],
				loaded: false
			},
			documentUnload: {
				queue: [],
				loaded: false
			}
		};

		/*
		 * second closure creates private instance-wide scope
		 */
		function createInstance(name) {

			var localroot = {};

			/*
			 * add any private variables used by instance-wide exported functions
			 * as children of localroot
			 */
			localroot.name = name;

			return localroot;
		}

		/*
		 * here declare and implement any private functions
		 * used by global exported functions
		 */

		function makeURI(name, version, params) {
			return name + '?v=' + version + encodeParams(params) + defaults.params;
		}

		function encodeParams(params) {
			var b = '';
			if (params !== undefined) {
				for (var d in params) {
					/* TODO check validity of param */
					b += '&' + d + '=' + encodeURIComponent(params[d]);
				}
			}
			return b;
		}

		function registerLoadHandlers(c, d) {
			var a = window;
			if (a.addEventListener) {
				a.addEventListener('unload', d, false);
				if (document.addEventListener) {
					document.addEventListener('DOMContentLoaded', c, false);
				} else {
					a.addEventListener('load', c, false);
				}
			} else if (a.attachEvent) {
				a.attachEvent('onload', c);
				a.attachEvent('onunload', d);
			} else {
				a.onload = c;
				a.onunload = d;
			}
		}

		function runOnLoad(f, phase, idx) {
			if (idx === undefined) {
				idx = 100;
			}
			if (phase === undefined) {
				phase = 'documentLoad';
			}
			var q = root.queue[phase];
			if (q.loaded) {
				f();
			} else {
				q = q.queue;
				q[q.length] = [idx, f];
			}
		}

		function runQueue(queue) {
			if (queue.loaded) {
				return;
			}
			var q = queue.queue;
			q.sort(function(a, b) {
				return (a[0] - b[0]);
			});
			for (var i = 0; i < q.length; i++) {
				try {
					q[i][1]();
				}
				catch(e) {}
			}
			queue.loaded = true;
			delete queue.queue;
		}

		registerLoadHandlers(
		function() {
			runQueue(root.queue.documentLoad);
		},
		function() {
			runQueue(root.queue.documentUnload);
		});

		function includeScriptByURI(uri) {
			var headID = document.getElementsByTagName('head')[0];
			var newScript = document.createElement('script');
			newScript.type = 'text/javascript';
			newScript.src = uri;
			headID.appendChild(newScript);
		}

		function addPlugin(params) {
			try {
				var ob = new ActiveXObject('Aplix.WebVM');
				root.activex = true;
				return ob;
			} catch(e) {
				if (navigator.mimeTypes && navigator.mimeTypes[defaults.mimetype]) {
					var ob = document.createElement('object');
					ob.width = 0;
					ob.height = 0;
					ob.type = defaults.mimetype;
					for (var d in params) {
						var param = document.createElement('param');
						ob.appendChild(param);
						param.name = d;
						param.value = params[d];
					}
					document.documentElement.appendChild(ob);
					return ob;
				}
			}
		}

		function addInstance(successCallback, errorCallback, name) {
			runOnLoad(function() {
				addInstanceNow(successCallback, errorCallback, name);
			},
			'documentLoad', 10);
		}

		function addInstanceNow(successCallback, errorCallback, name) {

			/* create local root */
			var instanceRoot = createInstance(name);
			var _bondi = window.bondi;

			/* define callbacks */
			var baseCallback = function(state) {
				if (state == _bondi.defs.state.aborted || state == _bondi.defs.state.failed) {
					if (errorCallback) {
						errorCallback('Loading of feature <' + name + '> failed; state = ' + state);
					}
					return;
				}
				if (state == _bondi.defs.state.denied) {
					if (errorCallback) {
						errorCallback('Loading of feature <' + name + '> denied');
					}
					return;
				}
			};
			var startCallback = function(state) {
				if (state == _bondi.defs.state.started) {
					try {
						var feature = root.ob.getFeature(name);
						var featureRoot = root.ob.getFeatureName(name);
						if (featureRoot !== undefined) {
							var ob = bondi;
							featureRoot = featureRoot.split('.').reverse();
							while (featureRoot.length > 1) {
								var next = featureRoot.pop();
								if (ob[next] === undefined) {
									ob[next] = {};
								}
								ob = ob[next];
							}
							ob[featureRoot[0]] = feature;
						}
						if (successCallback) {
							successCallback();
						}
					}
					catch(e) {}
					return;
				}
				baseCallback(state);
			};

			var loadCallback = function(state) {
				if (state == _bondi.defs.state.loaded) {
					// Assign result to return value on ActiveX objects for Pocket IE
					var result = root.ob.startFeature(name, startCallback);
					return;
				}
				baseCallback(state);
			};

			/* load the feature */
			var loadStatus = root.ob.loadFeature(name, {},
			loadCallback);
			if (loadStatus != _bondi.defs.status.ok) {
				if (errorCallback) {
					errorCallback('Plugin failed to start; status = ' + loadStatus);
				}
			}
		}

		bondi.requestFeature = addInstance;
		bondi.ext.getError = function(e) { // Merged in from Toby's code
			var ret = {};
			var message = (e === null || e.message === null) ? "unknown error|10000|unknown type": e.message;
			var tokens = message.split('|');
			ret.message = tokens.length > 0 ? tokens[0] : message;
			ret.code = tokens.length > 1 ? tokens[1] : 0;
			ret.errorType = tokens.length > 2 ? tokens[2] : "unknown type";
			return ret;
		};
		bondi.ext.releaseFeature = function(name) {};
		bondi.ext.getProperty = function(name) {
			return root.ob.getProperty(name);
		};
		bondi.ext.getFeature = function(name) {
			return root.ob.getFeature(name);
		};
		bondi.ext.setPolicy = function(txt) {
			return root.ob.setPolicy(txt);
		};

		bondi.runOnLoad = runOnLoad;
	})();
}

