/*
Copyright (c) 2009, www.redips.net  All rights reserved.
Code licensed under the BSD License: http://www.redips.net/license/

http://www.redips.net/javascript/drag-and-drop-table-content/
version 1.4.2
Sep 01, 2009.
*/

// parameters that can be changed
var hover_color = '#D2E3FF';//'#E1EBFB';//'#E7AB83';//'#E1FFEA' ;// hover color
var bound       = 25;			// bound width for autoscroll
var speed       = 20;			// scroll speed in milliseconds
var forbid      = 'forbid';		// cell class name where draggable element can not be dropped
var trash       = 'trash';		// cell class name where draggable element will be destroyed
var trash_ask   = false;		// confirm object deletion (ask a question "Are you sure?" before delete)
var pref_etiqueta = 'Eid_'		// Prefijo del id de la etiqueta clickeada, en DIV (id del div) interno al TD
var no_move		= 'no_move';	/* S.R.O. para evitar que la etiqueta se pueda mover, excepto a la papelera añadir la clase no_move al td que deseamos que contenga dicha etiqueta (Tiene que ser drop_option = 'etiqueta')*/
var receptor	= 'receptor_etiqueta';	/* S.R.O. clase del div interno del td para contener las etiquetas(Tiene que ser drop_option = 'etiqueta')*/
var drop_option = 'etiqueta';	/* drop_option has three options: multiple, single and switch y etiqueta (S.R.O)
								 Añadido por Salvador Ramos Ortega;
	Con drop_option == 'etiqueta' no permite clonar en la misma celda, el td contenedor del <div class='clone'>, tiene que ser de la clase 'clone'' (entre otras de usuario) y se activa la opción no_move */

// other parameters
var obj = false;                    // draggable object
var obj_margin;            			// space from clicked point to the object bounds (top, right, bottom, left)
var mouseButton = 0;				// if mouseButton == 1 then first mouse button is pressed
var mouseX, mouseY;    			    // mouse coordinates (used in onmousedown, onmousemove and autoscroll)
var window_width= 0, window_height=0;  // window width and height (parameters are set in onload and onresize event handler)
var scroll_width, scroll_height;       // scroll width and height of the window (it is usually greater then window)
var edgeX=0, edgeY=0;                  // autoscroll bound values (closer to the page edge, faster scroll) calculated in onmousemove handler
var bgcolor_old; 					   // old cell background color
var bgcolor_old_tr; 				   // anterior TR background color

var tables;                            // table offsets and row offsets (initialized in onload event)
var autoscrollX_flag=autoscrollY_flag=0;// needed to prevent multiple calls of autoscrollX and autoscrollY from onmousemove event handler
var moved_flag = 0;

// selected, previous and started table, row and cell
var table = table_old = table_source = null;
var row   = row_old   = row_source   = null;
var cell  = cell_old  = cell_source  = null;
var gemail_id = getiqueta_id =  uid = null; //S.R.O. Para guardar el id del Gemail (como clase en el TD Gid_nº si tiene o Gid_ ), el de Getiqueta (como id en el DIV interno Eid_nº) y el uid del email (clase en el TD Euid_nº)
//
// EVENTOS
//

// onLoad event
//window.onload = function (){
windowonload = function (){
//	function windowonload(){
	// collect tables inside div with id=drag
	tables = document.getElementById('drag').getElementsByTagName('table');
	// set initial window width/height, scroll width/height and define onresize event handler
	// onresize event handler calls calculate columns
	
/*
//SALVA PRUEBA	
	for (var i=0; i<tables.length; i++) 
		alert(tables[i].id) 
*/		
		
	handler_onresize();
	window.onresize = handler_onresize;
	// collect div elements inside tables (draggable elements)
	var divs = document.getElementById('drag').getElementsByTagName('div');
	// attach onmousedown event handler only to DIV elements that have "drag" in class name
	// allow other div elements inside <div id="drag" ...
	for (var i=0; i<divs.length; i++) 
		if (divs[i].className.indexOf('drag') > -1) 
			divs[i].onmousedown = handler_onmousedown;

	// dissable text selection for IE (but not for the form elements)
	document.onselectstart = function(e) {var evt = e || window.event; if (!isFormElement(evt)) return false}
	// attach onscroll event (needed for recalculating table cells positions)
	window.onscroll = calculate_cells;
}

//SALVA PRUEBA	
function windowonload(){
	// collect tables inside div with id=drag
	tables = document.getElementById('drag').getElementsByTagName('table');
	// set initial window width/height, scroll width/height and define onresize event handler
	// onresize event handler calls calculate columns
	
/*
//SALVA PRUEBA	
	for (var i=0; i<tables.length; i++) 
		alert(tables[i].id) 
*/		
		
	handler_onresize();
	window.onresize = handler_onresize;
	// collect div elements inside tables (draggable elements)
	var divs = document.getElementById('drag').getElementsByTagName('div');
	// attach onmousedown event handler only to DIV elements that have "drag" in class name
	// allow other div elements inside <div id="drag" ...
	for (var i=0; i<divs.length; i++) 
		if (divs[i].className.indexOf('drag') > -1) 
			divs[i].onmousedown = handler_onmousedown;

	// dissable text selection for IE (but not for the form elements)
	document.onselectstart = function(e) {var evt = e || window.event; if (!isFormElement(evt)) return false}
	// attach onscroll event (needed for recalculating table cells positions)
	window.onscroll = calculate_cells;
}




