if ('coss' in window) {
if ('HtmlNotificationManager' in coss) {


coss.Conduit = function () {};

coss.Conduit.prototype.getAjaxTunnel = function () {
	if (this._conduit.ajaxTunnel == null) {
		this._conduit.ajaxTunnel = new coss.AjaxTunnel();
		this._conduit.ajaxTunnel.construct();
	}
	
	return this._conduit.ajaxTunnel;
};

coss.Conduit.prototype.addDataBinder = function (aBinder) {
	this._conduit.dataBinders.push(aBinder);
};

coss.Conduit.prototype.bindData = function (aData) {
	var i;
	
	for (i = 0; i < this._conduit.dataBinders.length; i++) {
		//call data binder function in global/window scope
		this._conduit.dataBinders[i].apply(window, [aData]);
	}
};

coss.Conduit.prototype.construct = function () {
	this._conduit = {
		dataBinders : [],
		ajaxTunnel : null,
		iframeTunnel : null
	};
};




coss.AjaxTunnel = function () {};

coss.AjaxTunnel.prototype.execute = function (aData, aOptions) {
	var url, urlQs, matches, data, method;
	
	var form = null;
	if (aOptions && 'form' in aOptions && aOptions.form != null) {
		form = aOptions.form;
		if (!(typeof form == 'object' && 'className' in form)) {
			form = document.getElementById(form);
		}
		if (form == null) {
			throw "aOptions.form must be an element reference or string element id.";
		}
	}
	
	//resolve url
	if (aOptions && 'url' in aOptions && aOptions.url != null && aOptions.url != '') {
		url = aOptions.url;
	}
	else if (form != null) {
		url = form.action;
	}
	else {
		url = this.getUrl();
	}
	urlQs = '';
	matches = url.match(/\?([^#]+)/);
	if (matches != null && matches.length == 2) {
		urlQs = matches[1];
		url = url.replace(/\?(.+)/, '');
	}
	if (url == null) {
		throw "Invalid URL: '" + this._ajaxTunnel.url + "'";
	}
	
	//resolve method
	if (aOptions && 'method' in aOptions && aOptions.method != null && aOptions.method != '') {
		method = aOptions.method;
	}
	else if (form != null && form.method != '') {
		method = form.method;
	}
	else {
		method = this.getMethod();
	}
	
	//resolve data
	data = aData;
	if (form != null) data = $(form).serialize() + '&' + data;
	if (urlQs != '') data = urlQs + '&' + data;
	
	this.dispatchEvent('begin');
	
	jQuery.ajax({
		'context' : this,
		'dataType' : 'json',
		'data' : data,
		'type' : method,
		'url' : url,
		'success' : this._ajaxTunnel.jquerySuccessHandler,
		'error' : this._ajaxTunnel.jqueryErrorHandler
	});
};

coss.AjaxTunnel.prototype.getMethod = function () {
	return this._ajaxTunnel.method;
};

coss.AjaxTunnel.prototype.setMethod = function (aMethod) {
	this._ajaxTunnel.method = aMethod;
};

coss.AjaxTunnel.prototype.getUrl = function () {
	return this._ajaxTunnel.url;
};

coss.AjaxTunnel.prototype.setUrl = function (aUrl) {
	this._ajaxTunnel.url = aUrl;
};

coss.AjaxTunnel.prototype.addEventListener = function (aEventType, aFunction) {
	if ((aEventType in this._ajaxTunnel.eventListeners) == false) {
		throw "Unknown event type: '" + aEventType + "'.";
	}
	
	this._ajaxTunnel.eventListeners[aEventType].push(aFunction);
};

coss.AjaxTunnel.prototype.dispatchEvent = function (aEventType, aEvent) {
	var i;
	
	if ((aEventType in this._ajaxTunnel.eventListeners) == false) {
		throw "Unknown event type: '" + aEventType + "'.";
	}
	
	for (i = 0; i < this._ajaxTunnel.eventListeners[aEventType].length; i++) {
		this._ajaxTunnel.eventListeners[aEventType][i].apply(this, [aEvent]);
	}
};

coss.AjaxTunnel.prototype.construct = function () {
	this._ajaxTunnel = {
		method : null,
		url : null,
		
		eventListeners : {
			'begin' : [],
			'end' : []
		},
		
		jquerySuccessHandler : function (aJson) {
			this.dispatchEvent('end', {
				error : null,
				data : aJson
			});
		},
		
		jqueryErrorHandler : function (aXhr, aStatus) {
			this.dispatchEvent('end', {
				error : {type : aStatus},
				data : null
			});
		}
	};
	
	this.setMethod('post');
	this.setUrl('index.php');
};


coss.ModuleHelper = function () {};

coss.ModuleHelper.prototype.construct = function (aModule) {
	this._moduleHelper = {
		parent : aModule
	};
};

coss.ModuleHelper.prototype.getParent = function () {
	return this._moduleHelper.parent;
};


coss.ModuleModel = function () {
	if (!(arguments.length == 1 && arguments[0] == coss.ModuleHelper)) this.construct.apply(this, arguments);	
};
coss.extend(coss.ModuleModel, coss.HashMap);




coss.Module = function () {};

coss.Module.prototype.handleMainConduitAjaxEnd = function (aResult) {
	if (aResult.error == null) {
		gModule.getMainConduit().bindData(aResult.data);
	}
	
	else {
		gModule.getMainConduit().bindData({
			system : {
				notifications : [
					{
						body :
							"An error has ocurred, please try again."
					}
				]
			}
		});
	}
};

coss.Module.prototype.createNotificationManager = function () {
	return new coss.HtmlNotificationManager();
}

coss.Module.prototype.getNotificationManager = function () {
	if (this._module.notificationManager == null) this._module.notificationManager = this.createNotificationManager();
	return this._module.notificationManager;
};

coss.Module.prototype.getMainConduit = function () {
	return this._module.mainConduit;
};

coss.Module.prototype.getHashManager = function () {
	if (this._module.hashManager == null) this._module.hashManager = new coss.HashManager();
	return this._module.hashManager;
};

coss.Module.prototype.getPendingData = function () {
	return this._module.pendingData;
};

coss.Module.prototype.setPendingData = function (aData) {
	this._module.pendingData = aData;
};

coss.Module.prototype.getHelper = function (aCode) {
	var i;
	for (i = 0; i < this._module.helpers.length; i++) {
		if (this._module.helpers[i].code == aCode) {
			return this._module.helpers[i].helper;
		}
	}
	throw "Unknown helper with code: '" + aCode + "'";
};

coss.Module.prototype.getAllHelpers = function () {
	return this._module.helpers.concat([]); //copy
};

coss.Module.prototype.setHelper = function (aCode, aHelper) {
	var m;
	
	//for each member of the helper (function or property)
	for (m in aHelper) {
		//if the member is not 'private' and does not already exist on the module
		if (m.charAt(0) != '_' && !(m in this)) {
			//if member is a function
			if (typeof aHelper[m] == 'function') {
				//create a placeholder method on the module which just delegates to helpers
				this[m] = new Function("this.delegateToHelpers.apply(this, ['" + m + "', arguments]);");
			}
			
			//else member is a property
			else {
				//just assign the property to the module
				this[m] = aHelper[m];
			}
		}
	}
	
	this._module.helpers.push({
		code : aCode,
		helper : aHelper
	});
};

coss.Module.prototype.delegateToHelpers = function (aCallerFunction, aFunctionName, aArgs, aRequired, aSurfaceOnly, aOptions) {
	//if function is called with old style arguments (i.e. aFunctionName is the first argument)
	if (typeof aCallerFunction == 'string') {
		//reassign/shift all of the arguments
		aOptions = aSurfaceOnly;
		aSurfaceOnly = aRequired;
		aRequired = aArgs;
		aArgs = aFunctionName;
		aFunctionName = aCallerFunction;
		aCallerFunction = undefined;
	}
	
	var i, helpers;
	
	var surfaceOnly = aSurfaceOnly !== undefined ? aSurfaceOnly : (aCallerFunction == undefined ? false : true);
	if (surfaceOnly && aCallerFunction == undefined) {
		throw "Cannot use aSurfaceOnly=true without specifying aCallerFunction.";
	}
	
	if (surfaceOnly && !(aCallerFunction === this.constructor.prototype[aFunctionName])) {
		return null;
	}
	
	helpers = this.getAllHelpers();
	for (i = 0; i < helpers.length; i++) {
		if (aFunctionName in helpers[i].helper) {
			helpers[i].helper[aFunctionName].apply(helpers[i].helper, aArgs);
		}
	}
};

coss.Module.prototype.resolveHelpers = function () {
	
};

coss.Module.prototype.getModel = function () {
	if (this._module.model == null) this._module.model = new coss.ModuleModel();
	return this._module.model;
};

coss.Module.prototype.hookUp = function () {
	this.getMainConduit().addDataBinder(function (aData) {
		var notifications = coss.arrayGet(aData, 'system.notifications');
		if (notifications && notifications.length > 0) {
			for (i = 0; i < notifications.length; i++) {
				gModule.getNotificationManager().queue(notifications[i]);
			}
		}
	});
};

coss.Module.prototype.init = function () {
	this.resolveHelpers();
};

coss.Module.prototype.construct = function () {
	var t;
	
	this._module = {
		pendingData : null,
		hashManager : null,
		helpers : [],
		model : null
	};
	
	t = new coss.Conduit();
	t.construct();
	this._module.mainConduit = t;
	
	t = this.getMainConduit().getAjaxTunnel();
	t.addEventListener('end', this.handleMainConduitAjaxEnd);
	
	$(document).bind('ready', function() {
		gModule.hookUp();
		gModule.getMainConduit().bindData(gModule.getPendingData());
	});
};




} else throw "Package coss-lib-notification.js must be included.";
} else throw "Package coss.js must be included.";
