/*
jQuery grab 
https://github.com/jussi-kalliokoski/jQuery.grab
Ported from Jin.js::gestures   
https://github.com/jussi-kalliokoski/jin.js/
Created by Jussi Kalliokoski
Licensed under MIT License. 

Includes fix for IE
*/


(function($){
    var extend      = $.extend,
        mousedown   = 'mousedown',
        mousemove   = 'mousemove',
        mouseup     = 'mouseup',
        touchstart  = 'touchstart',
        touchmove   = 'touchmove',
        touchend    = 'touchend',
        touchcancel = 'touchcancel';

    function unbind(elem, type, func){
        if (type.substr(0,5) !== 'touch'){ // A temporary fix for IE8 data passing problem in Jin.
            return $(elem).unbind(type, func);
        }
        var fnc, i;
        for (i=0; i<bind._binds.length; i++){
            if (bind._binds[i].elem === elem && bind._binds[i].type === type && bind._binds[i].func === func){
                if (document.addEventListener){
                    elem.removeEventListener(type, bind._binds[i].fnc, false);
                } else {
                    elem.detachEvent('on'+type, bind._binds[i].fnc);
                }
                bind._binds.splice(i--, 1);
            }
        }
    }

    function bind(elem, type, func, pass){
        if (type.substr(0,5) !== 'touch'){ // A temporary fix for IE8 data passing problem in Jin.
            return $(elem).bind(type, pass, func);
        }
        var fnc, i;
        if (bind[type]){
            return bind[type].bind(elem, type, func, pass);
        }
        fnc = function(e){
            if (!e){ // Fix some ie bugs...
                e = window.event;
            }
            if (!e.stopPropagation){
                e.stopPropagation = function(){ this.cancelBubble = true; };
            }
            e.data = pass;
            func.call(elem, e);
        };
        if (document.addEventListener){
            elem.addEventListener(type, fnc, false);
        } else {
            elem.attachEvent('on' + type, fnc);
        }
        bind._binds.push({elem: elem, type: type, func: func, fnc: fnc});
    }

    function grab(elem, options)
    {
        var data = {
            move: {x: 0, y: 0},
            offset: {x: 0, y: 0},
            position: {x: 0, y: 0},
            start: {x: 0, y: 0},
            affects: document.documentElement,
            stopPropagation: false,
            preventDefault: true,
            touch: true // Implementation unfinished, and doesn't support multitouch
        };
        extend(data, options);
        data.element = elem;
        bind(elem, mousedown, mouseDown, data);
        if (data.touch){
            bind(elem, touchstart, touchStart, data);
        }
    }
    function ungrab(elem){
        unbind(elem, mousedown, mousedown);
    }
    function mouseDown(e){
        e.data.position.x = e.pageX;
        e.data.position.y = e.pageY;
        e.data.start.x = e.pageX;
        e.data.start.y = e.pageY;
        e.data.event = e;
        if (e.data.onstart && e.data.onstart.call(e.data.element, e.data)){
            return;
        }
        if (e.preventDefault && e.data.preventDefault){
            e.preventDefault();
        }
        if (e.stopPropagation && e.data.stopPropagation){
            e.stopPropagation();
        }
        bind(e.data.affects, mousemove, mouseMove, e.data);
        bind(e.data.affects, mouseup, mouseUp, e.data);
    }
    function mouseMove(e){
        if (e.preventDefault && e.data.preventDefault){
            e.preventDefault();
        }
        if (e.stopPropagation && e.data.preventDefault){
            e.stopPropagation();
        }
        e.data.move.x = e.pageX - e.data.position.x;
        e.data.move.y = e.pageY - e.data.position.y;
        e.data.position.x = e.pageX;
        e.data.position.y = e.pageY;
        e.data.offset.x = e.pageX - e.data.start.x;
        e.data.offset.y = e.pageY - e.data.start.y;
        e.data.event = e;
        if (e.data.onmove){
            e.data.onmove.call(e.data.element, e.data);
        }
    }
    function mouseUp(e){
        if (e.preventDefault && e.data.preventDefault){
            e.preventDefault();
        }
        if (e.stopPropagation && e.data.stopPropagation){
            e.stopPropagation();
        }
        unbind(e.data.affects, mousemove, mouseMove);
        unbind(e.data.affects, mouseup, mouseUp);
        e.data.event = e;
        if (e.data.onfinish){
            e.data.onfinish.call(e.data.element, e.data);
        }
    }
    function touchStart(e){
        e.data.position.x = e.touches[0].pageX;
        e.data.position.y = e.touches[0].pageY;
        e.data.start.x = e.touches[0].pageX;
        e.data.start.y = e.touches[0].pageY;
        e.data.event = e;
        if (e.data.onstart && e.data.onstart.call(e.data.element, e.data)){
            return;
        }
        if (e.preventDefault && e.data.preventDefault){
            e.preventDefault();
        }
        if (e.stopPropagation && e.data.stopPropagation){
            e.stopPropagation();
        }
        bind(e.data.affects, touchmove, touchMove, e.data);
        bind(e.data.affects, touchend, touchEnd, e.data);
    }
    function touchMove(e){
        if (e.preventDefault && e.data.preventDefault){
            e.preventDefault();
        }
        if (e.stopPropagation && e.data.stopPropagation){
            e.stopPropagation();
        }
        e.data.move.x = e.touches[0].pageX - e.data.position.x;
        e.data.move.y = e.touches[0].pageY - e.data.position.y;
        e.data.position.x = e.touches[0].pageX;
        e.data.position.y = e.touches[0].pageY;
        e.data.offset.x = e.touches[0].pageX - e.data.start.x;
        e.data.offset.y = e.touches[0].pageY - e.data.start.y;
        e.data.event = e;
        if (e.data.onmove){
            e.data.onmove.call(e.data.elem, e.data);
        }
    }
    function touchEnd(e){
        if (e.preventDefault && e.data.preventDefault){
            e.preventDefault();
        }
        if (e.stopPropagation && e.data.stopPropagation){
            e.stopPropagation();
        }
        unbind(e.data.affects, touchmove, touchMove);
        unbind(e.data.affects, touchend, touchEnd);
        e.data.event = e;
        if (e.data.onfinish){
            e.data.onfinish.call(e.data.element, e.data);
        }
    }

    bind._binds = [];

    $.fn.grab = function(a, b){
        return this.each(function(){
            return grab(this, a, b);
        });
    };
    $.fn.ungrab = function(a){
        return this.each(function(){
            return ungrab(this, a);
        });
    };
})(jQuery);
