﻿var Popup = new Class({
	
	Implements: [Options, Events],
	
	options: {
		/*
		onBeforeLoad: $empty,
		onLoad: $empty,
		onShow: $empty,
		onHide: $empty,
		onTransition: $empty,
		onCancel: $empty,
		multipleChildren: false,
		hideWhenEmpty: false
		*/
	},
	
	/*
	visible: false,
	enableBeforeLoad: false,
	enableLoad: false,
	*/
	children: [],
	
	initialize: function(element, options){
		this.element = $(element);
		if(options){
			if(options.holder){
				options.holder.addChild(this);
				delete options.holder;
			}
			if(options.onBeforeLoad)
				this.enableBeforeLoad = true;
			
			if(options.onLoad)
				this.enableLoad = true;
		}
				
		this.setOptions(options);
	},
	
	addChild: function(child){
		child.holder = this;
		this.children.include(child);
	},
	
	show: function(){
		if(this.holder)
			if(!this.holder.shown)
				this.holder.show();
			else if(!this.holder.options.multipleChildren){
				var th = this;
				this.holder.children.each(function(c){if(c != th) c._hide();});
			}

		if(this.enableBeforeLoad)
			this.call(this.onBeforeLoad.bind(this, arguments));	
							
		if(this.enableLoad)
			this.call(this.onLoad.bind(this, arguments));
		else
			this.loadComplete.apply(this, arguments);
	},

	hide: function(){
		if(this.holder && this.holder.visible && this.holder.options.hideWhenEmpty){
			var c = this.holder.children;
			for(var i=0;i<c.length;i++)
				if(c[i].visible && c[i] != this){
					this._hide();
					return;
				}
			this.holder.hide();
			return;
		}
		this._hide();
	},
	
	_hide: function(){
		if(this.visible){
			this.children.each(function(c){ c._hide(); });
			this.visible = false;
			this.call(this.onHide);
		}
	},

	$next: $empty,
	
	requestQueue: function(popup){
		if(this.holder)
			this.holder.requestQueue(popup);
		else if(this.running){
			(this.$queue = (this.$queue || []).erase(popup)).push(popup);
		} else {
			this.running = true;
			popup.callNext();
		}
	},
		
	nextInQueue: function(){
		if(this.holder)
			this.holder.nextInQueue();
		else if(this.$queue && this.$queue.length > 0)
			this.$queue.shift().callNext();
		else
			this.running = false;
	},
	
	call: function(fn){
		// TODO: Check to see if event exists, so we can remove checks in initialize
		this.$next = fn;
		this.requestQueue(this);
	},
	
	callNext: function(){
		this.running = true;
		this.$next.apply(this);
		this.$next = $empty;
	},
	
	cancel: function(){
		if(this.running){
			this.running = false;
			this.$next = false;
			if(this.$queue) this.$queue.empty();
			this.children.each(function(c){c.cancel();});
		}
	},
	
	complete: function(){
		this.running = false;
		this.nextInQueue();
	},
	
	loadComplete: function(){
		this.complete.apply(this);
	
		if(this.visible)
			this.call(this.onTransition.bind(this, arguments));
		else {
			this.visible = true;
			this.call(this.onShow.bind(this, arguments));
		}
	},
	
	onBeforeLoad: function(){ return this.fireEvent('onBeforeLoad', arguments); },
	
	onLoad: function(){ return this.fireEvent('onLoad', arguments); },
	
	onShow: function(){ return this.fireEvent('onShow', arguments); },
	
	onHide: function(){ return this.fireEvent('onHide', arguments); },
	
	onTransition: function(){ return this.fireEvent('onTransition', arguments); },
	
	onCancel: function(){ return this.fireEvent('onCancel', arguments); }
});