// onresize window event handler
// this event handler sets window_width and window_height variables used in onmousemove handler
function handler_onresize(){
	// Non-IE
  if (typeof(window.innerWidth) == 'number'){
    window_width  = window.innerWidth;
    window_height = window.innerHeight;
  }
  // IE 6+ in 'standards compliant mode'
  else if (document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)){
    window_width  = document.documentElement.clientWidth;
    window_height = document.documentElement.clientHeight;
  }
  // IE 4 compatible
  else if (document.body && (document.body.clientWidth || document.body.clientHeight)){
    window_width  = document.body.clientWidth;
    window_height = document.body.clientHeight;
  }
  // set scroll size (onresize, onload and onmouseup event)
	scroll_width  = document.documentElement.scrollWidth;
	scroll_height = document.documentElement.scrollHeight;
	// calculate colums and rows offset (cells dimensions)
	calculate_cells();  
}



// onmousedown handler
function handler_onmousedown(e){
	// define event (cross browser)
	var evt = e || window.event;
	// enable control for form elements
	if (isFormElement(evt)) return true;
	// set a reference to the moved object and z-index (if object is not of "clone" type)
	obj = this;
	if (obj.className.indexOf('clone') == -1) obj.style.zIndex = 999;
	obj.style.marginBottom = '0px';
	obj.style.display = 'inline';
	//obj.style.marginLeft = '1px';
	
	// set clicked position
	mouseX = evt.clientX;
	mouseY = evt.clientY;
	// set current table, row and cell
	set_tcr(evt);
	// remember started table, row and cell
	table_source = table;
	row_source   = row;
	cell_source  = cell;
	// define pressed mouse button
	if (evt.which) mouseButton = evt.which;
	else           mouseButton = evt.button;
	// activate onmousemove and onmouseup event handlers on document level
	// if left mouse button is pressed
	if (mouseButton == 1){
		obj.style.cursor = "url("+miRutaCompleta+"img/pointer_c.png), pointer"
		document.getElementById('obj_new').style.display = 'block';
		moved_flag = 0; // set moved_flag (if need to clone object in handler_onmousemove)
		document.onmousemove = handler_onmousemove;
		document.onmouseup   = handler_onmouseup;
		if (drop_option != 'etiqueta')	myhandler_clicked(); // call myhandler
	}
	else
	{
		obj.style.cursor = "url("+miRutaCompleta+"img/pointer_a.png), pointer"	
	}
	// remember background cell color
	bgcolor_old = tables[table].rows[row].cells[cell].style.backgroundColor;
	bgcolor_old_tr = tables[table].rows[row].style.backgroundColor;
	
	//S.R.O. Guardo el id de la etiqueta (Es el id de un div interno, viene como Eid_nº)
	tabla = tables[table_source].rows[row_source].cells[cell_source];
	//Si tiene hijos (DIV, etc)...
	if (mouseButton == 1 && tabla.childNodes.length > 0)
	{ 
		for(x=0;x<tabla.childNodes.length;x++)
			if (tabla.childNodes[x].tagName == 'DIV' && tabla.childNodes[x].id.indexOf('Eid_') > -1)
			{
				//if (tabla.childNodes[0].id.indexOf(pref_etiqueta) > -1)     alert(tabla.childNodes[0].id);
				getiqueta_id = substr( tabla.childNodes[x].id, 4 );
				//alert(getiqueta_id);
				break;
			}
	}
/**/			
	// define object offset
	var offset = box_offset(obj);
	// calculate ofsset from the clicked point inside element to the
	// top, right, bottom and left side of the element
	obj_margin = [mouseY-offset[0], offset[1]-mouseX, offset[2]-mouseY, mouseX-offset[3]];
	// disable text selection
	return false;
}



