﻿if (typeof Effect == "undefined") {	Effect = {}; }

Element.addMethods({
	/**
	 *  Element#cloak(@element) -> element
	 **/
	cloak: function(element) {
		element.style.visibility = "hidden";
	},
	/**
	 *  Element#reveal(element) -> element
	 **/
	reveal: function(element) {
		element.style.visibility = "visible";
	},
	/**
	 *  Element#cloaked(@element) -> Boolean
	 **/
	cloaked: function(element) {
		return element.style.visibility == "hidden";
	}
});

var BoxBox = {
	Overlay: Class.create({
		initialize: function(defaults) {
			// Set defaults based on class defaults and user input. These can be overridden at runtime.
			this.defaults = Object.extend(Object.clone(BoxBox.Overlay.Defaults), defaults || {});
            
            // for the styles below, i moved position into css as ie6 needs absolute, not fixed. ie6 check needs to be built into this boxbox. BF
			this.element = new Element("div", {"class": "bb-overlay"}).setStyle({
				display: "none",
				width: "100%", height: "100%",
				left: 0, top: 0,
				background: this.defaults.background
			});
			$(document.body).insert({top: this.element}); // Should this go up top?
		},
		/**
		 *  BoxBox.Overlay#show() -> this
		 **/
		show: function() {
			// TODO: allow passing runtime options which override defaults
			// Fade-in overlay
			new Effect.Appear(this.element, {
				transition: this.defaults.transition,
				duration: this.defaults.duration,
				afterFinish: function(fx) {
					$(document).fire("boxbox:overlay:appear", {
						effect: fx,
						sender: this
					});
				}.bind(this)
			});
			return this;
		},
		/**
		 *  BoxBox.Overlay#hide() -> this
		 **/
		hide: function() {
			// Fade-out overlay
			new Effect.Fade(this.element, {
				transition: this.defaults.transition,
				duration: this.defaults.duration,
				afterFinish: function(fx) {
					$(document).fire("boxbox:overlay:fade", {
						effect: fx,
						sender: this
					});
				}.bind(this)
			});
			return this;
		},
		/**
		 *  BoxBox.Overlay#visible() -> Boolean
		 **/
		visible: function() {
			return this.element.visible();
		},
		/**
		 *  BoxBox.Overlay#toString() -> String
		 **/
		toString: function() { return "[object BoxBox.Overlay]"; }
	}),
	
	Window: Class.create({
		initialize: function(defaults) {
			// Set defaults based on class defaults and user input. These can be overridden at runtime.
			this.defaults = Object.extend(Object.clone(BoxBox.Window.Defaults), defaults || {});

			// Create and insert default elements
			this.wrapper = new Element("div", {"class": "bb-wrapper", style: "display:none; position:absolute;"});
			$(document.forms[1]).insert({top: this.wrapper});
			this.contentTarget = new Element("div", {"class": "bb-content-target", style: "overflow: auto;"});
			this.wrapper.insert(this.contentTarget);
		},
		
		//
		// API: Public Methods
		//
		
		/**
		 *  BoxBox.Window#show() -> this
		 **/
		show: function(content, options) {
			var options = Object.extend(Object.clone(this.defaults), options || {});
			
			if (content) {
				// Set content if provided
				this.setContent(content);
			}
			
			// Find width and height of CONTENT
			var viewPortWidthHeight = document.viewport.getDimensions();
			var width = Math.min(viewPortWidthHeight.width, options.width);
			var height = Math.min(viewPortWidthHeight.height, options.height);
			
			// Resize CONTENT
			this.contentTarget.setStyle({
				width: width + "px",
				height: height + "px"
			});
			
			this._center();
			
			// Show the elements
			this.wrapper.show();
			this.contentTarget.reveal();
			return this;
		},
		/**
		 *  BoxBox.Window#hide() -> this
		 **/
		hide: function() {
			this.wrapper.hide();
			this.contentTarget.cloak();
			return this;
		},
		/**
		 *  BoxBox.Window#resize(width, height) -> this
		 **/
		resize: function(width, height) {
			// Find width and height of CONTENT
			var viewPortWidthHeight = $(document).viewport.getDimensions();
			var width = Math.min(viewPortWidthHeight.width, width);
			var height = Math.min(viewPortWidthHeight.height, height);

			new Effect.Morph(this.contentTarget, {
				style: {
					width: width + "px",
					height: height + "px"
				},
				duration: this.defaults.duration,
				afterUpdate: function(e) {
					this._center();
				}.bind(this),
				queue: { position: 'end', scope: 'boxbox' }
			});
			return this;
		},
		/**
		 *  BoxBox.Window#resizeToContent() -> this
		 **/
		resizeToContent: function() {
			throw "Not implemented";
			return this;
		},
		/**
		 *  BoxBox.Window#visible() -> Boolean
		 **/
		visible: function() {
			return this.wrapper.visible() && !this.contentTarget.cloaked();
		},
		
		/**
		 *  BoxBox.Window#setContent(content[, type]]) -> this
		 **/
		setContent: function(content, type) {
			// TYPE will determine how the content is treated. Otherwise we try to discern it (think url string vs iframe url)
			if (false) {
				[["previous", "after"], ["next", "before"], ["up", "bottom"]].each(function(position) {
					if (content[position[0]]()) {
						var rel = content[position[0]]();
						var dir = position[1];
					}
				});
			}
			
			this.contentTarget.update(content);
			return this;
		},
		
		//
		// Private Methods
		//
		
		/**
		 *  BoxBox.Window#_getContentSize()() -> Array
		 **/
		_getContentSize: function() {
			throw "Not implemented";
		},
		
		_center: function() {
			var viewPortWidthHeight = $(document).viewport.getDimensions();

			// Find new position of WRAPPER
			var boxWidthHeight = this.wrapper.getDimensions();
			var left = Math.max(0, (viewPortWidthHeight.width - boxWidthHeight.width) / 2) + document.documentElement.scrollLeft;
			var top = Math.max(0, (viewPortWidthHeight.height - boxWidthHeight.height) / 2) + document.documentElement.scrollTop;

			// Position WRAPPER
			this.wrapper.setStyle({ left: left + "px", top: top + "px" });
		},

		/**
		 *  BoxBox.Window#toString() -> String
		 **/
		toString: function() { return "[object BoxBox.Window]"; }
	}),
	
	Controller: Class.create({
		initialize: function() {
			this.overlay = new BoxBox.Overlay();
			this.window = new BoxBox.Window();
		},
		open: function(content, options) {
			this.overlay.show();
			
			// Open window when overlay should be open
			setTimeout(function() {
				this.window.show(content);
			}.bind(this), this.overlay.defaults.duration * 1000);
			
			return this;
		},
		close: function() {
			this.window.hide();
			this.overlay.hide();
			return this;
		},
		resize: function(width, height) {
			if (typeof height == "undefined") {
				height = width;
			}
			this.window.resize(width, height);
			return this;
		},
		resizeToContent: function() {
			throw "Not implemented";
		},
		/**
		 *  BoxBox.Controller#toString() -> String
		 **/
		toString: function() { return "[object BoxBox.Controller]"; }
	}),
	
	create: function() {
	    if(!BoxBox._created) {
	        BoxBox._created = true;
    		TheBox = new BoxBox.Controller();
		}
	}
};

// WINDOW DEFAULTS
Object.extend(BoxBox.Window, {
	Defaults: {
		width: 800,
		height: 550,
		duration: 0.25
	}
});

// OVERLAY DEFAULTS
Object.extend(BoxBox.Overlay, {
	Defaults: {
		background: "#000",
		transition: Effect.Transitions.sinoidal,
		duration: 0.25
	}
});

