/**

* @author Ryan Johnson <http://syntacticx.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;

	}

});