// onmouseup handler
function handler_onmouseup(e){
	document.getElementById('obj_new').style.display = 'none';
	// define destination and source table cell
	var destination_cell, source_cell;
	// define destination elements and destination elements length needed for switching table cells
	// destination_elements_length is needed because nodeList objects in the DOM are live 
	// please see http://www.redips.net/javascript/nodelist-objects-are-live/
	var destination_elements, destination_elements_length;
	// reset mouseButton variable
	mouseButton = 0;
	// reset left and top styles
	obj.style.left = 0;
	obj.style.top  = 0;
	obj.style.marginBottom = '0px';
	obj.style.display = 'inline';
	//obj.style.marginLeft = '1px';
	// return z-index
	obj.style.zIndex = 10;
	obj.style.cursor = "url("+miRutaCompleta+"img/pointer_a.png), pointer"	
	// if object was dropped inside table then define a new location for destination cell
	if (table < tables.length)
		{destination_cell = tables[table].rows[row].cells[cell]; destination_cell1 = tables[table].rows[row];/**/}
	else // or use the last possible location (object was dropped outside table)
		{destination_cell = tables[table_old].rows[row_old].cells[cell_old]; destination_cell1 = tables[table_old].rows[row];/**/}
	
	//S.R.O. Guardo el uid del email y el id del Gemail o '' (Está en la clase del TD, vienen como Euid_nº y Gid_nº, donde nº es el id o ''(en el Gid) si no está en la BBDD)
	// PARA NUEVA ETIQUETA
	uid = '';
	if (destination_cell.className.indexOf('Euid_') > -1)
	{
		cadena = destination_cell.className;
		array_clases = explode( ' ', cadena);
		for(x=0;x<array_clases.length;x++)
			if(array_clases[x].indexOf('Euid_') > -1)
			{
				uid = substr( array_clases[x], 5 );
				break;
			}		
	}
	gemail_id = '';
	if (destination_cell.className.indexOf('Gid_') > -1)
	{
		cadena = destination_cell.className;
		array_clases = explode( ' ', cadena);
		for(x=0;x<array_clases.length;x++)
			if(array_clases[x].indexOf('Gid_') > -1)
			{
				gemail_id = substr( array_clases[x], 4 );
				break;
			}		
	}
	// PARA BORRAR
	gemail_id_origen = '';
	origen_cell = tables[table_source].rows[row_source].cells[cell_source];
	origen_cell.style.cursor = "url("+miRutaCompleta+"img/pointer_a.png), pointer"	
	if (origen_cell.className.indexOf('Gid_') > -1)
	{
		cadena = origen_cell.className;
		array_clases = explode( ' ', cadena);
		for(x=0;x<array_clases.length;x++)
			if(array_clases[x].indexOf('Gid_') > -1)
			{
				gemail_id_origen = substr( array_clases[x], 4 );
				break;
			}		
	}
	// return background color for destination color (cell had hover color)
	destination_cell.style.backgroundColor = bgcolor_old;destination_cell1.style.backgroundColor = bgcolor_old_tr;
	// detach onmousemove and onmouseup events
	document.onmousemove = null;
	document.onmouseup   = null;
	// document.body.scroll... only works in compatibility (aka quirks) mode,
	// for standard mode, use: document.documentElement.scroll...
	scroll_width  = document.documentElement.scrollWidth;
	scroll_height = document.documentElement.scrollHeight;	
	// reset autoscroll flags
	autoscrollX_flag = autoscrollY_flag = 0;
	// reset old positions
	table_old = row_old = cell_old = null;
	copiar = false;
	// element was not moved - button was clicked and released
	// call myhandler_notmoved handler and place clicked element to the bottom of TD (if table cell contains more than one element)
	if (moved_flag == 0){
		if (drop_option != 'etiqueta')	myhandler_notmoved();
		destination_cell.appendChild(obj);
	}
	// A PAPELERA, BORRAR LA ETIQUETA remove child if destination cell has "trash" in class name
	else if (destination_cell.className.indexOf(trash) > -1)
	{
		// remove child from DOM (node still exists in memory)
/*		if(origen_cell.className.indexOf('clone') > -1)
		{
			if(confirm('La etiqueta ser\xE1 eliminada de todos los emails.\nLos emails no ser\xE1n borrados\n\xBFDesea eliminarla\x3F'))
			{
				var tr = origen_cell.parentNode;
		        var table = tr.parentNode;
		        table.removeChild(tr);
		        myhandler_elimina_registros(getiqueta_id);
	        }
		}
*/		
		obj.parentNode.removeChild(obj);
		
		table_old = table_source = null;
		row_old   = row_source   = null;
		cell_old  = cell_source  = null;
		
		// if parameter trash_ask is "true", confirm deletion (function trash_delete is at bottom of this script)
		if (trash_ask) 
			setTimeout(trash_delete, 10);
		// else call myhandler_deleted handler (reference to the obj still exists)
		else 
		{
			//S.R.O. Elimino las entradas en la BBDD que contengan esa etiqueta
			if( origen_cell.className.indexOf('clone') > -1 && drop_option == 'etiqueta' )
			{
				if(confirm('La etiqueta ser\xE1 eliminada de todos los emails.\nLos emails no ser\xE1n borrados\n\xBFDesea eliminarla\x3F'))
				{
					var tr = origen_cell.parentNode;
			        var table = tr.parentNode;
			        table.removeChild(tr);
			        myhandler_elimina_registros(getiqueta_id);
		        }
			}
			else if (drop_option == 'etiqueta')
			{
				myhandler_deletedBBDD(gemail_id_origen,getiqueta_id); //Genera el evento de borrado en la BBDD (S.R.O.)
			}
			else
				myhandler_deleted(); // Evento normal (alert en td id="message" class="forbid")
		}
		
		//ELIMINO EL ID DE Gemail, Getiqueta de la etiqueta eliminada y el uid del email guardado
		gemail_id = getiqueta_id = uid = null
/*		table_old = table_source = null;
		row_old   = row_source   = null;
		cell_old  = cell_source  = null;
*/
	}
	// switch source and destination content
	else if (drop_option == 'switch')
	{
		// set source cell
		source_cell = tables[table_source].rows[row_source].cells[cell_source];
		// remove dragged element from DOM (source cell) - node still exists in memory
		obj.parentNode.removeChild(obj);
		// move object from the destination to the source cell
		destination_elements = destination_cell.getElementsByTagName('DIV');
		destination_elements_length = destination_elements.length
		for (var i=0; i< destination_elements_length; i++){
			source_cell.appendChild(destination_elements[0]); // '0', not 'i' because NodeList objects in the DOM are live
		}
		// and finaly, append dragged object to the destination table cell
		destination_cell.appendChild(obj);
		// if destination element exists, than elements are switched, otherwise element is dropped to the empty cells
		if (destination_elements_length) 
		{
			if (drop_option != 'etiqueta')	
				myhandler_switched();
		}
		else if (drop_option != 'etiqueta') 
			myhandler_dropped();
	}
	// Añadido por Salvador Ramos Ortega
	//Para evitar que se clone una etiqueta en su propio td y que se mueva una etiqueta de
	// otro lugar al td con clase clone, eliminando la etiqueta VIRTUAL creada
	else if (drop_option == 'etiqueta' && destination_cell.className.indexOf('clone') > -1)
	{
		//Igual que papelera
		// remove child from DOM (node still exists in memory)
		obj.parentNode.removeChild(obj);
	}
	// Añadido por Salvador Ramos
	//Para evitar que se mueva una etiqueta en su propio td y que se mueva a otra etiqueta de
	// otro lugar, excepto a la papelera
	else if (drop_option == 'etiqueta' && tables[table_source].rows[row_source].cells[cell_source].className.indexOf(no_move) > -1)
	{
	//	myhandler_deleted();
	}
	// Añadido por Salvador Ramos Ortega
	//Para evitar que se duplique una etiqueta en un email, eliminando la etiqueta VIRTUAL creada
	else if (drop_option == 'etiqueta' && destination_cell.className.indexOf('no_move') > -1)
	{
		//Igual que papelera
		//Si tiene hijos (DIV, etc)...
		duplicada = false;
		if (destination_cell.childNodes.length > 0)
		{ 
			getiqueta_origen = substr( obj.id, 4 );
			for(x=0;x<destination_cell.childNodes.length;x++)
			{
				if (destination_cell.childNodes[x].tagName == 'DIV' && destination_cell.childNodes[x].id.indexOf('Eid_') > -1)
				{
					getiqueta_destino = substr( destination_cell.childNodes[x].id, 4 );
					//alert(getiqueta_origen);
					//alert(getiqueta_destino);
					if(getiqueta_origen == getiqueta_destino)
					{
						// Elimino la etiqueta duplicada
						obj.parentNode.removeChild(obj);
						duplicada = true;
						break;
					}
				}
			}
			if(duplicada == false)
				copiar = true;
		}
		else
			copiar = true;	
	}
	// else call myhandler and append object to the cell
	//else
	if(copiar == true)
	{
/*		//Añadido por Salvador Ramos Ortega
		contenedor_org = destination_cell; //Guardo el contenedor original (td)
		contenido_org = destination_cell.innerHTML; //Guardo el contenido original
		alert('DENTRO')
		if (destination_cell.childNodes.length > 0 ) //Si tiene hijos (DIV)...
		{
			for(x=0;x<destination_cell.childNodes.length;x++)
				if (destination_cell.childNodes[x].tagName == 'DIV' && destination_cell.childNodes[x].className.indexOf(receptor) > -1)
				{
					//el contenedor de la nueva etiqueta es el DIV
					contenedor_org = destination_cell.childNodes[x];
					contenido_org = destination_cell.childNodes[x].innerHTML; //Guardo el contenido del DIV
				}
		}
		contenedor_org.innerHTML = '';//Elimino todo el contenido
		contenedor_org.appendChild(obj);//Añado la nueva etiqueta
*/
		destination_cell.appendChild(obj); //ORGINAL
/*		contenido = contenedor_org.innerHTML;//Guardo la nueva etiqueta
		contenedor_org.innerHTML = contenido+contenido_org;//Muestro la nueva etiqueta + contenido anterior
*/
		if (drop_option == 'etiqueta')
			myhandler_nuevaBBDD(uid, getiqueta_id);//Genera el evento de añadir etiqueta a un amail en la BBDD (S.R.O.)
		else
			myhandler_dropped(); //ORGINAL	Notifico el cambio
	}
	// recalculate table cells and scrollers because cell content could change row dimensions 
	calculate_cells();
	
	//Añadido por Salvador Ramos Ortega
	if(drop_option == 'etiqueta')
	{
		table_old = table_source = null;
		row_old   = row_source   = null;
		cell_old  = cell_source  = null;
		gemail_id = getiqueta_id = uid = null;
	}
	document.getElementById('obj_new').innerHTML = '';
}



