/*
---
name: TabSwapper.js
authors: Aaron Newton
description: Handles the scripting for a common UI layout; the tabbed box.
license: MIT-Style License
requires:
 core:1.2.4: [Element.Event, Fx.Tween, Fx.Morph]
 more:1.2.4.2: [Element.Shortcuts, Element.Dimensions, Element.Measure]
provides: [TabSwapper]
...
*/

var TabSwapper = new Class({
	Implements: [Options, Events],
	options: {
		selectedClass: 'tabSelected',
		mouseoverClass: 'tabOver',
		deselectedClass: '',
		rearrangeDOM: true,
		initPanel: 0,
		smooth: false,
		smoothSize: false,
		maxSize: null,
		effectOptions: {
			duration: 500
		},
		cookieName: null,
		cookieDays: 999
//	onActive: $empty,
//	onActiveAfterFx: $empty,
//	onBackground: $empty
	},
	tabs: [],
	sections: [],
	clickers: [],
	sectionFx: [],
	initialize: function(options){
		this.setOptions(options);
		var prev = this.setup();
		if (prev) return prev;
		if (this.options.cookieName && this.recall()) this.show(this.recall().toInt());
		else this.show(this.options.initPanel);
	},
	setup: function(){
		var opt = this.options;
		sections = $$(opt.sections);
		tabs = $$(opt.tabs);
		if (tabs[0] && tabs[0].retrieve('tabSwapper')) return tabs[0].retrieve('tabSwapper');
		clickers = $$(opt.clickers);
		tabs.each(function(tab, index){
			this.addTab(tab, sections[index], clickers[index], index);
		}, this);
	},
	addTab: function(tab, section, clicker, index){
		tab = document.id(tab); clicker = document.id(clicker); section = document.id(section);
		//if the tab is already in the interface, just move it
		if (this.tabs.indexOf(tab) >= 0 && tab.retrieve('tabbered')
			 && this.tabs.indexOf(tab) != index && this.options.rearrangeDOM) {
			this.moveTab(this.tabs.indexOf(tab), index);
			return this;
		}
		//if the index isn't specified, put the tab at the end
		if (!$defined(index)) index = this.tabs.length;
		//if this isn't the first item, and there's a tab
		//already in the interface at the index 1 less than this
		//insert this after that one
		if (index > 0 && this.tabs[index-1] && this.options.rearrangeDOM) {
			tab.inject(this.tabs[index-1], 'after');
			section.inject(this.tabs[index-1].retrieve('section'), 'after');
		}
		this.tabs.splice(index, 0, tab);
		clicker = clicker || tab;

		tab.addEvents({
			mouseout: function(){
				tab.removeClass(this.options.mouseoverClass);
			}.bind(this),
			mouseover: function(){
				tab.addClass(this.options.mouseoverClass);
			}.bind(this)
		});

		clicker.addEvent('click', function(e){
			e.preventDefault();
			this.show(index);
		}.bind(this));

		tab.store('tabbered', true);
		tab.store('section', section);
		tab.store('clicker', clicker);
		this.hideSection(index);
		return this;
	},
	removeTab: function(index){
		var now = this.tabs[this.now];
		if (this.now == index){
			if (index > 0) this.show(index - 1);
			else if (index < this.tabs.length) this.show(index + 1);
		}
		this.now = this.tabs.indexOf(now);
		return this;
	},
	moveTab: function(from, to){
		var tab = this.tabs[from];
		var clicker = tab.retrieve('clicker');
		var section = tab.retrieve('section');

		var toTab = this.tabs[to];
		var toClicker = toTab.retrieve('clicker');
		var toSection = toTab.retrieve('section');

		this.tabs.erase(tab).splice(to, 0, tab);

		tab.inject(toTab, 'before');
		clicker.inject(toClicker, 'before');
		section.inject(toSection, 'before');
		return this;
	},
	show: function(i){
		if (!$chk(this.now)) {
			this.tabs.each(function(tab, idx){
				if (i != idx)
					this.hideSection(idx);
			}, this);
		}
		this.showSection(i).save(i);
		return this;
	},
	save: function(index){
		if (this.options.cookieName)
			Cookie.write(this.options.cookieName, index, {duration:this.options.cookieDays});
		return this;
	},
	recall: function(){
		return (this.options.cookieName)?$pick(Cookie.read(this.options.cookieName), false): false;
	},
	hideSection: function(idx) {
		var tab = this.tabs[idx];
		if (!tab) return this;
		var sect = tab.retrieve('section');
		if (!sect) return this;
		if (sect.getStyle('display') != 'none') {
			this.lastHeight = sect.getSize().y;
			sect.setStyle('display', 'none');
			tab.swapClass(this.options.selectedClass, this.options.deselectedClass);
			this.fireEvent('onBackground', [idx, sect, tab]);
		}
		return this;
	},
	showSection: function(idx) {
		var tab = this.tabs[idx];
		if (!tab) return this;
		var sect = tab.retrieve('section');
		if (!sect) return this;
		var smoothOk = this.options.smooth && !Browser.Engine.trident4;
		if (this.now != idx) {
			if (!tab.retrieve('tabFx'))
				tab.store('tabFx', new Fx.Morph(sect, this.options.effectOptions));
			var overflow = sect.getStyle('overflow');
			var start = {
				display:'block',
				overflow: 'hidden'
			};
			if (smoothOk) start.opacity = 0;
			var effect = false;
			if (smoothOk) {
				effect = {opacity: 1};
			} else if (sect.getStyle('opacity').toInt() < 1) {
				sect.setStyle('opacity', 1);
				if (!this.options.smoothSize) this.fireEvent('onActiveAfterFx', [idx, sect, tab]);
			}
			if (this.options.smoothSize) {
				var size = sect.getDimensions().height;
				if ($chk(this.options.maxSize) && this.options.maxSize < size)
					size = this.options.maxSize;
				if (!effect) effect = {};
				effect.height = size;
			}
			if ($chk(this.now)) this.hideSection(this.now);
			if (this.options.smoothSize && this.lastHeight) start.height = this.lastHeight;
			sect.setStyles(start);
			if (effect) {
				tab.retrieve('tabFx').start(effect).chain(function(){
					this.fireEvent('onActiveAfterFx', [idx, sect, tab]);
					sect.setStyles({
						height: this.options.maxSize == effect.height ? this.options.maxSize : "auto",
						overflow: overflow
					});
					sect.getElements('input, textarea').setStyle('opacity', 1);
				}.bind(this));
			}
			this.now = idx;
			this.fireEvent('onActive', [idx, sect, tab]);
		}
		tab.swapClass(this.options.deselectedClass, this.options.selectedClass);
		return this;
	}
});


