/**
 * @author Ryan Johnson <http://saucytiger.com/>
 * @copyright 2008 PersonalGrid Corporation <http://personalgrid.com/>
 * @package LivePipe UI
 * @license MIT
 * @url http://livepipe.net/core
 * @require prototype.js
 */

if(typeof(Control) == 'undefined')
	Control = {};
	
var $proc = function(proc){
	return typeof(proc) == 'function' ? proc : function(){return proc};
};

var $value = function(value){
	return typeof(value) == 'function' ? value() : value;
};

Object.Event = {
	extend: function(object){
		object._objectEventSetup = function(event_name){
			this._observers = this._observers || {};
			this._observers[event_name] = this._observers[event_name] || [];
		};
		object.observe = function(event_name,observer){
			if(typeof(event_name) == 'string' && typeof(observer) != 'undefined'){
				this._objectEventSetup(event_name);
				if(!this._observers[event_name].include(observer))
					this._observers[event_name].push(observer);
			}else
				for(var e in event_name)
					this.observe(e,event_name[e]);
		};
		object.stopObserving = function(event_name,observer){
			this._objectEventSetup(event_name);
			if(event_name && observer)
				this._observers[event_name] = this._observers[event_name].without(observer);
			else if(event_name)
				this._observers[event_name] = [];
			else
				this._observers = {};
		};
		object.observeOnce = function(event_name,outer_observer){
			var inner_observer = function(){
				outer_observer.apply(this,arguments);
				this.stopObserving(event_name,inner_observer);
			}.bind(this);
			this._objectEventSetup(event_name);
			this._observers[event_name].push(inner_observer);
		};
		object.notify = function(event_name){
			this._objectEventSetup(event_name);
			var collected_return_values = [];
			var args = $A(arguments).slice(1);
			try{
				for(var i = 0; i < this._observers[event_name].length; ++i)
					collected_return_values.push(this._observers[event_name][i].apply(this._observers[event_name][i],args) || null);
			}catch(e){
				if(e == $break)
					return false;
				else
					throw e;
			}
			return collected_return_values;
		};
		if(object.prototype){
			object.prototype._objectEventSetup = object._objectEventSetup;
			object.prototype.observe = object.observe;
			object.prototype.stopObserving = object.stopObserving;
			object.prototype.observeOnce = object.observeOnce;
			object.prototype.notify = function(event_name){
				if(object.notify){
					var args = $A(arguments).slice(1);
					args.unshift(this);
					args.unshift(event_name);
					object.notify.apply(object,args);
				}
				this._objectEventSetup(event_name);
				var args = $A(arguments).slice(1);
				var collected_return_values = [];
				try{
					if(this.options && this.options[event_name] && typeof(this.options[event_name]) == 'function')
						collected_return_values.push(this.options[event_name].apply(this,args) || null);
					for(var i = 0; i < this._observers[event_name].length; ++i)
						collected_return_values.push(this._observers[event_name][i].apply(this._observers[event_name][i],args) || null);
				}catch(e){
					if(e == $break)
						return false;
					else
						throw e;
				}
				return collected_return_values;
			};
		}
	}
};

/* Begin Core Extensions */

//Element.observeOnce
Element.addMethods({
	observeOnce: function(element,event_name,outer_callback){
		var inner_callback = function(){
			outer_callback.apply(this,arguments);
			Element.stopObserving(element,event_name,inner_callback);
		};
		Element.observe(element,event_name,inner_callback);
	}
});

//mouseenter, mouseleave
//from http://dev.rubyonrails.org/attachment/ticket/8354/event_mouseenter_106rc1.patch
Object.extend(Event, (function() {
	var cache = Event.cache;

	function getEventID(element) {
		if (element._prototypeEventID) return element._prototypeEventID[0];
		arguments.callee.id = arguments.callee.id || 1;
		return element._prototypeEventID = [++arguments.callee.id];
	}

	function getDOMEventName(eventName) {
		if (eventName && eventName.include(':')) return "dataavailable";
		//begin extension
		if(!Prototype.Browser.IE){
			eventName = {
				mouseenter: 'mouseover',
				mouseleave: 'mouseout'
			}[eventName] || eventName;
		}
		//end extension
		return eventName;
	}

	function getCacheForID(id) {
		return cache[id] = cache[id] || { };
	}

	function getWrappersForEventName(id, eventName) {
		var c = getCacheForID(id);
		return c[eventName] = c[eventName] || [];
	}

	function createWrapper(element, eventName, handler) {
		var id = getEventID(element);
		var c = getWrappersForEventName(id, eventName);
		if (c.pluck("handler").include(handler)) return false;

		var wrapper = function(event) {
			if (!Event || !Event.extend ||
				(event.eventName && event.eventName != eventName))
					return false;

			Event.extend(event);
			handler.call(element, event);
		};
		
		//begin extension
		if(!(Prototype.Browser.IE) && ['mouseenter','mouseleave'].include(eventName)){
			wrapper = wrapper.wrap(function(proceed,event) {	
				var rel = event.relatedTarget;
				var cur = event.currentTarget;			 
				if(rel && rel.nodeType == Node.TEXT_NODE)
					rel = rel.parentNode;	  
				if(rel && rel != cur && !rel.descendantOf(cur))	  
					return proceed(event);   
			});	 
		}
		//end extension

		wrapper.handler = handler;
		c.push(wrapper);
		return wrapper;
	}

	function findWrapper(id, eventName, handler) {
		var c = getWrappersForEventName(id, eventName);
		return c.find(function(wrapper) { return wrapper.handler == handler });
	}

	function destroyWrapper(id, eventName, handler) {
		var c = getCacheForID(id);
		if (!c[eventName]) return false;
		c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));
	}

	function destroyCache() {
		for (var id in cache)
			for (var eventName in cache[id])
				cache[id][eventName] = null;
	}

	if (window.attachEvent) {
		window.attachEvent("onunload", destroyCache);
	}

	return {
		observe: function(element, eventName, handler) {
			element = $(element);
			var name = getDOMEventName(eventName);

			var wrapper = createWrapper(element, eventName, handler);
			if (!wrapper) return element;

			if (element.addEventListener) {
				element.addEventListener(name, wrapper, false);
			} else {
				element.attachEvent("on" + name, wrapper);
			}

			return element;
		},

		stopObserving: function(element, eventName, handler) {
			element = $(element);
			var id = getEventID(element), name = getDOMEventName(eventName);

			if (!handler && eventName) {
				getWrappersForEventName(id, eventName).each(function(wrapper) {
					element.stopObserving(eventName, wrapper.handler);
				});
				return element;

			} else if (!eventName) {
				Object.keys(getCacheForID(id)).each(function(eventName) {
					element.stopObserving(eventName);
				});
				return element;
			}

			var wrapper = findWrapper(id, eventName, handler);
			if (!wrapper) return element;

			if (element.removeEventListener) {
				element.removeEventListener(name, wrapper, false);
			} else {
				element.detachEvent("on" + name, wrapper);
			}

			destroyWrapper(id, eventName, handler);

			return element;
		},

		fire: function(element, eventName, memo) {
			element = $(element);
			if (element == document && document.createEvent && !element.dispatchEvent)
				element = document.documentElement;

			var event;
			if (document.createEvent) {
				event = document.createEvent("HTMLEvents");
				event.initEvent("dataavailable", true, true);
			} else {
				event = document.createEventObject();
				event.eventType = "ondataavailable";
			}

			event.eventName = eventName;
			event.memo = memo || { };

			if (document.createEvent) {
				element.dispatchEvent(event);
			} else {
				element.fireEvent(event.eventType, event);
			}

			return Event.extend(event);
		}
	};
})());

Object.extend(Event, Event.Methods);

Element.addMethods({
	fire:			Event.fire,
	observe:		Event.observe,
	stopObserving:	Event.stopObserving
});

Object.extend(document, {
	fire:			Element.Methods.fire.methodize(),
	observe:		Element.Methods.observe.methodize(),
	stopObserving:	Element.Methods.stopObserving.methodize()
});

//mouse:wheel
(function(){
	function wheel(event){
		var delta;
		// normalize the delta
		if(event.wheelDelta) // IE & Opera
			delta = event.wheelDelta / 120;
		else if (event.detail) // W3C
			delta =- event.detail / 3;
		if(!delta)
			return;
		var custom_event = event.element().fire('mouse:wheel',{
			delta: delta
		});
		if(custom_event.stopped){
			event.stop();
			return false;
		}
	}
	document.observe('mousewheel',wheel);
	document.observe('DOMMouseScroll',wheel);
})();

/* End Core Extensions */

