/*
Script: ethonsidebar.v.1.00.js
	Contains the <EthonSidebar> class.

Author:
	<http://www.ethon.co.uk/>
	
Credits:
	Based on the PBBSideBar by PokemonJoJo <http://www.mibhouse.org/pokemon_jojo>
	Loading image created by <http://www.ajaxload.info/>

License:
	MIT-style license.
*/

/*
Class: EthonSidebar
	Creates a sidebar that can be populated with content either via the page using the script or from URLs via Ajax.

Arguments:
	options - optional, an object containing options.

Options:
	position - position of the sidebar, defaults to right
	transition - type of sidebar transition when showing and hiding (slide or appear), defaults to slide
	display - integer, show the sidebar at start (with a transition), defaults to 0
	styles - css for the sidebar (width, height, color, background-color, opacity)
	displayLoadingText - boolean, whether to display any loading text when loading content from a url, defaults to true
	loadingText - the text to display when loading content from a url, defaults to 'loading...'
	loadingImage - the path to the image to display when loading content from a url
	showDuration - duration of the sidebar transition when showing, defaults to 500 ms
	showEffect - transitions, to be used when showing the sidebar
	hideDuration - duration of the sidebar transition when hiding, defaults to 500 ms
	hideEffect - transitions, to be used when hiding the sidebar
	onShowStart - function to execute when the sidebar begins its show transition
	onHideStart - function to execute when the sidebar has completed its show transition
	onShowComplete - function to execute when the sidebar begins its hide transition
	onHideComplete - function to execute when the sidebar has completed its hide transition
	
Events:
	onShowStart - function to execute when the sidebar begins its show transition
	onShowComplete - function to execute when the sidebar has completed its show transition
	onHideStart - function to execute when the sidebar begins its hide transition
	onHideComplete - function to execute when the sidebar has completed its hide transition
*/
var EthonSidebar = new Class({

	getOptions: function() {
		return {
			position : 'right',
			transition : 'slide',
			display: 0,
			styles: {
				'width': '250',
				'height': window.getScrollHeight() + 'px',
				'color': 'white',
				'background-color': 'black',
				'opacity': 0.8
			},
			displayLoadingText: true,
			loadingText: 'loading...',
			loadingImage: './ajax-loader.gif',
			showDuration: 500,
			showEffect: Fx.Transitions.linear,
			hideDuration: 500,
			hideEffect: Fx.Transitions.linear,
			onShowStart : Class.empty,
			onShowComplete : Class.empty,
			onHideStart : Class.empty,
			onHideComplete : Class.empty,
			hideElements: new Array('select', 'iframe', 'applet')
		};
	},

	initialize: function(options) {
		this.setOptions(this.getOptions(), options);
		
		this.Sidebar = new Element('div').addClass('EthonSidebar').setStyles({
			'z-index': '9999',
			'position': 'absolute',
			'opacity': '0',
			'top': '0',
			'width': '0',
			'background-color': this.options.styles['background-color'],
			'color': this.options.styles['color'],
			'height': this.options.styles['height'],
			'overflow-x': 'hidden',
			'overflow-y': 'hidden'
		}).injectInside(document.body);

		if (this.options.position != 'left') this.options.position = 'right';
		this.Sidebar.setStyle(this.options.position, '0');
		
		if (this.options.transition == 'appear') {
			this.options.transitionStyle = 'opacity';
			this.Sidebar.setStyle('width', this.options.styles['width'].toInt() + 'px');
		} else {
			this.options.transitionStyle = 'width';
			this.Sidebar.setStyle('opacity', this.options.styles['opacity']);
		}
		this.SidebarContent = new Element('div').addClass('EthonSidebarContent').setStyle('width', this.options.styles['width'].toInt() + 'px').injectInside(this.Sidebar);
		
		window.addEvent('resize', function() {
			this.Sidebar.setStyle('height', this.options.styles['height']);
		}.bind(this));
		
		this.SidebarLoadingImage = new Asset.image(this.options.loadingImage);
		this.SidebarLoading = new Element('div').addClass('EthonLoadingSidebar').setStyle('text-align', 'center').setStyle('padding', '20px 10px');
		this.SidebarLoadingImage.injectInside(this.SidebarLoading);
		if (this.options.displayLoadingText) {
			this.SidebarLoadingText = new Element('div').setStyle('padding', '4px').setText(this.options.loadingText).injectInside(this.SidebarLoading);
		}
		
		if (this.options.display != 0) {
			this.options.display = 0;
			this.display(true, null);
		}
	},

	/*
	Property: display
		Show or hide the sidebar and optionally load content from a url at the same time
		
	Argument:
		show - boolean, true to show the sidebar and false to hide it
		url - optional url to load content from a url
	*/
	display: function(show, url) {
		if ($defined(url)) {
			this.loadUrl(url);
		}
		if (this.Transition) {
			this.Transition.stop();
		}
			
		if (show && this.options.display == 0) {
			this.options.display = 1;
			this.onShowStart();
			
			this.Transition = this.Sidebar.effect(
				this.options.transitionStyle, 
				{
					duration: this.options.hideDuration,
					transition: this.options.showEffect,
					onComplete: function() {
						this.onShowComplete();
					}.bind(this)
				}
			).start(this.options.styles[this.options.transitionStyle]);
		} else if (!$defined(url)) {
			this.options.display = 0;
			this.onHideStart();
	
			this.Transition = this.Sidebar.effect(
				this.options.transitionStyle, 
				{
					duration: this.options.hideDuration,
					transition: this.options.hideEffect,
					onComplete: function() {
						this.onHideComplete();
					}.bind(this)
				}
			).start(0);
		}
	},
	
	/*
	Property: loadUrl
		Loads content into the sidebar from a url using Ajax
		
	Argument:
		url - url to load the content from
	*/
	loadUrl: function(url) {
		this.SidebarContent.empty();
		this.SidebarLoading.clone().injectInside(this.SidebarContent);
		new Ajax(
			url, {
				method: 'get',
				onComplete: function(responseText, responseXML) {
					this.setContent(responseText);
				}.bind(this),
				onFailure: function(transport) {
					this.setContent('An internal error occurred while loading your content from url [' + url + '] status was [' + transport.status + ':' + transport.statusText + ']');
				}.bind(this)
			}
		).request();
	},
 
	/*
	Property: setContent
		Sets the content of the sidebar, note that this empties the previous content first
		
	Argument:
		content - the content to set
	*/
	setContent: function(content) {
		this.SidebarContent.empty();
		this.SidebarContent.setHTML(content);
	},
	
	/*
	Property: fixCoveredElements
		Internal function (which should not need to be called) to hide and show problematic elements when the sidebar covers them
		so that they do not show through it, the elements are select, iframe and applet
		
	Argument:
		shouldHideElements - boolean, true if the elements should be hidden ,false if they should be reshown
	*/
	fixCoveredElements: function(shouldHideElements) {
		var selfSize = $$('div.EthonSidebarContent')[0].getSize();
		var selfPosition = $$('div.EthonSidebarContent')[0].getPosition();
		
		for (var i = this.options.hideElements.length; i > 0; ) {
			var elements = $$(this.options.hideElements[--i]);
			for (var j = 0; j < elements.length; j++) {
				var elementSize = elements[j].getSize();
				var elementPosition = elements[j].getPosition();
				
				if (shouldHideElements &&
						((elementSize['size']['x'] > (selfPosition['x'] + selfSize['size']['x'])) ||
						((elementPosition['x'] + elementSize['size']['x']) < selfSize['size']['x']))) {
					elements[j].setStyle('visibility', 'hidden');
				} else {
					elements[j].setStyle('visibility', '');
				}
			}
		}
	},
	
	onShowStart: function() {
		if (window.ie6) this.fixCoveredElements(true);
		this.fireEvent('onShowStart', this);
	},
	
	onShowComplete: function() {
		if (window.opera || window.webkit) this.SidebarContent.setStyle('display', 'block');
		if (window.gecko || window.webkit) {
			var height = this.SidebarContent.getStyle('height').toInt() + this.SidebarContent.getPosition()['y'].toInt();
			if (height > window.innerHeight) this.Sidebar.setStyle('height', height + 'px');
		}
		this.fireEvent('onShowComplete', this);
	},
	
	onHideStart: function() {
		//if (window.opera || window.webkit) this.SidebarContent.setStyle('display', 'none');
		if (window.gecko || window.webkit) this.Sidebar.setStyle('height', this.options.styles['height']);
		this.fireEvent('onHideStart', this);
	},
	
	onHideComplete: function() {
		if (window.ie6) this.fixCoveredElements(false);
		this.fireEvent('onHideComplete', this);
	}
});

EthonSidebar.implement(new Events, new Options);