/**
 *************************************************************************************
 * [标题：ExmayUI JQuery Draggalbe 插件]<br>
 *************************************************************************************
 * [描述：ExmayUI JQuery Draggalbe 插件]<br>
 *************************************************************************************
 * @author Exmay Team / 亿美团队
 *************************************************************************************
 * @version Version 1.0.1 Beta / v1.0.1 测试版
 *************************************************************************************
 */

/*
 * ***********************************************************************************
 * 版权：Copyright © 2012 Exmay Inc. All Rights Reserved. 长沙亿美软件有限公司　版权所有
 * ***********************************************************************************
 * 企业文化：专注　创新　分享　共赢
 * ***********************************************************************************
 * 官方网站：http://www.exmay.com
 * ***********************************************************************************
 * 官方邮箱：service@exmay.com
 * ***********************************************************************************
 */

(function($) {
	
	function exmaySetDragPosition(e) {
		var opts = $(e.data.target).data("exmayDraggable").options;
		var dragData = e.data;
		var left = dragData.startLeft + e.pageX - dragData.startX;
		var top = dragData.startTop + e.pageY - dragData.startY;
		if (opts.deltaX != null && opts.deltaX != undefined) {
			left = e.pageX + opts.deltaX;
		}
		if (opts.deltaY != null && opts.deltaY != undefined) {
			top = e.pageY + opts.deltaY;
		}
		if (e.data.parnet != document.body) {
			if ($.boxModel == true) {
				left += $(e.data.parent).scrollLeft();
				top += $(e.data.parent).scrollTop();
			}
		}
		if (opts.axis == "h") {
			dragData.left = left;
		} else {
			if (opts.axis == "v") {
				dragData.top = top;
			} else {
				dragData.left = left;
				dragData.top = top;
			}
		}
	};
	
	function exmayInitDragEvents(target) {
		var $target = $(target);
		var opts = $(target).data("exmayDraggable").options;
		$target.bind("mousedown.exmayDraggable", {
			target : target
		}, exmayOnMouseDown);
		$target.bind("mousemove.exmayDraggable", {
			target : this
		}, exmayOnMouseOver);
		function exmayOnMouseDown(e) {
			if (exmayIsHover(e) == false) {
				return;
			}
			var $this = $(e.data.target);
			var position = $this.position();
			var dragData = {
				startPosition : $this.css("position"),
				startLeft : position.left,
				startTop : position.top,
				left : position.left,
				top : position.top,
				startX : e.pageX,
				startY : e.pageY,
				target : e.data.target,
				parent : $this.parent()[0]
			};
			if (opts.onBeforeDrag.call(e.data.target, e) == false) {
				return;
			}
			$(document).bind("mousedown.exmayDraggable", dragData, exmayDragOnMouseDown);
			$(document).bind("mousemove.exmayDraggable", dragData, exmayDragOnMouseOver);
			$(document).bind("mouseup.exmayDraggable", dragData, exmayDragOnMouseUp);
		};
		
		function exmayOnMouseOver(e) {
			if (exmayIsHover(e)) {
				$(this).css("cursor", opts.cursor);
			} else {
				$(this).css("cursor", "default");
			}
		};
		
		function exmayIsHover(e) {
			var offset = $target.offset();
			var width = $target.outerWidth();
			var height = $target.outerHeight();
			var top = e.pageY - offset.top;
			var right = offset.left + width - e.pageX;
			var botttom = offset.top + height - e.pageY;
			var left = e.pageX - offset.left;
			return Math.min(top, right, botttom, left) > opts.edge;
		};
	};
	
	function exmayGetDragProxy(e) {
		var $this = $(e.data.target);
		var opts = $this.data("exmayDraggable").options;
		var $dragProxy = $this.data("exmayDraggable").proxy;
		if ($dragProxy) {
			$dragProxy.css("cursor", opts.cursor);
		} else {
			$dragProxy = $this;
			$this.data("exmayDraggable").handle.css("cursor", opts.cursor);
		}
		$dragProxy.css( {
			left : e.data.left,
			top : e.data.top
		});
	};
	
	function exmayDragOnMouseDown(e) {
		var $this = $(e.data.target);
		var opts = $this.data("exmayDraggable").options;
		var filterTarget = $(".exmayui-droppable").filter(function() {
			return e.data.target != this;
		}).filter(function() {
			var acceptTarget = $(this).data("exmayDroppable").options.acceptTarget;
			if (acceptTarget) {
				return $(acceptTarget).filter(function() {
					return this == e.data.target;
				}).length > 0;
			} else {
				return true;
			}
		});
		$this.data("exmayDraggable").droppables = filterTarget;
		var $dragProxy = $this.data("exmayDraggable").proxy;
		if (!$dragProxy) {
			if (opts.proxy) {
				if (opts.proxy == "clone") {
					$dragProxy = $this.clone().insertAfter(e.data.target);
				} else {
					$dragProxy = opts.proxy.call(e.data.target, e.data.target);
				}
				$this.data("exmayDraggable").proxy = $dragProxy;
			} else {
				$dragProxy = $this;
			}
		}
		$dragProxy.css("position", "absolute");
		exmaySetDragPosition(e);
		exmayGetDragProxy(e);
		opts.onStartDrag.call(e.data.target, e);
		return false;
	};
	
	function exmayDragOnMouseOver(e) {
		exmaySetDragPosition(e);
		var $this = $(e.data.target);
		if ($this.data("exmayDraggable").options.onDrag.call(e.data.target, e) != false) {
			exmayGetDragProxy(e);
		}
		var target = e.data.target;
		$this.data("exmayDraggable").droppables.each(function() {
			var $this = $(this);
			var offset = $(this).offset();
			if (e.pageX > offset.left && e.pageX < offset.left + $this.outerWidth() && e.pageY > offset.top && e.pageY < offset.top + $this.outerHeight()) {
				if (!this.entered) {
					$(this).trigger("_exmayDragenter", [ target ]);
					this.entered = true;
				}
				$(this).trigger("_exmayDragover", [ target ]);
			} else {
				if (this.entered) {
					$(this).trigger("_exmayDragleave", [ target ]);
					this.entered = false;
				}
			}
		});
		return false;
	}
	;
	function exmayDragOnMouseUp(e) {
		exmaySetDragPosition(e);
		var $this = $(e.data.target);
		var $dragProxy = $this.data("exmayDraggable").proxy;
		var opts = $this.data("exmayDraggable").options;
		if (opts.revert) {
			if (exmayIsDraging() == true) {
				exmayRemoveDragProxy();
				$this.css( {
					position : e.data.startPosition,
					left : e.data.startLeft,
					top : e.data.startTop
				});
			} else {
				if ($dragProxy) {
					$dragProxy.animate( {
						left : e.data.startLeft,
						top : e.data.startTop
					}, function() {
						exmayRemoveDragProxy();
					});
				} else {
					$this.animate( {
						left : e.data.startLeft,
						top : e.data.startTop
					}, function() {
						$this.css("position", e.data.startPosition);
					});
				}
			}
		} else {
			$this.css( {
				position : "absolute",
				left : e.data.left,
				top : e.data.top
			});
			exmayRemoveDragProxy();
			exmayIsDraging();
		}
		
		opts.onStopDrag.call(e.data.target, e);
		
		function exmayRemoveDragProxy() {
			if ($dragProxy) {
				$dragProxy.remove();
			}
			$(e.data.target).data("exmayDraggable").proxy = null;
		};
		
		function exmayIsDraging() {
			var flag = false;
			var $this = $(e.data.target);
			$this.data("exmayDraggable").droppables.each(function() {
				var $this = $(this);
				var offset = $(this).offset();
				if (e.pageX > offset.left && e.pageX < offset.left + $this.outerWidth() && e.pageY > offset.top && e.pageY < offset.top + $this.outerHeight()) {
					if (opts.revert) {
						$this.css( {
							position : e.data.startPosition,
							left : e.data.startLeft,
							top : e.data.startTop
						});
					}
					$(this).trigger("_drop", [ e.data.target ]);
					flag = true;
					this.entered = false;
				}
			});
			return flag;
		};
		
		$(document).unbind(".exmayDraggable");
		return false;
	};
	
	$.fn.exmayDraggable = function(options, data) {
		if (typeof options == "string") {
			return $.fn.exmayDraggable.methods[options](this, data);
		}
		return this.each(function() {
			var opts;
			var cache = $(this).data("exmayDraggable");
			if (cache) {
				cache.handle.unbind(".exmayDraggable");
				opts = $.extend(cache.options, options);
			} else {
				opts = $.extend( {}, $.fn.exmayDraggable.defaults, options || {});
			}
			if (opts.disabled == true) {
				$(this).css("cursor", "default");
				return;
			}
			var $this = null;
			if (typeof opts.handle == "undefined" || opts.handle == null) {
				$this = $(this);
			} else {
				$this = (typeof opts.handle == "string" ? $(opts.handle, this) : $this);
			}
			$(this).data("exmayDraggable", {
				options : opts,
				handle : $this
			});
			exmayInitDragEvents(this);
		});
	};
	
	$.fn.exmayDraggable.methods = {
		options : function(target) {
			return $(target).data("exmayDraggable").options;
		},
		proxy : function(target) {
			return $(target).data("exmayDraggable").proxy;
		},
		enable : function(target) {
			return $(target).each(function() {
				$(this).exmayDraggable( {
					disabled : false
				});
			});
		},
		disable : function(target) {
			return $(target).each(function() {
				$(this).exmayDraggable( {
					disabled : true
				});
			});
		}
	};
	
	$.fn.exmayDraggable.defaults = {
		proxy : null,
		revert : false,
		cursor : "move",
		deltaX : null,
		deltaY : null,
		handle : null,
		disabled : false,
		edge : 0,
		axis : null,
		onBeforeDrag : function(e) {
		},
		onStartDrag : function(e) {
		},
		onDrag : function(e) {
		},
		onStopDrag : function(e) {
		}
	};
})(jQuery);
