/*
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);