/*

		layerGroup.js
		
		Mootools-based class to provide customizable layer functionality
		
		Written by:		Ken Kolodziej
		Created on:		September 17, 2007
		Updated on:		December 11, 2008
		
		USAGE:			Instantiate a new RolloutGroup and pass two arrays in the options object (rollout div ids and
					trigger object ids).  The two arrays MUST be synchronized for the rollouts to be effective.
*/

var LayerGroup = new Class({
	Implements: [Options, Events],
	options: {
		divIDs:[],
		triggerObjIDs:[],
		triggerEvents:[],
		closeOnHotZone: false
	},
	initialize: function(options){
		this.setOptions(options);
		
		if(this.options.divIDs.length != this.options.triggerObjIDs.length)
			throw("Array lengths do not match (" + this.options.divIDs.length + "," + this.options.triggerObjIDs.length + ")");
		
		this.layers = new Array();
		this.iframes = new Array();
		this.overflows = new Array();
		
		this.openLayer = null;
	},
	getLayer: function(id) {
		for(var i = 0; i < this.layers.length; i++) {
			if(this.layers[i].getID() == id)
				return this.layers[i];
		}
		return null;
	},
	getLayerByTrigger: function(triggerID) {
		for(var i = 0; i < this.layers.length; i++) {
			if(this.layers[i].getTriggerObj().id == triggerID)
				return this.layers[i];
		}
		return null;
	},
	closeAll: function(layer) {
		for(var i = 0; i < this.layers.length; i++) {
			if(this.layers[i].getID() != layer.getDiv().id)
				this.forceClose(layers[i]);
		}
	},
	showLayer: function(layer) {
		this.hideOpenLayer();
		this.createIFrameLayers(layer);
		//this.makeVisible(layer);
		layer.setState('opening');
		layer.runShowEffect();
		this.openLayer = layer;
	},
	hideLayer: function(layer, e) {
		// Only close if mouse is outside the div area
		
		//if(layer.getState() == 'visible') {
		if(this.options.closeOnHotZone == true) {
			if(!this.mouseIsInHotZone(layer, e))
				this.forceClose(layer);
		}
		else
			this.forceClose(layer);
		//}
		
		if(this.openLayer) {
			if(this.openLayer.getID() == layer.getID())
				this.openLayer = null;
		}
	},
	hideOpenLayer: function() {
		if(this.openLayer) {
			this.forceClose(this.openLayer);
			this.openLayer = null;
		}
	},
	forceClose: function(layer) {
		layer.setState('closing');
		layer.runHideEffect();
		this.destroyIFrameLayers();
	},
	makeInvisible: function(layer) {
		if(layer.getParent() && layer.getUseParent() == true) var theEl = layer.getParent();
		else var theEl = layer.getDiv();
		
		theEl.setStyles({
			'visibility': 'hidden',
			'opacity': 0
		});
	},
	makeVisible: function(layer) {
		if(layer.getParent && layer.useParent == true) var theEl = layer.getParent();
		else var theEl = layer.getDiv();
		
		theEl.setStyles({
			'visibility': 'visible',
			'opacity': 1
		});
	},
	mouseIsInHotZone: function(layer, e) {
		var coords = layer.getDiv().getCoordinates();
		// If mouse cursor is within coordinates of div, return true
		if( ( (e.page.x >= coords.left) && (e.page.x <= coords.left + coords.width) ) && ( (e.page.y >= coords.top) && (e.page.y <= coords.top + coords.height) ) )
			return true;
		else
			return false;
	},
	createIFrameLayers: function(layer) {
		// Cover all interfering objects with an iframe
		$$('embed').each(function(el) {
			var coords = el.getCoordinates();
			
			var newFrame = new Element('iframe', {
				styles: {
					'zIndex': layer.getDiv().getStyle("zIndex") - 1,
					'top': coords['top'] + 'px',
					'left': coords['left'] + 'px',
					'width': coords['width'] + 'px',
					'height': coords['height'] + 'px',
					'position': 'absolute',
					'visibility': 'visible',
					'border':'0'
				}
			});
			newFrame.setAttribute("allowtransparency", "true");
			newFrame.setAttribute("frameborder", "0");
			newFrame.set("html", "javascript:'<html></html>';");
			newFrame.injectInside(document.body);
			this.iframes[this.iframes.length] = newFrame;
		}, this);
	},
	destroyIFrameLayers: function() {
		for(var i = 0; i < this.iframes.length; i++)
			this.iframes[i].destroy();
		
		this.iframes.length = 0;
	},
	hideOverflowElements: function(layer) {
		this.overflows.length = 0;
		layer.getDiv().getElements('div').each(function(el) {
			var overflow = el.getStyle('overflow');
			//alert(overflow + ' ' + el.id);
			if(overflow == 'auto' || overflow == 'scroll') {
				this.overflows[this.overflows.length] = new Object({
					'div': el,
					'overflow': overflow
				});
				el.setStyle('overflow', 'hidden');
			}
		}, this);
	},
	showOverflowElements: function() {
		for(var i = 0; i < this.overflows.length; i++)
			this.overflows[i]['div'].setStyle('overflow', this.overflows[i]['overflow']);
		
		this.overflows.length = 0;
	}
});