//from PrototypeUI
var IframeShim = Class.create({
	initialize: function() {
		this.element = new Element('iframe',{
			style: 'position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);display:none',
			src: 'javascript:void(0);',
			frameborder: 0 
		});
		$(document.body).insert(this.element);
	},
	hide: function() {
		this.element.hide();
		return this;
	},
	show: function() {
		this.element.show();
		return this;
	},
	positionUnder: function(element) {
		var element = $(element);
		var offset = element.cumulativeOffset();
		var dimensions = element.getDimensions();
		this.element.setStyle({
			left: offset[0] + 'px',
			top: offset[1] + 'px',
			width: dimensions.width + 'px',
			height: dimensions.height + 'px',
			zIndex: element.getStyle('zIndex') - 1
		}).show();
		return this;
	},
	setBounds: function(bounds) {
		for(prop in bounds)
			bounds[prop] += 'px';
		this.element.setStyle(bounds);
		return this;
	},
	destroy: function() {
		if(this.element)
			this.element.remove();
		return this;
	}
});

/**
 * @author Ryan Johnson <http://saucytiger.com/>
 * @copyright 2008 PersonalGrid Corporation <http://personalgrid.com/>
 * @package LivePipe UI
 * @license MIT
 * @url http://livepipe.net/control/window
 * @require prototype.js, effects.js, draggable.js, resizable.js, livepipe.js
 */

