/**
 * draggable - Class allows to make any element draggable
 * 
 * Written by
 * Egor Khmelev (hmelyoff@gmail.com)
 *
 * Licensed under the MIT (MIT-LICENSE.txt).
 *
 * @author Egor Khmelev
 * @version 0.1.0-BETA ($Id$)
 * 
 **/

(function( $ ){

  function Draggable(){
  	this._init.apply( this, arguments );
  };

	Draggable.prototype.oninit = function(){
	  
	};
	
	Draggable.prototype.events = function(){
	  
	};
	
	Draggable.prototype.onmousedown = function(){
		this.ptr.css({ position: "absolute" });
	};
	
	Draggable.prototype.onmousemove = function( evt, x, y ){
		this.ptr.css({ left: x, top: y });
	};
	
	Draggable.prototype.onmouseup = function(){
	  
	};

	Draggable.prototype.isDefault = {
		drag: false,
		clicked: false,
		toclick: true,
		mouseup: false
	};

	Draggable.prototype._init = function(){
		if( arguments.length > 0 ){
			this.ptr = $(arguments[0]);
			this.outer = $(".draggable-outer");

			this.is = {};
			$.extend( this.is, this.isDefault );

			var _offset = this.ptr.offset();
			this.d = {
				left: _offset.left,
				top: _offset.top,
				width: this.ptr.width(),
				height: this.ptr.height()
			};

			this.oninit.apply( this, arguments );

			this._events();
		}
	};
	
	Draggable.prototype._getPageCoords = function( event ){
	  if( event.targetTouches && event.targetTouches[0] ){
	    return { x: event.targetTouches[0].pageX, y: event.targetTouches[0].pageY };
	  } else
	    return { x: event.pageX, y: event.pageY };
	};
	
	Draggable.prototype._bindEvent = function( ptr, eventType, handler ){
	  var self = this;

	  if( this.supportTouches_ )
      ptr.get(0).addEventListener( this.events_[ eventType ], handler, false );
	  
	  else
	    ptr.bind( this.events_[ eventType ], handler );
	};
	
	Draggable.prototype._events = function(){
		var self = this;

    this.supportTouches_ = 'ontouchend' in document;
    this.events_ = {
      "click": this.supportTouches_ ? "touchstart" : "click",
      "down": this.supportTouches_ ? "touchstart" : "mousedown",
      "move": this.supportTouches_ ? "touchmove" : "mousemove",
      "up"  : this.supportTouches_ ? "touchend" : "mouseup"
    };

    this._bindEvent( $( document ), "move", function( event ){
			if( self.is.drag ){
        event.stopPropagation();
        event.preventDefault();
				self._mousemove( event );
			}
		});
    this._bindEvent( $( document ), "down", function( event ){
			if( self.is.drag ){
        event.stopPropagation();
        event.preventDefault();
			}
		});
    this._bindEvent( $( document ), "up", function( event ){
			self._mouseup( event );
		});
		
    this._bindEvent( this.ptr, "down", function( event ){
			self._mousedown( event );
			return false;
		});
    this._bindEvent( this.ptr, "up", function( event ){
			self._mouseup( event );
		});
		
		this.ptr.find("a")
			.click(function(){
				self.is.clicked = true;

				if( !self.is.toclick ){
					self.is.toclick = true;
					return false;
				}
			})
			.mousedown(function( event ){
				self._mousedown( event );
				return false;
			});

		this.events();
	};
	
	Draggable.prototype._mousedown = function( evt ){
		this.is.drag = true;
		this.is.clicked = false;
		this.is.mouseup = false;

		var _offset = this.ptr.offset();
		var coords = this._getPageCoords( evt );
		this.cx = coords.x - _offset.left;
		this.cy = coords.y - _offset.top;

		$.extend(this.d, {
			left: _offset.left,
			top: _offset.top,
			width: this.ptr.width(),
			height: this.ptr.height()
		});

		if( this.outer && this.outer.get(0) ){
			this.outer.css({ height: Math.max(this.outer.height(), $(document.body).height()), overflow: "hidden" });
		}

		this.onmousedown( evt );
	};
	
	Draggable.prototype._mousemove = function( evt ){
		this.is.toclick = false;
		var coords = this._getPageCoords( evt );
		this.onmousemove( evt, coords.x - this.cx, coords.y - this.cy );
	};
	
	Draggable.prototype._mouseup = function( evt ){
		var oThis = this;

		if( this.is.drag ){
			this.is.drag = false;

			if( this.outer && this.outer.get(0) ){

				if( $.browser.mozilla ){
					this.outer.css({ overflow: "hidden" });
				} else {
					this.outer.css({ overflow: "visible" });
				}

        if( $.browser.msie && $.browser.version == '6.0' ){
         this.outer.css({ height: "100%" });
        } else {
         this.outer.css({ height: "auto" });
        }  
			}

			this.onmouseup( evt );
		}
	};
	
	window.Draggable = Draggable;

})( jQuery );
