/*!
* jQuery UI Mouse @VERSION
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Mouse
*
* Depends:
*	jquery.ui.widget.js
*/
(function ($, undefined) {

	var mouseHandled = false;
	$(document).mouseup(function (e) {
		mouseHandled = false;
	});

	$.widget("ui.mouse", {
		version: "@VERSION",
		options: {
			cancel: ':input,option',
			distance: 1,
			delay: 0
		},
		_mouseInit: function () {
			var self = this;

			this.element
			.bind('mousedown.' + this.widgetName, function (event) {
				return self._mouseDown(event);
			})
			.bind('click.' + this.widgetName, function (event) {
				if (true === $.data(event.target, self.widgetName + '.preventClickEvent')) {
					$.removeData(event.target, self.widgetName + '.preventClickEvent');
					event.stopImmediatePropagation();
					return false;
				}
			});

			this.started = false;
		},

		// TODO: make sure destroying one instance of mouse doesn't mess with
		// other instances of mouse
		_mouseDestroy: function () {
			this.element.unbind('.' + this.widgetName);
		},

		_mouseDown: function (event) {
			// don't let more than one widget handle mouseStart
			if (mouseHandled) { return };

			// we may have missed mouseup (out of window)
			(this._mouseStarted && this._mouseUp(event));

			this._mouseDownEvent = event;

			var self = this,
			btnIsLeft = (event.which == 1),
			// event.target.nodeName works around a bug in IE 8 with
			// disabled inputs (#7620)
			elIsCancel = (typeof this.options.cancel == "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
			if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
				return true;
			}

			this.mouseDelayMet = !this.options.delay;
			if (!this.mouseDelayMet) {
				this._mouseDelayTimer = setTimeout(function () {
					self.mouseDelayMet = true;
				}, this.options.delay);
			}

			if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
				this._mouseStarted = (this._mouseStart(event) !== false);
				if (!this._mouseStarted) {
					event.preventDefault();
					return true;
				}
			}

			// Click event may never have fired (Gecko & Opera)
			if (true === $.data(event.target, this.widgetName + '.preventClickEvent')) {
				$.removeData(event.target, this.widgetName + '.preventClickEvent');
			}

			// these delegates are required to keep context
			this._mouseMoveDelegate = function (event) {
				return self._mouseMove(event);
			};
			this._mouseUpDelegate = function (event) {
				return self._mouseUp(event);
			};
			$(document)
			.bind('mousemove.' + this.widgetName, this._mouseMoveDelegate)
			.bind('mouseup.' + this.widgetName, this._mouseUpDelegate);

			event.preventDefault();

			mouseHandled = true;
			return true;
		},

		_mouseMove: function (event) {
			// IE mouseup check - mouseup happened when mouse was out of window
			if ($.browser.msie && !(document.documentMode >= 9) && !event.button) {
				return this._mouseUp(event);
			}

			if (this._mouseStarted) {
				this._mouseDrag(event);
				return event.preventDefault();
			}

			if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
				this._mouseStarted =
				(this._mouseStart(this._mouseDownEvent, event) !== false);
				(this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
			}

			return !this._mouseStarted;
		},

		_mouseUp: function (event) {
			$(document)
			.unbind('mousemove.' + this.widgetName, this._mouseMoveDelegate)
			.unbind('mouseup.' + this.widgetName, this._mouseUpDelegate);

			if (this._mouseStarted) {
				this._mouseStarted = false;

				if (event.target == this._mouseDownEvent.target) {
					$.data(event.target, this.widgetName + '.preventClickEvent', true);
				}

				this._mouseStop(event);
			}

			return false;
		},

		_mouseDistanceMet: function (event) {
			return (Math.max(
				Math.abs(this._mouseDownEvent.pageX - event.pageX),
				Math.abs(this._mouseDownEvent.pageY - event.pageY)
			) >= this.options.distance
		);
		},

		_mouseDelayMet: function (event) {
			return this.mouseDelayMet;
		},

		// These are placeholder methods, to be overriden by extending plugin
		_mouseStart: function (event) { },
		_mouseDrag: function (event) { },
		_mouseStop: function (event) { },
		_mouseCapture: function (event) { return true; }
	});

})(jQuery);

