coss.NOTIFICATION_TYPE_NORMAL = 1;
coss.NOTIFICATION_TYPE_SUCCESS = 2;
coss.NOTIFICATION_TYPE_ERROR = 3;
coss.NOTIFICATION_TYPE_WARNING = 4;
coss.NOTIFICATION_TYPE_QUESTION = 5;

coss.DIALOG_OPTION_OK = 'ok';
coss.DIALOG_OPTION_CANCEL = 'cancel';
coss.DIALOG_OPTION_YES = 'yes';
coss.DIALOG_OPTION_NO = 'no';

coss.DIALOG_OPTIONS_OK = coss.DIALOG_OPTION_OK;
coss.DIALOG_OPTIONS_OK_CANCEL = coss.DIALOG_OPTION_OK + ' ' + coss.DIALOG_OPTION_CANCEL;
coss.DIALOG_OPTIONS_YES_NO_CANCEL = coss.DIALOG_OPTION_YES + ' ' + coss.DIALOG_OPTION_NO + ' ' + coss.DIALOG_OPTION_CANCEL;

coss.HtmlNotification = function (aMessage, aType) {
	var thisInstance    = this;
	var mEventListeners = {};
	var mButtons        = [];
	var mDocument;
	var mHtmlNode;
	
	function mChooseOption(aOption) {
		var i;
		
		if ('chooseOption' in mEventListeners) {
			for (i = 0; i < mEventListeners['chooseOption'].length; i++) {
				mEventListeners['chooseOption'][i].apply(thisInstance, [new coss.NotificationChooseOptionEvent(this, aOption)]);
			}
		}
	};
	
	this.type          = null;
	this.title         = null;
	this.message       = null;
	this.channel       = null;
	this.id            = null;
	this.options       = null;
	this.boundHtmlNode = null;

	this.addEventListener = function addEventListener(aEventName, aListener) {
		if ((aEventName in mEventListeners) == false) {
			mEventListeners[aEventName] = [];
		}
		
		mEventListeners[aEventName].push(aListener);
	};

	this.render = function () {
		var container, title, message, controls, button, menu, menuItem, el, el2;
		var i;
		
		var typeClassMap = {};
		typeClassMap[coss.NOTIFICATION_TYPE_NORMAL]   = 'type-normal';
		typeClassMap[coss.NOTIFICATION_TYPE_ERROR]    = 'type-error';
		typeClassMap[coss.NOTIFICATION_TYPE_WARNING]  = 'type-warning';
		typeClassMap[coss.NOTIFICATION_TYPE_SUCCESS]  = 'type-success';
		typeClassMap[coss.NOTIFICATION_TYPE_QUESTION] = 'type-question';
		
		var optionButtonMap = {};
		optionButtonMap[coss.DIALOG_OPTION_OK]     = ['OK'];
		optionButtonMap[coss.DIALOG_OPTION_CANCEL] = ['Cancel'];
		optionButtonMap[coss.DIALOG_OPTION_YES]    = ['Yes'];
		optionButtonMap[coss.DIALOG_OPTION_NO]     = ['No'];
		
		var buttonClickHandlers = {};
		buttonClickHandlers[coss.DIALOG_OPTION_OK]     = function () {mChooseOption(coss.DIALOG_OPTION_OK);};
		buttonClickHandlers[coss.DIALOG_OPTION_CANCEL] = function () {mChooseOption(coss.DIALOG_OPTION_CANCEL);};
		buttonClickHandlers[coss.DIALOG_OPTION_YES]    = function () {mChooseOption(coss.DIALOG_OPTION_YES);};
		buttonClickHandlers[coss.DIALOG_OPTION_NO]     = function () {mChooseOption(coss.DIALOG_OPTION_NO);};
		
				
		container = mDocument.createElement('div');
		container.className = 'role-section w-notification ' + typeClassMap[this.type];
		
		if (this.title != '') {
			title = mDocument.createElement('div');
			title.className = 'role-header';
			el = mDocument.createElement('div');
			el.className = 'role-hgroup';
			title.appendChild(el);
			el2 = mDocument.createElement('div');
			el2.className = 'role-h';
			el.appendChild(el2);
			el2.innerHTML = this.title;
			container.appendChild(title);
		}
		
		message = mDocument.createElement('div');
		message.className = 'role-section';
		message.innerHTML = this.message;
		container.appendChild(message);
		
		if (mButtons.length > 0) {
			controls = mDocument.createElement('div');
			controls.className = 'role-footer';
			menu = mDocument.createElement('ul');
			menu.className = 'role-menu';
			controls.appendChild(menu);
			
			for (i = 0; i < mButtons.length; i++) {
				menuItem = mDocument.createElement('li');
				menuItem.className = 'role-menuItem';
				menu.appendChild(menuItem);
				
				button = mDocument.createElement('button');
				button.setAttribute('type', 'button'); //HACK: setting button.type breaks IE
				button.className = 'role-button';
				
				$(button).bind('click', buttonClickHandlers[mButtons[i]]);
				
				button.appendChild(mDocument.createTextNode(optionButtonMap[mButtons[i]][0]));
				menuItem.appendChild(button);
			}
			
			container.appendChild(controls);
		}
		
		this.boundHtmlNode = container;
		
		return this.boundHtmlNode;
	};
	
	this._construct = function _construct(aMessage, aType) {
		mDocument = document;
		
		this.type = aType != null ? aType : coss.NOTIFICATION_TYPE_NORMAL;
		
		this.message = aMessage + '';
		
		if (this.type == coss.NOTIFICATION_TYPE_SUCCESS) {
			this.title = 'Success';
	 	}
		else if (this.type == coss.NOTIFICATION_TYPE_ERROR) {
			this.title = 'Error';
		}
		else {
			this.title = 'Message';
		}
		
		this.channel = Math.random();
		
		this.id = Math.random();
				
		if (false) {
			if (aOptions == coss.DIALOG_OPTIONS_OK_CANCEL) {
				this.options = coss.DIALOG_OPTIONS_OK_CANCEL;
				mButtons.push(coss.DIALOG_OPTION_OK);
				mButtons.push(coss.DIALOG_OPTION_CANCEL);
			}
			
			else if (aOptions == coss.DIALOG_OPTIONS_YES_NO_CANCEL) {
				this.options = coss.DIALOG_OPTIONS_YES_NO_CANCEL;
				mButtons.push(coss.DIALOG_OPTION_YES);
				mButtons.push(coss.DIALOG_OPTION_NO);
				mButtons.push(coss.DIALOG_OPTION_CANCEL);
			}
			
			else if (aOptions == coss.DIALOG_OPTIONS_OK) {
				this.options = coss.DIALOG_OPTIONS_OK;
				mButtons.push(coss.DIALOG_OPTION_OK);
			}
			
			else {
				throw "Unknown dialog options: '" + aOptions + "'";
			}
		}
		
		else {
			this.options = coss.DIALOG_OPTION_OK;
			mButtons.push(coss.DIALOG_OPTION_OK);
		}
	};
	
	//call constructor if not using object as prototype
	if ((arguments.length == 1 && arguments[0] == this.constructor) == false) {this._construct.apply(this, arguments);}
};


