/*
* jQuery Touchable
*
* Simplified BSD License (@see License)
* @author Gregor Schwab
* @copyright (c) 2010 Gregor Schwab
* Usage Command Line: $(elem).Touchable() (@see Readme.md)
* @version 0.0.5
* @requires jQuery
*/


(function($) {

   $.fn.Touchable = function(conf) {
       return this.each(function() {
       var t= $(this).data['Touchable']=new Touchable(this, conf);
       return t;
     });
   }
   $.fn.newHover = function(fn1, fn2, disableHover) {
       return this.each(function() {
         $(this).bind('newHoverIn', fn1).bind('newHoverOut', fn2);
     });
   }
   $.fn.newHover2 = function(fn1, fn2) {
       return this.each(function() {
         $(this).bind('newHoverIn2', fn1).bind('newHoverOut2', fn2);
     });
   }

    $.Touchable=Touchable;

   /**
* @constructor
*/

   function Touchable(elem, conf)
   {

     this.logging=false; //set to false to disabele logging gets overwritten by conf see below
     var log=function(a){if(self.logging && (typeof console !== 'undefined')){
        console.log(Array.prototype.slice.call(arguments));}
        }; //private logging function

     this.elem=elem;
     this.$elem=$(elem);
     this.is_doubleTap=false;
     this.is_currentlyTouching=false;
     this.isOneFingerGesture = false;

     this.startTouch={x:0,y:0};
     this.currentTouch={x:0,y:0};
     this.previousTouch={x:0,y:0};
     this.currentDelta={x:0,y:0};//measured from previous move event
     this.currentStartDelta={x:0,y:0}; //measured from start
     this.currentPosition={x:0,y:0};
     this.doubleTapTimer=null, this.longTapTimer=null;

     var self=this;

     if (typeof conf!=='undefined'){
       if(typeof conf.logging!=='undefined'){this.logging=conf.logging;}
     }
     //make IE happy
     var addEventListener=elem.addEventListener||elem.attachEvent
     var removeEventListener = elem.removeEventListener||elem.detachEvent
     //add touchstart eventlistener
     addEventListener.call(elem, 'touchstart', function(){self.$elem.trigger('touchstart')}, true);
     addEventListener.call(elem, 'touchend', function(){self.$elem.trigger('touchend')}, false);
     addEventListener.call(elem, 'touchmove', function(){self.$elem.trigger('touchmove')}, false);

     addEventListener.call(elem, 'touchstart', touchstart, false);
     this.$elem.mousedown(touchstart);

     function touchstart (e) {
       if(typeof e.touches!== "undefined")
         {
         log('Touchable Touchstart touches length ' + e.touches.length);
         //only handle 1 or 2 touches
    if (e.touches.length !== 1 && e.touches.length !== 2) {
    return false;
    }
    if (self.isCurrentlyTouching) {
    return false;
    }


    self.isCurrentlyTouching = true;
    if (e.touches.length == 1) { //1 finger
    self.isOneFingerGesture = true;
    //init pos
    self.startTouch.x = self.previousTouch.x = e.touches[0].clientX;
    self.startTouch.y = self.previousTouch.y = e.touches[0].clientY;
    } else if (e.touches.length == 2) { //two fingers
    self.isOneFingerGesture = false;
    if (e.touches[0].clientY > e.touches[1].clientY) {//0 is lower
    self.startTouch.x = self.previousTouch.x = e.touches[0].clientX;
    self.startTouch.y = self.previousTouch.y = e.touches[0].clientY;
    } else {
    self.startTouch.x = self.previousTouch.x = self.touches[1].clientX;
    self.startTouch.y = self.previousTouch.y = self.touches[1].clientY;
    }
    }

    addEventListener.call(document, 'touchmove', touchmove, false);
    addEventListener.call(document, 'touchend', touchend, false);
   }else{
         log('Touchable Touchstart touches length ' + e.pageX + ' ' + e.pageY);
    self.startTouch.x = self.previousTouch.x = e.pageX;
    self.startTouch.y = self.previousTouch.y = e.pageY;
    $(document).mousemove(touchmove);
    $(document).mouseup(touchend);
   }
   //don't shallow links, but all the rest
   self.target=e.target;//some browser loose the info here
      self.currentTarget=e.currentTarget;//some browser loose the info here so save it for later
      var x=self.startTouch.x; var y=self.startTouch.y;
      self.hitTarget = ( document.elementFromPoint ) ? (document.elementFromPoint(x, y)):'';
   //if (self.hitTarget && !(self.hitTarget instanceof HTMLAnchorElement) &&!(e.currentTarget instanceof HTMLAnchorElement))
   e.preventDefault()


   //setup double tapping
   if (!self.inDoubleTap) {
   self.inDoubleTap = true;
   //setup a timer
   self.doubleTapTimer = setTimeout(function() {
   self.inDoubleTap = false;
   }, 500);
   } else {//we are double tapping
   // call function to run if double-tap
   log('Touchable doubleTap');
   self.$elem.trigger('doubleTap', self); //trigger a doubleTap
   //reset doubleTap state
   clearTimeout(self.doubleTapTimer);
   self.inDoubleTap = false;
       }
   //setup long tapping and long mousedown
   //setup a timer
   self.longTapTimer = setTimeout(function() {
   log('Touchable longTap'/*, self.hitTarget, self.target, self.currentTarget, self.elem*/);
   $(self.elem).trigger('longTap', self); //trigger a longTap
   }, 1000);

   log('Touchable Tap');
   $(self.elem).trigger('tap', self); //trigger a tap
   $(self.elem).trigger('touchablestart', self); //trigger a tap


   }


   //called on iPad/iPhone when touches started and the finger is moved
   function touchmove(e) {

   if (typeof e.touches !== 'undefined'){
       log('Touchable Touchsmove touches length ' + e.touches.length);
    if (e.touches.length !== 1 && e.touches.length !== 2) //use touches to track all fingers on the screen currently (also the ones not in the pane) if there are more than 2 its a gesture
    return false;

         //1 finger
    if (e.touches.length == 1 || self.isOneFingerGesture) {//we ignore the second finger if we are already in movement
    self.currentTouch.x = e.touches[0].clientX;
    self.currentTouch.y = e.touches[0].clientY;
           //2 finger
    } else if (self.touches.length == 2 && !self.isOneFingerGesture) {//two fingers move , take the upper finger as reference
    if (e.touches[0].clientY > e.touches[1].clientY) {//0 is lower
    self.currentTouch.x = e.touches[0].clientX;
    self.currentTouch.y = e.touches[0].clientY;
    } else {
    self.currentTouch.x = e.touches[1].clientX;
    self.currentTouch.y = e.touches[1].clientY;
    }
    }
   }else{
   self.currentTouch.x = e.pageX;
   self.currentTouch.y = e.pageY;
   }
   //if we are moving stop any css animations currently running
   $(self.elem).removeClass('webkitAnimate');
   //e.preventDefault();

   self.currentDelta.x = (self.currentTouch.x - self.previousTouch.x);///s.currentScale;
   self.currentDelta.y = (self.currentTouch.y - self.previousTouch.y);///s.currentScale;
   self.currentStartDelta.x = (self.currentTouch.x - self.startTouch.x);///s.currentScale;
   self.currentStartDelta.y = (self.currentTouch.y - self.startTouch.y);///s.currentScale;
   //just for the records (accumulation)
   self.currentPosition.x = self.currentPosition.x + self.currentDelta.x;
   self.currentPosition.y = self.currentPosition.y + self.currentDelta.y;
   //reset the start position for the next delta
   self.previousTouch.x = self.currentTouch.x;
   self.previousTouch.y = self.currentTouch.y;
       log('Touchable Touchablemove self e.target' + e.target + 'e.currentTarget '+ e.currentTarget +' x:'+ self.currentStartDelta.x);
       //Target handling
       self.target=e.target;//some browser loose the info here
       self.currentTarget=e.currentTarget;//some browser loose the info here so save it for later
      var x=self.currentTouch.x; var y=self.currentTouch.y;
       self.hitTarget = ( document.elementFromPoint ) ? (document.elementFromPoint(x, y)):'';
       $(self.elem).trigger('touchablemove', self);

   //clear the long tap timer on mousemove
    if (self.longTapTimer) clearTimeout(self.longTapTimer);
   }
     function touchend(e) {
       if (typeof e.touches !== 'undefined'){
    if (e.targetTouches.length > 0)
    return false;
      removeEventListener.call(self.elem, 'touchmove', touchmove, false);
      removeEventListener.call(self.elem, 'touchend', touchend, false);
   }else{
      $(document).unbind('mousemove',touchmove);
      $(document).unbind('mouseup',touchend);
   }

   //e.preventDefault();
   self.isCurrentlyTouching = false;
   //clear the long tap timer on mouseup
    if (self.longTapTimer) clearTimeout(self.longTapTimer);
       log('Touchable Touchend self ' + self.currentStartDelta.x);
       $(self.elem).trigger('touchableend', self);
   log('Touchable: touchableend');
       $(self.hitTarget).trigger('click', self);//trigger a click on the hittarget cause on iPad/Mobile Safari preventdefault seems to shallow click events
   log('Touchable: Hittarget click');

   }
   }
})(jQuery);//end closure