LayerGroup.Rollout = new Class({
	Extends: LayerGroup,
	options: {
		theModes: []
	},
	initialize: function(options) {
		this.parent(options);
		
		this.setOptions(options);
		
		if(this.options.divIDs.length != this.options.theModes.length)
			throw("Array lengths do not match (" + this.options.divIDs.length + "," + this.options.triggerObjIDs.length + "," + this.options.theModes.length + ")");
		
		var t = this;
		
		for(var i = 0; i < this.options.divIDs.length; i++) {
			if(!this.options.triggerEvents[i])
				this.options.triggerEvents[i] = 'click';
			
			// Create and push a new layer
			var newLayer = new Layer({
				div: $(this.options.divIDs[i]),
				triggerObj: $(this.options.triggerObjIDs[i]),
				id: this.options.divIDs[i],
				theParent: $(this.options.divIDs[i]).getParent().getParent()
			});
			this.layers.push(newLayer);
			
			// Set the layer events
			if(this.options.triggerEvents[i] == 'click') {
				newLayer.getTriggerObj().addEvent(this.options.triggerEvents[i], function(e) {
					var layer = this.getLayerByTrigger(e.target.id);
					
					if(layer.getState() == 'hidden')
						this.showLayer(layer);
					else if(layer.getState() == 'visible')
						this.hideLayer(layer, e);
				}.bind(this));
			}
			else {
				newLayer.getTriggerObj().addEvent(this.options.triggerEvents[i], function(e) {
					this.showLayer(this.getLayerByTrigger(e.target.id));
				}.bind(this));
				
				newLayer.getTriggerObj().addEvent('mouseleave', function(e) {
					var layer = this.getLayerByTrigger(e.target.id);
					
					if(layer.getState() == 'visible')
						this.hideLayer(layer, e);
				}.bind(this));
			}
			
			// Layer effects
			newLayer.effect = new Fx.Slide(this.options.divIDs[i], {
				mode: t.options.theModes[i],
				onStart: function() {
					this.hideOverflowElements(newLayer);
				}.bind(this),
				onComplete: function() {
					//this.showOverflowElements();
					if(this.getState() == 'opening') { this.setState('visible'); }
					else {
						this.setState('hidden');
						//this.makeInvisible();
					}
				}.bind(newLayer)
			}).hide();
			
			newLayer.runShowEffect = function() {
				this.effect.slideIn();
			}.bind(newLayer);
			newLayer.runHideEffect = function() {
				this.effect.slideOut();
			}.bind(newLayer);
			
			//this.makeInvisible(newLayer);
		}
	}
});


