(function($){

	// to track if the mouse button is pressed
	var isMouseDown    = false;

	// to track the current element being dragged
	var currentElement = null;

	// callback holders
	var dropCallbacks = {};
	var dragCallbacks = {};
	var startDragCallbacks = {};

	// global position records
	var lastMouseX;
	var lastMouseY;
	var lastElemTop;
	var lastElemLeft;
	
	var lastMarginLeft = 0;
	var currentMarginLeft = 0;
	
	// Bounce variables
	var allowBounce = false;
	var bounceWidth = 0;
	var bounceSpeed = 0;

	// returns the mouse (cursor) current position
	$.getMousePosition = function(e){
	
		var posx = 0;
		var posy = 0;

		if (!e) var e = window.event;

		if (e.pageX || e.pageY) {
			posx = e.pageX;
			posy = e.pageY;
		}
		else if (e.clientX || e.clientY) {
			posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
			posy = e.clientY + document.body.scrollTop  + document.documentElement.scrollTop;
		}

		return { 'x': posx, 'y': posy };
	}

	// updates the position of the current element being dragged
	$.updatePosition = function(e) {
	
		var pos = $.getMousePosition(e);
		var spanX = (pos.x - lastMouseX);
		var spanY = (pos.y - lastMouseY);
		
		if(allowBounce == true){
		
			var divWidth = $(currentElement).find('span').width();
		
			divWidth = divWidth - 2 * divWidth - bounceWidth  + $(window).width() ;
			lastMarginLeft = currentMarginLeft;
			currentMarginLeft = (lastElemLeft + spanX);

			if(currentMarginLeft < bounceWidth && currentMarginLeft > divWidth ){
				$(currentElement).css("marginLeft", currentMarginLeft);
			}
			
		}else{
			$(currentElement).css("marginLeft", currentMarginLeft);
		}
	}

	// when the mouse is moved while the mouse button is pressed
	$(document).mousemove(function(e){
		if(isMouseDown){
			// update the position and call the registered function
			$.updatePosition(e);
			if(dragCallbacks[currentElement.id] != undefined){
				dragCallbacks[currentElement.id](e);
			}

			return false;
		}
	});

	// when the mouse button is released
	$(document).mouseup(function(e){
		if(isMouseDown){
			
			isMouseDown = false;
			
			if(lastMarginLeft != currentMarginLeft) {
				if(dropCallbacks[currentElement.id] != undefined) {
					dropCallbacks[currentElement.id](e);
					
					if(allowBounce == true){
		
						var divWidth = $(currentElement).find('span').width();
						divWidth = divWidth - 2*divWidth  + $(window).width() ;

						//if(currentMarginLeft > bounceWidth ){
						if(currentMarginLeft > 0 ){
							$(currentElement).animate({ marginLeft: "0px" }, bounceSpeed );
						}
						if( currentMarginLeft < divWidth ){
							$(currentElement).animate({ marginLeft: divWidth }, bounceSpeed );
						}
						
					}
				}
			}

			return false;
		}
	});

	// register the function to be called while an element is being dragged
	$.fn.ondrag = function(callback){
		return this.each(function(){
			dragCallbacks[this.id] = callback;
		});
	}

	// register the function to be called when an element is dropped
	$.fn.ondrop = function(callback){
		return this.each(function(){
			dropCallbacks[this.id] = callback;
		});
	}
	
	$.fn.getDragDirection = function (){
		return lastMarginLeft > currentMarginLeft ? 1 : -1;
	}
	
	// set an element as draggable 
	// allowBubbling , allowBounce, BounceWidth,  BounceSpeed

	$.fn.easydrag = function(allowBubbling, get_allowBounce, get_bounceWidth,  get_bounceSpeed){

		return this.each(function(){

			// if no id is defined assign a unique one
			if(undefined == this.id) this.id = 'easydrag'+time();

			// change the mouse pointer
			$(this).css("cursor", "move");

			// set bounce variables
			allowBounce = get_allowBounce;
			bounceWidth = get_bounceWidth;
			bounceSpeed = get_bounceSpeed;
			
			// when an element receives a mouse press
			$(this).mousedown(function(e) {			
					
				// update track variables
				isMouseDown    = true;
				currentElement = this;

				// retrieve positioning properties
				var pos    = $.getMousePosition(e);
				lastMouseX = pos.x;
				lastMouseY = pos.y;

				lastElemTop  = this.offsetTop;
				lastElemLeft = this.offsetLeft;

				$.updatePosition(e);
				
				if(startDragCallbacks[currentElement.id] != undefined) {
					startDragCallbacks[currentElement.id](e);
				}

				return allowBubbling ? true : false;
			});
		});
	}

})(jQuery);
