/*
 * jQuery UI @VERSION
 *
 * Copyright (c) 2008 Paul Bakaus (ui.jquery.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI
 *
 * $Id: ui.core.js 5587 2008-05-13 19:56:42Z scott.gonzalez $
 */
;(function($) {
	
	$.ui = {
		plugin: {
			add: function(module, option, set) {
				var proto = $.ui[module].prototype;
				for(var i in set) {
					proto.plugins[i] = proto.plugins[i] || [];
					proto.plugins[i].push([option, set[i]]);
				}
			},
			call: function(instance, name, args) {
				var set = instance.plugins[name];
				if(!set) { return; }
				
				for (var i = 0; i < set.length; i++) {
					if (instance.options[set[i][0]]) {
						set[i][1].apply(instance.element, args);
					}
				}
			}	
		},
		cssCache: {},
		css: function(name) {
			if ($.ui.cssCache[name]) { return $.ui.cssCache[name]; }
			var tmp = $('<div class="ui-resizable-gen">').addClass(name).css({position:'absolute', top:'-5000px', left:'-5000px', display:'block'}).appendTo('body');
			
			//if (!$.browser.safari)
				//tmp.appendTo('body'); 
			
			//Opera and Safari set width and height to 0px instead of auto
			//Safari returns rgba(0,0,0,0) when bgcolor is not set
			$.ui.cssCache[name] = !!(
				(!(/auto|default/).test(tmp.css('cursor')) || (/^[1-9]/).test(tmp.css('height')) || (/^[1-9]/).test(tmp.css('width')) || 
				!(/none/).test(tmp.css('backgroundImage')) || !(/transparent|rgba\(0, 0, 0, 0\)/).test(tmp.css('backgroundColor')))
			);
			try { $('body').get(0).removeChild(tmp.get(0));	} catch(e){}
			return $.ui.cssCache[name];
		},
		disableSelection: function(e) {
			e.unselectable = "on";
			e.onselectstart = function() { return false; };
			if (e.style) { e.style.MozUserSelect = "none"; }
		},
		enableSelection: function(e) {
			e.unselectable = "off";
			e.onselectstart = function() { return true; };
			if (e.style) { e.style.MozUserSelect = ""; }
		},
		hasScroll: function(e, a) {
			var scroll = /top/.test(a||"top") ? 'scrollTop' : 'scrollLeft', has = false;
			if (e[scroll] > 0) return true; e[scroll] = 1;
			has = e[scroll] > 0 ? true : false; e[scroll] = 0;
			return has;
		}
	};
	
	
	/** jQuery core modifications and additions **/
	
	var _remove = $.fn.remove;
	$.fn.remove = function() {
		$("*", this).add(this).trigger("remove");
		return _remove.apply(this, arguments );
	};
	
	// $.widget is a factory to create jQuery plugins
	// taking some boilerplate code out of the plugin code
	// created by Scott González and Jörn Zaefferer
	function getter(namespace, plugin, method) {
		var methods = $[namespace][plugin].getter || [];
		methods = (typeof methods == "string" ? methods.split(/,?\s+/) : methods);
		return ($.inArray(method, methods) != -1);
	}
	
	var widgetPrototype = {
		init: function() {},
		destroy: function() {
			this.element.removeData(this.widgetName);
		},
		
		getData: function(key) {
			return this.options[key];
		},
		setData: function(key, value) {
			this.options[key] = value;
		},
		
		enable: function() {
			this.setData('disabled', false);
		},
		disable: function() {
			this.setData('disabled', true);
		}
	};
	
	$.widget = function(name, prototype) {
		var namespace = name.split(".")[0];
		name = name.split(".")[1];
		// create plugin method
		$.fn[name] = function(options) {
			var isMethodCall = (typeof options == 'string'),
				args = Array.prototype.slice.call(arguments, 1);
			
			if (isMethodCall && getter(namespace, name, options)) {
				var instance = $.data(this[0], name);
				return (instance ? instance[options].apply(instance, args)
					: undefined);
			}
			
			return this.each(function() {
				var instance = $.data(this, name);
				if (!instance) {
					$.data(this, name, new $[namespace][name](this, options));
				} else if (isMethodCall) {
					instance[options].apply(instance, args);
				}
			});
		};
		
		// create widget constructor
		$[namespace][name] = function(element, options) {
			var self = this;
			
			this.widgetName = name;
			
			this.options = $.extend({}, $[namespace][name].defaults, options);
			this.element = $(element)
				.bind('setData.' + name, function(e, key, value) {
					return self.setData(key, value);
				})
				.bind('getData.' + name, function(e, key) {
					return self.getData(key);
				})
				.bind('remove', function() {
					return self.destroy();
				});
			this.init();
		};
		
		// add widget prototype
		$[namespace][name].prototype = $.extend({}, widgetPrototype, prototype);
	};
	
	
	/** Mouse Interaction Plugin **/
	
	$.ui.mouse = {
		mouseInit: function() {
			var self = this;
			
			this.element.bind('mousedown.mouse', function(e) {
				return self.mouseDown(e);
			});
			
			// Prevent text selection in IE
			if ($.browser.msie) {
				this._mouseUnselectable = this.element.attr('unselectable');
				this.element.attr('unselectable', 'on');
			}
			
			this.started = false;
		},
		
		// TODO: make sure destroying one instance of mouse doesn't mess with
		// other instances of mouse
		mouseDestroy: function() {
			this.element.unbind('.mouse');
			
			// Restore text selection in IE
			($.browser.msie
				&& this.element.attr('unselectable', this._mouseUnselectable));
		},
		
		mouseDown: function(e) {
			// we may have missed mouseup (out of window)
			(this._mouseStarted && this.mouseUp(e));
			
			this._mouseDownEvent = e;
			
			var self = this,
				btnIsLeft = (e.which == 1),
				elIsCancel = ($(e.target).is(this.options.cancel));
			if (!btnIsLeft || elIsCancel) {
				return true;
			}
			
			this._mouseDelayMet = !this.options.delay;
			if (!this._mouseDelayMet) {
				this._mouseDelayTimer = setTimeout(function() {
					self._mouseDelayMet = true;
				}, this.options.delay);
			}
			
			// these delegates are required to keep context
			this._mouseMoveDelegate = function(e) {
				return self.mouseMove(e);
			};
			this._mouseUpDelegate = function(e) {
				return self.mouseUp(e);
			};
			$(document)
				.bind('mousemove.mouse', this._mouseMoveDelegate)
				.bind('mouseup.mouse', this._mouseUpDelegate);
			
			return false;
		},
		
		mouseMove: function(e) {
			// IE mouseup check - mouseup happened when mouse was out of window
			if ($.browser.msie && !e.button) {
				return this.mouseUp(e);
			}
			
			if (this._mouseStarted) {
				this.mouseDrag(e);
				return false;
			}
			
			if (this.mouseDistanceMet(e) && this.mouseDelayMet(e)) {
				this._mouseStarted =
					(this.mouseStart(this._mouseDownEvent, e) !== false);
				(this._mouseStarted || this.mouseUp(e));
			}
			
			return !this._mouseStarted;
		},
		
		mouseUp: function(e) {
			$(document)
				.unbind('mousemove.mouse', this._mouseMoveDelegate)
				.unbind('mouseup.mouse', this._mouseUpDelegate);
			
			if (this._mouseStarted) {
				this._mouseStarted = false;
				this.mouseStop(e);
			}
			
			return false;
		},
		
		mouseDistanceMet: function(e) {
			return (Math.max(
					Math.abs(this._mouseDownEvent.pageX - e.pageX),
					Math.abs(this._mouseDownEvent.pageY - e.pageY)
				) >= this.options.distance
			);
		},
		
		mouseDelayMet: function(e) {
			return this._mouseDelayMet;
		},
		
		// These are placeholder methods, to be overriden by extending plugin
		mouseStart: function(e) {},
		mouseDrag: function(e) {},
		mouseStop: function(e) {}
	};
	
	$.ui.mouse.defaults = {
		cancel: null,
		distance: 0,
		delay: 0
	};
})(jQuery);