// onmousemove handler for the document level
// activated after left mouse button is pressed on draggable element
function handler_onmousemove(e){
	// define event (FF & IE)
	var evt = e || window.event;
	// if moved_flag isn't set and object has clone in class name, then duplicate object and call myhandler_cloned
	if (moved_flag == 0 && obj.className.indexOf('clone') > -1){
		clone_obj();
		if (drop_option != 'etiqueta')	myhandler_cloned();
	}
	// object is only moved, call myhandler_moved
	else if (moved_flag == 0){
		if (drop_option != 'etiqueta')	myhandler_moved();
	}
	// set moved_flag
	moved_flag = 1;
	// set left and top styles for the moved element if element is inside window
	// this conditions will stop element on window bounds
	if (evt.clientX > obj_margin[3] && evt.clientX < window_width - obj_margin[1])  obj.style.left = (evt.clientX - mouseX) + "px";
	if (evt.clientY > obj_margin[0] && evt.clientY < window_height - obj_margin[2])	obj.style.top  = (evt.clientY - mouseY) + "px";
	// set current table, row and cell
	set_tcr(evt);
	// if new location is inside table and new location is different then old location
	// set background colors for the previous and new table cell
	if (table < tables.length && (table != table_old || cell != cell_old || row != row_old)){
		// set cell background color to the previous cell
		if (table_old != null && row_old != null && cell_old != null)
			{tables[table_old].rows[row_old].style.backgroundColor = bgcolor_old_tr; tables[table_old].rows[row_old].cells[cell_old].style.backgroundColor = bgcolor_old;}
		// remember background color before setting the new background color
		bgcolor_old_tr = tables[table].rows[row].style.backgroundColor; bgcolor_old = tables[table].rows[row].cells[cell].style.backgroundColor;
		// set background color to the current table cell
		tables[table].rows[row].style.backgroundColor = hover_color; tables[table].rows[row].cells[cell].style.backgroundColor = hover_color;
		// remember current position (for table, row and cell)
		table_old=table; row_old=row; cell_old=cell;
	}
	// test if is still first mouse button pressed (in case when user release mouse button out of a window)
	if (evt.which) mouseButton = evt.which;
	else           mouseButton = evt.button;
	// if first mouse button is released
	if (mouseButton != 1){handler_onmouseup(evt);	return;}	
	// calculate horizontally crossed page bound
	edgeX = bound - (window_width/2  > evt.clientX ? evt.clientX-obj_margin[3] : window_width - evt.clientX - obj_margin[1]);
	// if element crosses page bound then set scroll direction and call auto scroll 
	if (edgeX > 0){
		// in case when object is only half visible (page is scrolled on that object)
		if (edgeX > bound) edgeX = bound;
		// set scroll direction: negative - left, positive - right
		edgeX *= evt.clientX < window_width/2 ? -1 : 1; 
		// remove onscroll event handler and call autoscrollY function only once
		if (autoscrollX_flag++ == 0) {window.onscroll = null; autoscrollX()}
	}
	else edgeX = 0;
	// calculate vertically crossed page bound
	edgeY = bound - (window_height/2 > evt.clientY ? evt.clientY-obj_margin[0] : window_height - evt.clientY - obj_margin[2]);
	// if element crosses page bound then set scroll direction and call auto scroll
	if (edgeY > 0){
		// in case when object is only half visible (page is scrolled on that object)
		if (edgeY > bound) edgeY = bound;
		// set scroll direction: negative - up, positive - down
		edgeY *= evt.clientY < window_height/2 ? -1 : 1;
		// remove onscroll event handler and call autoscrollY function only once
		if (autoscrollY_flag++ == 0) {window.onscroll = null; autoscrollY()}
	}
	else edgeY = 0;
}

