function NavigationModel() {
	var _state = null;
	var _observers = new Array();
	
	this.subscribe = function(o) {
		var pos = $.inArray(o, _observers);
		if (pos == -1) _observers.push(o);
	}
	
	this.unsubscribe = function(o) {
		var pos = $.inArray(o, _observers);
		if (pos != -1) _observers.splice(pos, 1);
	}
	
	this.setState = function(state) {
		_state = state;
		notifyObservers();
	}
	
	this.getState = function() {
		return _state;
	}
	
	this.getObservers = function() {
		return _observers;
	}
	
	function notifyObservers() {
		$(_observers).each(function() {
			this.update('hide');
		});
	}
}

function SubMenuController() {
	var _model = null;
	
	this.initialize = function(model) {
		_model = model;
	}
	
	this.actionPerformed = function(evt, view, e) {
		switch(evt) {
			case "mouseenter":
				performRequest('show', view);
				break;
				
			case "mouseleave":
				performRequest('hide', view);
				break;
				
			case "click":
				$(e).clone().insertAfter(e);
                $(e).css('visibility', 'hidden').appendTo(document.body);
				performRequest('hide', view);
                break;
		}
	}
	
	function performRequest(action, view) {		
		view.setHasFocus();
		var hasFocus = view.getHasFocus();
		
		var isFlyout = view instanceof FlyOutSubMenuView ? true : false;
		if (!isFlyout && _model.getState() != view) _model.setState(view);
		if (hasFocus || isFlyout) view.update(action);				
		else {
			var checkFocus = function() {
				var hasFocus = view.getHasFocus();
				if (!hasFocus) view.update(action);
			}
			setTimeout(checkFocus, 350);
		}
	}
}

function SubMenuView() {
	this.iframe = null;
	
	this.initialize = function(list) {
		this.hasFocus = false;
		this.list = $(list);
		this.parent = $(list).parent();
		if ($.browser.msie) setupIFrame.call(this);
	}
	
	this.update = function(action) {
		switch(action) {
			case "show":
				this.parent.addClass('hover');
				if(this.iframe) this.iframe.addClass('hover');
				break;
				
			case "hide":
				this.parent.removeClass('hover');
				if(this.iframe) this.iframe.removeClass('hover');
				break;
		}
	}
	
	this.setHasFocus = function() {
		this.hasFocus = (this.hasFocus) ? false : true;
	}
	
	this.getHasFocus = function() {
		return this.hasFocus;
	}
	
	this.getDimensions = function() {
		return {
			'menu': this.list.outerWidth(),
			'parent': this.parent.outerWidth(),
			'min': 100
		}
	}
	
	this.addEventHandlers = function(controller) {
		var action = function(e) { controller.actionPerformed(e.type, e.data, this) }
		$(this.parent).bind('mouseenter mouseleave', this, action);
		$(this.list).find('a').bind('click', this, action);
	}
	
	this.positionSubMenuHorizontally = function() {
		throw new Error('positionSubMenuHorizontally is an abstract method and must be overriden in a subclass!');
	}
	
	function setupIFrame() {
		this.iframe = $('<iframe src="/distrib/web/html/blank.htm"></iframe>');
		$(this.list).before(this.iframe);
	}
}

function SubMenuFactory() {
	this.order = function(m) {
		var menu = getSubMenuView($(m).parent());
			menu.initialize(m);
			return menu;
	}
	
	function getSubMenuView(view) {
		switch($(view).css('float')) {
			case 'left':
			case 'right':
				return new StaticSubMenuView();
				break;

			case 'none':
				return new FlyOutSubMenuView();
				break;
		}
	}
}

function FlyOutSubMenuView() {
	this.setupMenu = function(controller) {
		setMenuAppearance.call(this);
		this.positionSubMenuHorizontally();
		this.addEventHandlers(controller);
	}
	
	this.positionSubMenuHorizontally = function() {
		var cur_pos = this.parent.offset().left + this.parent.outerWidth() + this.list.outerWidth() - $('#nav').offset().left;
		var positionRight = cur_pos > $('#nav').outerWidth();
		var width_list = positionRight ? this.parent.outerWidth() - 1 : -this.list.outerWidth();
		var width_iframe = positionRight ? this.parent.outerWidth() - 1 : -this.list.outerWidth();
		
		positionRight ? this.list.addClass('right') : this.list.removeClass('right');
		this.list.css('right', width_list);
		if (this.iframe) this.iframe.css('right', width_iframe);
	}
	
	function setMenuAppearance() {
		var width = this.getDimensions();
		if (width.menu < width.min) this.list.css('width', width.min);
		if (this.iframe) this.iframe.css({
			'width': this.list.outerWidth(),
			'height': this.list.outerHeight()
		});
	}
}

function StaticSubMenuView() {
	this.setupMenu = function(controller) {
		setMenuAppearance.call(this);
		this.positionSubMenuHorizontally();
		this.addEventHandlers(controller);
	}
	
	this.positionSubMenuHorizontally = function() {
		if (this.iframe) (this.parent.hasClass('right')) ? this.iframe.css('right', 0) : this.iframe.css('left', 0);
	}
	
	function setMenuAppearance() {
		var width = this.getDimensions();
		if (width.menu < width.parent) this.list.css('width', width.parent);
		if (this.iframe) {
			this.iframe.css({
				'top': this.list.css('top'),
				'width': this.list.outerWidth(),
				'height': this.list.outerHeight()
			});
		}
	}
}

FlyOutSubMenuView.prototype = new SubMenuView;
StaticSubMenuView.prototype = new SubMenuView;