var Dialog = {
	dialogwidth: 700,
	defaultwidth: 700,
	init: function(dw)
	{
		if (dw) {this.dialogwidth = dw;}
		this.overlay = new Element('div').setProperty('id', 'dlgOverlay').setStyles({display: 'none'}).injectInside(document.body);
		this.container = new Element('div').setProperty('id', 'dlgContainer').setStyles({width: this.dialogwidth, display: 'none'}).injectInside(document.body);
		this.content = new Element('div').setProperty('id', 'dlgContent').injectInside(this.container);
		this.closelabel = new Element('a').setProperty('id', 'dlgClose').injectInside(this.container);
		this.overlay.setStyle('height',  window.getHeight());
		this.container.setStyles({'margin-left': (window.getWidth() - this.dialogwidth) / 2 + 'px'})

		window.addEvent('resize', function(){
			this.overlay.setStyles({top: window.getScrollTop()+'px', height: window.getHeight()+'px'});
			this.position();
		}.bind(Dialog));

		window.addEvent('scroll', function(){
			this.overlay.setStyles({top: window.getScrollTop()+'px', height: window.getHeight()+'px'});
			this.position();
		}.bind(Dialog));

		this.overlay.addEvent('mousedown', function(e){e.stop();});

		this.overlay.addEvent('click', function(e){this.hide()}.bind(Dialog));

		this.closelabel.set('text','Close');

		this.closelabel.addEvent('click', function(e){this.hide()}.bind(Dialog));

	},

	show: function(fragmentURL, dw)
	{
		this.overlay.setStyles({top: window.getScrollTop()+'px', height: window.getHeight()+'px'});
		this.dialogwidth = (dw) ? dw : this.defaultwidth;
		this.container.setStyles({width: this.dialogwidth});
		this.container.setStyles({'margin-left': (window.getWidth() - this.dialogwidth) / 2 + 'px'})
		this.overlay.setStyles({'display':'block', 'opacity':'0'});
		this.overlay.fade(0.8);
		this.container.setStyles({'display':'block', 'opacity':'0'});


		var req = new Request.HTML({url:fragmentURL,
			onSuccess: function(a, b, html, js) {
				//Clear the text currently inside the results div.
				this.content.set('text', '');
				//Inject the new DOM elements into the results div.
				this.content.innerHTML = html;
				this.position();
				eval(js);
				//this.container.setStyle('height', $('dlgContent').getHeight());
				this.container.morph({'opacity': 1, 'margin-top': [10, 20]});
			}.bind(Dialog),
			//Our request will most likely succeed, but just in case, we'll add an
			//onFailure method which will let the user know what happened.
			onFailure: function() {
				this.content.set('html', '<h2>Error</h2><p>Unable to load the dialog fragment.</p>');
				this.container.setStyle('height', $('dlgContent').getHeight());
				this.container.fade(1);
			}.bind(Dialog),
			evalScripts: false,
			data: {'async':1}

		}).send();


		$('dlgContainer').setStyles({'display':'block'});
	},

	hide: function()
	{
		$('dlgContainer').setStyles({'display':'none'});
		$('dlgOverlay').fade('out');
		$('dlgContent').empty();

	},

	position: function()
	{
		var scroll = window.getScroll(), size = window.getSize();
		this.container.setStyles({'margin-left': (window.getWidth() - this.dialogwidth) / 2 + 'px', top: (scroll.y + 40) + 'px'})
	},

	scanPage: function()
	{
		$$('a[rel~="dialog"]').addEvent('click', function(e){
			e.stop();
			if (e.target.tagName == 'a' || e.target.tagName == 'A')
			{
				Dialog.show(e.target.getAttribute('href'));
			}
			else
			{
				Dialog.show($(e.target).getParent('a').getAttribute('href'));
			}

		});
	}
};

window.addEvent('domready', Dialog.init.bind(Dialog));
window.addEvent('domready', function(){Dialog.scanPage();});