//
// auto scroll functions
//

// horizontal auto scroll function
function autoscrollX(call){
	// define old scroll position and current scroll position
	var old = 0; 
	var scrollPosition = getScrollPosition('X');
	// mouse button should be pressed and
	// if moved element is over left or right margin
	// scroll_width - window_width returns maximum horizontal scroll position
	if (mouseButton == 1 && ((edgeX < 0 && scrollPosition > 0) || (edgeX > 0 && scrollPosition < (scroll_width - window_width)))){
		// horizontal window scroll 
		window.scrollBy(edgeX, 0);
		// set previous scroll position and new after window is scrolled
		old = scrollPosition;
		scrollPosition = getScrollPosition('X');
		// set style left for the moved element
		obj.style.left = (parseInt(obj.style.left) + scrollPosition - old) + "px";
		// move X point
		mouseX -= scrollPosition - old; 
		// recursive autoscroll call 
		setTimeout("autoscrollX('recursive')", speed);
	}
	// autoscroll stopped by moving element out of the page edge
	// or element faced maximum position (left or right)
	else{
		// recalculate cell positions if call was function itself (spare CPU if moving object across bound)
		if (call == 'recursive') calculate_cells();
		// return onscroll event handler and reset auto scroll flag
		window.onscroll  = calculate_cells;
		autoscrollX_flag = 0;
	}
}

// vertical auto scroll function
function autoscrollY(call){
	var top;     // top style
	var old = 0; // define old scroll position
	// define current scroll position
	var scrollPosition = getScrollPosition('Y');
	// mouse button should be pressed and 
	// if moved element is over page top or page bottom
	// scroll_height - window_height returns maximum vertical scroll position
	if (mouseButton == 1 && ((edgeY < 0 && scrollPosition > 0) || (edgeY > 0 && scrollPosition < (scroll_height - window_height)))){
		// vertical window scroll 
		window.scrollBy(0, edgeY);
		// set previous scroll position and new after window is scrolled
		old = scrollPosition;
		scrollPosition = getScrollPosition('Y');
		// set top style of the object
		top = (isNaN(parseInt(obj.style.top)) ? 0 : parseInt(obj.style.top));
		// set style top for the moved element
		obj.style.top = (top + scrollPosition - old) + "px";
		// move Y point
		mouseY -= scrollPosition - old; 
		// recursive autoscroll call 
		setTimeout("autoscrollY('recursive')", speed);
	}
	// autoscroll stopped by moving element out of the page edge
	// or element faced maximum position (top or bottom)
	else{
		// recalculate cell positions if call was function itself (spare CPU if moving object across bound)
		if (call == 'recursive') calculate_cells();
		// return onscroll event handler and reset auto scroll flag
		window.onscroll  = calculate_cells;
		autoscrollY_flag = 0;
	}
}



