/**
Inicialização dos objetos com propriedades de movimentação
Ex: 
initDragObj(document.getElementById('name'), 
			{
				type				: 'simple' | 'position' | 'preview' | 'connection',
				dragRegion			: element,
				onDragStart			: function,
				onDrag				: function,
				onDragEnd			: function,
				onChangePosition	: function,
				onAnimateEnd		: function,
				moveOpacity			: number
			})
*/
function initDragObj(obj, config) {
	var v_drag = new DragObj()
	v_drag.initObj(obj, config);
}

/**
 * Objeto de controle das movimentações
 */
function DragObj(config) {
	this.config = (config)?config:{ type: 'simple' };
	this.enabled = true;
	if(!this.config.moveOpacity) {
		this.config.moveOpacity = 80;
	}
	if(!this.config.minDistance) 
		this.config.minDIstance = 100;
	if(this.config.positionPreviewObj)
		this.config.positionPreviewObj.style.display = 'none';
	this.v_div = null;
	this.returnInterval = null;
	this.movePreview = false;
	this.objArray = [];
	this.posArray = [];
	/**
	 * Insere um objeto estatico (objetos que nao podem ser
	 *							  movimentados, mas influem nos outros)
	 */
	this.addStaticObj = function(obj) {
		obj.isDragObj = true;
		this.objArray.push(obj);
	}	
	/**
	 * Inicializa as propriedades de movimentacao do objeto
	 */
	this.addObj = function(obj, dragRegion) {
		obj.dragObj = this;
		this.addStaticObj(obj);
		if (this.config.type != 'position') 
			obj.style.position = 'absolute';
		if(isNaN(parseInt(obj.style.left)))
			obj.style.left = "0px";
		if(isNaN(parseInt(obj.style.top)))
			obj.style.top  = "0px";
		if(!dragRegion && dragRegion == null)
			dragRegion = obj;
		obj.dragRegion = dragRegion;
		dragRegion.drag = obj;
		//chama o start da movimentacao no clique do mouse
		dragRegion.onmousedown = obj.dragObj.start;
		//Cria as funções para tratamento das etapas de movimentação
		obj.onDragStart = function(left,top) {
			//para as movimentações com posições fixas, cria o div de movimentação e reinicia o intervalo de ajuste
			if (this.dragObj.config.type == 'position' || this.dragObj.config.type == 'connection' || this.dragObj.config.type == 'preview') {
				this.dragObj.movePreview = true;
				clearInterval(this.dragObj.returnInterval);
				this.origNextSibling = this.nextSibling;
				this.dragObj.duplicateInDiv(this, 80,this.dragObj.config.movePreviewObj);
			}
			//marca o objeto como não movimentado ainda
			this.dragged	 = false;
		};
		obj.onDrag=function(left,top){
			//marca objeto como movido
			this.dragged=true;
		};
	}
	/**
	 * Gera novas posições
	 */
	this.addPosition = function (obj, maxElements) {
		if(obj == null) {
			alert("Não foi possivel criar a posição de DRAG: Objeto nulo fornecido ");
			return;
		}
		var vPositionEnd;
		switch(obj.tagName.toUpperCase()) {
			case 'TBODY':
			case 'TABLE':
			case 'TFOOT':
			case 'THEAD':
				vPositionEnd = document.createElement('tr');
				vPositionEnd.style.display = 'none';
				vPositionEnd.style.visibility = 'hidden';
				break;
			case 'TR':
			    vPositionEnd = document.createElement('TD');
				vPositionEnd.innerHTML = '';
				vPositionEnd.style.display = 'none';
				vPositionEnd.id = 'posicao_final_'
				break;
			default:
				vPositionEnd = document.createElement("div");
				vPositionEnd.id = 'posicao_final_';
//				vPositionEnd.innerHTML = 'teste';
				with(vPositionEnd) {
					style.height = '0px';
					style.width = '0px';
					style.fontSize = '0px';
					style.border = '0';	
					style.visibility = 'hidden';
//					style.display = 'none';
				}
				break;
		}
		
		obj.isDragPosition = true;
		obj.maxDragElements = maxElements;
		obj.appendChild(vPositionEnd);
		vPositionEnd.isDragEndPosition = true;
		this.addStaticObj(vPositionEnd);
		this.posArray.push(obj);
	}
	/**
	 * Duplica um objeto em um Div (utilizado nas movimentações com preview)
	 */
	this.duplicateInDiv = function(obj, opacity, objDup) {
		if(objDup == null) {
			if(!this.v_div){
				this.v_div = document.createElement("DIV");
				with(this.v_div.style) {
					display="none";
					position="absolute";
					cursor="move";
					paddingTop="3px";
				}
				document.body.appendChild(this.v_div);
			}
			this.v_div.style.left  			= this.posicaoObjeto(obj,true);
			this.v_div.style.top			= this.posicaoObjeto(obj,false);
			this.v_div.style.height			= obj.offsetHeight;
			this.v_div.style.width			= obj.offsetWidth;
			this.v_div.style.display 		= "block";
			this.v_div.style.opacity 		= this.config.moveOpacity/100;
			this.v_div.style.filter	 		= "alpha(opacity="+this.config.moveOpacity+")";
			this.v_div.innerHTML	 		= obj.innerHTML;
			if (obj.className == '') {
				this.v_div.className		= obj.parentNode.className;
			} else {
				this.v_div.className		= obj.className;
			}
			try {
				this.v_div.align				= obj.align;
			} catch(e) {}
			this.v_div.style.paddingTop   	= obj.style.paddingTop;
			this.v_div.style.paddingLeft   	= obj.style.paddingLeft;
			this.v_div.style.paddingRight  	= obj.style.paddingRight;
			this.v_div.style.paddingBottom 	= obj.style.paddingBottom;
			this.v_div.style.verticalAlign 	= obj.style.verticalAlign;
			this.v_div.style.backgroundColor = obj.style.backgroundColor;
			this.v_div.style.display 		= 'none';
			this.v_div.style.zIndex		= Number.MAX_VALUE;
		} else {
			this.v_div = objDup;
				with(this.v_div.style) {
					display="none";
					position="absolute";
					cursor="move";
				}
			this.v_div.style.display 		= 'none';
			this.v_div.style.zIndex		= Number.MAX_VALUE;
			this.v_div.style.display 		= "block";
			this.v_div.style.opacity 		= this.config.moveOpacity/100;
			this.v_div.style.filter	 		= "alpha(opacity="+this.config.moveOpacity+")";
			this.v_div.style.left  			= this.posicaoObjeto(obj,true);
			this.v_div.style.top			= this.posicaoObjeto(obj,false);
		}
	}
	/**
	 * 
	 */
	this.animateDiv = function (obj,aa,ab){
		var ac=parseInt(vDragObj.v_div.style.left);
		var ad=parseInt(vDragObj.v_div.style.top);
		var ae=(ac-this.posicaoObjeto(obj,true))/ab;
		var af=(ad-this.posicaoObjeto(obj,false))/ab;
		ap = setInterval( function(){
			if(ab<1){
				clearInterval(ap);
				if(vDragObj.config.onAnimateEnd)
					vDragObj.config.onAnimateEnd();
				vDragObj.v_div.style.display = 'none';
				return
			}
			vDragObj.v_div.style.display = '';
			ab--;
			ac-=ae;
			ad-=af;
			vDragObj.v_div.style.left=parseInt(ac)+"px";
			vDragObj.v_div.style.top=parseInt(ad)+"px";
		},aa/ab);
	}	
	/**
	 * Inicio da movimentação do objeto
	 */
	this.start = function(a){
		if(window.event && window.event.button && window.event.button != 1)
			return;
		if(!this.drag.dragObj.enabled) 
			return;
		var aa = this.drag.dragObj.obj = this.drag;
		//retorna o evento da janela
		a = this.drag.dragObj.fixE(a);
		var ab = parseInt(this.style.top);
		var ac = parseInt(this.style.left);
		//aparentemente nao utilizada
		aa.onDragStart(ac,ab,a.clientX,a.clientY);
		//grava as ultimas posições on o objeto se encontrava
		aa = ((this.drag.dragObj.movePreview)?this.drag.dragObj.v_div:this.drag.dragObj.obj);
		aa.lastMouseX = a.clientX;
		aa.lastMouseY = a.clientY;
		aa.lastCursor = aa.style.cursor;
		//seta as funções de tratamento de movimentação e termino
		vDragObj = this.drag.dragObj;
		document.onmousemove = this.drag.dragObj.drag;
		document.onmouseup   = this.drag.dragObj.end;
		if (this.drag.dragObj.config.onDragStart)
			this.drag.dragObj.config.onDragStart(vDragObj.obj);
		return false;
	};
	/**
	 * Calcula o movimento efetuado pelo mouse para a movmentacao do objeto
	 */
	this.drag = function(a){
		//retorna o evento da janela
		a = vDragObj.fixE(a);
		if(vDragObj.movePreview) {
			vDragObj.v_div.style.display = '';
		}
		var aa = (vDragObj.movePreview)?vDragObj.v_div:vDragObj.obj;
		aa.style.cursor = 'move';
		var af,ag;
		f_get_scroll();
		if(isNaN(Number(aa.lastScrOfY))) {
			aa.lastScrOfY = scrOfY;
			aa.lastScrOfX = scrOfX;
		}
		af = parseInt(aa.style.left) + a.clientX - aa.lastMouseX - Number(aa.lastScrOfX);
		ag = parseInt(aa.style.top) + a.clientY - aa.lastMouseY - Number(aa.lastScrOfY);
		aa.style.left = (af  + scrOfX) + "px";
		aa.style.top  = (ag + scrOfY) + "px";
		aa.lastScrOfX = scrOfX;
		aa.lastScrOfY = scrOfY;
		aa.lastMouseX = a.clientX;
		aa.lastMouseY = a.clientY;
		if(vDragObj.config.type == 'position') {
			if(vDragObj.config.movePreviewObj != null) {
				aa.style.top = a.clientY + scrOfY - 5;
				aa.style.left = a.clientX + scrOfX - 5;
				ag = a.clientY + scrOfY - 5;
				af = a.clientX + scrOfX - 5
			}
			var insAntes = vDragObj.posicaoProxima(vDragObj.obj,af,ag);
			if(insAntes && insAntes != null && vDragObj.obj != insAntes && insAntes.id != '' ) {
				vDragObj.obj.style.position = '';
				if(vDragObj.config.beforeChangePosition)
					if(!vDragObj.config.beforeChangePosition(vDragObj.obj, insAntes)) {
						vDragObj.obj.parentNode.insertBefore(vDragObj.config.positionPreviewObj,vDragObj.obj);
						return false;
					}
				if(vDragObj.config.positionPreviewObj) {
					insAntes.parentNode.insertBefore(vDragObj.config.positionPreviewObj,insAntes);
					vDragObj.config.positionPreviewObj.style.display = '';
				} else {
					insAntes.parentNode.insertBefore(vDragObj.obj,insAntes);
				}
				if(vDragObj.config.onChangePosition)
					vDragObj.config.onChangePosition(vDragObj.obj, insAntes);
			}
		}
		if(vDragObj.config.type == 'connection' || vDragObj.config.type == 'position') {
			vDragObj.overObj = vDragObj.overObject(vDragObj.obj,a.clientX,a.clientY);
		}
		if(vDragObj.config.onDrag) {
			vDragObj.config.onDrag(vDragObj.obj, aa);
		}
		return false;
	};
	/**
	 * Finaliza a movimentacao do objeto
	 */
	this.end = function(){
		//retira as funções de controle de movimentacao
		document.onmousemove = null;
		document.onmouseup   = null;
		var aa = (vDragObj.movePreview)?vDragObj.v_div:vDragObj.obj;
		aa.style.cursor = aa.lastCursor;
		if(vDragObj.movePreview) {
		}
		if(vDragObj.config.type == 'preview') {
			vDragObj.v_div.style.display = 'none';
			vDragObj.obj.style.left = vDragObj.v_div.style.left;
			vDragObj.obj.style.top = vDragObj.v_div.style.top
		}
		if(vDragObj.config.type == 'position') {
			if(vDragObj.config.positionPreviewObj) {
				vDragObj.config.positionPreviewObj.parentNode.insertBefore(vDragObj.obj,vDragObj.config.positionPreviewObj);
				vDragObj.config.positionPreviewObj.style.display = 'none';
			}
			vDragObj.v_div.style.display = 'none';
			vDragObj.animateDiv(vDragObj.obj,150,15);
		}	
		if(vDragObj.config.type != 'connection') {
			if(vDragObj.config.onDragEnd)
				vDragObj.config.onDragEnd(vDragObj.obj);
		} else {			
			vDragObj.v_div.style.display = 'none';
			if(vDragObj.overObj != null)
				if(vDragObj.config.onEndOverObj)
					vDragObj.config.onEndOverObj(vDragObj.obj, vDragObj.overObj);
			vDragObj.overObj = null;
		}
	};
	/**
	 * Captura o evento da janela
	 */
	this.fixE = function(a){
		if(typeof a=="undefined")
			a=window.event;
		if(typeof a.layerX=="undefined")
			a.layerX=a.offsetX;
		if(typeof a.layerY=="undefined")
			a.layerY=a.offsetY;
		return a;
	};	
	/**
	 * Calcula qual das posicoes encontra-se mais proxima do div de movimentacao 
	 *   retornando o objeto antes do qual deve ser inserido 
	 */
	this.posicaoProxima = function(obj,left,top){
		var objeto = null;
		var minDistance = this.config.minDistance; 
		for(var i=0;i<this.objArray.length;i++) {
			var posicao = this.objArray[i];
			if(posicao == obj)
				continue;
			var distance = Math.sqrt(Math.pow(left-this.posicaoObjeto(posicao,true),2)+Math.pow(top-this.posicaoObjeto(posicao,false),2));
			if(isNaN(distance))
				continue;
			if(distance < minDistance && posicao.parentNode && posicao.parentNode.isDragPosition ){
				if(posicao.parentNode != obj.parentNode && posicao.parentNode.maxDragElements) {
					var dragObjs = 0;
					for(var j=0;j<posicao.parentNode.childNodes.length;j++) {
						if( posicao.parentNode.childNodes[j].isDragObj && !posicao.parentNode.childNodes[j].isDragEndPosition) {
							dragObjs++;
						}
					}
					if(dragObjs >= posicao.parentNode.maxDragElements) 
						continue;
				}
				minDistance = distance;
				objeto 		= posicao;
			}
		}
		if(objeto != null && obj.nextSibling != objeto) {
			return objeto;
		} else {
			return null;
		}
	}	
	/**
	 * Calcula se o mouse encontra-se sobre outro objeto
	 */
	this.overObject = function(obj,left,top){
		var objeto = null;
		for(var i=0;i<this.objArray.length;i++) {
			var posicao = this.objArray[i];
			if(posicao == obj)
				continue;
			if(left < this.posicaoObjeto(posicao,true) || left > this.posicaoObjeto(posicao,true)+posicao.offsetWidth)
				continue;
			if(top < this.posicaoObjeto(posicao,false) || top > this.posicaoObjeto(posicao,false)+posicao.offsetHeight)
				continue;
			return posicao;
		}
		return null;
	}	
	/**
	 * Retorna a posicao atual do objeto 
	 */
	this.posicaoObjeto = function(obj,left){
		var total=0;
		while(obj!=null){
			total += obj["offset"+(left?"Left":"Top")];
			try {
				obj=obj.offsetParent;
			} catch(e) { 
				obj=obj.parentNode;
			}
		}
		return total;
	}	
}