LayerGroup.Fade = new Class({
	Extends: LayerGroup,
	options: {
		targetOpacity: [],	// 0 - 1
		duration: []		// milliseconds
	},
	initialize: function(options) {
		this.parent(options);
		
		this.setOptions(options);
		
		var t = this;
		
		for(var i = 0; i < this.options.divIDs.length; i++) {
			var opacity = t.options.targetOpacity[i];
			
			if(!this.options.triggerEvents[i])
				this.options.triggerEvents[i] = 'click';
			
			// Create and push a new layer
			var newLayer = new Layer({
				div: $(this.options.divIDs[i]),
				triggerObj: $(this.options.triggerObjIDs[i]),
				id: this.options.divIDs[i]
			});
			this.layers.push(newLayer);
			
			// Set the layer events
			if(this.options.triggerEvents[i] == 'click') {
				newLayer.getTriggerObj().addEvent(this.options.triggerEvents[i], function(e) {
					e = new Event(e);
					
					var target = $(e.target);
					
					// Make sure the target is a td
					if(target.get('tag') != 'td')
						target = target.getParent('td');
					
					var layer = this.getLayerByTrigger(target.id);
					
					if(layer.getState() == 'hidden')
						this.showLayer(layer);
					else if(layer.getState() == 'visible')
						this.hideLayer(layer, e);
				}.bind(this));
			}
			else if(this.options.triggerEvents[i] == 'mouseenter'
				|| this.options.triggerEvents[i] == 'mouseover') {
				newLayer.getTriggerObj().addEvent(this.options.triggerEvents[i], function(e) {
					this.showLayer(this.getLayerByTrigger(e.target.id));
				}.bind(this));
				
				newLayer.getTriggerObj().addEvent('mouseleave', function(e) {
					var layer = this.getLayerByTrigger(e.target.id);
					
					if(layer.getState() == 'visible')
						this.hideLayer(layer, e);
				}.bind(this));
			}
			else {
				var theLink = this.options.triggerEvents[i];
				newLayer.getTriggerObj().addEvent('click', function(e){
					e = new Event(e);
					location.href = theLink;
					e.stop();
				}.bind(this));
			}
			
			// Layer effects
			newLayer.effect = new Fx.Elements([$(this.options.divIDs[i])], {
				duration: this.options.duration[i],
				onStart: function() {
					this.hideOverflowElements(newLayer);
				}.bind(this),
				onComplete: function() {
					//this.showOverflowElements();
					if(this.getState() == 'opening') { this.setState('visible'); }
					else {
						this.setState('hidden');
						//this.makeInvisible();
					}
				}.bind(newLayer)
			});
			
			newLayer.runShowEffect = function() {
				this.effect.start({
					'0': {
						'opacity': [0, opacity]
					}
				});
			}.bind(newLayer);
			newLayer.runHideEffect = function() {
				//if(this.getState() == 'visible') {
					this.effect.start({
						'0': {
							'opacity': [opacity, 0]
						}
					});
				//}
			}.bind(newLayer);
			
			this.makeInvisible(newLayer);
		}
	}
});
	
	
var Layer = new Class({
	Implements: [Options, Events],
	options: {
		div: '',
		triggerObj: '',
		id: '',
		theParent: null
	},
	initialize: function(options) {
		this.setOptions(options);
		
		this.state = 'hidden';
	},
	getID: function() { return this.options.id; },
	setID: function(id) { this.options.id = id; },
	getState: function() { return this.state; },
	setState: function(state) { this.state = state; },
	getDiv: function() { return this.options.div; },
	setDiv: function(div) { this.options.div = div; },
	getTriggerObj: function() { return this.options.triggerObj; },
	setTriggerObj: function(triggerObj) { this.options.triggerObj = triggerObj; },
	getParent: function() { return this.options.theParent; }
});