/**
 * Returns real offset for inset element
 * @param {Object} DOM element
 * @return {Object} Coordinates
 */
function getOffset(element)
{
	var currentLeft = 0;
	var currentTop = 0;
	
	if (element.offsetParent)
	{
		currentLeft = element.offsetLeft;
		currentTop = element.offsetTop;
		
		while (element = element.offsetParent)
		{
			currentLeft += element.offsetLeft
			currentTop += element.offsetTop
		}
	}
	
	return {left: currentLeft, top: currentTop};
}

/**
 * Determine whether a variable is set
 * @param {Object} The variable or property to be checked
 * @return {Boolean} Returns TRUE if variable exists; FALSE otherwise
 */
function isset(variable)
{
	return (typeof(variable) != 'undefined');
}



var Broadcaster = new Class(
{
	initialize: function()
	{
		this.listeners = new Array();
	},
	
	addListener: function(oListener)
	{
		for (var i = 0; i < this.listeners.length; i++)
		{
			if (this.listeners[i] == oListener)
				return;
		}
		
		this.listeners.push(oListener);			
	},
	
	removeListener: function(oListener)
	{
		var newListeners = new Array();
		
		for (var i = this.listeners.length - 1; i >= 0; i--)
		{
			if (this.listeners[i] != oListener)
				newListeners.push(oListener);
		}
	},
	
	broadcastMessage: function(sMessage)
	{
		for (var i = 0; i < this.listeners.length; i++)
		{
			if (this.listeners[i][sMessage])
				this.listeners[i][sMessage].apply(this.listeners[i]);
		}
	}
});

var Module = Broadcaster.extend(
{
	initSystem: function(systemObjects)
	{
		this.app = systemObjects.app;
		this.interfaceController = systemObjects.interfaceController;
	},
	
	initModule: function(){}
});

var Interface = Broadcaster.extend(
{
	initInterface: function()
	{
		this.dragData = null;
		
		this.initTsCheckboxes();
		this.initFoldTogglers();
		
		window.addEvent('resize', this.resizeWindow.bind(this));
		window.addEvent('scroll', this.scrollWindow.bind(this));
		document.addEvent('mousemove', this.moveMouse.bind(this));
	},
	
	resizeWindow: function()
	{
		this.broadcastMessage('resizeWindow');
	},

	scrollWindow: function()
	{
		this.broadcastMessage('scrollWindow');
	},
		
	startDrag: function(dragData)
	{
		this.dragData = dragData;
	},
	
	stopDrag: function(dragData)
	{
		this.dragData = null;
	},

	moveMouse: function(event)
	{
	    var e = event || window.event;

	    if (this.dragData != null)
	    {
	        this.dragData.dragObject.left = e.clientX + this.dragData.dragOffsetX;
	        this.dragData.dragObject.top = e.clientY + this.dragData.dragOffsetY;
	        this.dragData.dragObject.redraw();
	    }
	},
	
	addFlash: function(targetContainer, flashData)
	{
		defaultData = 
		{
			'wmode': 'transparent',
			'vars': '',
			'backgroundColor': 'transparent'
		}
		
		flashData = $merge(defaultData, flashData);
		
		$(targetContainer).innerHTML = '<object id="' + flashData.id + '" width="' + flashData.width + 'px" height="' + flashData.height + 'px" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0">'
		+ ' <param name="allowScriptAccess" value = "sameDomain" />'
		+ ' <param name="movie" value="' + flashData.url + '" />'
		+ ' <param name="loop" value="true" />'
		+ ' <param name="menu" value="false" />'
		+ ' <param name="quality" value="high" />'
		+ ' <param name="bgcolor" value="' + flashData.backgroundColor + '" />'
		+ ' <param name="flashvars" value="' + flashData.vars + '" />'
		+ ' <param name="wmode" value="' + flashData.wmode + '" />'
		+ ' <embed name="' + flashData.id + '" bgcolor="' + flashData.backgroundColor + '" src="' + flashData.url + '" swLiveConnect="true" loop="true" play="true" menu="false" quality="best" allowScriptAccess="sameDomain" width="' + flashData.width + 'px" height="' + flashData.height + 'px" allowScriptAccess="sameDomain" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="' + flashData.vars + '" wmode="' + flashData.wmode + '"></embed>'
		+ ' </object>';
	},
	
	scrollToAnchor: function(anchorName)
	{
		var anchorElement = $E('a[name=' + anchorName + ']');
		
		if (!anchorElement)
			return false;
			
		new Fx.Scroll(window).scrollTo(0, anchorElement.getTop());
	},
	
	initTsCheckboxes: function()
	{
		var tsCheckboxes = document.getElements('div.tsCheckbox');

		for (var i = 0; i < tsCheckboxes.length; i++)
		{
			new Interface.TsCheckbox(tsCheckboxes[i]);
		}
	},
	
	initFoldTogglers: function()
	{
		var foldTogglers = document.getElements('div.foldToggler');

		for (var i = 0; i < foldTogglers.length; i++)
		{
			new Interface.FoldToggler(foldTogglers[i]);
		}
	},
	
	openWindow: function(url, windowData)
	{
		var windowAttributes = new Array();
		var windowTitle = windowData.title ? windowData.title : '';
		
		windowAttributes.push('status=0');
		windowAttributes.push('resizable=0');
		windowAttributes.push('toolbar=0');
		windowAttributes.push('location=0');
		windowAttributes.push('directories=0');
		windowAttributes.push('menubar=0');
		windowAttributes.push('scrollbars=0');
		windowAttributes.push('left=50');
		windowAttributes.push('top=50');
		
		if (windowData.width && windowData.height)
		{
			windowAttributes.push('width=' + windowData.width);
			windowAttributes.push('height=' + windowData.height);
		}
		
		return window.open(url, windowTitle, windowAttributes.join(', '));
	}
});

