/*!
 * jQuery UI Touch Punch 0.2.3
 *
 * Copyright 2011–2014, Dave Furfero
 * Dual licensed under the MIT or GPL Version 2 licenses.
 *
 * Depends:
 *  jquery.ui.widget.js
 *  jquery.ui.mouse.js
 */
(function (factory, jQuery) {
    if (typeof define === "function" && define.amd) {
        define(["jquery-ui/jquery.ui.widget", "jquery-ui/jquery.ui.mouse"], factory);
    } else {
    	if(jQuery && jQuery.ui){
    		factory(jQuery);
    	}else{
    		throw("jQuery UI is not loaded.");
    	}
    }
}(
	function ($) {

	  // Detect touch support
	  $.support.touch = 'ontouchend' in document;

	  // Ignore browsers without touch support
	  if (!$.support.touch) {
	    return;
	  }

	  var mouseProto = $.ui.mouse.prototype,
	      _mouseInit = mouseProto._mouseInit,
	      _mouseDestroy = mouseProto._mouseDestroy,
	      touchHandled;

	  /**
	   * Simulate a mouse event based on a corresponding touch event
	   * @param {Object} event A touch event
	   * @param {String} simulatedType The corresponding mouse event
	   */
	  function simulateMouseEvent (event, simulatedType) {

	    // Ignore multi-touch events
	    if (event.originalEvent.touches.length > 1) {
	      return;
	    }

	    event.preventDefault();

	    var touch = event.originalEvent.changedTouches[0],
	        simulatedEvent = document.createEvent('MouseEvents');

	    // Initialize the simulated mouse event using the touch event's coordinates
	    simulatedEvent.initMouseEvent(
	      simulatedType,    // type
	      true,             // bubbles
	      true,             // cancelable
	      window,           // view
	      1,                // detail
	      touch.screenX,    // screenX
	      touch.screenY,    // screenY
	      touch.clientX,    // clientX
	      touch.clientY,    // clientY
	      false,            // ctrlKey
	      false,            // altKey
	      false,            // shiftKey
	      false,            // metaKey
	      0,                // button
	      null              // relatedTarget
	    );

	    // Dispatch the simulated event to the target element
	    event.target.dispatchEvent(simulatedEvent);
	  }

	  /**
	   * Handle the jQuery UI widget's touchstart events
	   * @param {Object} event The widget element's touchstart event
	   */
	  mouseProto._touchStart = function (event) {

	    var self = this;

	    // Ignore the event if another widget is already being handled
	    if (touchHandled || !self._mouseCapture(event.originalEvent.changedTouches[0])) {
	      return;
	    }

	    // Set the flag to prevent other widgets from inheriting the touch event
	    touchHandled = true;

	    // Track movement to determine if interaction was a click
	    self._touchMoved = false;

	    // Simulate the mouseover event
	    simulateMouseEvent(event, 'mouseover');

	    // Simulate the mousemove event
	    simulateMouseEvent(event, 'mousemove');

	    // Simulate the mousedown event
	    simulateMouseEvent(event, 'mousedown');
	  };

	  /**
	   * Handle the jQuery UI widget's touchmove events
	   * @param {Object} event The document's touchmove event
	   */
	  mouseProto._touchMove = function (event) {

	    // Ignore event if not handled
	    if (!touchHandled) {
	      return;
	    }

	    // Interaction was not a click
	    this._touchMoved = true;

	    // Simulate the mousemove event
	    simulateMouseEvent(event, 'mousemove');
	  };

	  /**
	   * Handle the jQuery UI widget's touchend events
	   * @param {Object} event The document's touchend event
	   */
	  mouseProto._touchEnd = function (event) {

	    // Ignore event if not handled
	    if (!touchHandled) {
	      return;
	    }

	    // Simulate the mouseup event
	    simulateMouseEvent(event, 'mouseup');

	    // Simulate the mouseout event
	    simulateMouseEvent(event, 'mouseout');

	    // If the touch interaction did not move, it should trigger a click
	    if (!this._touchMoved) {

	      // Simulate the click event
	      simulateMouseEvent(event, 'click');
	    }

	    // Unset the flag to allow other widgets to inherit the touch event
	    touchHandled = false;
	  };

	  /**
	   * A duck punch of the $.ui.mouse _mouseInit method to support touch events.
	   * This method extends the widget with bound touch event handlers that
	   * translate touch events to mouse events and pass them to the widget's
	   * original mouse event handling methods.
	   */
	  mouseProto._mouseInit = function () {

	    var self = this;

	    // Delegate the touch handlers to the widget's element
	    self.element.bind({
	      touchstart: $.proxy(self, '_touchStart'),
	      touchmove: $.proxy(self, '_touchMove'),
	      touchend: $.proxy(self, '_touchEnd')
	    });

	    // Call the original $.ui.mouse init method
	    _mouseInit.call(self);
	  };

	  /**
	   * Remove the touch event handlers
	   */
	  mouseProto._mouseDestroy = function () {

	    var self = this;

	    // Delegate the touch handlers to the widget's element
	    self.element.unbind({
	      touchstart: $.proxy(self, '_touchStart'),
	      touchmove: $.proxy(self, '_touchMove'),
	      touchend: $.proxy(self, '_touchEnd')
	    });

	    // Call the original $.ui.mouse destroy method
	    _mouseDestroy.call(self);
	  };

	}
), this.jQuery);