//adds onDraw and constrainToViewport option to draggable
if(typeof(Draggable) != 'undefined'){
	//allows the point to be modified with an onDraw callback
	Draggable.prototype.draw = function(point) {
		var pos = Position.cumulativeOffset(this.element);
		if(this.options.ghosting) {
			var r = Position.realOffset(this.element);
			pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
		}
		
		var d = this.currentDelta();
		pos[0] -= d[0]; pos[1] -= d[1];
		
		if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
			pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
			pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
		}
		
		var p = [0,1].map(function(i){ 
			return (point[i]-pos[i]-this.offset[i]) 
		}.bind(this));
		
		if(this.options.snap) {
			if(typeof this.options.snap == 'function') {
				p = this.options.snap(p[0],p[1],this);
			} else {
				if(this.options.snap instanceof Array) {
					p = p.map( function(v, i) {return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
				} else {
					p = p.map( function(v) {return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
	  			}
			}
		}
		
		if(this.options.onDraw)
			this.options.onDraw.bind(this)(p);
		else{
			var style = this.element.style;
			if(this.options.constrainToViewport){
				var viewport_dimensions = document.viewport.getDimensions();
				var container_dimensions = this.element.getDimensions();
				var margin_top = parseInt(this.element.getStyle('margin-top'));
				var margin_left = parseInt(this.element.getStyle('margin-left'));
				var boundary = [[
					0 - margin_left,
					0 - margin_top
				],[
					(viewport_dimensions.width - container_dimensions.width) - margin_left,
					(viewport_dimensions.height - container_dimensions.height) - margin_top
				]];
				if((!this.options.constraint) || (this.options.constraint=='horizontal')){ 
					if((p[0] >= boundary[0][0]) && (p[0] <= boundary[1][0]))
						this.element.style.left = p[0] + "px";
					else
						this.element.style.left = ((p[0] < boundary[0][0]) ? boundary[0][0] : boundary[1][0]) + "px";
				} 
				if((!this.options.constraint) || (this.options.constraint=='vertical')){ 
					if((p[1] >= boundary[0][1] ) && (p[1] <= boundary[1][1]))
						this.element.style.top = p[1] + "px";
				  else
						this.element.style.top = ((p[1] <= boundary[0][1]) ? boundary[0][1] : boundary[1][1]) + "px";			   
				}
			}else{
				if((!this.options.constraint) || (this.options.constraint=='horizontal'))
				  style.left = p[0] + "px";
				if((!this.options.constraint) || (this.options.constraint=='vertical'))
				  style.top	 = p[1] + "px";
			}
			if(style.visibility=="hidden")
				style.visibility = ""; // fix gecko rendering
		}
	};
}

if(typeof(Prototype) == "undefined")
	throw "Control.Window requires Prototype to be loaded.";
if(typeof(IframeShim) == "undefined")
	throw "Control.Window requires IframeShim to be loaded.";
if(typeof(Object.Event) == "undefined")
	throw "Control.Window requires Object.Event to be loaded.";
/*
	known issues:
		- when iframe is clicked is does not gain focus
		- safari can't open multiple iframes properly
		- constrainToViewport: body must have no margin or padding for this to work properly
		- iframe will be mis positioned during fade in
		- document.viewport does not account for scrollbars (this will eventually be fixed in the prototype core)
	notes
		- setting constrainToViewport only works when the page is not scrollable
		- setting draggable: true will negate the effects of position: center
*/
Control.Window = Class.create({
	initialize: function(container,options){
		Control.Window.windows.push(this);
		
		//attribute initialization
		this.container = false;
		this.isOpen = false;
		this.href = false;
		this.sourceContainer = false; //this is optionally the container that will open the window
		this.ajaxRequest = false;
		this.remoteContentLoaded = false; //this is set when the code to load the remote content is run, onRemoteContentLoaded is fired when the connection is closed
		this.numberInSequence = Control.Window.windows.length + 1; //only useful for the effect scoping
		this.indicator = false;
		this.effects = {
			fade: false,
			appear: false
		};
		this.indicatorEffects = {
			fade: false,
			appear: false
		};
		
		//options
		this.options = Object.extend({
			//lifecycle
			beforeOpen: Prototype.emptyFunction,
			afterOpen: Prototype.emptyFunction,
			beforeClose: Prototype.emptyFunction,
			afterClose: Prototype.emptyFunction,
			//dimensions and modes
			height: null,
			width: null,
			className: false,
			position: 'center', //'center', 'relative', [x,y], [function(){return x;},function(){return y;}]
			offsetLeft: 0, //available only for anchors opening the window, or windows set to position: hover
			offsetTop: 0, //""
			iframe: false, //if the window has an href, this will display the href as an iframe instead of requesting the url as an an Ajax.Request
			hover: false, //element object to hover over, or if "true" only available for windows with sourceContainer (an anchor or any element already on the page with an href attribute)
			indicator: false, //element to show or hide when ajax requests, images and iframes are loading
			closeOnClick: false, //does not work with hover,can be: true (click anywhere), 'container' (will refer to this.container), or element (a specific element)
			iframeshim: true, //wether or not to position an iFrameShim underneath the window 
			//effects
			fade: false,
			fadeDuration: 0.75,
			//draggable
			draggable: false,
			onDrag: Prototype.emptyFunction,
			//resizable
			resizable: false,
			minHeight: false,
			minWidth: false,
			maxHeight: false,
			maxWidth: false,
			onResize: Prototype.emptyFunction,
			//draggable and resizable
			constrainToViewport: false,
			//ajax
			method: 'post',
			parameters: {},
			onComplete: Prototype.emptyFunction,
			onSuccess: Prototype.emptyFunction,
			onFailure: Prototype.emptyFunction,
			onException: Prototype.emptyFunction,
			//any element with an href (image,iframe,ajax) will call this after it is done loading
			onRemoteContentLoaded: Prototype.emptyFunction,
			insertRemoteContentAt: false //false will set this to this.container, can be string selector (first returned will be selected), or an Element that must be a child of this.container
		},options || {});
		
		//container setup
		this.indicator = this.options.indicator ? $(this.options.indicator) : false;
		if(container){
			if(typeof(container) == "string" && container.match(Control.Window.uriRegex))
				this.href = container;
			else{
				this.container = $(container);
				//need to create the container now for tooltips (or hover: element with no container already on the page)
				//second call made below will not create the container since the check is done inside createDefaultContainer()
				this.createDefaultContainer(container);
				//if an element with an href was passed in we use it to activate the window
				if(this.container && ((this.container.readAttribute('href') && this.container.readAttribute('href') != '') || (this.options.hover && this.options.hover !== true))){						
					if(this.options.hover && this.options.hover !== true)
						this.sourceContainer = $(this.options.hover);
					else{
						this.sourceContainer = this.container;
						this.href = this.container.readAttribute('href');
						var rel = this.href.match(/^#(.+)$/);
						if(rel && rel[1]){
							this.container = $(rel[1]);
							this.href = false;
						}else
							this.container = false;
					}
					//hover or click handling
					this.sourceContainerOpenHandler = function(event){
						this.open(event);
						event.stop();
						return false;
					}.bindAsEventListener(this);
					this.sourceContainerCloseHandler = function(event){
						this.close(event);
					}.bindAsEventListener(this);
					this.sourceContainerMouseMoveHandler = function(event){
						this.position(event);
					}.bindAsEventListener(this);
					if(this.options.hover){
						this.sourceContainer.observe('mouseenter',this.sourceContainerOpenHandler);
						this.sourceContainer.observe('mouseleave',this.sourceContainerCloseHandler);
						if(this.options.position == 'mouse')
							this.sourceContainer.observe('mousemove',this.sourceContainerMouseMoveHandler);
					}else
						this.sourceContainer.observe('click',this.sourceContainerOpenHandler);
				}
			}
		}
		this.createDefaultContainer(container);
		if(this.options.insertRemoteContentAt === false)
			this.options.insertRemoteContentAt = this.container;
		var styles = {
			margin: 0,
			position: 'absolute',
			zIndex: Control.Window.initialZIndexForWindow()
		};
		if(this.options.width)
			styles.width = $value(this.options.width) + 'px';
		if(this.options.height)
			styles.height = $value(this.options.height) + 'px';
		this.container.setStyle(styles);
		if(this.options.className)
			this.container.addClassName(this.options.className);
		this.positionHandler = this.position.bindAsEventListener(this);
		this.outOfBoundsPositionHandler = this.ensureInBounds.bindAsEventListener(this);
		this.bringToFrontHandler = this.bringToFront.bindAsEventListener(this);
		this.container.observe('mousedown',this.bringToFrontHandler);
		this.container.hide();
		this.closeHandler = this.close.bindAsEventListener(this);
		//iframeshim setup
		if(this.options.iframeshim){
			this.iFrameShim = new IframeShim();
			this.iFrameShim.hide();
		}
		//resizable support
		this.applyResizable();
		//draggable support
		this.applyDraggable();
		
		//makes sure the window can't go out of bounds
		Event.observe(window,'resize',this.outOfBoundsPositionHandler);
		
		this.notify('afterInitialize');
	},
	open: function(event){
		if(this.isOpen){
			this.bringToFront();
			return false;
		}
		if(this.notify('beforeOpen') === false)
			return false;
		//closeOnClick
		if(this.options.closeOnClick){
			if(this.options.closeOnClick === true)
				this.closeOnClickContainer = $(document.body);
			else if(this.options.closeOnClick == 'container')
				this.closeOnClickContainer = this.container;
			else if (this.options.closeOnClick == 'overlay'){
				Control.Overlay.load();
				this.closeOnClickContainer = Control.Overlay.container;
			}else
				this.closeOnClickContainer = $(this.options.closeOnClick);
			this.closeOnClickContainer.observe('click',this.closeHandler);
		}
		if(this.href && !this.options.iframe && !this.remoteContentLoaded){
			//link to image
			this.remoteContentLoaded = true;
			if(this.href.match(/\.(jpe?g|gif|png|tiff?)$/i)){
				var img = new Element('img');
				img.observe('load',function(img){
					this.getRemoteContentInsertionTarget().insert(img);
					this.position();
					if(this.notify('onRemoteContentLoaded') !== false){
						if(this.options.indicator)
							this.hideIndicator();
						this.finishOpen();
					}
				}.bind(this,img));
				img.writeAttribute('src',this.href);
			}else{
				//if this is an ajax window it will only open if the request is successful
				if(!this.ajaxRequest){
					if(this.options.indicator)
						this.showIndicator();
					this.ajaxRequest = new Ajax.Request(this.href,{
						method: this.options.method,
						parameters: this.options.parameters,
						onComplete: function(request){
							this.notify('onComplete',request);
							this.ajaxRequest = false;
						}.bind(this),
						onSuccess: function(request){
							this.getRemoteContentInsertionTarget().insert(request.responseText);
							this.notify('onSuccess',request);
							if(this.notify('onRemoteContentLoaded') !== false){
								if(this.options.indicator)
									this.hideIndicator();
								this.finishOpen();
							}
						}.bind(this),
						onFailure: function(request){
							this.notify('onFailure',request);
							if(this.options.indicator)
								this.hideIndicator();
						}.bind(this),
						onException: function(request,e){
							this.notify('onException',request,e);
							if(this.options.indicator)
								this.hideIndicator();
						}.bind(this)
					});
				}
			}
			return true;
		}else if(this.options.iframe && !this.remoteContentLoaded){
			//iframe
			this.remoteContentLoaded = true;
			if(this.options.indicator)
				this.showIndicator();
			this.getRemoteContentInsertionTarget().insert(Control.Window.iframeTemplate.evaluate({
				href: this.href
			}));
			var iframe = this.container.down('iframe');
			iframe.onload = function(){
				this.notify('onRemoteContentLoaded');
				if(this.options.indicator)
					this.hideIndicator();
				iframe.onload = null;
			}.bind(this);
		}
		this.finishOpen(event);
		return true
	},
	close: function(event){ //event may or may not be present
		if(!this.isOpen || this.notify('beforeClose',event) === false)
			return false;
		if(this.options.closeOnClick)
			this.closeOnClickContainer.stopObserving('click',this.closeHandler);
		if(this.options.fade){
			this.effects.fade = new Effect.Fade(this.container,{
				queue: {
					position: 'front',
					scope: 'Control.Window' + this.numberInSequence
				},
				from: 1,
				to: 0,
				duration: this.options.fadeDuration / 2,
				afterFinish: function(){
					if(this.iFrameShim)
						this.iFrameShim.hide();
					this.isOpen = false;
					this.notify('afterClose');
				}.bind(this)
			});
		}else{
			this.container.hide();
			if(this.iFrameShim)
				this.iFrameShim.hide();
		}
		if(this.ajaxRequest)
			this.ajaxRequest.transport.abort();
		if(!(this.options.draggable || this.options.resizable) && this.options.position == 'center')
			Event.stopObserving(window,'resize',this.positionHandler);
		if(!this.options.draggable && this.options.position == 'center')
			Event.stopObserving(window,'scroll',this.positionHandler);
		if(this.options.indicator)
			this.hideIndicator();
		if(!this.options.fade){
			this.isOpen = false;
			this.notify('afterClose');
        }
		return true;
	},
	position: function(event){
		//this is up top for performance reasons
		if(this.options.position == 'mouse'){
			var xy = [Event.pointerX(event),Event.pointerY(event)];
			this.container.setStyle({
				top: xy[1] + $value(this.options.offsetTop) + 'px',
				left: xy[0] + $value(this.options.offsetLeft) + 'px'
			});
			return;
		}
		var container_dimensions = this.container.getDimensions();
		var viewport_dimensions = document.viewport.getDimensions();
		Position.prepare();
		var offset_left = (Position.deltaX + Math.floor((viewport_dimensions.width - container_dimensions.width) / 2));
		var offset_top = (Position.deltaY + ((viewport_dimensions.height > container_dimensions.height) ? Math.floor((viewport_dimensions.height - container_dimensions.height) / 2) : 0));
		if(this.options.position == 'center'){
			this.container.setStyle({
				top: (container_dimensions.height <= viewport_dimensions.height) ? ((offset_top != null && offset_top > 0) ? offset_top : 0) + 'px' : 0,
				left: (container_dimensions.width <= viewport_dimensions.width) ? ((offset_left != null && offset_left > 0) ? offset_left : 0) + 'px' : 0
			});
		}else if(this.options.position == 'relative'){
			var xy = this.sourceContainer.cumulativeOffset();
			var top = xy[1] + $value(this.options.offsetTop);
			var left = xy[0] + $value(this.options.offsetLeft);
			this.container.setStyle({
				top: (container_dimensions.height <= viewport_dimensions.height) ? (this.options.constrainToViewport ? Math.max(0,Math.min(viewport_dimensions.height - (container_dimensions.height),top)) : top) + 'px' : 0,
				left: (container_dimensions.width <= viewport_dimensions.width) ? (this.options.constrainToViewport ? Math.max(0,Math.min(viewport_dimensions.width - (container_dimensions.width),left)) : left) + 'px' : 0
			});
		}else if(this.options.position.length){
			var top = $value(this.options.position[1]) + $value(this.options.offsetTop);
			var left = $value(this.options.position[0]) + $value(this.options.offsetLeft);
			this.container.setStyle({
				top: (container_dimensions.height <= viewport_dimensions.height) ? (this.options.constrainToViewport ? Math.max(0,Math.min(viewport_dimensions.height - (container_dimensions.height),top)) : top) + 'px' : 0,
				left: (container_dimensions.width <= viewport_dimensions.width) ? (this.options.constrainToViewport ? Math.max(0,Math.min(viewport_dimensions.width - (container_dimensions.width),left)) : left) + 'px' : 0
			});
		}
		if(this.iFrameShim)
			this.updateIFrameShimZIndex();
	},
	ensureInBounds: function(){
		if(!this.isOpen)
			return;
		var viewport_dimensions = document.viewport.getDimensions();
		var container_offset = this.container.cumulativeOffset();
		var container_dimensions = this.container.getDimensions();
		if(container_offset.left + container_dimensions.width > viewport_dimensions.width){
			this.container.setStyle({
				left: (Math.max(0,viewport_dimensions.width - container_dimensions.width)) + 'px'
			});
		}
		if(container_offset.top + container_dimensions.height > viewport_dimensions.height){
			this.container.setStyle({
				top: (Math.max(0,viewport_dimensions.height - container_dimensions.height)) + 'px'
			});
		}
	},
	bringToFront: function(){
		Control.Window.bringToFront(this);
		this.notify('bringToFront');
	},
	destroy: function(){
		this.container.stopObserving('mousedown',this.bringToFrontHandler);
		if(this.draggable){
			Resizables.removeObserver(this.container);
			this.draggable.handle.stopObserving('mousedown',this.bringToFrontHandler);
			this.draggable.destroy();
		}
		if(this.resizable){
			Resizables.removeObserver(this.container);
			this.resizable.handle.stopObserving('mousedown',this.bringToFrontHandler);
			this.resizable.destroy();
		}
		if(this.container && !this.sourceContainer)
			this.container.remove();
		if(this.sourceContainer){
			if(this.options.hover){
				this.sourceContainer.stopObserving('mouseenter',this.sourceContainerOpenHandler);
				this.sourceContainer.stopObserving('mouseleave',this.sourceContainerCloseHandler);
				if(this.options.position == 'mouse')
					this.sourceContainer.stopObserving('mousemove',this.sourceContainerMouseMoveHandler);
			}else
				this.sourceContainer.stopObserving('click',this.sourceContainerOpenHandler);
		}
		if(this.iFrameShim)
			this.iFrameShim.destroy();
		Event.stopObserving(window,'resize',this.outOfBoundsPositionHandler);
		Control.Window.windows = Control.Window.windows.without(this);
		this.notify('afterDestroy');
	},
	//private
	applyResizable: function(){
		if(this.options.resizable){
			if(typeof(Resizable) == "undefined")
				throw "Control.Window requires resizable.js to be loaded.";
			var resizable_handle = null;
			if(this.options.resizable === true){
				resizable_handle = new Element('div',{
					className: 'resizable_handle'
				});
				this.container.insert(resizable_handle);
			}else
				resizable_handle = $(this.options.resziable);
			this.resizable = new Resizable(this.container,{
				handle: resizable_handle,
				minHeight: this.options.minHeight,
				minWidth: this.options.minWidth,
				maxHeight: this.options.constrainToViewport ? function(element){
					//viewport height - top - total border height
					return (document.viewport.getDimensions().height - parseInt(element.style.top || 0)) - (element.getHeight() - parseInt(element.style.height || 0));
				} : this.options.maxHeight,
				maxWidth: this.options.constrainToViewport ? function(element){
					//viewport width - left - total border width
					return (document.viewport.getDimensions().width - parseInt(element.style.left || 0)) - (element.getWidth() - parseInt(element.style.width || 0));
				} : this.options.maxWidth
			});
			this.resizable.handle.observe('mousedown',this.bringToFrontHandler);
			Resizables.addObserver(new Control.Window.LayoutUpdateObserver(this,function(){
				if(this.iFrameShim)
					this.updateIFrameShimZIndex();
				this.notify('onResize');
			}.bind(this)));
		}
	},
	applyDraggable: function(){
		if(this.options.draggable){
			if(typeof(Draggables) == "undefined")
				throw "Control.Window requires dragdrop.js to be loaded.";
			var draggable_handle = null;
			if(this.options.draggable === true){
				draggable_handle = new Element('div',{
					className: 'draggable_handle'
				});
				this.container.insert(draggable_handle);
			}else
				draggable_handle = $(this.options.draggable);
			this.draggable = new Draggable(this.container,{
				handle: draggable_handle,
				constrainToViewport: this.options.constrainToViewport,
				zindex: this.container.getStyle('z-index'),
				starteffect: function(){
					if(Prototype.Browser.IE){
						this.old_onselectstart = document.onselectstart;
						document.onselectstart = function(){
							return false;
						};
					}
				}.bind(this),
				endeffect: function(){
					document.onselectstart = this.old_onselectstart;
				}.bind(this)
			});
			this.draggable.handle.observe('mousedown',this.bringToFrontHandler);
			Draggables.addObserver(new Control.Window.LayoutUpdateObserver(this,function(){
				if(this.iFrameShim)
					this.updateIFrameShimZIndex();
				this.notify('onDrag');
			}.bind(this)));
		}
	},
	createDefaultContainer: function(container){
		if(!this.container){
			//no container passed or found, create it
			this.container = new Element('div',{
				id: 'control_window_' + this.numberInSequence
			});
			$(document.body).insert(this.container);
			if(typeof(container) == "string" && $(container) == null && !container.match(/^#(.+)$/) && !container.match(Control.Window.uriRegex))
				this.container.update(container);
		}
	},
	finishOpen: function(event){
		this.bringToFront();
		if(this.options.fade){
			if(typeof(Effect) == "undefined")
				throw "Control.Window requires effects.js to be loaded."
			if(this.effects.fade)
				this.effects.fade.cancel();
			this.effects.appear = new Effect.Appear(this.container,{
				queue: {
					position: 'end',
					scope: 'Control.Window.' + this.numberInSequence
				},
				from: 0,
				to: 1,
				duration: this.options.fadeDuration / 2,
				afterFinish: function(){
					if(this.iFrameShim)
						this.updateIFrameShimZIndex();
					this.isOpen = true;
					this.notify('afterOpen');
				}.bind(this)
			});
		}else
			this.container.show();
		this.position(event);
		if(!(this.options.draggable || this.options.resizable) && this.options.position == 'center')
			Event.observe(window,'resize',this.positionHandler,false);
		if(!this.options.draggable && this.options.position == 'center')
			Event.observe(window,'scroll',this.positionHandler,false);
		if(!this.options.fade){
			this.isOpen = true;
			this.notify('afterOpen');
		}
		return true;
	},
	showIndicator: function(){
		this.showIndicatorTimeout = window.setTimeout(function(){
			if(this.options.fade){
				this.indicatorEffects.appear = new Effect.Appear(this.indicator,{
					queue: {
						position: 'front',
						scope: 'Control.Window.indicator.' + this.numberInSequence
					},
					from: 0,
					to: 1,
					duration: this.options.fadeDuration / 2
				});
			}else
				this.indicator.show();
		}.bind(this),Control.Window.indicatorTimeout);
	},
	hideIndicator: function(){
		if(this.showIndicatorTimeout)
			window.clearTimeout(this.showIndicatorTimeout);
		this.indicator.hide();
	},
	getRemoteContentInsertionTarget: function(){
		return typeof(this.options.insertRemoteContentAt) == "string" ? this.container.down(this.options.insertRemoteContentAt) : $(this.options.insertRemoteContentAt);
	},
	updateIFrameShimZIndex: function(){
		if(this.iFrameShim)
			this.iFrameShim.positionUnder(this.container);
	}
});
//class methods
Object.extend(Control.Window,{
	windows: [],
	baseZIndex: 9999,
	indicatorTimeout: 250,
	iframeTemplate: new Template('<iframe src="#{href}" width="100%" height="100%" frameborder="0"></iframe>'),
	uriRegex: /^(\/|\#|https?\:\/\/|[\w]+\/)/,
	bringToFront: function(w){
		Control.Window.windows = Control.Window.windows.without(w);
		Control.Window.windows.push(w);
		Control.Window.windows.each(function(w,i){
			var z_index = Control.Window.baseZIndex + i;
			w.container.setStyle({
				zIndex: z_index
			});
			if(w.isOpen){
				if(w.iFrameShim)
				w.updateIFrameShimZIndex();
			}
			if(w.options.draggable)
				w.draggable.options.zindex = z_index;
		});
	},
	open: function(container,options){
		var w = new Control.Window(container,options);
		w.open();
		return w;
	},
	//protected
	initialZIndexForWindow: function(w){
		return Control.Window.baseZIndex + (Control.Window.windows.length - 1);
	}
});
Object.Event.extend(Control.Window);

//this is the observer for both Resizables and Draggables
Control.Window.LayoutUpdateObserver = Class.create({
	initialize: function(w,observer){
		this.w = w;
		this.element = $(w.container);
		this.observer = observer;
	},
	onStart: Prototype.emptyFunction,
	onEnd: function(event_name,instance){
		if(instance.element == this.element && this.iFrameShim)
			this.w.updateIFrameShimZIndex();
	},
	onResize: function(event_name,instance){
		if(instance.element == this.element)
			this.observer(this.element);
	},
	onDrag: function(event_name,instance){
		if(instance.element == this.element)
			this.observer(this.element);
	}
});

//overlay for Control.Modal
Control.Overlay = {
	id: 'control_overlay',
	loaded: false,
	container: false,
	lastOpacity: 0,
	styles: {
		position: 'fixed',
		top: 0,
		left: 0,
		width: '100%',
		height: '100%',
		zIndex: 9998
	},
	ieStyles: {
		position: 'absolute',
		top: 0,
		left: 0,
		zIndex: 9998
	},
	effects: {
		fade: false,
		appear: false
	},
	load: function(){
		if(Control.Overlay.loaded)
			return false;
		Control.Overlay.loaded = true;
		Control.Overlay.container = new Element('div',{
			id: Control.Overlay.id
		});
		$(document.body).insert(Control.Overlay.container);
		if(Prototype.Browser.IE){
			Control.Overlay.container.setStyle(Control.Overlay.ieStyles);
			Event.observe(window,'scroll',Control.Overlay.positionOverlay);
			Event.observe(window,'resize',Control.Overlay.positionOverlay);
			Control.Overlay.observe('beforeShow',Control.Overlay.positionOverlay);
		}else
			Control.Overlay.container.setStyle(Control.Overlay.styles);
		Control.Overlay.iFrameShim = new IframeShim();
		Control.Overlay.iFrameShim.hide();
		Event.observe(window,'resize',Control.Overlay.positionIFrameShim);
		Control.Overlay.container.hide();
		return true;
	},
	unload: function(){
		if(!Control.Overlay.loaded)
			return false;
		Event.stopObserving(window,'resize',Control.Overlay.positionOverlay);
		Control.Overlay.stopObserving('beforeShow',Control.Overlay.positionOverlay);
		Event.stopObserving(window,'resize',Control.Overlay.positionIFrameShim);
		Control.Overlay.iFrameShim.destroy();
		Control.Overlay.container.remove();
		Control.Overlay.loaded = false;
		return true;
	},
	show: function(opacity,fade){
		if(Control.Overlay.notify('beforeShow') === false)
			return false;
		Control.Overlay.lastOpacity = opacity;
		Control.Overlay.positionIFrameShim();
		Control.Overlay.iFrameShim.show();
		if(fade){
			if(typeof(Effect) == "undefined")
				throw "Control.Window requires effects.js to be loaded."
			if(Control.Overlay.effects.fade)
				Control.Overlay.effects.fade.cancel();
			Control.Overlay.effects.appear = new Effect.Appear(Control.Overlay.container,{
				queue: {
					position: 'end',
					scope: 'Control.Overlay'
				},
				afterFinish: function(){
					Control.Overlay.notify('afterShow');
				},
				from: 0,
				to: Control.Overlay.lastOpacity,
				duration: (fade === true ? 0.75 : fade) / 2
			});
		}else{
			Control.Overlay.container.setStyle({
				opacity: opacity || 1
			});
			Control.Overlay.container.show();
			Control.Overlay.notify('afterShow');
		}
		return true;
	},
	hide: function(fade){
		if(Control.Overlay.notify('beforeHide') === false)
			return false;
		if(Control.Overlay.effects.appear)
			Control.Overlay.effects.appear.cancel();
		Control.Overlay.iFrameShim.hide();
		if(fade){
			Control.Overlay.effects.fade = new Effect.Fade(Control.Overlay.container,{
				queue: {
					position: 'front',
					scope: 'Control.Overlay'
				},
				afterFinish: function(){
					Control.Overlay.notify('afterHide');
				},
				from: Control.Overlay.lastOpacity,
				to: 0,
				duration: (fade === true ? 0.75 : fade) / 2
			});
		}else{
			Control.Overlay.container.hide();
			Control.Overlay.notify('afterHide');
		}
		return true;
	},
	positionIFrameShim: function(){
		if(Control.Overlay.container.visible())
			Control.Overlay.iFrameShim.positionUnder(Control.Overlay.container);
	},
	//IE only
	positionOverlay: function(){
		Control.Overlay.container.setStyle({
			width: document.body.clientWidth + 'px',
			height: document.body.clientHeight + 'px'
		});
	}
};
Object.Event.extend(Control.Overlay);

Control.ToolTip = Class.create(Control.Window,{
	initialize: function($super,container,tooltip,options){
		$super(tooltip,Object.extend(Object.extend(Object.clone(Control.ToolTip.defaultOptions),options || {}),{
			position: 'mouse',
			hover: container
		}));
	}
});
Object.extend(Control.ToolTip,{
	defaultOptions: {
		offsetLeft: 10
	}
});

Control.Modal = Class.create(Control.Window,{
	initialize: function($super,container,options){
		Control.Modal.InstanceMethods.beforeInitialize.bind(this)();
		$super(container,Object.extend(Object.clone(Control.Modal.defaultOptions),options || {}));
	}
});
Object.extend(Control.Modal,{
	defaultOptions: {
		overlayOpacity: 0.5,
		closeOnClick: 'overlay'
	},
	current: false,
	open: function(container,options){
		var modal = new Control.Modal(container,options);
		modal.open();
		return modal;
	},
	close: function(){
		if(Control.Modal.current)
			Control.Modal.current.close();
	},
	InstanceMethods: {
		beforeInitialize: function(){
			Control.Overlay.load();
			this.overlayFinishedOpening = false;
			this.observe('beforeOpen',Control.Modal.Observers.beforeOpen.bind(this));
			this.observe('afterOpen',Control.Modal.Observers.afterOpen.bind(this));
			this.observe('afterClose',Control.Modal.Observers.afterClose.bind(this));
		}
	},
	Observers: {
		beforeOpen: function(){
			if(!this.overlayFinishedOpening){
				Control.Overlay.observeOnce('afterShow',function(){
					this.overlayFinishedOpening = true;
					this.open();
				}.bind(this));
				Control.Overlay.show(this.options.overlayOpacity,this.options.fade ? this.options.fadeDuration : false);
				throw $break;
			}else
			Control.Window.windows.without(this).invoke('close');
		},
		afterOpen: function(){
			Control.Modal.current = this;
		},
		afterClose: function(){
			Control.Overlay.hide(this.options.fade ? this.options.fadeDuration : false);
			Control.Modal.current = false;
			this.overlayFinishedOpening = false;
		}
	}
});

Control.LightBox = Class.create(Control.Window,{
	initialize: function($super,container,options){
		this.allImagesLoaded = false;
		if(options.modal){
			var options = Object.extend(Object.clone(Control.LightBox.defaultOptions),options || {});
			options = Object.extend(Object.clone(Control.Modal.defaultOptions),options);
			options = Control.Modal.InstanceMethods.beforeInitialize.bind(this)(options);
			$super(container,options);
		}else
			$super(container,Object.extend(Object.clone(Control.LightBox.defaultOptions),options || {}));
		this.hasRemoteContent = this.href && !this.options.iframe;
		if(this.hasRemoteContent)
			this.observe('onRemoteContentLoaded',Control.LightBox.Observers.onRemoteContentLoaded.bind(this));
		else
			this.applyImageObservers();
		this.observe('beforeOpen',Control.LightBox.Observers.beforeOpen.bind(this));
	},
	applyImageObservers:function(){
		var images = this.getImages();
		this.numberImagesToLoad = images.length;
		this.numberofImagesLoaded = 0;
		images.each(function(image){
			image.observe('load',function(image){
				++this.numberofImagesLoaded;
				if(this.numberImagesToLoad == this.numberofImagesLoaded){
					this.allImagesLoaded = true;
					this.onAllImagesLoaded();
				}
			}.bind(this,image));
			image.hide();
		}.bind(this));
	},
	onAllImagesLoaded: function(){
		this.getImages().each(function(image){
			this.showImage(image);
		}.bind(this));
		if(this.hasRemoteContent){
			if(this.options.indicator)
				this.hideIndicator();
			this.finishOpen();
		}else
			this.open();
	},
	getImages: function(){
		return this.container.select(Control.LightBox.imageSelector);
	},
	showImage: function(image){
		image.show();
	}
});
Object.extend(Control.LightBox,{
	imageSelector: 'img',
	defaultOptions: {},
	Observers: {
		beforeOpen: function(){
			if(!this.hasRemoteContent && !this.allImagesLoaded)
				throw $break;
		},
		onRemoteContentLoaded: function(){
			this.applyImageObservers();
			if(!this.allImagesLoaded)
				throw $break;
		}
	}
});

/**
 * @author Ryan Johnson <http://saucytiger.com/>
 * @copyright 2008 PersonalGrid Corporation <http://personalgrid.com/>
 * @package LivePipe UI
 * @license MIT
 * @url http://livepipe.net/control/tabs
 * @require prototype.js, livepipe.js
 */

if(typeof(Prototype) == "undefined")
	throw "Control.Tabs requires Prototype to be loaded.";
if(typeof(Object.Event) == "undefined")
	throw "Control.Tabs requires Object.Event to be loaded.";

Control.Tabs = Class.create({
	initialize: function(tab_list_container,options){
		if(!$(tab_list_container))
			throw "Control.Tabs could not find the element: " + tab_list_container;
		this.activeContainer = false;
		this.activeLink = false;
		this.containers = $H({});
		this.links = [];
		Control.Tabs.instances.push(this);
		this.options = {
			beforeChange: Prototype.emptyFunction,
			afterChange: Prototype.emptyFunction,
			hover: false,
			linkSelector: 'li a',
			setClassOnContainer: false,
			activeClassName: 'active',
			defaultTab: 'first',
			autoLinkExternal: true,
			targetRegExp: /#(.+)$/,
			showFunction: Element.show,
			hideFunction: Element.hide
		};
		Object.extend(this.options,options || {});
		(typeof(this.options.linkSelector == 'string')
			? $(tab_list_container).select(this.options.linkSelector)
			: this.options.linkSelector($(tab_list_container))
		).findAll(function(link){
			return (/^#/).exec((Prototype.Browser.WebKit ? decodeURIComponent(link.href) : link.href).replace(window.location.href.split('#')[0],''));
		}).each(function(link){
			this.addTab(link);
		}.bind(this));
		this.containers.values().each(Element.hide);
		if(this.options.defaultTab == 'first')
			this.setActiveTab(this.links.first());
		else if(this.options.defaultTab == 'last')
			this.setActiveTab(this.links.last());
		else
			this.setActiveTab(this.options.defaultTab);
		var targets = this.options.targetRegExp.exec(window.location);
		if(targets && targets[1]){
			targets[1].split(',').each(function(target){
				this.setActiveTab(this.links.find(function(link){
					return link.key == target;
				}));
			}.bind(this));
		}
		if(this.options.autoLinkExternal){
			$A(document.getElementsByTagName('a')).each(function(a){
				if(!this.links.include(a)){
					var clean_href = a.href.replace(window.location.href.split('#')[0],'');
					if(clean_href.substring(0,1) == '#'){
						if(this.containers.keys().include(clean_href.substring(1))){
							$(a).observe('click',function(event,clean_href){
								this.setActiveTab(clean_href.substring(1));
							}.bindAsEventListener(this,clean_href));
						}
					}
				}
			}.bind(this));
		}
	},
	addTab: function(link){
		this.links.push(link);
		link.key = link.getAttribute('href').replace(window.location.href.split('#')[0],'').split('/').last().replace(/#/,'');
		var container = $(link.key);
		if(!container)
			throw "Control.Tabs: #" + link.key + " was not found on the page."
		this.containers.set(link.key,container);
		link[this.options.hover ? 'onmouseover' : 'onclick'] = function(link){
			if(window.event)
				Event.stop(window.event);
			this.setActiveTab(link);
			return false;
		}.bind(this,link);
	},
	setActiveTab: function(link){
		if(!link && typeof(link) == 'undefined')
			return;
		if(typeof(link) == 'string'){
			this.setActiveTab(this.links.find(function(_link){
				return _link.key == link;
			}));
		}else if(typeof(link) == 'number'){
			this.setActiveTab(this.links[link]);
		}else{
			if(this.notify('beforeChange',this.activeContainer,this.containers.get(link.key)) === false)
				return;
			if(this.activeContainer)
				this.options.hideFunction(this.activeContainer);
			this.links.each(function(item){
				(this.options.setClassOnContainer ? $(item.parentNode) : item).removeClassName(this.options.activeClassName);
			}.bind(this));
			(this.options.setClassOnContainer ? $(link.parentNode) : link).addClassName(this.options.activeClassName);
			this.activeContainer = this.containers.get(link.key);
			this.activeLink = link;
			this.options.showFunction(this.containers.get(link.key));
			this.notify('afterChange',this.containers.get(link.key));
		}
	},
	next: function(){
		this.links.each(function(link,i){
			if(this.activeLink == link && this.links[i + 1]){
				this.setActiveTab(this.links[i + 1]);
				throw $break;
			}
		}.bind(this));
	},
	previous: function(){
		this.links.each(function(link,i){
			if(this.activeLink == link && this.links[i - 1]){
				this.setActiveTab(this.links[i - 1]);
				throw $break;
			}
		}.bind(this));
	},
	first: function(){
		this.setActiveTab(this.links.first());
	},
	last: function(){
		this.setActiveTab(this.links.last());
	}
});
Object.extend(Control.Tabs,{
	instances: [],
	findByTabId: function(id){
		return Control.Tabs.instances.find(function(tab){
			return tab.links.find(function(link){
				return link.key == id;
			});
		});
	}
});
Object.Event.extend(Control.Tabs);



/* Copyright (c) 2007 Paul Bakaus (paul.bakaus@googlemail.com) and Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * $LastChangedDate: 2007-12-20 08:43:48 -0600 (Thu, 20 Dec 2007) $
 * $Rev: 4257 $
 *
 * Version: 1.2
 *
 * Requires: jQuery 1.2+
 */
eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(5($){$.19={P:\'1.2\'};$.u([\'j\',\'w\'],5(i,d){$.q[\'O\'+d]=5(){p(!3[0])6;g a=d==\'j\'?\'s\':\'m\',e=d==\'j\'?\'D\':\'C\';6 3.B(\':y\')?3[0][\'L\'+d]:4(3,d.x())+4(3,\'n\'+a)+4(3,\'n\'+e)};$.q[\'I\'+d]=5(b){p(!3[0])6;g c=d==\'j\'?\'s\':\'m\',e=d==\'j\'?\'D\':\'C\';b=$.F({t:Z},b||{});g a=3.B(\':y\')?3[0][\'8\'+d]:4(3,d.x())+4(3,\'E\'+c+\'w\')+4(3,\'E\'+e+\'w\')+4(3,\'n\'+c)+4(3,\'n\'+e);6 a+(b.t?(4(3,\'t\'+c)+4(3,\'t\'+e)):0)}});$.u([\'m\',\'s\'],5(i,b){$.q[\'l\'+b]=5(a){p(!3[0])6;6 a!=W?3.u(5(){3==h||3==r?h.V(b==\'m\'?a:$(h)[\'U\'](),b==\'s\'?a:$(h)[\'T\']()):3[\'l\'+b]=a}):3[0]==h||3[0]==r?S[(b==\'m\'?\'R\':\'Q\')]||$.N&&r.M[\'l\'+b]||r.A[\'l\'+b]:3[0][\'l\'+b]}});$.q.F({z:5(){g a=0,f=0,o=3[0],8,9,7,v;p(o){7=3.7();8=3.8();9=7.8();8.f-=4(o,\'K\');8.k-=4(o,\'J\');9.f+=4(7,\'H\');9.k+=4(7,\'Y\');v={f:8.f-9.f,k:8.k-9.k}}6 v},7:5(){g a=3[0].7;G(a&&(!/^A|10$/i.16(a.15)&&$.14(a,\'z\')==\'13\'))a=a.7;6 $(a)}});5 4(a,b){6 12($.11(a.17?a[0]:a,b,18))||0}})(X);',62,72,'|||this|num|function|return|offsetParent|offset|parentOffset|||||borr|top|var|window||Height|left|scroll|Left|padding|elem|if|fn|document|Top|margin|each|results|Width|toLowerCase|visible|position|body|is|Right|Bottom|border|extend|while|borderTopWidth|outer|marginLeft|marginTop|client|documentElement|boxModel|inner|version|pageYOffset|pageXOffset|self|scrollTop|scrollLeft|scrollTo|undefined|jQuery|borderLeftWidth|false|html|curCSS|parseInt|static|css|tagName|test|jquery|true|dimensions'.split('|'),0,{}))

eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(5($){8 g=[],B=[],G=12=k,3c=$(\'<E Y="1g-E 3x" 24="1Z:3h;1i:0;1w:0;2r:2X;"><E Y="3G"></E><E Y="3E"></E><E Y="3C"></E></E>\')[0],2L=$(\'<29 Y="1g-29 3q"></29>\')[0],2H=$(\'<X 24="1Z:3j;"><E Y="1g-1k"></E></X>\')[0],3g=$(\'<3Q Y="1g-1k-3P" />\')[0],$1V=$(\'<E 3N="3M-1g-E" 24="1Z:3h;1i:0;1w:0;"></E>\'),1P={34:31,2Y:31,2p:0,2V:0,2U:0,1J:0,2B:k,2i:k,1r:k,2d:k,2M:Q,2J:Q};$(5(){$1V.3s(\'3p\')});$.R({25:5(a){2.11=[];2.1s(a)}});$.R($.25,{1X:{1s:5(a){4(a&&a.9){J(8 i=0;i<a.9;i++){2.2y(a[i]);a[i].V=2}}},2y:5(a){4(a 2x $.C)2.11.16(a);a.V=2;8 b=2;$(a.q).1T(5(){4(a.M)s;J(8 i=0;i<b.11.9;i++){4(b.11[i].M){b.11[i].W();a.14();s}}},5(){})}}});$.R({C:5(a,b,c){2.l=[];2.1c=[];2.M=Q;2.O=Q;2.N=k;2.u=$.R({},1P,c);2.q=a;2.$w=k;2.$1q=k;2.17=k;2.V=k;2.1L=k;2.1s();4(b&&b.2T==2S)2.2Q(b)}});$.R($.C,{2m:5(e){8 t=e.q;4(B.9&&t==B[0].q)s;1y(t.2t&&t.2t!=$1V[0])t=t.2t;4(!$(B).3B(5(){s 2.$w[0]==t}).9){$.C.1n()}},2f:5(e){3A(e.2c){1m 13:4(12)12.1a(e,12.$p[0]);1h;1m 27:$.C.1n();1h;1m 37:4(!G)G=B[0];8 a=G;4(a&&a.N){8 b=a.N;b.$p.K(\'1F\').K(\'1E\');a.W();b.15(P);2l(5(){b.23()})}v 4(a&&a.V){8 c,F=a.V.11;4((c=$.18(a,F))>-1){4(--c<0)c=F.9-1;$.C.1n();F[c].14();F[c].Z();4(F[c].l.9)F[c].l[0].15(P)}}1h;1m 38:4(G)G.1Y(-1);1h;1m 39:4(!G)G=B[0];8 m,a=G,1t=12?12.x:k;4(a){4(1t&&1t.l.9){1t.14();1t.l[0].15()}v 4((a=a.2C())){8 c,F=a.V.11;4((c=$.18(a,F))>-1){4(++c>=F.9)c=0;$.C.1n();F[c].14();F[c].Z();4(F[c].l.9)F[c].l[0].15(P)}}}1h;1m 3i:4(!G){4(B.9&&B[0].l.9)B[0].l[0].15()}v G.1Y();1h}4(e.2c>36&&e.2c<3S)s Q},1n:5(){1y(B.9)B[0].W()},3R:5(d){$.R(1P,d)},1X:{1s:5(){8 a=2;4(!2.q)s;v 4(2.q 2x $.1j){2.N=2.q;2.q.3f(2);2.q=2.q.$p}g.16(2);2.$w=$(3c.1A(1));2.$1q=$(2L.1A(1));2.$w[0].1z(2.$1q[0]);$1V[0].1z(2.$w[0]);4(!2.N){$(2.q).1a(5(e){a.1r(e)}).1T(5(e){a.Z();4(a.u.2p){a.1L=2l(5(){4(!a.M)a.1r(e)},a.u.2p)}},5(){4(!a.M)$(2).1W(\'2w\');4(a.1L)3e(a.1L)})}v{2.$w.1T(5(){a.Z()},5(){})}},Z:5(){4(!2.N)$(2.q).10(\'2w\');v 2.O=P},2v:5(a){4(a 2x $.1j){4($.18(a,2.l)==-1){2.$1q.3O(a.$p);2.l.16(a);a.A=2;4(a.x)2.1c.16(a.x)}}v{2.2v(19 $.1j(a,2.u))}},2Q:5(a){J(8 i=0;i<a.9;i++){2.2v(a[i])}},3d:5(a){8 b=$.18(a,2.l);4(b>-1)2.l.1U(b,1);a.A=k},W:5(){4(!2.M)s;8 i,I=$.18(2,B);2.$w.W();4(I>=0)B.1U(I,1);2.M=2.O=Q;$(2.q).1W(\'2w\');J(i=0;i<2.1c.9;i++){2.1c[i].W()}J(i=0;i<2.l.9;i++){4(2.l[i].O)2.l[i].1S()}4(!B.9)$(2u).K(\'3b\',$.C.2m).K(\'3a\',$.C.2f);4(G==2)G=k;4(2.u.2i)2.u.2i.1R(2)},14:5(e){4(2.M)s;8 a,D=2.N;4(2.l.9){4(D){a=35(D.A.$w.1e(\'z-33\'));2.$w.1e(\'z-33\',(3L(a)?1:a+1))}2.$w.1e({32:\'3K\',2r:\'3J\'});4(2.u.1J){4(2.$w.L()<2.u.1J)2.$w.1e(\'L\',2.u.1J)}2.30();2.$w.1e({2r:\'2X\',32:\'\'}).14();4($.2Z.3I)2.$1q.1e(\'L\',35($.2Z.3H)==6?2.$w.L()-7:2.$1q.L());4(2.u.2B)2.u.2B.1R(2)}4(B.9==0)$(2u).2W(\'3b\',$.C.2m).2W(\'3a\',$.C.2f);2.M=P;B.16(2)},30:5(){8 a,o,S,H,1N,1b,1o,2o=$(1K).L(),1p=$(1K).T(),D=2.N,T=2.$w[0].2R,L=2.$w[0].3F,1M;4(D){o=D.$p.2q();S=o.1w+D.$p.L();H=o.1i}v{a=$(2.q);o=a.2q();S=o.1w+2.u.2U;H=o.1i+a.T()+2.u.2V}4($.2s.2P){1b=$(1K).2P();4(1p<T){H=1b}v 4(1p+1b<H+T){4(D){1N=D.A.$w.2q();1M=D.A.$w[0].2R;4(T<=1M){H=1N.1i+1M-T}v{H=1N.1i}4(1p+1b<H+T){H-=H+T-(1p+1b)}}v{H-=H+T-(1p+1b)}}}4($.2s.2O){1o=$(1K).2O();4(2o+1o<S+L){4(D){S-=D.$p.L()+L;4(S<1o)S=1o}v{S-=S+L-(2o+1o)}}}2.$w.1e({1w:S,1i:H})},1r:5(e){4(2.M){2.W();2.Z()}v{$.C.1n();2.14(e)}},2k:5(a,b){8 c=2;2.17=2l(5(){a.1R(c);c.17=k},b)},1d:5(){4(2.17){3e(2.17);2.17=k}},1Y:5(a){8 i,I=0,1O=2.l.9,o=a||1;J(i=0;i<1O;i++){4(2.l[i].O){I=i;1h}}2.l[I].2j();3D{I+=o;4(I>=1O)I=0;v 4(I<0)I=1O-1}1y(2.l[I].1Q);2.l[I].15(P)},2C:5(){8 m=2;1y(m.N)m=m.N.A;s m.V?m:k},1I:5(){8 a,1k;2.W();4(!2.N)$(2.q).K(\'1a\').K(\'1E\').K(\'1F\');v 2.$w.K(\'1E\').K(\'1F\');1y(2.l.9){1k=2.l[0];1k.1I();2N 1k}4((a=$.18(2,g))>-1)g.1U(a,1);4(2.V){4((a=$.18(2,2.V.11))>-1)2.V.11.1U(a,1)}2.$w.2h()}}});$.R({1j:5(a,b){4(2g a==\'2e\')a={y:a};2.y=a.y||\'\';2.1D=a.1D||k;2.20=a.q||k;2.10=a.10||k;2.1B=a.1B||k;2.$p=k;2.A=k;2.x=k;2.u=$.R({},1P,b);2.O=Q;2.1l=P;2.1Q=Q;2.1s();4(a.x)19 $.C(2,a.x,b)}});$.R($.1j,{1X:{1s:5(){8 i,1C,y=2.y,2b=2;2.$p=$(2H.1A(1));4(2.10)2.$p[0].2K(\'Y\',2.10);4(2.u.2M&&2.1B)2.$p[0].3z=2.1B;4(y==\'\'){2.$p.10(\'1g-1Q\');2.1Q=P}v{1C=2g y==\'2e\';4(1C&&2.1D)y=$(\'<a 3y="\'+2.1D+\'"\'+(2.20?\'q="\'+2.20+\'"\':\'\')+\'>\'+y+\'</a>\');v 4(1C||!y.9)y=[y];J(i=0;i<y.9;i++){4(2g y[i]==\'2e\'){2a=2u.3w(\'3v\');2a.3t=y[i];2.$p[0].1u.1z(2a)}v 2.$p[0].1u.1z(y[i].1A(1))}}2.$p.1a(5(e){2b.1a(e,2)});2.23()},1a:5(e,a){4(2.1l&&2.u.1r)2.u.1r.1R(a,e,2)},23:5(){8 a=2;2.$p.1T(5(){a.15()},5(){a.2j()})},15:5(a){2.1d();8 i,1f=2.A.1c,D=2.A.l,2b=2;4(2.A.17)2.A.1d();4(!2.1l)s;J(i=0;i<D.9;i++){4(D[i].O)D[i].1S()}2.Z();G=2.A;J(i=0;i<1f.9;i++){4(1f[i].M&&1f[i]!=2.x&&!1f[i].17)1f[i].2k(5(){2.W()},1f[i].u.2Y)}4(2.x&&!a){2.x.2k(5(){2.14()},2.x.u.34)}},2j:5(){2.1d();4(!2.1l)s;4(!2.x||!2.x.M)2.1S()},1d:5(){4(2.x){2.x.1d()}},Z:5(){2.O=P;2.$p.10(\'O\');8 a=2.A.N;4(a&&!a.O)a.Z();12=2},1S:5(){2.O=Q;2.$p.1W(\'O\');4(2==12)12=k},3r:5(){2.$p.1W(\'2I\');2.1l=P},3u:5(){2.$p.10(\'2I\');2.1l=Q},1I:5(){2.1d();2.$p.2h();2.$p.K(\'1E\').K(\'1F\').K(\'1a\');4(2.x){2.x.1I();2N 2.x}2.A.3d(2)},3f:5(b){4(2.x)s;2.x=b;4(2.A&&$.18(b,2.A.1c)==-1)2.A.1c.16(b);4(2.u.2d){8 a=3g.1A(0);a.2K(\'y\',2.u.2d);2.$p[0].1u.1z(a)}}}});$.R($.2s,{28:5(c,d,e){8 f=5(a){8 b=[],1v,1G,U,$X,i,1H,3o,q,26=k;U=j(a,\'2G\');J(i=0;i<U.9;i++){1v=[];4(!U[i].1x.9){b.16(19 $.1j(\'\',c));3n}4((1H=h(U[i],\'2n\'))){1v=f(1H);$(1H).2h()}$X=$(U[i]);4($X[0].1x.9==1&&$X[0].1x[0].22==3)q=$X[0].1x[0].3m;v q=$X[0].1x;4(c&&c.2J)26=$X.3l(\'Y\');1G=19 $.1j({y:q,10:26},c);b.16(1G);4(1v.9)19 $.C(1G,1v,c)}s b};s 2.2z(5(){8 a,m;4(d||(a=h(2,\'2n\'))){a=d?$(d).3k(P)[0]:a;l=f(a);4(l.9){m=19 $.C(2,l,c);4(e)e.2y(m)}$(a).W()}})},2F:5(a){s 2.2z(5(){8 i,U=j(2,\'2G\');4(U.9){2E=19 $.25();J(i=0;i<U.9;i++)$(U[i]).28(a,k,2E)}})},1g:5(a,b){s 2.2z(5(){4(b&&b.2T==2S)19 $.C(2,b,a);v{4(2.21.2A()==\'2n\')$(2).2F(a);v $(2).28(a,b)}})}});8 h=5(a,b){4(!a)s k;8 n=a.1u;J(;n;n=n.2D){4(n.22==1&&n.21.2A()==b)s n}s k};8 j=5(a,b){4(!a)s[];8 r=[],n=a.1u;J(;n;n=n.2D){4(n.22==1&&n.21.2A()==b)r[r.9]=n}s r}})(3T);',62,242,'||this||if|function|||var|length|||||||||||null|menuItems||||eLI|target||return||settings|else|eDIV|subMenu|src||parentMenu|visibleMenus|Menu|pmi|div|mcm|activeMenu|posY|pos|for|unbind|width|visible|parentMenuItem|active|true|false|extend|posX|height|lis|menuCollection|hide|li|class|setActive|addClass|menus|activeItem||show|hoverIn|push|timer|inArray|new|click|wst|subMenus|removeTimer|css|pms|menu|break|top|MenuItem|item|enabled|case|closeAll|wsl|wh|eUL|onClick|init|asm|firstChild|subItems|left|childNodes|while|appendChild|cloneNode|data|isStr|url|mouseover|mouseout|menuItem|subUL|destroy|minWidth|window|openTimer|pheight|pmo|mil|defaults|separator|call|setInactive|hover|splice|rootDiv|removeClass|prototype|selectNextItem|position|urlTarget|nodeName|nodeType|bindHover|style|MenuCollection|classNames||menuFromElement|ul|elem|self|keyCode|arrowSrc|string|checkKey|typeof|remove|onClose|hoverOut|addTimer|setTimeout|checkMouse|UL|ww|hoverOpenDelay|offset|display|fn|parentNode|document|addItem|activetarget|instanceof|addMenu|each|toUpperCase|onOpen|inMenuCollection|nextSibling|bar|menuBarFromUL|LI|menuItemElement|disabled|copyClassAttr|setAttribute|menuULElement|addExpando|delete|scrollLeft|scrollTop|addItems|clientHeight|Array|constructor|offsetLeft|offsetTop|bind|none|hideDelay|browser|setPosition|200|visibility|index|showDelay|parseInt|||||keydown|mousedown|menuDIVElement|removeItem|clearTimeout|addSubMenu|arrowElement|absolute|40|relative|clone|attr|nodeValue|continue|submenu|body|innerbox|enable|appendTo|innerHTML|disable|span|createElement|outerbox|href|menuData|switch|filter|shadowbox3|do|shadowbox2|clientWidth|shadowbox1|version|msie|block|hidden|isNaN|root|id|append|arrow|img|setDefaults|41|jQuery'.split('|'),0,{}));


var ColourPicker = Class.create();
ColourPicker.prototype = {
    colourArray: new Array(),
    element: null,
    trigger: null,
    tableShown: false,
    
    initialize: function(element, trigger) {
        this.colourArray = new Array();
        this.element = $(element);
        this.trigger = $(trigger);
        
        this.trigger.onclick = this.toggleTable.bindAsEventListener(this);
        // Initialise the color array
        this.initColourArray();
        this.buildTable();
        
    },
    initColourArray: function() {
        var colourMap = new Array('00', '33', '66', '99', 'AA', 'CC', 'EE', 'FF');
        for(i = 0; i < colourMap.length; i++) {
            this.colourArray.push(colourMap[i] + colourMap[i] + colourMap[i]);
        }
        
        // Blue
        for(i = 1; i < colourMap.length; i++) {
            if(i != 0 && i != 4 && i != 6) {
                this.colourArray.push(colourMap[0] + colourMap[0] + colourMap[i]);
            }
        }
        for(i = 1; i < colourMap.length; i++) {
            if(i != 2 && i != 4 && i != 6 && i != 7) {
                this.colourArray.push(colourMap[i] + colourMap[i] + colourMap[7]);
            }
        }
        
        // Green
        for(i = 1; i < colourMap.length; i++) {
            if(i != 0 && i != 4 && i != 6) {
                this.colourArray.push(colourMap[0] + colourMap[i] + colourMap[0]);
            }
        }
        for(i = 1; i < colourMap.length; i++) {
            if(i != 2 && i != 4 && i != 6 && i != 7) {
                this.colourArray.push(colourMap[i] + colourMap[7] + colourMap[i]);
            }
        }
        
        // Red
        for(i = 1; i < colourMap.length; i++) {
            if(i != 0 && i != 4 && i != 6) {
                this.colourArray.push(colourMap[i] + colourMap[0] + colourMap[0]);
            }
        }
        for(i = 1; i < colourMap.length; i++) {
            if(i != 2 && i != 4 && i != 6 && i != 7) {
                this.colourArray.push(colourMap[7] + colourMap[i] + colourMap[i]);
            }
        }
        
        // Yellow
        for(i = 1; i < colourMap.length; i++) {
            if(i != 0 && i != 4 && i != 6) {
                this.colourArray.push(colourMap[i] + colourMap[i] + colourMap[0]);
            }
        }
        for(i = 1; i < colourMap.length; i++) {
            if(i != 2 && i != 4 && i != 6 && i != 7) {
                this.colourArray.push(colourMap[7] + colourMap[7] + colourMap[i]);
            }
        }
        
        // Cyan
        for(i = 1; i < colourMap.length; i++) {
            if(i != 0 && i != 4 && i != 6) {
                this.colourArray.push(colourMap[0] + colourMap[i] + colourMap[i]);
            }
        }
        for(i = 1; i < colourMap.length; i++) {
            if(i != 2 && i != 4 && i != 6 && i != 7) {
                this.colourArray.push(colourMap[i] + colourMap[7] + colourMap[7]);
            }
        }
        
        // Magenta
        for(i = 1; i < colourMap.length; i++) {
            if(i != 0 && i != 4 && i != 6) {
                this.colourArray.push(colourMap[i] + colourMap[0] + colourMap[i]);
            }
        }
        for(i = 1; i < colourMap.length; i++) {
            if(i != 2 && i != 4 && i != 6 && i != 7) {
                this.colourArray.push(colourMap[7] + colourMap[i] + colourMap[i]);
            }
        }
    },
    buildTable: function() {
        if(!this.tableShown) {
            html = "<table id=\"" + this.trigger.id + "ColourPicker\" style=\"display: none\" class=\"colorPicker\">"
            for(i = 0; i < this.colourArray.length; i++) {
                if(i % 8 == 0) {
                    html += "<tr>";
                }
                html += "<td style=\"background-color: #" + this.colourArray[i] + ";\" title=\"#" + this.colourArray[i] +  "\" onClick=\"$('" + this.element.id + "').value = '#" + this.colourArray[i] + "'; $('" + this.trigger.id + "ColourPicker').style.display = 'none';\">";
                if(i % 8 == 7) {
                    html += "</tr>";
                }
            }
            html += "</table>";
            new Insertion.After(this.trigger, html);
        }
    },
    toggleTable: function(sender) {
        var obj = $(Event.element(sender).id + 'ColourPicker');
        obj.style.display = (obj.style.display == 'block' ? 'none' : 'block');

//        $(Event.element(sender)).observe('click', Event.stop);
        return false;
    }
}