coss.NotificationChooseOptionEvent = function (aTarget, aOption) {
	this.target = aTarget;
	this.option = aOption;
};


coss.HtmlNotificationManager = function (aViewContainer) {
	var thisInstance   = this;
	var mNotifications = {};
	
	this.viewContainer = null;
	
	this.queue = function queue(aNotification) {
		if (this.viewContainer == null) {
			alert(aNotification.body);
			return;
		}
		
		var htmlNode, t;
		var alreadyQueued = false;
		var notification = aNotification;
		
		if ((notification instanceof coss.HtmlNotification) == false) {
			notification = new coss.HtmlNotification(
				notification.body,
				notification.type
			);
		}
		
		if (notification.channel in mNotifications) {
			if (notification.id in mNotifications[notification.channel]) {
				alreadyQueued = true;
				this.clear(notification.channel, notification.id);
			}
		}
		else {
			mNotifications[notification.channel] = {};
		}
		
		notification.addEventListener('chooseOption', function () {
			thisInstance.clear(this.channel, this.id);
		});
		
		//add to list of queued notifications
		mNotifications[notification.channel][notification.id] = notification;

		//show the notification	
		this.notify(notification, alreadyQueued);

		this._syncContainerState();
	};

	this.notify = function notify(aNotification, aQueued) {
		//show notification dom
		htmlNode = aNotification.boundHtmlNode != null ? aNotification.boundHtmlNode : aNotification.render();

		this.viewContainer.appendChild(htmlNode);

		if (aQueued == false) {
    		//if viewport is scrolled down past notification container
    		t = this.viewContainer.offsetTop;

			if (document.documentElement.scrollTop > t) {
				//scroll to top of notification container
				window.scrollTo(0, t);
			}
  		}
	};
	
	this.clear = function clear(aChannel, aId) {
		var channel, id;
		
		for (channel in mNotifications) {
			if (aChannel == null || channel == aChannel) {
				for (id in mNotifications[channel]) {
					if (aChannel == null || aId == null || id == aId) {
						if (mNotifications[channel][id].boundHtmlNode && mNotifications[channel][id].boundHtmlNode.parentNode) {
							mNotifications[channel][id].boundHtmlNode.parentNode.removeChild(mNotifications[channel][id].boundHtmlNode);	
						}
						
						delete mNotifications[channel][id];
					}
				}
			}
		}
		
		this._syncContainerState();
	};
	
	this.getAll = function () {
		var items = [];
		var channel, id;
		
		for (channel in mNotifications) {
			for (id in mNotifications[channel]) {
				items.push(mNotifications[channel][id]);
			}
		}
		
		return items;
	};
	
	this._syncContainerState = function() {
		if (this.viewContainer != null) {
			this.viewContainer.style.display = this.getAll().length == 0 ? 'none' : '';
		}
	};

	this._construct = function _construct(aViewContainer) {
		if (aViewContainer) {
			this.setContainerElement(aViewContainer);
			this._syncContainerState();
		}
	};
	
	//call constructor if not using object as prototype
	if ((arguments.length == 1 && arguments[0] == this.constructor) == false) {this._construct.apply(this, arguments);}
};

coss.HtmlNotificationManager.prototype.setContainerElement = function (aContainerElement) {
	this.viewContainer = aContainerElement;
};