// function returns scroll position for X or Y scrollbar
// input parameter is dimension (X or Y)
function getScrollPosition(d){
	var scrollX, scrollY; // define scroll position variables
	// Netscape compliant
  if (typeof(window.pageYOffset) == 'number'){
    scrollX = window.pageXOffset;
    scrollY = window.pageYOffset;
  }
  // DOM compliant
  else if (document.body && (document.body.scrollLeft || document.body.scrollTop)){
    scrollX = document.body.scrollLeft;
    scrollY = document.body.scrollTop;
  }
  // IE6 standards compliant mode
  else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)){
    scrollX = document.documentElement.scrollLeft;
    scrollY = document.documentElement.scrollTop;
  }
  // needed for IE6 (when vertical scroll bar was on the top)
  else scrollX = scrollY = 0;
  // return scroll position
  if (d == 'X') return scrollX;
  else          return scrollY
}

//
// other functions
//

// calculate table colums and row offsets (cells dimensions) 
function calculate_cells(){
	// local variables used in for loops
	var i, j;
	// open loop for each HTML table inside id=drag (tables variable is initialized in onload event)
	for (i=0; i<tables.length; i++){
		// define row offsets variable
		var row_offset = new Array();
		// collect table rows and initialize row offsets array
		var tr = tables[i].getElementsByTagName('tr');
		// backward loop has better perfomance
		for (j=tr.length-1; j>=0; j--) row_offset[j] = box_offset(tr[j]);
		// save table informations (table offset and row offsets)
		tables[i].offset     = box_offset(tables[i]);
		tables[i].row_offset = row_offset;
	}
}

// function sets current table, row and cell
// please note that variables used in this function (table, cell and row)
// are defined at the beginning of the script (global scope) 
function set_tcr(evt){
	// define variables for left & right cell offset
	var offsetLeft, offsetRight;
	// define current cell (needed for some test at the function bottom
	var cell_current;
	// find table below draggable object
	for (table=0; table < tables.length; table++){
		// mouse pointer is inside table
		if (tables[table].offset[3] < evt.clientX  &&  evt.clientX < tables[table].offset[1] &&	
				tables[table].offset[0] < evt.clientY  &&  evt.clientY < tables[table].offset[2]){
					// row offsets for the selected table (row bounds)
					var row_offset = tables[table].row_offset;
					// find the current row (loop will stop at the current row; row_offset[row][0] is row top offset)
					for (row=0; row<row_offset.length-1 && row_offset[row][0] < evt.clientY; row++)
						if (evt.clientY <= row_offset[row][2]) break;
					// do loop - needed for rowspaned cells (if there is any)
					do{
						// set the number of cells in the selected row
						var cells = tables[table].rows[row].cells.length - 1;
						// find current cell (X mouse position between cell offset left and right)
						for (cell = cells; cell >= 0; cell--){
							// row left offset + cell left offset
							offsetLeft = row_offset[row][3] + tables[table].rows[row].cells[cell].offsetLeft;
							// cell right offset is left offset + cell width  
							offsetRight = offsetLeft + tables[table].rows[row].cells[cell].offsetWidth;
							// is mouse pointer is between left and right offset, then cell is found
							if (offsetLeft <= evt.clientX && evt.clientX < offsetRight) break;
						}
					} // mouse pointer is inside table but cell not found (hmm, rowspaned cell - try in upper row)
					while (cell == -1 && row-- > 0)
					// set current cell TD
					cell_current = tables[table].rows[row].cells[cell];
					
					// Si el TD es de clase 'forbid'...
					if (cell_current.className.indexOf(forbid) > -1)
					{
					//	var tr_current = tables[table].rows[row]; //Guardo el TR
						//if(cell_current.childNodes.length >= 1 )
						{
							var encontrada = false;
							var item;
						//	for (var index = 0; index < cell_current.childNodes.length; ++index) 
						//	{
						//		item = cell_current.childNodes[index];
						//	  	if(item.className.indexOf('drag') > -1)
							  	{
						//	  		alert('1')
							  		for(var index1=0; index1 < tables[table].rows[row].cells.length; ++index1)
							  		{
							  			if(tables[table].rows[row].cells[index1].className.indexOf('no_move') > -1)
							  			{
							  				//alert(index1)
							  				cell=index1; 
							  				encontrada = true;
							  				break;
							  			}
							  		}	
							  	}
						//	}
							if(!encontrada)
							{
								table=table_old; row=row_old; cell=cell_old; 
								break;
							}	
						}
				/*		else
						{
							table=table_old; row=row_old; cell=cell_old; 
							break;
						}
				*/
					} 
				/*	{
						table=table_old; row=row_old; cell=cell_old; 
						break;
					}*/

					// if drop_option == single and current cell has child nodes then test if cell is occupied
					if (drop_option == 'single' &&	cell_current.childNodes.length > 0){
						// if cell has only one node and that is text node then break - because this is empty cell
						if (cell_current.childNodes.length == 1 && cell_current.firstChild.nodeType == 3) break;
						// define and set has_content flag to false
						var has_content = false;
						// open loop for each child node and jump out if 'drag' className found
						for (var i=cell_current.childNodes.length-1; i>=0 ; i--){
							if (cell_current.childNodes[i].className && cell_current.childNodes[i].className.indexOf('drag') > -1) {has_content = true; break;} 
						}
						// if cell has content and old position exists ...
						if (has_content && table_old != null && row_old != null && cell_old != null){
							// .. and current position is different then source position then return previous position
							if (table_source != table || row_source != row || cell_source != cell) {table=table_old; row=row_old; cell=cell_old; break;}
						}
					}
					// Añadido por Salvador Ramos
					//Para evitar que se clone una etiqueta en su propio td y que se mueva una etiqueta de
					// otro lugar al td con clase clone
					// Si drop_option == etiqueta y en la clase del td destino está clone ...
					if (drop_option == 'etiqueta' && cell_current.className.indexOf('clone') > -1)
					{
						// .. y la posición original no es null
						if ( table_source != null && row_source != null && cell_source != null && ( table_source != table || row_source != row || cell_source != cell ) )
						{
							// Cambia las coordenadas de destino a las originales de la etiqueta
							table=table_source; 
							row=row_source; 
							cell=cell_source; 
						}
						break;
					}
					else if ( table_source != null && row_source != null && cell_source != null )
					{
						tabla_origen = tables[table_source].rows[row_source].cells[cell_source];
						if (drop_option == 'etiqueta' && tabla_origen.className.indexOf('no_move') > -1 && cell_current.className.indexOf(trash) <= -1)
						{
							// Cambia las coordenadas de destino a las originales de la etiqueta
							table=table_source; 
							row=row_source; 
							cell=cell_source; 
							break;
						}
					}
					// break table loop 
					break;
		}
	}
}