Interface.TsCheckbox = new Class(
{
	initialize: function(container)
	{
		this.container = container;
		this.valueDisplay = this.container.getElement('span.value');
		this.valueForm = $(this.container.id.match(/\w+/g).join(''));
		
		this.container.addEvent
		(
			'click',
			this.switchState.bind(this, [null])
		);
		
		this.container.onselectstart = function() { return false; }

		this.redraw();
	},
	
	switchState: function(newValue)
	{
		if (newValue == null)
			this.valueForm.value++;
		else
			this.valueForm.value = newValue;
		
		if (this.valueForm.value > 1)
			this.valueForm.value = -1;
			
		if (this.valueForm.value < -1)
			this.valueForm.value = 1;
			
		this.redraw();
	},
	
	redraw: function()
	{
		this.valueDisplay.removeClass('state-1');
		this.valueDisplay.removeClass('state0');
		this.valueDisplay.removeClass('state1');

		this.valueDisplay.addClass('state' + this.valueForm.value);
	}
});

Interface.FoldToggler = new Class(
{
	initialize: function(container)
	{
		this.container = container;
		this.target = $(this.container.id.substr(0, this.container.id.length - 3));
		
		this.container.addEvent
		(
			'click',
			this.switchState.bind(this, [null])
		);
	},
	
	switchState: function(newValue)
	{
		var folded = this.container.hasClass('stateUnfold');
		
		if (newValue == null)
			newValue = !folded;
		
		if (newValue)
			this.fold();
		else
			this.unfold();
	},
	
	unfold: function()
	{
		this.container.removeClass('stateUnfold');
		this.container.addClass('stateFold');

		new Fx.Styles
		(
			this.target, 
			{
				duration: 500, 
				transition: Fx.Transitions.Quad
			}
		).start({'height': [0, this.target.getSize().scrollSize.y]});
	},
	
	fold: function()
	{
		this.container.removeClass('stateFold');
		this.container.addClass('stateUnfold');
		
		new Fx.Styles
		(
			this.target, 
			{
				duration: 500, 
				transition: Fx.Transitions.Quad
			}
		).start({'height': [this.target.getSize().scrollSize.y, 0]});
	}
});

Interface.Accordion = Broadcaster.extend(
{
	initialize: function(domElement)
	{
		this.parent();

		this.duration = 500;
		this.domElement = domElement;
		this.segments = domElement.getElementsBySelector('ul');
		this.maxHeight = 0;
		
		for (var i = 0; i < this.segments.length; i++)
		{
			var segmentMaxHeight = this.segments[i].getSize().scrollSize.y - 1;
			
			this.segments[i] =
			{
				'domElement': this.segments[i],
				'height': segmentMaxHeight
			};
			
			this.maxHeight = Math.max(this.maxHeight, segmentMaxHeight);
			
			var segmentToggler = this.segments[i].domElement.getParent().getElement('a');
			
			segmentToggler.setProperty('href', 'javascript://');
			segmentToggler.addEvent
			(
				'click',
				this.toggleSegment.bind(this, [i])
			);
			segmentToggler.addEvent
			(
				'focus',
				this.blurToggler.bind(this, [segmentToggler])
			);
			
			if (segmentToggler.getParent().hasClass('act'))
				this.showSegment(i, 10);
		}
	},
	
	blurToggler: function(toggler)
	{
		toggler.blur();
	},
	
	toggleSegment: function(elementIndex)
	{
		for (var i = 0; i < this.segments.length; i++) 
		{
			if (this.segments[i].domElement.getStyle('height').toInt() > 0)
				this.hideSegment(i);
			else if (i == elementIndex)
				this.showSegment(i);
		}
	},
	
	showSegment: function(elementIndex, duration)
	{
		if (duration == undefined)
			duration = this.duration;
			
		new Fx.Style
		(
			this.segments[elementIndex].domElement, 
			'height', 
			{
				duration: duration,
				transition: Fx.Transitions.Quad.easeOut
			}
		).start(0, this.segments[elementIndex].height);
	},

	hideSegment: function(elementIndex, duration)
	{
		if (duration == undefined)
			duration = this.duration;
			
		new Fx.Style
		(
			this.segments[elementIndex].domElement, 
			'height', 
			{
				duration: duration,
				transition: Fx.Transitions.Quad.easeOut
			}
		).start(this.segments[elementIndex].height, 0);
	}
});

