/*
 * jQuery dragscrollable Plugin
 * version: 1.0 (25-Jun-2009)
 * Copyright (c) 2009 Miquel Herrera
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 */
var Easing = {
    Circ : {
        easeIn : function(t, b, c, d) {
                return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
        },
        easeOut : function(t, b, c, d) {
                return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
        },
        easeInOut : function(t, b, c, d) {
                if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
                return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
        }
    }
};

;
(function($){ // secure $ jQuery alias

    /**
 * Adds the ability to manage elements scroll by dragging
 * one or more of its descendant elements. Options parameter
 * allow to specifically select which inner elements will
 * respond to the drag events.
 * 
 * options properties:
 * ------------------------------------------------------------------------		
 *  dragSelector         | jquery selector to apply to each wrapped element 
 *                       | to find which will be the dragging elements. 
 *                       | Defaults to '>:first' which is the first child of 
 *                       | scrollable element
 * ------------------------------------------------------------------------		
 *  acceptPropagatedEvent| Will the dragging element accept propagated 
 *	                     | events? default is yes, a propagated mouse event 
 *	                     | on a inner element will be accepted and processed.
 *	                     | If set to false, only events originated on the
 *	                     | draggable elements will be processed.
 * ------------------------------------------------------------------------
 *  preventDefault       | Prevents the event to propagate further effectivey
 *                       | dissabling other default actions. Defaults to true
 * ------------------------------------------------------------------------
 *  
 *  usage examples:
 *
 *  To add the scroll by drag to the element id=viewport when dragging its 
 *  first child accepting any propagated events
 *	$('#viewport').dragscrollable(); 
 *
 *  To add the scroll by drag ability to any element div of class viewport
 *  when dragging its first descendant of class dragMe responding only to
 *  evcents originated on the '.dragMe' elements.
 *	$('div.viewport').dragscrollable({dragSelector:'.dragMe:first',
 *									  acceptPropagatedEvent: false});
 *
 *  Notice that some 'viewports' could be nested within others but events
 *  would not interfere as acceptPropagatedEvent is set to false.
 *		
 */
    $.fn.dragscrollable = function( options ){
   
        var settings = $.extend(
        {   
            dragSelector:'>:first',
            acceptPropagatedEvent: true,
            preventDefault: true
        },options || {});
	var canReadMove = true;
	
        var dragscroll= {
            canReadMove:true,
            mouseDownHandler : function(event) {
                // mousedown, left click, check propagation
                if (event.which!=1 ||
                    (!event.data.acceptPropagatedEvent && event.target != this)){ 
                    return false; 
                }
			
                // Initial coordinates will be the last when dragging
                event.data.lastCoord = {
                    left: event.clientX, 
                    top: event.clientY
                    }; 
                event.data.start = {
                    scrollLeft: event.data.scrollable.scrollLeft(),	
                    scrollTop: event.data.scrollable.scrollTop()
                    }; 
                event.data.speed = {
                    left: event.clientX, 
                    top: event.clientY
                    }; 
		
                $.e = event;
                
                $.event.add( document, "mouseup", 
                    dragscroll.mouseUpHandler, event.data );
                $.event.add( document, "mousemove", 
                    dragscroll.mouseMoveHandler, event.data );
                    
                 //   console.log(event.data);
                    
                    event.data.prevX = event.clientX;
                    
                      if($.inte) clearInterval($.inte);
                      $.e.data.scrollable.stop(false);
                      
                    $.inte = setInterval(dragscroll.interval, 25);
                    
                if (event.data.preventDefault) {
                    event.preventDefault();
                    return false;
                }
            },
            mouseMoveHandler : function(event) { // User is dragging
                // How much did the mouse move?
                var delta = {
                    left: (event.clientX - event.data.lastCoord.left),
                    top: (event.clientY - event.data.lastCoord.top)
                    };
			
                // Set the scroll position relative to what ever the scroll is now
                //event.data.scrollable.scrollLeft(
                //				event.data.scrollable.scrollLeft() - delta.left);
                //event.data.scrollable.scrollTop(
                //				event.data.scrollable.scrollTop() - delta.top);
			
                //console.log({ scrollLeft: event.data.scrollable.scrollLeft() - delta.left,
                //		scrollTop: event.data.scrollable.scrollTop() - delta.top });
		
                $.e = event;
                
                //event.data.scrollable.
                //stop(true,false).
                //scrollLeft(event.data.start.scrollLeft - delta.left/1.9).
               // scrollTop( event.data.start.scrollTop - delta.top/1.9 ).
               // animate({ scrollLeft: event.data.start.scrollLeft - delta.left  ,
		//	scrollTop: event.data.start.scrollTop - delta.top },1500 ,"easeOutQuint");
//                scrollLeft( event.data.start.scrollLeft - delta.left/1.9 ).
//                scrollTop( event.data.start.scrollTop - delta.top );
			
                // Save where the cursor is
                //event.data.lastCoord={left: event.clientX, top: event.clientY}
                
               //console.log($.e.data.canReadMove);
               if( $.e.data.canReadMove )
               {

                   $.e.data.canReadMove = false;

                   setTimeout(  function(){ $.e.data.canReadMove = true; } , 20 );
                    dragscroll.speedRead();    
               }
               
                event.data.speed = {
                    left: Math.abs(event.data.speed.left - event.clientX), 
                    top: Math.abs(event.data.speed.top - event.clientY)
                    }
                if (event.data.preventDefault) {
                    event.preventDefault();
                    return false;
                }
                
                

            },

            mouseUpHandler : function(event) { // Stop scrolling
                $.event.remove( document, "mousemove", dragscroll.mouseMoveHandler);
                $.event.remove( document, "mouseup", dragscroll.mouseUpHandler);
                if($.inte) clearInterval($.inte);
                    var delta = {
                    left: ($.e.clientX - $.e.data.lastCoord.left),
                    top: ($.e.clientY - $.e.data.lastCoord.top)
                    };
//                 $.e.data.scrollable.stop(false).
//                                scrollTop( $.e.data.start.scrollTop - delta.top/1.9 ).
//                                animate({scrollLeft: event.data.start.scrollLeft - delta.left  ,
//                                	scrollTop: event.data.start.scrollTop - delta.top},1500 ,"easeOutQuint");
                
                
                dragscroll.overRun();
                if (event.data.preventDefault) {
                    event.preventDefault();
                    return false;
                }
            },
            interval: function(){
                
                    var delta = {
                    left: ($.e.clientX - $.e.data.lastCoord.left),
                    top: ($.e.clientY - $.e.data.lastCoord.top)
                    };
                    var moveto;
                   // console.log($.e.clientX);
                  //  console.log($.e.data.lastCoord.left);
//                  var diff = $.e.data.start.scrollLeft - $.e.data.scrollable.scrollLeft();
//                    console.log("scrollLeft:"+$.e.data.scrollable.scrollLeft()+
//                        ", $.e.clientX:"+$.e.clientX,
//                        ", $.e.data.prevX:"+$.e.data.prevX,
//                        ", $.e.data.lastXSpeed:"+$.e.data.lastXSpeed,
//                        ", d:"+ ( moveto =  delta.left/Math.sqrt(Math.abs(delta.left)) )
//                     );
                         
            var scrollleft = $.e.data.scrollable.scrollLeft();
            scrollleft += -( $.e.clientX - $.e.data.prevX ) * 0.5;
              $.e.data.scrollable.scrollLeft( scrollleft );

            
             $.e.data.prevX = $.e.clientX - ( $.e.clientX - $.e.data.prevX );
             $.e.data.prevX = $.e.clientX ;

             
          
                // $.e.data.scrollable.
                              
                               // scrollTop( $.e.data.start.scrollTop - delta.top/1.9 ).
                             
                                //scrollLeft( $.e.data.scrollable.scrollLeft() - delta );
                              
            },
             overRun : function()
             {
                   if(  Math.abs( $.e.data.lastXSpeed ) > 1  )
                   {
                       // console.log("overRun");
                           var scrollleft = $.e.data.scrollable.scrollLeft();
                           scrollleft  += Math.floor( $.e.data.lastXSpeed *= 0.9 );
                          $.e.data.scrollable.scrollLeft(scrollleft);

                        
                         $.e.data.overRunTimer = setTimeout(  function(){ dragscroll.overRun(); } , 30 );

                         $.e.data.lastLeft = $.e.data.scrollable.scrollLeft();

                   }
             },
             speedRead : function()
             {
               
                 $.e.data.lastXSpeed = $.e.data.scrollable.scrollLeft() -  $.e.data.lastLeft;

                
                 $.e.data.lastLeft = $.e.data.scrollable.scrollLeft();

               
             }
        }
	
        // set up the initial events
        this.each(function() {
            // closure object data for each scrollable element
            var data = {
                scrollable : $(this),
                acceptPropagatedEvent : settings.acceptPropagatedEvent,
                preventDefault : settings.preventDefault,
                canReadMove:true
            }
            // Set mouse initiating event on the desired descendant
            $(this).find(settings.dragSelector).
            bind('mousedown', data, dragscroll.mouseDownHandler);
        });
    }; //end plugin dragscrollable

})( jQuery ); // confine scope