// calculate object (box) offset (top, right, bottom, left)
// function returns array of box bounds
// used in calculate_cells and onmousedown event handler
function box_offset(box){
	var oLeft = 0 - getScrollPosition('X'); // define offset left (take care of scroll position)
	var oTop  = 0 - getScrollPosition('Y'); // define offset top (take care od scroll position)
	// remember box object
	var box_old = box;
	// loop to the root element and return box offset (top, right, bottom, left)
	do {oLeft += box.offsetLeft; oTop += box.offsetTop} while (box = box.offsetParent);
	// return box offset array
	//       top               right,                     bottom             left
	return [ oTop, oLeft + box_old.offsetWidth, oTop + box_old.offsetHeight, oLeft ];
}



// clone object
function clone_obj(){
	// clone div object and append to the div element (id="obj_new")
	var obj_new = obj.cloneNode(true);
	document.getElementById('obj_new').appendChild(obj_new);
	// offset of the original object
	var offset = box_offset(obj);
	// offset of the new object (cloned)
	var offset_dragged = box_offset(obj_new);
	// calculate top and left offset of the new object
	obj_new.style.top   = (offset[0] - offset_dragged[0]) + "px";
	obj_new.style.left  = (offset[3] - offset_dragged[3]) + "px";
	// set onmouse down event for the new object
	obj_new.onmousedown = handler_onmousedown;
	// remove clone from the class name of the new object
	obj_new.className = obj_new.className.replace('clone', '');
	// append 'd' to the innerHTML of the new object 'Clone' -> 'Cloned'
	//obj_new.innerHTML += 'd';
	// set new position because div is appended to div id="obj_new"
	mouseX -= parseInt(obj_new.style.left);
	mouseY -= parseInt(obj_new.style.top);	
	// replace reference with new object	
	obj = obj_new;
}



// delete object
function trash_delete(){
	var div_text; // div content (inner text)
	var border;   // border color (green or blue)
	// find the border color of DIV element (t1 - green, t2 - blue, t3 - orange)
	if (obj.className.indexOf('t1') > 0)      border = 'green';
	else if (obj.className.indexOf('t2') > 0) border = 'blue';
	else border = 'orange';
	// set div text (cross browser)
	if (obj.getElementsByTagName('INPUT').length || obj.getElementsByTagName('SELECT').length)
		div_text = 'form element';
	else 
		div_text = '"' + (obj.innerText || obj.textContent) + '"';
	// ask if user is sure
	if (confirm('Delete '+div_text+' ('+border+') from\n table '+table_source+', row '+row_source+' and column '+cell_source+'?')){
		// yes, user is sure only call myhandler_deleted function
		myhandler_deleted();
	}
	// user is unsure - do undelete
	else{
		// append removed object to the source table cell
		tables[table_source].rows[row_source].cells[cell_source].appendChild(obj);
		// and recalculate table cells because undelete can change row dimensions 
		calculate_cells();
		// call undeleted handler
		if (drop_option != 'etiqueta')	myhandler_undeleted();	
	}
}



// function returns true or false if source tag name is form element
function isFormElement(evt){
	// declare form element and source tag name
	var formElement;
	var srcName;
	// set source tag name for IE and FF
	if (evt.srcElement)	srcName = evt.srcElement.tagName;
	else                srcName = evt.target.tagName;
	// set flag (true or false) for form elements
	switch(srcName){
		case 'INPUT':
		case 'SELECT':
		case 'OPTION':
			formElement = true;
			break;
		default:
			formElement = false;
	}
	// return formElement flag
 	return formElement;
}

//
// other, other functions
// if you don't need "show table content" or toggling, than this functions can be left out 
//

