/*
// MultiBox - a multi purpose prototype class for showing content without reloading or modifying the web page.
// Copyright (C) 2009  Dino Ivankov <dinoivankov@gmail.com>

// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

var MultiBox = Class.create({
	version : '1.0b',
	id : null,
	link : null,
	element : null,
	title : null,
	draggable : false,
	image : null,
	imageUrl : null,
	options : {
		skinsDir : 'skins/',
		skinName : 'multibox',
		body : null,
		className : 'multibox',
		draggableHandle : '.title'
	},
	status : {
		visible : false,
		idle : false
	},
	axes : {
		x : Array(),
		outerX : Array(),
		y : Array(),
		outerY : Array()
	},
	differences : {
		x : 0,
		y : 0
	},
	elements : {	
		contentDiv : null,
		loaderDiv : null,
		errorDiv : null,
		link : null
	},
	animations : {
		loaderFade : null,
		errorFade : null,
		contentFade : null,
		scaleX : null,
		scaleXOuter : null,
		scaleY : null,
		scaleYOuter : null,
		moveBox : null,
		boxFade : null
	},
	timeouts : {
		idle : null,
		delayedHide : null,
		showImage : null
	},
	reset : function(){
		this.options = {};
		this.options.skinsDir = 'skins/';
		this.options.skinName = 'multibox';
		this.options.body = null;
		this.options.className = 'multibox';
		this.id = null;
		this.link = null;
		this.element = null;
		this.title = null;
		this.draggable = false;
		this.options.draggableHandleSelector = '.title';
		this.image = null;
		this.imageUrl = null;
		this.status = {};
		this.status.visible = false;
		this.status.idle = false;
		this.axes = {};
		this.axes.x = Array();
		this.axes.y = Array();
		this.axes.outerX = Array();
		this.axes.outerY = Array();
		this.differences = {};
		this.differences.x = 0;
		this.differences.y = 0;
		this.elements = {};
		this.elements.contentDiv = null;
		this.elements.loaderDiv = null;
		this.elements.errorDiv = null;
		this.animations = {};
		this.animations.loaderFade = null;
		this.animations.errorFade = null;
		this.animations.contentFade = null;
		this.animations.boxFade = null;
		this.animations.moveBox = null;
		this.animations.scaleX = null;
		this.animations.scaleY = null;
		this.animations.scaleXOuter = null;
		this.animations.scaleYOuter = null;
		this.timeouts = {};
		this.timeouts.delayedHide = null;
		this.timeouts.showImage = null;
		this.timeouts.idle = null;
		
	},
	initialize : function(link, options){
		this.reset();
		if (typeof options == "object"){
			Object.extend(this.options, options);
		};
		this.addHTML();
		this.link = link;
		this.initializeAnimations();
		this.initializeElements();
		this.initializeDifferences();
		this.initializeAxes();
		
	},
	initializeElements : function(){
		this.elements.contentDiv =  this.element.down('.content');
		this.elements.loaderDiv =  this.element.down('.loader');
		this.elements.errorDiv =  this.element.down('.error');
		if (this.elements.errorDiv){
			this.elements.errorDiv.identify();
		};
		if (this.elements.loaderDiv){
			this.elements.loaderDiv.identify();
		};
		if (this.elements.contentDiv){
			this.elements.contentDiv.identify();
		};
	},
	initializeAxes : function(){
		this.axes.x = Array();
		this.axes.y = Array();
		this.axes.outerX = Array();
		this.axes.outerY = Array();

		this.axes.x.push(this.element.down('.body'));
		this.axes.x.push(this.elements.contentDiv);
		this.axes.x.push(this.elements.loaderDiv);
		this.axes.x.push(this.element.down('.t'));
		this.axes.x.push(this.element.down('.b'));
		
		this.axes.y.push(this.element.down('.body'));
		this.axes.y.push(this.elements.contentDiv);
		this.axes.y.push(this.elements.loaderDiv);
		this.axes.y.push(this.element.down('.middle'));
		this.axes.y.push(this.element.down('.r'));
		this.axes.y.push(this.element.down('.l'));
		
		this.axes.outerX.push(this.element.down('.header'));
		this.axes.outerX.push(this.element.down('.middle'));
		this.axes.outerX.push(this.element.down('.footer'));
		this.axes.outerX.push(this.element);
		
		this.axes.outerY.push(this.element);
	},
	initializeDifferences : function(){
		var outerWidth = this.element.getWidth();
		var innerWidth = this.element.down('.body').getWidth();
		var outerHeight = this.element.getHeight();
		var innerHeight = this.element.down('.body').getHeight();
		this.differences.x = outerWidth - innerWidth;
		this.differences.y  = outerHeight - innerHeight;
	},
	initializeAnimations : function(){
		this.animations.loaderFade = null;
		this.animations.errorFade = null;
		this.animations.contentFade = null;
		this.animations.adFade = null;
		this.animations.scaleX = Array();
		this.animations.scaleXOuter = Array();
		this.animations.scaleY = Array();
		this.animations.scaleYOuter = Array();
		this.animations.moveBox = null
	},
	addHTML : function(){
		var bodyElement = $$('body')[0];
		this.element = document.createElement('div');
		this.element = bodyElement.appendChild(this.element);
		this.element = $(this.element);
		this.element.className = this.options.skinName;
		this.element.innerHTML = this.options.body;
		this.element.cleanWhitespace();
		this.id = this.element.identify();
	},
	setContent : function(content){
		this.element.down('.content').innerHTML = content;
	},
	setTitle : function(title){
		var linkTitle = this.link.readAttribute("title");
		if (linkTitle){
			this.title = linkTitle;
			this.element.down('.title').innerHTML += linkTitle;
		}
	},
	makeDraggable : function(){
		var draggableOptions = {
				scroll : window,
				zindex : 990
			};
			if (this.options.draggableHandleSelector && this.element.down(this.options.draggableHandleSelector)){
				this.element.down(this.options.draggableHandleSelector).setStyle({cursor:'move'});
				draggableOptions.handle = this.element.down(this.options.draggableHandleSelector);
			};
		this.draggable = new Draggable(this.element.id, draggableOptions);
	}
});
var MultiBoxes = Class.create({
	reset : function(){
		this.hideAll();
		this.options = {};
		this.options.body = null;
		this.options.skinsDir = 'skins/';
		this.options.skinName = 'multibox';
		this.options.rootElement = null;
		this.options.selector = '.mb_link';
		this.options.showEvents = new Array('click');
		this.options.hideEvents = new Array('');
		this.options.contentUrl = 'index.php';
		this.options.contentUrlParameterName = 'content';
		this.options.animate = true;
		this.options.animationDuration = 0.7;
		this.options.maxOpacity = 1;
		this.options.minOpacity = 0;
		this.options.draggable = true;
		this.options.draggableHandleSelector = '.title';
		this.options.sustainTime = 1;
		this.options.topOffset = 0;
		this.options.leftOffset = 0;
		this.options.startWidth = 245;
		this.options.startHeight = 110;
		this.options.maxWidth = null;
		this.options.maxHeight = null;
		this.options.minWidth = null;
		this.options.minHeight = null;
		this.options.finalX = null;
		this.options.finalY = null;
		this.options.respectViewportSize = true;
		this.options.scrollContents = false;
		this.options.scrollBarWidth = 25;
		this.options.persistent = true;
		this.options.closeHandleSelector = '.close';
		this.options.debug = true;
		if (this.boxes && this.boxes.each){
			this.boxes.each(function(box){
				box.reset();
			});
		};
		this.boxes = Array();
		this.boxLinks = Array();
		this.request = null;
		this.activeLink = null;
		this.listeners = {
			hideBox : null,
			showLoader : null,
			delayedHide : null,
			cancelHide : null
		};
		this.activeLink = null;
	},
	initialize : function(options){
		//console.log hack
		try {console.log();}catch(e){if(e.message){console={};console.log=function(m){if(typeof m !="object"){/*this.log(m)*/;}}.bind(this)}};
		this.reset();
		if (options && typeof options == "object"){
			Object.extend(this.options, options);
		};
		//load ie6 css if neccessary
		this.collectElements();
		this.listeners = {
			hideBox : this.hideBox.bindAsEventListener(this),
			showLoader : this.showLoader.bindAsEventListener(this),
			delayedHide : this.hideBoxDelayed.bindAsEventListener(this),
			cancelHide : this.cancelHide.bindAsEventListener(this)
		};
		this.addListeners();
		this.addCSS();
		this.loadBody();
	},
	addCSS : function(){
		var cssFile = this.options.skinsDir + this.options.skinName + '/css/multibox.css';
		var cssExists = false;
		$$('link').each(function(element){
			if (element.readAttribute('href') == cssFile){
				cssExists = true;
			};
		});
		if (cssExists == false){
			var cssFileNode = $(document.createElement('link'));
			cssFileNode.writeAttribute('href',  cssFile);
			cssFileNode.writeAttribute('rel', 'stylesheet');
			cssFileNode.writeAttribute('type', 'text/css');
			$$('head')[0].appendChild(cssFileNode);
			/*if (Prototype.Browser.IE && parseInt(navigator.userAgent.substring (navigator.userAgent.indexOf("MSIE")+5))==6){
				//append ie6 styles to the document <head> element and add filter and background properties
				var rules = document.styleSheets[(document.styleSheets.length-1)].rules;
				var additionalCssText = '';
				$A(rules).each(function(rule){
					if (rule.style.backgroundImage && rule.style.backgroundImage.match(/.png\)$/)){
						var imagePath = rule.style.backgroundImage.replace('url\(\.\.', this.options.skinsDir + this.options.skinName).replace(')', '');
						additionalCssText += rule.selectorText + "{background:none; background-image:none; filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + imagePath + "', sizingMethod='scale'}";
					}
				}.bind(this));
				var newStyle = document.createElement('style');
				var cssTextNode = document.createElement();
				newStyle = $(newStyle);
				newStyle.writeAttribute('type', 'text/css');
				newStyle = $$('head')[0].appendChild(newStyle);
				newStyle.styleSheet.cssText = additionalCssText;
			};*/
		};
	},
	loadBody : function(){
		var bodyFile = this.options.skinsDir + this.options.skinName + '/box_body.htm';
		new Ajax.Request(bodyFile, {
			onSuccess : function(transport){
				this.options.body = transport.responseText;
			}.bind(this)
		});
	},
	setBaseWidths : function(currentBox, forceAll){
		currentBox.axes.x.each(function(element){
			element.setStyle({width:this.options.startWidth+'px'});
		}.bind(this));
		currentBox.axes.outerX.each(function(forceAll, element){
			element.setStyle({width : this.options.startWidth + currentBox.differences.x+'px'});
		}.bind(this, forceAll));
		
	},
	setBaseHeights : function(currentBox, forceAll){
		currentBox.axes.y.each(function(element){
			if(element.className!='body'){
				element.setStyle({height:this.options.startHeight+'px'});
			} else if (forceAll){
			 	element.setStyle({height:this.options.startHeight+'px'});
			}
		}.bind(this));
		currentBox.axes.outerY.each(function(element){
			element.setStyle({height:this.options.startHeight+currentBox.differences.y+'px'});
		}.bind(this));

	},
	setBaseDimensions : function(currentBox, forceAll){
		forceAll ? forceAll = true : forceAll = false;
		this.setBaseWidths(currentBox, forceAll);
		this.setBaseHeights(currentBox, forceAll);
	},
	getContentDimensions : function(currentBox){
		//TODO : determine a better way to do this?
		element = $(currentBox.elements.contentDiv);
		if (!element){
			return {width:0, height:0};
		};
		var clone = $(element.cloneNode(true));
		clone.setStyle({width:null, height:null, position:'absolute', top:-10000,left:-10000});
		clone.show();
		$$('body')[0].appendChild(clone);
		if (element.childElements().length==1){
			var dims = $(clone.down()).getDimensions();	
		} else {
			var dims = clone.getDimensions();
		};
		$$('body')[0].removeChild(clone);
		if (this.options.maxHeight && dims.height>(this.options.maxHeight-currentBox.differences.y)){
			dims.height = this.options.maxHeight-currentBox.differences.y;
			if (this.options.scrollContents){
				dims.width += this.options.scrollBarWidth;
			};
		};
		if (this.options.maxWidth && dims.width>this.options.maxWidth-currentBox.differences.x){
			dims.width = this.options.maxWidth-currentBox.differences.x;
		};
		if (this.options.minHeight && dims.height<this.options.minHeight){
			dims.height = this.options.minHeight;
		};
		if (this.options.minWidth && dims.width<this.options.minWidth){
			dims.width = this.options.minWidth;
		};
		if (this.options.respectViewportSize){
			var viewportDimensions = document.viewport.getDimensions();
			if (dims.width>viewportDimensions.width){
				dims.width = document.viewport.getDimensions().width-currentBox.differences.x;
			};
			if (dims.height>viewportDimensions.height){
				dims.height = document.viewport.getDimensions().height-currentBox.differences.y;
			};
		};
		return dims;
	},
	setFinalDimensions : function(currentBox){
		var dimensions = this.getContentDimensions(currentBox);
		dimensions.height < this.options.startHeight ? dimensions.height = this.options.startHeight : false;
		dimensions.width < this.options.startWidth ? dimensions.width = this.options.startWidth : false;
		var innerWidthStyle = {
				width : dimensions.width + 'px'
			};
			var innerHeightStyle = {
				height : dimensions.height + 'px'
			};
			var outerWidthStyle = {
				width : dimensions.width + currentBox.differences.x + 'px'
			};
			var outerHeightStyle = {
				height : dimensions.height + currentBox.differences.y + 'px'
			};
			currentBox.axes.x.each(function(element){
				element.setStyle(innerWidthStyle);
			});
			currentBox.axes.y.each(function(element){
				element.setStyle(innerHeightStyle);
			});
			currentBox.axes.outerX.each(function(element){
				element.setStyle(outerWidthStyle);
			});
			currentBox.axes.outerY.each(function(element){
				element.setStyle(outerHeightStyle);
			});
	},
	log : function(message){
		if (this.options.debug){
			if ($('mb_debug')){
				$('mb_debug').innerHTML += '<div>'+message+'</div>';
			};
		};
	},
	collectElements : function(){
		if (this.options.rootElement && $(this.options.rootElement)){
			this.options.rootElement = $(this.options.rootElement);
			$(this.options.rootElement).select(this.options.selector).each(function(element){
				this.boxLinks.push(element);
			}.bind(this));
		} else {
			$$(this.options.selector).each(function(element){
				this.boxLinks.push(element);
			}.bind(this));
		};
	},
	addListeners : function(){
		this.boxLinks.each(function(element){
			this.options.showEvents.each(function(element, eventName){
				element.observe(eventName, this.listeners.showLoader);	
			}.bind(this, element));
			this.options.hideEvents.each(function(element, eventName){
				element.observe(eventName, this.listeners.hideBox);	
			}.bind(this, element));
		}.bind(this));
	},
	removeListeners : function(){
			this.options.showEvents.each(function(eventName){
				this.boxLinks.each(function(eventName, boxLink){
					boxLink.stopObserving(eventName, this.listeners.showLoader);
				}.bind(this, eventName));
			}.bind(this));
			/*
			TODO: hide event listeners removing - this triggers 'too many recursions' error in firebug ???
			this.options.hideEvents.each(function(eventName){
				this.boxLinks.each(function(eventName, boxLink){
					boxLink.stopObserving(eventName, this.listeners.hideBox);
				}.bind(this, eventName));
			}.bind(this));
			*/
	},
	showLoader : function(event){
		this.activeLink = Event.element(event);
		var element = Event.element(event);
		Event.stop(event);
		var currentBox = this.getBoxByLink(element);
		var newBox = false;
		if (!currentBox){
			newBox = true;
			this.boxes.push(new MultiBox(this.activeLink, {
				skinsDir : this.options.skinsDir,
				skinName : this.options.skinName,
				body : this.options.body,
				draggableHandleSelector : this.options.draggableHandleSelector
			}));
			currentBox = this.boxes.last();
			currentBox.setTitle();
		};
		if (this.options.closeHandleSelector && currentBox.element.down(this.options.closeHandleSelector)){
			currentBox.element.down(this.options.closeHandleSelector).setStyle({cursor:'pointer'});
			currentBox.element.down(this.options.closeHandleSelector).observe('click', this.hideBox.bindAsEventListener(this));
		};
		if (this.options.draggable){
			currentBox.makeDraggable();
		};
		currentBox.element.hide();
		if (newBox){
			this.adjustLoaderPosition(currentBox);
		};
		if (!this.options.animate){
			if (newBox){
				currentBox.elements.contentDiv.hide();
				currentBox.elements.loaderDiv.show();
			};
			currentBox.element.show();
		} else {
			currentBox.animations.boxFade = new Effect.Appear(currentBox.id, {
				duration : this.options.animationDuration,
				from : this.options.minOpacity,
				to : this.options.maxOpacity
			});
		};
		if (newBox){
			this.loadContent(currentBox);
		} else {
			currentBox.timeouts.idle = setTimeout(this.idle.bind(this, currentBox), 1000*this.options.animationDuration);
		};
		return true;
	},
	adjustLoaderPosition : function(currentBox){
		var eventElement = currentBox.link;
		var eventElementPosition = eventElement.cumulativeOffset();
		var eventElementDimensions = eventElement.getDimensions();
		var elementDimensions = {};
		elementDimensions.width = this.options.startWidth;
		elementDimensions.height = this.options.startHeight;
		var viewportDimensions = document.viewport.getDimensions();
		var boxTop = eventElementPosition.top + eventElementDimensions.height;
		var boxLeft = (eventElementPosition.left + (eventElementDimensions.width/2)) - (elementDimensions.width/2);
		if (boxLeft + elementDimensions.width>viewportDimensions.width+document.viewport.getScrollOffsets().left){
			boxLeft = viewportDimensions.width-elementDimensions.width;
		} else if (boxLeft <=0){
			boxLeft = 0;
		};
		if (boxTop + elementDimensions.height > viewportDimensions.height + document.viewport.getScrollOffsets().top){
			boxTop = eventElement.positionedOffset().top - elementDimensions.height;
		};
		boxTop = parseInt(boxTop);
		boxLeft = parseInt(boxLeft);
		currentBox.element.setStyle({top : boxTop + 'px', left : boxLeft + 'px'});
	},
	adjustFinalPosition : function(currentBox){
		var boxPosition = {
			left : null,
			top : null
		};
		if (this.options.finalX == null || this.options.finalY == null){
			var finalDimensions = this.getContentDimensions(currentBox);
			var viewportDimensions = document.viewport.getDimensions();
			var viewportOffsets = document.viewport.getScrollOffsets();
			finalDimensions.height = finalDimensions.height + currentBox.differences.y;
			finalDimensions.width = finalDimensions.width + currentBox.differences.x;
			boxPosition.left = parseInt(currentBox.element.getStyle('left'))+this.options.leftOffset;
			boxPosition.top = parseInt(currentBox.element.getStyle('top'))+this.options.topOffset;
			if (this.options.finalY == null){
				if ((boxPosition.top + finalDimensions.height) >= (viewportDimensions.height + viewportOffsets.top)){
						boxPosition.top = Math.round((viewportDimensions.height + viewportOffsets.top) - (finalDimensions.height));
				};
				if (boxPosition.top < viewportOffsets.top){
					boxPosition.top = viewportOffsets.top;
				};
			} else {
					boxPosition.top = this.options.finalY;
			};
			if (this.options.finalX == null){
				boxPosition.left = Math.round(boxPosition.left + ((this.options.startWidth+currentBox.differences.x)/2) - (finalDimensions.width/2));
				if ((boxPosition.left + (finalDimensions.width)) >= (viewportDimensions.width + viewportOffsets.left)){
					boxPosition.left = Math.round((viewportDimensions.width + viewportOffsets.left) - ((finalDimensions.width)));
				};
				if (boxPosition.left < 0){
					boxPosition.left = 0;
				};
			} else {
				boxPosition.left = this.options.finalX;
			};
		} else {
				boxPosition.top = this.options.finalY;
				boxPosition.left = this.options.finalX;
		};
		if (!this.options.animate){
			currentBox.element.setStyle({
				top : boxPosition.top + 'px',
				left : boxPosition.left + 'px'
			});
		} else {
			// TODO: try to determine a better way than (8/9) to aviod multibox crossing the viewport edge while resizing 
			currentBox.animations.moveBox = new Effect.Move(currentBox.element, {
				x:boxPosition.left,
				y:boxPosition.top,
				mode:'absolute',
				duration:this.options.animationDuration*(8/9) 
			});
		};
	},
	loadContent : function(currentBox){
		if (!(/#/.match(currentBox.link.href))){
			var url = currentBox.link.getAttribute('href');
			if (/\.(png|jpg|jpeg|jpe|gif|bmp)$/.match(url)){
				currentBox.imageUrl=url;
				currentBox.image = new Image();
				currentBox.image.src = currentBox.imageUrl;
				this.showImage(currentBox);
				return;
			};
			this.request = new Ajax.Request(url, {
				method : 'get',
				parameters : null,
				onSuccess : function(currentBox, transport){
					if (transport.responseText){
						currentBox.setContent(transport.responseText);
						this.showBoxContents(currentBox);
					} else {
						this.showError(currentBox);
					};
				}.bind(this, currentBox),
				onFailure : function(currentBox){
					this.showError(currentBox);
				}.bind(this, currentBox)
			});
		} else {
			var url=this.options.contentUrl;
			eval("var requestParams = {parameters : {"+this.options.contentUrlParameterName+" : '"+this.activeLink.innerHTML.toLowerCase()+"'}}");
			var ajax = new Ajax.Request(url, Object.extend(requestParams, {
				method : 'post',
				onComplete : function(currentBox, transport){
					if (transport.responseText){
						currentBox.setContent(transport.responseText);
						this.showBoxContents(currentBox);
					} else {
						this.showError(currentBox);
					}
				}.bind(this, currentBox)
			}));
		};
	},
	showImage : function(currentBox){
		if (currentBox.timeouts.showImage){
			clearTimeout(currentBox.timeouts.showImage);
		};
		if (currentBox.image.complete){
			currentBox.elements.contentDiv.innerHTML = '<img name="multibox_image" src="'+currentBox.imageUrl+'" width="'+currentBox.image.width+'" height="'+currentBox.image.height+'" alt="'+currentBox.imageUrl+'" />';
			this.showBoxContents(currentBox);
			return true;
		};
		currentBox.timeouts.showImage = setTimeout(this.showImage.bind(this, currentBox), 100);
		return false;
	},
	scaleBox : function(currentBox){
		var xAxisArray = Array();
			currentBox.axes.x.each(function(element){
				if (!element.id){
					element.identify();
				};
				xAxisArray.push(element.id);
			});
			var yAxisArray = Array();
			currentBox.axes.y.each(function(element){
				if (!element.id){
					element.identify();
				};
				yAxisArray.push(element.id);
			});
			var finalDimensions = this.getContentDimensions(currentBox);
			var heightPercent = (finalDimensions.height/this.options.startHeight) * 100;
			var widthPercent = (finalDimensions.width/this.options.startWidth) * 100;
			var outerHeightPercent = ((finalDimensions.height+currentBox.differences.y)/(this.options.startHeight+currentBox.differences.y)) * 100;
			var outerWidthPercent = (finalDimensions.width+currentBox.differences.x)/(this.options.startWidth+currentBox.differences.x) * 100;
			
			var outerXOptions = {
				duration : this.options.animationDuration,
					scaleMode : {
						originalWidth : this.options.startWidth+currentBox.differences.x,
						originalHeight : this.options.originalHeight+currentBox.differences.y
					},
					scaleY : false,
					scaleContent : false
			};
			if (finalDimensions.width < this.options.startWidth){
				Object.extend(outerXOptions, {delay : this.options.animationDuration*2, duration : 0});
			} else {
				Object.extend(outerXOptions, {delay : 0, duration : this.options.animationDuration*(8/9)});
			};
			currentBox.axes.outerX.each(function(outerWidthPercent, element){
				currentBox.animations.scaleX.push(new Effect.Scale(element, outerWidthPercent, outerXOptions));
			}.bind(this, outerWidthPercent));
			
			var xOptions = {
					duration : this.options.animationDuration,
					scaleMode : {
						originalWidth : this.options.startWidth,
						originalHeight : this.options.originalHeight
					},
					scaleY : false,
					scaleContent : false
			};
			currentBox.axes.x.each(function(widthPercent, element){
				currentBox.animations.scaleX.push(new Effect.Scale(element, widthPercent, xOptions));
			}.bind(this, widthPercent));
			
			var outerYOptions = {
				scaleMode : {
					originalWidth : this.options.startWidth+currentBox.differences.x,
					originalHeight : this.options.startHeight+currentBox.differences.y
				},
				scaleX : false,
				scaleContent : false
			};
			if (finalDimensions.height < this.options.startHeight){
				Object.extend(outerYOptions, {delay : this.options.animationDuration*2, duration : 0});
			} else {
				Object.extend(outerYOptions, {delay : 0, duration : this.options.animationDuration*(8/9)});
			};
			currentBox.axes.outerY.each(function(outerHeightPercent, element){
				currentBox.animations.scaleYOuter.push(new Effect.Scale(element, outerHeightPercent, outerYOptions));
			}.bind(this, outerHeightPercent));
			
			var yOptions = {
				duration : this.options.animationDuration,
				scaleMode : {
					originalWidth : this.options.startWidth,
					originalHeight : this.options.startHeight
				},
				scaleX : false,
				scaleContent : false
			};
			currentBox.axes.y.each(function(element){
				currentBox.animations.scaleY.push(new Effect.Scale(element, heightPercent, yOptions));
			}.bind(this));
			
			currentBox.animations.loaderFade = new Effect.Fade(currentBox.elements.loaderDiv.id, {
				to : this.options.minOpacity,
				from : this.options.maxOpacity,
				duration : this.options.animationDuration,
				delay : this.options.animationDuration
			});
			currentBox.animations.contentFade = new Effect.Appear(currentBox.elements.contentDiv, {
				duration : this.options.animationDuration,
				from : this.options.minOpacity,
				to : this.options.maxOpacity,
				queue : "end"
			});
	},
	showBoxContents : function(currentBox){
		currentBox.elements.contentDiv.setStyle({overflow : 'hidden'});
		if (!this.options.animate){
			currentBox.elements.loaderDiv.hide();
			currentBox.elements.contentDiv.show();
			this.setFinalDimensions(currentBox);
			this.adjustFinalPosition(currentBox);
			this.idle(currentBox);
		} else {
			this.adjustFinalPosition(currentBox);
			this.scaleBox(currentBox);
		};
		currentBox.timeouts.idle = setTimeout(this.idle.bind(this, currentBox), 4000*this.options.animationDuration);
		currentBox.status.visible = true;
	},
	getBoxById : function(id){
		var currentBox = false;
		this.boxes.each(function(box){
			if (box.id == id){
				currentBox = box;
			};
		});
		return currentBox;
	},
	getBoxByLink : function(link){
		var currentBox = false;
		this.boxes.each(function(box){
			if (box.link == link){
				currentBox = box;
			};
		});
		return currentBox;
	},
	hideBox : function(event, force){
		force = force == true ? true : false;

		var element = Event.element(event);
		if (element.className == this.options.skinName){
			currentBox = this.getBoxById(element.id);
		} else {
			currentBox = this.getBoxById(element.up('.'+this.options.skinName).id);
		};
		if (event.stop){
			Event.stop(event);
		};
		this.hideParticularBox(currentBox);
	},
	hideParticularBox : function(currentBox, force){
		currentBox.status.idle = false;
		if (this.request){
			this.request.onSuccess = null;
			this.request = null;
		};
		if (currentBox.timeouts.delayedHide){
			clearTimeout(currentBox.timeouts.delayedHide);
		};
		if (currentBox.timeouts.showImage){
			clearTimeout(currentBox.timeouts.showImage);
		};
		if (currentBox.element){
			if (currentBox.element != null){
				if (!this.options.persistent){
					currentBox.element.stopObserving("mouseout", this.listeners.delayedHide);
					currentBox.element.descendants().each(function(element){
						element.stopObserving("mouseover", this.listeners.cancelHide);
					}.bind(this));
				};
				if (this.options.closeHandleSelector && currentBox.element.down(this.options.closeHandleSelector)){
					currentBox.element.down(this.options.closeHandleSelector).stopObserving('click', this.hideBox.bindAsEventListener(this));
				};
				if (this.options.animate){
						currentBox.animations.boxFade = new Effect.Fade(currentBox.element.id, {
						duration : this.options.animationDuration/2,
						queue :  'front'
					});
				} else {
					currentBox.element.hide();
				};
				this.activeLink = null;
			};
		};
		this.idle(currentBox);
		currentBox.status.visible = false;
	},
	hideBoxDelayed : function(event){
		Event.extend(event);
		element = Event.element(event);
		if (element.className == this.options.skinName){
			var element = element;
		} else {
			var element = element.up('.'+this.options.skinName);
		};
		var currentBox = this.getBoxById(element.id);
		if (currentBox.timeouts.delayedHide){
			clearTimeout(currentBox.timeouts.delayedHide);
		};
		currentBox.timeouts.delayedHide = setTimeout(this.hideParticularBox.bind(this, currentBox), this.options.sustainTime*1000);
	},
	cancelHide : function(event){
		var element = Event.element(event);
		var element = element.className == this.options.skinName ? element : element.up('.'+this.options.skinName);
		var currentBox = this.getBoxById(element.id);
		if (currentBox.timeouts.delayedHide){
			clearTimeout(currentBox.timeouts.delayedHide);
		};
	},
	idle : function(currentBox){
		if (this.options.scrollContents){
				currentBox.elements.contentDiv.setStyle({overflow:'auto'});
		};
		if (!this.options.persistent){
			currentBox.element.observe("mouseout", this.listeners.delayedHide);
			currentBox.element.descendants().each(function(element){
				element.observe("mouseover", this.listeners.cancelHide);
			}.bind(this));
		};
		if (currentBox.timeouts.idle){
			clearTimeout(currentBox.timeouts.idle);
		};
		currentBox.status.idle = true;
	},
	showError : function(currentBox){
		if (!this.options.animate){
			currentBox.elements.loaderDiv.hide();
			currentBox.elements.errorDiv.show();
			this.idle();
		} else {
			currentBox.animations.loaderFade = new Effect.Fade(currentBox.elements.loaderDiv, {
				duration : this.options.animationDuration,
				from : this.options.maxOpacity,
				to : this.options.minOpacity
			});
			currentBox.animations.errorFade = new Effect.Appear(currentBox.elements.errorDiv, {
				duration : this.options.animationDuration,
				from : this.options.minOpacity,
				to : this.options.maxOpacity,
				delay : this.options.animationDuration
			});
			currentBox.timeouts.idle = setTimeout(this.idle.bind(this, currentBox), 2000*this.options.animationDuration);
		};
		currentBox.element.observe("mouseout", this.listeners.delayedHide);
	},
	hideAll : function(){
		if (this.boxes && this.boxes.each){
			this.boxes.each(function(box){
				box.element.hide();
			}.bind(this));
		};
	}
});
 
