//Yamoodow 1.0 - (c) 2009 Christian Opitz, Netzelf - http://netzelf.de - Released under the MIT License
(function() 
{
	/*
	 * This is a static that keeps the current window when present
	 * @var window.yamoodow
	 */ 
	var openYamoodow = null;
	
	window.yamoodowGlobals = {
		options: {}
	};
	
	window.yamoodow = new Class({
		Implements: [Options,Events],
		options: {
			opener:null,
			title:'',
			buildTabs:true,
			width: 500,
			height: 400,
			horizontalGap: 20,
			verticalGap: 20,
			overlayOpacity: 0.6,
			template: 
				'<div id="{cssPrefix}Head" class="{cssPrefix}RightCorner">'+
					'<div class="{cssPrefix}LeftCorner">'+
						'<div id="{cssPrefix}Title"></div>'+
						'<div id="{cssPrefix}CloseHandle"></div>'+
					'</div>'+
				'</div>'+
				'{tabs}'+
				'{content}'+
				'<div id="{cssPrefix}Bottom">'+
					'<div class="{cssPrefix}RightCorner">'+
						'<div class="{cssPrefix}LeftCorner">'+
							'<div class="{cssPrefix}StatusBar"></div>'+
						'</div>'+
					'</div>'+
				'</div>',
			placeholders: {},
			cssPrefix: 'ymd',
			selectors: {
				closeHandle: '#{cssPrefix}CloseHandle',
				title: '#{cssPrefix}Title',
				statusText: '.{cssPrefix}StatusBar',
				loading: '.{cssPrefix}StatusBar'
			},
			contentPosition: {
				left: 0,
				right: 0,
				top: 46,
				bottom: 24
			},
			overlayTweenOptions: {
				duration: 300
			},
			windowTweenOptions: {
				duration: 300
			},
    		requestOptions: {
    			evalScripts:true,
    			cache: false
    		},
			lang: {
		  		loading: 'Loading...',
		  		loaded: 'Ready',
		  		failure: 'Error: ',
		  		httpCodes: {
			        '404':'page not found',
			        '403':'forbidden'
				}
			},
			cache: true
		},
		initialize: function(tabs, options) {
			this.setOptions(window.yamoodowGlobals.options);
			this.setOptions(options);
			this.tabs = tabs;
			
			this.overlay = new Element('div', {id: this.options.cssPrefix+'Overlay', events: {click: this.closeWin.bind(this)}});
			this.win = new Element('div', {id: this.options.cssPrefix+'Window', styles: {width: this.options.width}});
			this.overlay.set('tween', this.options.overlayTweenOptions).fade('hide');
			this.win.set('tween', this.options.windowTweenOptions).fade('hide');
					
			window.addEvent('domready',function(){
				$(document.body).adopt(this.overlay, this.win);
				
				var replace = new Hash(this.options);
				replace.extend(this.options.placeholders);
				replace.content = '<div id="'+this.options.cssPrefix+'ContainerWrap"></div>';
				if (this.tabs && this.options.buildTabs) {
					replace.tabs = '<div id="'+this.options.cssPrefix+'Navi'+'"></div>';
				}
				
				this.win.set('html', this.options.template.substitute(replace));
				
				if (this.tabs && this.options.buildTabs) {
					//Build Navi
					this.nav = new Element('ul',{styles:{'margin':0,'padding':0}}).inject(this.getElement('#'+this.options.cssPrefix+'Navi'));
					this.tabs.each(function(tab,i){
						this.tabs[i].li = new Element('li', {
							'text':tab.text,
							'events': { 
								'click': this.load.bind(this,i)
						}}).inject(this.nav)
					}.bind(this));
				}
				
				this.title = this.getElement(this.options.selectors.title.substitute(replace));
				this.title.set('text', this.options.title);
				this.closeHandle = this.getElement(this.options.selectors.closeHandle.substitute(replace));
				this.closeHandle.addEvent('click', this.closeWin.bind(this));
				this.statusText = this.getElement(this.options.selectors.statusText.substitute(replace));
				this.loadingEl = this.getElement(this.options.selectors.loading.substitute(replace));
				
				this.addEvent('success', this.resizeWin);
				
				this.containerWrap = this.getElement('#'+this.options.cssPrefix+'ContainerWrap').setStyles({'overflow':'auto','position':'absolute'});
				this.container = new Element('div', {'class': this.options.cssPrefix+'Content'}).inject(this.containerWrap);
				
				if (this.options.opener) {
					this.options.opener.removeEvent('click');
					this.options.opener.removeProperty('href');
					this.options.opener.addEvent('click', this.openWin.bind(this));
				}
			}.bind(this));
			
			this.active = -1;
			this.cache = [];
			
			return this;
		},
		getElement: function(selector) {
			var el = this.win.getElement(selector);
			return (el != null) ? el : new Element('div');
		},
		openWin: function() {
			this.overlaySetup(1);
			this.resizeWin();
			
			this.overlay.fade(this.options.overlayOpacity);
			this.win.setStyle('display','');
			this.win.fade('in');
			
			if (this.active == -1 || $type(arguments[0]) == 'number') {
				var tab = ($type(arguments[0]) == 'number') ? arguments[0] : 0;
				this.active = tab;
				this.load(tab);
			}
		},
		width: 0,
		height: 0,
		resizeWin: function()
		{
			this.windowSize = window.getSize();
			
			var tab = (this.active > -1) ? this.tabs[this.active] : {};
			
			// Adjust the width:
			this.width = tab.width ? tab.width : this.options.width;
			if (this.windowSize.x < (this.width + (2*this.options.horizontalGap))) {
				this.width = this.windowSize.x - (2*this.options.horizontalGap);
			}
			this.win.setStyle('width', this.width);
			
			// Ajdust the height:
			if (this.options.height == 'auto' || tab.height == 'auto') {
				if (tab.iframe) {
					// We can't measure 
					if (tab.height) {
						// Invoke the configured height for this iframe:
						this.height = tab.height;
						this.height += this.options.contentPosition.bottom;
						this.height += this.options.contentPosition.top;
					}else{
						// Give the maximum of available height:
						this.height = this.windowSize.y;
						this.height -= 2*this.options.verticalGap;
					}
				}else{
					// Measure the contents height
					// When there's a vertical margin it may happen that this is
					// not measured unless we set padding on the container:
					// overflow:hidden should cause hasLayout in IE
					this.container.setStyles({'padding-top':1,'overflow':'hidden','padding-bottom':1});
					this.containerWrap.setStyle('overflow', 'visible');
					this.height = this.container.getSize().y - 2;
					this.container.setStyles({'padding-top':0,'padding-bottom':0});
					this.containerWrap.setStyle('overflow', 'auto');
					this.height += this.options.contentPosition.bottom;
					this.height += this.options.contentPosition.top;
					
					// For some reason IE7 needs one pixel more to not show scroll bars (IE6 is just fine - ???)
					if (document.all && !window.opera && window.XMLHttpRequest) {
						this.height += 1;
					}
				}
			}else{
				this.height = tab.height ? tab.height : this.options.height;
			}
			if (this.windowSize.y < (this.height + (2*this.options.verticalGap))) {
				this.height = this.windowSize.y - (2*this.options.verticalGap);
			}
			
			this.win.setStyle('height', this.height);
			
			this.containerWrap.setStyles(this.options.contentPosition);
			this.position();
		},
		closeWin: function() {
			this.overlay.fade('out');
			this.win.fade('out');
			this.win.setStyle('display','none');
			this.overlaySetup(0);
		},
		position: function()
		{			
			compatibleOverlay = Browser.Engine.trident4 || (this.overlay.currentStyle && (this.overlay.currentStyle.position != "fixed"));
			if (compatibleOverlay) {
				this.overlay.style.position = "absolute";
			}
			var windowScroll = window.getScroll();
			this.win.setStyles({"left": windowScroll.x + (this.windowSize.x / 2) - (this.width / 2),'top': windowScroll.y + (this.windowSize.y / 2) - (this.height / 2)});
			if (compatibleOverlay) this.overlay.setStyles({left: windowScroll.x, top: windowScroll.y, width: this.windowSize.x, height: this.windowSize.y});
		},
		overlaySetup: function(open)
		{
			var fn = open ? "addEvent" : "removeEvent";
			window[fn]("scroll", this.position.bind(this))[fn]("resize", this.resizeWin.bind(this));
		},
		/* if second argument is set to true, cache of this tab is emptyed and tab gets reloaded */
		load: function(i)
		{
			if (this.options.buildTabs) {
				this.tabs[this.active].li.removeClass(this.options.cssPrefix+'Active');
				this.tabs[i].li.addClass(this.options.cssPrefix+'Active');
			}else if(this.tabs[this.active].title) {
				this.title.set('text', this.tabs[this.active].title);
			}
			this.toCache = this.active;
			this.active = i;
			if (!arguments[1]) {
				if (this.getCache()) return;
			} else this.cacheClear(this.active);
			this.tabs[this.active].status = null;
			if (this.tabs[i].iframe) this.loadIframe(); else this.loadAjax();
		},
		/* arguments:
		None (clear Statusbar immediately) or Text(optional), Add loading class (optional, bool), delay till message disappears (optional), Event (optional) */
		triggerStatus: function() {
			this.statusText.set('html',arguments[0] || '');
			$clear(this.statusTimer);
			if (arguments[1]) this.loadingEl.addClass(this.options.cssPrefix+'Loading'); else this.loadingEl.removeClass(this.options.cssPrefix+'Loading');
			if (arguments[2]) this.statusTimer = this.triggerStatus.delay(arguments[2]*1000,this);
			if (arguments[3]) this.fireEvent(arguments[3],[$merge({container:this.container},this.tabs[this.active]),this.active]);
		},
		loadIframe: function(){
			this.triggerStatus(this.options.lang.loading,1,0,'load');
			this.writeCache();
			this.container.setStyles({overflow:'hidden',height:'100%'});
			this.iframe = new IFrame({
				src: this.tabs[this.active].url,
				styles: {
					width:'100%',
					height:'100%',
					border:'none'
				},
				events: { load: this.triggerStatus.bind(this,[this.options.lang.loaded,0,3,'success']) }
			}).inject(this.container.empty());
		},
		loadAjax: function(){
			this.triggerStatus(this.options.lang.loading,1,0,'load');
			this.writeCache();
			new Request.HTML($merge(
				this.options.requestOptions,	
				{
					url:this.tabs[this.active].url,
					update:	this.container,
					onSuccess: function() { this.triggerStatus(this.options.lang.loaded,0,3,'success'); }.bind(this),
					onFailure: function(xhr){
						this.tabs[this.active].status = xhr.status;
						this.triggerStatus(this.options.lang.failure+this.options.lang.httpCodes[xhr.status],0,0,'failure'); }.bind(this)
				}
			)).get();
		},
		writeCache: function() {
			if (!this.options.cache) return;
			this.cache[this.toCache] = this.container.setStyle('display','none');
			this.container = new Element('div', {'class': this.options.cssPrefix+'Content'}).inject(this.containerWrap);
		},
		getCache: function() {
			if (!this.options.cache || !this.cache[this.active]) return false;
			this.cache[this.toCache] = this.container.setStyle('display','none');
			this.container = this.cache[this.active].setStyle('display','');
			return true;
		},
		cacheClear: function(i) {
			if (!this.options.cache) return;
			if (this.cache[this.active]) {
				this.cache[this.active].destroy();
				this.cache[this.active] = 0;
			}
		}
	});
})();