// function shows how to scan table and display cell content
// (fired on button "Click" click :)
// this function should be customized for your needs  
function table_content(id){
	// define local variables
	var message = ''; // final message
	var div_text;     // div content (inner text)
	var border;       // border color (green or blue)
	// set reference to the table
	var tbl = document.getElementById(id);
	// define number of table rows
	var tbl_rows = tbl.rows.length;
	// iterate through each table row
	for (var r=0; r<tbl_rows; r++){
		// set the number of cells in the current row
		var cells = tbl.rows[r].cells.length
		// iterate through each table cell
		for (var c=0; c<cells; c++){
			// set reference to the table cell
			var tbl_cell = tbl.rows[r].cells[c];
			// if cells isn't empty and hasn't forbid class 
			if (tbl_cell.childNodes.length > 0 && tbl_cell.className != forbid){
				// cell can contain more then one DIV element
				for (var d=0; d<tbl_cell.childNodes.length; d++){
					// childNodes should be DIVs, not \n childs
					if (tbl_cell.childNodes[d].tagName == 'DIV'){ // and yes, is should be uppercase
						// find the border color of DIV element (t1 - green, t2 - blue, t3 - orange)
						if (tbl_cell.childNodes[d].className.indexOf('t1') > 0)      border = 'green';
						else if (tbl_cell.childNodes[d].className.indexOf('t2') > 0) border = 'blue';
						else border = 'orange';
						// set message line if div contains form elements
						if (tbl_cell.childNodes[d].getElementsByTagName('INPUT').length || tbl_cell.childNodes[d].getElementsByTagName('SELECT').length)
							div_text = 'form element';
						// for other divs that contains only text (cross browser)
						else
							div_text = '"' + (tbl_cell.childNodes[d].innerText || tbl_cell.childNodes[d].textContent) + '"';
						// add line to the message
						message += 'row:' + r + ' col:' + c + ' ' + div_text + ' (' + border + ')\n';
					}
				}
			}
		}
	}
	// if table is empty print a nice message
	if (message == '') message = 'Table is empty!';
	// display message
	alert(message);
}


// functions toggles trash_ask defined at the top
function toggle_confirm(chk){
	trash_ask = chk.checked;
}

// function sets drop_option defined at the top
function set_drop_option(radio_button){
	drop_option = radio_button.value
}

// used for myhandlers demo to display events
function message(text){
	document.getElementById('message').innerHTML = text;
}

/*
* PARA ASIGNAR UNA FUNCION A UN EVENTO
* addEvento(event, elem, func);
* event – Evento que queremos controlar
* elem – Elemento al que añadir el evento
* func – Función que se ejecutará al lanzar el evento en nuestro elemento.*/

function addEvento(event, elem, func) {
    elem = $(elem);
    if (elem.addEventListener)  // W3C DOM
        elem.addEventListener(event,func,false);
    else if (elem.attachEvent) { // IE DOM
         var r = elem.attachEvent("on"+event, func);
	return r;
    }
    else throw 'No es posible añadir evento';
}

//Asigno la función windowonload al evento load del objeto window
//window.addEventListener('load',windowonload,false);


//
// handlers
// Here you can put custom JavaScript code instead of demo code.
// In each function you can use "obj" reference to the dragged object.
// Definition of all handler functions should exist, but can be empty if not needed.
// For example, if you don't need myhandler_notmoved handler, then handler code should look:
// function myhandler_notmoved() {}
//

function myhandler_clicked()   {message('Clicked');} 
function myhandler_moved()     {message('Moved');}
function myhandler_notmoved()  {message('Not moved');} 
function myhandler_dropped()   {if (drop_option != 'etiqueta')	message('Dropped');} 
function myhandler_switched()  {message('Switched');} 
function myhandler_cloned()    {message('Cloned');} 
function myhandler_deleted()   {if (drop_option != 'etiqueta')	message('Deleted');} 

//Para borrar etiqueta-email_id de la tabla GemailGetiqueta
function myhandler_deletedBBDD( gemail, getiqueta)   { new Ajax.Updater('para_recarga',miWebRoot+'comunicaciones/borrar_etiqueta/'+getiqueta+'/'+gemail, {asynchronous:true, evalScripts:true, onLoading:function(request) {deshabilitar_pantalla();$('mens_actualizar').show();}, onComplete:function(request) {habilitar_pantalla();$('mens_actualizar').hide();}, requestHeaders:['X-Update', 'para_recarga']});} 

//Para añadir etiqueta a un email en la BBDD(tablas Gemail y GemailGetiqueta)
function myhandler_nuevaBBDD( uid_id, getiqueta)   { new Ajax.Updater('para_recarga',miWebRoot+'comunicaciones/aniadir_etiqueta/'+uid_id+'/'+getiqueta, {asynchronous:true, evalScripts:true, onLoading:function(request) {deshabilitar_pantalla();$('mens_actualizar').show();}, onComplete:function(request) {habilitar_pantalla();$('mens_actualizar').hide();}, requestHeaders:['X-Update', 'para_recarga']}); } 

//Para eliminar etiqueta original y de todos los email que la tengan asignada en la BBDD(tablas Getiqueta y GemailGetiqueta)
function myhandler_elimina_registros(id_getiqueta)   
{
	deshabilitar_pantalla();
	$('mens_actualizar').show();
	document.location.href = miRutaCompleta+"menus/comunicaciones/comunicaciones/eliminar_etiqueta/"+id_getiqueta;
}

function myhandler_undeleted() {message('Undeleted');}

/*
document.onselectstart=function(){return false};
if (window.sidebar){
document.onmousedown=function(e){
var obj=e.target;
if (obj.tagName=="INPUT"){
return true;
}else if (obj.tagName=="BUTTON"){
return true;
}
return false;
}
}*/
