jQuery.cDrag = {
	dropZones : {},
	dropCount : 0,
	helper : null,
	prot : false,
	dragVars : {},
	o : {},
	dragged: null,

	build : function (o) {
		if (!o.containers || !o.moveable) {
			return;
		}

		jQuery.cDrag.o = o;

		if (!jQuery.cDrag.helper) {
			jQuery('body',document).append('<div id="dragHelper"></div>');
			jQuery.cDrag.helper = jQuery('#dragHelper');
			var el = jQuery.cDrag.helper.get(0);
			var els = el.style;
			els.position = 'absolute';
			els.display = 'none';
			els.cursor = 'move';
			els.listStyle = 'none';
			els.overflow = 'hidden';
			if (window.ActiveXObject) {
				el.unselectable = "on";
			} else {
				els.mozUserSelect = 'none';
				els.userSelect = 'none';
				els.KhtmlUserSelect = 'none';
			}
		}


		$(o.containers).each(
			function() {
				if (this.isDroppable == true || !this.id) {
					return;
				}

				this.isDroppable = true;

				jQuery.cDrag.dropZones[this.id] = jQuery(this);
				jQuery.cDrag.dropCount++;


				jQuery(o.moveable).each(function() {
					jQuery.cDrag.buildMoves(this);
				});
			}
		);
	},
	
	buildMoves : function(elm) {
		if (elm.isDraggable) return;

		if (window.ActiveXObject) {
			elm.onselectstart = function(){return false;};
			elm.ondragstart = function(){return false;};
		}

		var dhe = jQuery.cDrag.o.handle ? jQuery(elm).find(jQuery.cDrag.o.handle) : jQuery(elm);

		if (jQuery.browser.msie) {
			dhe.each(
				function()
				{
					elm.unselectable = "on";
				}
			);
		} else {
			dhe.css('-moz-user-select', 'none');
			dhe.css('user-select', 'none');
			dhe.css('-khtml-user-select', 'none');
		}

		elm.isDraggable = true;
		elm.handleElem = dhe;

		dhe.each(
			function(){
				this.dragElem = elm;
			}
		);

		dhe.bind('mousedown', jQuery.cDrag.dragInit);

	},
	
	dragInit : function(e) {
		e.preventDefault();
		if (jQuery.cDrag.dragged != null) {
			if (jQuery.cDrag.dragVars.init) {
				jQuery.cDrag.dragStop(e);
			}
			jQuery.cDrag.dragged = null;
			return true;
		}
		if (jQuery.cDrag.prot) return true;

		var elm = this.dragElem;
		this.style.cursor = 'move';
		jQuery.cDrag.dragged = elm;

		jQuery(document)
			.bind('mousemove', jQuery.cDrag.dragMove)
			.bind('mouseup', jQuery.cDrag.dragStop);

		jQuery.cDrag.dragVars.pointer = jQuery.iUtil.getPointer(e);
		jQuery.cDrag.dragVars.currentPointer = jQuery.cDrag.dragVars.pointer;
		jQuery.cDrag.dragVars.init = false;

		return true;	
	},
	
	dragStart : function(e) {
		jQuery.cDrag.dragVars.init = true;

		var elm = jQuery.cDrag.dragged;
		var dEs = elm.style;

		jQuery.cDrag.dragVars.dragPos = $(elm).nextAll(jQuery.cDrag.o.moveable).get(0);

		jQuery.cDrag.dragVars.oD = jQuery.css(elm, 'display');
		jQuery.cDrag.dragVars.oP = jQuery.css(elm, 'position');

		if (!jQuery.cDrag.dragVars.initialPosition)
			jQuery.cDrag.dragVars.initialPosition = jQuery.cDrag.dragVars.oP;

		jQuery.cDrag.dragVars.oR = {
			x : parseInt(jQuery.css(elm,'left')) || 0,
			y : parseInt(jQuery.css(elm,'top')) || 0
		};

		jQuery.cDrag.dragVars.borderX = 0;
		jQuery.cDrag.dragVars.borderY = 0;
		if (jQuery.browser.msie) {
			var oldBorder = jQuery.iUtil.getBorder(elm, true);
			jQuery.cDrag.dragVars.borderX = oldBorder.l||0;
			jQuery.cDrag.dragVars.borderY = oldBorder.t||0;
		}

		jQuery.cDrag.dragVars.oC = jQuery.extend(
			jQuery.iUtil.getPosition(elm),
			jQuery.iUtil.getSize(elm)
		);

		if (jQuery.cDrag.dragVars.oP != 'relative' && jQuery.cDrag.dragVars.oP != 'absolute') {
			dEs.position = 'relative';
		}

		jQuery.cDrag.helper.empty();

		var clonedEl = elm.cloneNode(true);

		jQuery(clonedEl).css(
			{
				display:	'block',
				left:		'0px',
				top: 		'0px'
			}
		);
		clonedEl.style.marginTop = '0';
		clonedEl.style.marginRight = '0';
		clonedEl.style.marginBottom = '0';
		clonedEl.style.marginLeft = '0';

		jQuery(clonedEl).css('opacity', 0.66);
		if (window.ActiveXObject) {
			jQuery(clonedEl).css('filter', 'alpha(opacity=66)');
		}

		jQuery.cDrag.helper.append(clonedEl);

		var dhs = jQuery.cDrag.helper.get(0).style;

		dhs.height = jQuery.cDrag.dragVars.oC.hb + 'px';
		dhs.width = jQuery.cDrag.dragVars.oC.wb + 'px';

		dhs.display = 'block';
		dhs.marginTop = '0px';
		dhs.marginRight = '0px';
		dhs.marginBottom = '0px';
		dhs.marginLeft = '0px';

//remeasure the clone to check if the size was changed by user's functions
		jQuery.extend(
			jQuery.cDrag.dragVars.oC,
			jQuery.iUtil.getSize(clonedEl)
		);

		jQuery.cDrag.dragVars.nx = jQuery.cDrag.dragVars.oR.x;
		jQuery.cDrag.dragVars.ny = jQuery.cDrag.dragVars.oR.y;

		dhs.left = jQuery.cDrag.dragVars.oC.x - jQuery.cDrag.dragVars.borderX + 'px';
		dhs.top = jQuery.cDrag.dragVars.oC.y - jQuery.cDrag.dragVars.borderY + 'px';

//resize the helper to fit the clone
		dhs.width = jQuery.cDrag.dragVars.oC.wb + 'px';
		dhs.height = jQuery.cDrag.dragVars.oC.hb + 'px';

		jQuery.cDrag.dragVars.prot = false;

		if (jQuery.cDrag.dragVars.zIndex != false) {
			jQuery.cDrag.helper.css('zIndex', jQuery.cDrag.dragVars.zIndex);
		}

		$(jQuery.cDrag.dragged).hide();
		for (i in jQuery.cDrag.dropZones) {
			if (jQuery.cDrag.dropZones[i] == null) {
				continue;
			}

			var dropEl = jQuery.cDrag.dropZones[i].get(0);

			dropEl.p = jQuery.extend(
							jQuery.iUtil.getPositionLite(dropEl),
							jQuery.iUtil.getSizeLite(dropEl)
						);
			dropEl.elems = $(jQuery.cDrag.o.moveable, dropEl);
			dropEl.elems.each(
				function () {
					this.pos = jQuery.extend(
						jQuery.iUtil.getSizeLite(this),
						jQuery.iUtil.getPositionLite(this)
					);
				}
			);
		}
		$(jQuery.cDrag.dragged).show();

		dEs.visibility = 'hidden';

		var interval = 100;
		if ($.browser.msie && $.browser.version < 7) {
			interval = 200;
		}

		var windowWidth = 0;
		
		if (window.innerWidth) windowWidth = window.innerWidth;
		else if (document.documentElement.clientWidth) windowWidth = document.documentElement.clientWidth;
		else if (document.body.clientWidth) windowWidth = document.body.clientWidth;

		windowWidth -= 16;

		if (windowWidth > 0) jQuery.cDrag.dragVars.maxOffset = windowWidth - jQuery.cDrag.dragVars.oC.wb;

		$(jQuery.cDrag.helper).everyTime(interval, 'hoverCheck', jQuery.cDrag.checkhover, 0, true);

		return false;
	},
	
	moved : function() {
		var cp = jQuery.cDrag.dragVars.currentPointer;
		var p = jQuery.cDrag.dragVars.pointer;

		var dx = cp.x - p.x;
		if (dx > 5 || dx < -5) return true;
		var dy = cp.x - p.x;
		if (dy > 5 || dy < -5) return true;
		return false;
	},

	dragMove : function(e) {
		if (jQuery.cDrag.dragged == null) {
			return false;
		}

		var dragged = jQuery.cDrag.dragged;

		jQuery.cDrag.dragVars.currentPointer = jQuery.iUtil.getPointer(e);
		if (!jQuery.cDrag.dragVars.init) {
			if (jQuery.cDrag.moved()) {
				jQuery.cDrag.dragStart(e);
			} else {
				return false;
			}
		}

		jQuery.cDrag.dragVars.move = true;
		
		var dx = jQuery.cDrag.dragVars.currentPointer.x - jQuery.cDrag.dragVars.pointer.x;
		var dy = jQuery.cDrag.dragVars.currentPointer.y - jQuery.cDrag.dragVars.pointer.y;

		jQuery.cDrag.dragVars.nx = jQuery.cDrag.dragVars.oC.x + dx - jQuery.cDrag.dragVars.borderX;
		jQuery.cDrag.dragVars.ny = jQuery.cDrag.dragVars.oC.y + dy - jQuery.cDrag.dragVars.borderY;

		if (jQuery.cDrag.dragVars.nx < 0) jQuery.cDrag.dragVars.nx = 0;
		else if (jQuery.cDrag.dragVars.maxOffset && jQuery.cDrag.dragVars.nx > jQuery.cDrag.dragVars.maxOffset) jQuery.cDrag.dragVars.nx = jQuery.cDrag.dragVars.maxOffset;
		if (jQuery.cDrag.dragVars.ny < 0) jQuery.cDrag.dragVars.ny = 0;

		jQuery.cDrag.helper.get(0).style.left = jQuery.cDrag.dragVars.nx + 'px';
		jQuery.cDrag.helper.get(0).style.top = jQuery.cDrag.dragVars.ny + 'px';
		
		return false;
	},
	
	dragStop : function(e) {
		e.preventDefault();
		$(jQuery.cDrag.helper).stopTime('hoverCheck');

		jQuery(document)
			.unbind('mousemove', jQuery.cDrag.dragmove)
			.unbind('mouseup', jQuery.cDrag.dragstop);
	

		if (jQuery.cDrag.dragged == null) {
			return true;
		}

		if (jQuery.cDrag.dragVars.init) {
			jQuery.cDrag.checkhover();
		}

		var dragged = jQuery.cDrag.dragged;

		dragged.handleElem.css('cursor', 'pointer');

		jQuery.cDrag.dragged = null;

		if (jQuery.cDrag.dragVars.init == false) {
			return true;
		}

		var dEs = dragged.style;

		if (jQuery.cDrag.o.fx > 0) {
			jQuery.cDrag.prot = true;

			var dh = jQuery.iUtil.getPosition(dragged);

			jQuery.cDrag.helper.animate(
				{
					left : dh ? dh.x : jQuery.cDrag.dragVars.oC.x,
					top : dh ? dh.y : jQuery.cDrag.dragVars.oC.y
				},
				jQuery.cDrag.o.fx,
				function()
				{
					jQuery.cDrag.hidehelper(dragged);
					jQuery.cDrag.prot = false;
					if (jQuery.cDrag.o.onComplete) {
						jQuery.cDrag.o.onComplete(dragged);
					}
					dEs.visibility = 'visible';
				}
			);
		} else {
			jQuery.cDrag.hidehelper(dragged);
			if (jQuery.cDrag.o.onComplete) {
				jQuery.cDrag.o.onComplete(dragged);
			}
			dEs.visibility = 'visible';
		}

		jQuery.cDrag.checkEnd(dragged);


		return true;
	},
	
	checkhover : function() {
// Check horizontally...
		var dragCfg = jQuery.cDrag.dragVars;

		if (!dragCfg.move) return;
		dragCfg.move = false;

		var bestFit = null;
		var bestFitW = 0;

		for (i in jQuery.cDrag.dropZones) {
			if (jQuery.cDrag.dropZones[i] == null) {
				continue;
			}

			var dropEl = jQuery.cDrag.dropZones[i].get(0);

			var fit = 0;

			if (dragCfg.nx > dropEl.p.x) {
				fit = dropEl.p.x + dropEl.p.wb - dragCfg.nx;
			} else {
				fit = dragCfg.nx + dragCfg.oC.w - dropEl.p.x;
			}
			if (!bestFit || fit > bestFitW) {
				bestFit = dropEl;
				bestFitW = fit;
			}
		}

		if (!bestFit) {
			return;
		}
		
		var movableEl = bestFit.elems;

		var count = movableEl.size();
		var cur = null;
		while (--count >= 0) {
			var elm = movableEl.get(count);
			if (elm.style.display == 'none') continue;

			if (elm == jQuery.cDrag.dragged) {
				continue;
			}
			if ((elm.pos.y + elm.pos.hb / 2)  > dragCfg.ny) {
				cur = elm;
			} else {
				break;
			}
		}

		if (cur) {
			if (jQuery.cDrag.dragPos != cur) {
				jQuery.cDrag.dragPos = cur;
				jQuery(cur).before(jQuery.cDrag.dragged);
			}
		} else {
			if (jQuery.cDrag.dragPos != null || jQuery.cDrag.helper.get(0).parentNode != bestFit) {
				jQuery.cDrag.dragPos = null;
				jQuery(bestFit).append(jQuery.cDrag.dragged);
			}
		}
	},
	
	checkEnd : function() {
		var dragCfg = jQuery.cDrag.dragVars;
		if (jQuery.cDrag.o.onChange && (dragCfg.nRx != dragCfg.oR.x || dragCfg.nRy != dragCfg.oR.y)) {
			var ser = jQuery.cDrag.serialize();
			jQuery.cDrag.o.onChange(ser);
		}
	},
	
	serialize : function() {
		var ser = {};
		for (i in jQuery.cDrag.dropZones) {
			if (jQuery.cDrag.dropZones[i] == null) {
				continue;
			}
			var dropZone = jQuery.cDrag.dropZones[i];
			ser[i] = [];
			var els = $(jQuery.cDrag.o.moveable, dropZone);

			els.each(
				function () {
					ser[i].push(this.id);
				}
			);
		}
		return ser;
	},

	hidehelper : function(dragged) {
		jQuery.cDrag.helper.empty().hide();
		dragged.handleElem.bind('mousedown', jQuery.cDrag.dragInit);
	}
};