Interface.MenuContainer = Broadcaster.extend(
{
	initialize: function(domElement, parentContainer)
	{
		this.parent();

		this.hideDelay = 250;

		this.domElement = domElement;
	 	this.parentContainer = parentContainer;	
		this.menuItems = new Array();
		this.hideTimeout = null;
		
		this.setupMenuContainer();
	},
	
	setupMenuContainer: function()
	{
		var domItems = this.domElement.getElements('li');
		var i = domItems.length;

		do
		{
			if (domItems[i - 1].parentNode == this.domElement)
				this.menuItems.push(new Interface.MenuItem(domItems[i - 1], this));
		}
		while (--i);
	},
	
	onRollOver: function()
	{
		clearTimeout(this.hideTimeout);
		this.hideTimeout = null;
		
		this.domElement.removeClass('none');

		var eC = this.domElement.getCoordinates();
		var wS = window.getSize();
		
		if (this.domElement.getStyle('position') == 'absolute')
			if (eC.top + eC.height + 10 > wS.size.y + wS.scroll.y)
				this.domElement.style.top = (wS.size.y + wS.scroll.y - (eC.top + eC.height + 10)) + 'px';
		
		this.broadcastMessage('onRollOver');
	},
	
	onRollOut: function()
	{
		this.hideTimeout = setTimeout(this.hideContainer.bind(this), this.hideDelay);
		
		this.broadcastMessage('onRollOut');
	},
	
	hideContainer: function()
	{
		this.domElement.addClass('none');
		clearTimeout(this.hideTimeout);
	},
	
	hideChildContainers: function()
	{
		var i = this.menuItems.length;

		while (i--)
		{
			if (this.menuItems[i].childContainer && this.menuItems[i].childContainer.hideTimeout != null)
			{
				this.menuItems[i].childContainer.hideChildContainers();
				this.menuItems[i].childContainer.hideContainer();
			}
		}
	}
});

Interface.MenuItem = Broadcaster.extend(
{
	initialize: function(domElement, parentContainer)
	{
		this.parent();
		
		this.domElement = domElement;
		this.parentContainer = parentContainer;
		this.childContainer = null;

		this.setupMenuItem();
	},

	setupMenuItem: function()
	{
		this.domElement.onmouseover = this.onRollOver.bind(this);
		this.domElement.onmouseout = this.onRollOut.bind(this);
		this.domElement.onmouseup = this.onRelease.bind(this);
		
		var domItems = this.domElement.getElements('ul');
		
		if (domItems.length > 0)
		{
			this.childContainer = new Interface.MenuContainer(domItems[0], this);
		}
	},
	
	onRollOver: function()
	{
		this.domElement.getElement('a').addClass('rollover');

		if (this.childContainer != undefined)
			this.childContainer.onRollOver();
		
		this.parentContainer.hideChildContainers();
		
		this.broadcastMessage('onRollOver');
	},
	
	onRollOut: function()
	{
		this.domElement.getElement('a').removeClass('rollover');

		if (this.childContainer != undefined)
			this.childContainer.onRollOut();
		this.broadcastMessage('onRollOut');
	},
	
	onRelease: function()
	{
		this.broadcastMessage('onRelease');
	}
});

var App = Broadcaster.extend(
{
	initialize: function()
	{
	    this.modules = new Array();
	},

	initApplication: function()
	{
		this.interfaceController = new Interface();
		this.interfaceController.initInterface();

		for (var iModule = 0; iModule < this.modules.length; iModule++)
		{
			this.modules[iModule].initSystem(
			{
				'app': this,
				'interfaceController': this.interfaceController	
			});
			
			this.modules[iModule].initModule();
		}
		
		this.interfaceController.resizeWindow();
		
		return 'initApplication';
	},
	
	addModule: function(oModule, moduleName)
	{
		if (moduleName != undefined)
			oModule.name = moduleName;

		this.modules.push(oModule);
	},
	
	getModule: function(moduleName)
	{
		for (var iModule = 0; iModule < this.modules.length; iModule++)
			if (this.modules[iModule].name == moduleName)
				return this.modules[iModule];
	}
});

