function dNode(arrayProps) {
	//****************************************************************************************
	//a = new dNode({id:2, +:'tree root', url:'http://www.w3.org'});
	//****************************************************************************************
	//Parametros obligatorios
	this.id;          				//node id
	this.caption;     				//node caption
	this.captionClass;
   	//Parametros opcionales
	this.url="";         			//URL
	this.target;    				//target de la URL
	this.onClick;     				//javascript del evento OnClick
	this.onOpen;     				//javascript a ejecutar cuando se abre el nodo
	this.onClose;     				//javascript a ejecutar cuando el nodo se cierra
	this.onFirstOpen;			//javascript a ejecutar cuando se abre por primera vez el nodo
	this.iconClosed; 				//img.src del icono de cerrado
	this.iconOpen;   				//img.src del icono abierto
	this.runJS = true;       		//Ejecuta los eventos recibidos como parametros
	this.plusSign = true;    		//Define si el simbolo plus debe aparecer
        this.beopen = false;  			//Define si el nodo debe aparecer abierto
	this.profundidad = 0; 			//Define el nivel de profundidad del nodo dentro del arbol (se utiliza para indentación y asignar caracteristicas propias a cada nivel)
	this.tipo = "";				//Campo libre para identificar la naturaleza del nodo
	//Parametros privados
	this._opened = false; 			//Indica si el nodo ha sido ya abierto. Funciona como flasg de onFristOpen
        /*this._io = false; 				//Indica si esta abierto el nodo*/
	/*this._mark = false;			//Indica si el checkbox del nodo esta marcado*/
	this._children = []; 			//Array con los hijos
	this._parent; 				//Puntero al padre
	this._myTree; 				//Puntero al arbol
	for (i in arrayProps)	{
		if (i.charAt(0) != '_')		{
			eval('this.'+i+' = arrayProps[\''+i+'\'];');
		}
	}
    this._io = eval(this.beopen);
}
//****************************************************************************************
//Obtiene el path desde la raiz
//****************************************************************************************
dNode.prototype.getPathNode = function() {
    var path= this.id + "/";
    var padre = this._parent;
    while (padre!= this._myTree._root) {
        path = padre.id + "/" + path;
        padre = padre._parent;
    }
    return path;
}
//****************************************************************************************
//Cambia el estado del nodo
//****************************************************************************************
dNode.prototype.changeState = function() {
	if (this._io)	{
		this.close();
	}else	{
		this.open();
	}
}
//****************************************************************************************
//Cambio del estado del checkbox del Nodo
//****************************************************************************************
dNode.prototype.changeChk = function (estado) {
	this._changeSon(estado);
	if(estado) this._changeFather();
}
//****************************************************************************************
//****************************************************************************************
//Eventos del Nodo
//****************************************************************************************
dNode.prototype.open = function () { 
	if (!this._io)	{
		if (!this._opened && this.runJS && this.onFirstOpen != null && this._children.length>0)		{
			eval(this.onFirstOpen);
		}
		else if (this.runJS && this.onOpen != null && this._children.length>0)		{
			eval(this.onOpen);
		}
		this._opened = true;
		this._io = true;
		this._refresh();
	}
}
//****************************************************************************************
dNode.prototype.close = function() {
	if (this._io)	{
		if (this.runJS && this.onClose != null)		{
			eval(this.onClose);
		}
		this._io = false;
		this._refresh();
	}
}
//****************************************************************************************
dNode.prototype._refresh = function() {
	var nodeDiv      = getObjectById("n"+this.id);
	var plusSpan     = getObjectById("p"+this.id);
	var captionSpan  = getObjectById("l"+this.id);
	var childrenDiv  = getObjectById("ch"+this.id);

	if (nodeDiv != null)	{
		//Handling open and close: checks this._io and changes class as needed
		if (!this._io)  {//just closed
			childrenDiv.className = "closed";
		}
		else { //just opened
            //prevents IE undesired behaviour when displaying empty DIVs
            /*			if (this._children.length > 0) 
                {*/
				childrenDiv.className = "opened";
            //	}
		}
        plusSpan.innerHTML = this._properPlus();
        captionSpan.innerHTML = this.caption;
	}
}
//****************************************************************************************
//****************************************************************************************
//****************************************************************************************
//Modifica el icono del + y -
//****************************************************************************************
dNode.prototype._properPlus = function() {
	if (!this._io) 	{
		if (this._myTree.useIcons)		{
			return (this.plusSign)?imageHTML(this._myTree.icons.nlPlus):"";
		}	else	{
			return (this.plusSign)?"+":"";
		}
	}	else 	{
		if (this._myTree.useIcons)	{
			return (this.plusSign)?imageHTML(this._myTree.icons.nlMinus):"";
		}	else	{
			return (this.plusSign)?"-":"";
		}
	}
}
//****************************************************************************************
//changes node to selected style class. Perform further actions.
//****************************************************************************************
dNode.prototype._select = function() {
	var captionSpan;
	if (this._myTree._selected)	{
		this._myTree._selected._unselect();
	}
	this._myTree._selected = this;
	captionSpan  = getObjectById("l"+this.id);
	//changes class to selected link
	if (captionSpan)	{
		captionSpan.className = 'captionClassSel';
	}
}
//****************************************************************************************
//changes node to unselected style class. Perform further actions.
//****************************************************************************************
dNode.prototype._unselect = function() {
	var captionSpan  = getObjectById("l"+this.id);
	this._myTree._lastSelected = this._myTree._selected;
	this._myTree._selected = null;
	//changes class to selected link
	if (captionSpan)	{
		captionSpan.className = 'captionClass';
	}
}
//****************************************************************************************
//state can be open or closed
//warning: if drawed node is not child or root, bugs will happen
//****************************************************************************************
dNode.prototype._draw = function() {
	var str;
	var div;
	var myClass = (this._io)? "opened" : "closed";
	var myPlus = this._properPlus();
	var append = true;
	var myPlusOnClick = this._myTree.name+'.getNodeById(\''+this.id+'\').changeState();';
	var captionOnClickEvent = "";
        //	var cook;
	var plusEventHandler = function(){
            eval(myPlusOnClick);
	}
	var captionEventHandler = function(){
            eval(captionOnClickEvent);
	}
	var captionClickEvent = function(){
            eval(myPlusOnClick);
	}
    
	//**************************************
	//The div of this node
	divN = document.createElement('div');
	divN.id = 'n'+this.id;
        divN.className = 'son';
	//Modificaciones Sinapsis
	if (this.tipo==0) {
		divN.style.background="#F8F8F8";
	} else {
		divN.style.background=this._myTree.colores[this.profundidad];
                if(this.io){
                    eval(divN).close();
                }
	}
	//**************************************
        
	//The span that holds the plus/minus sign
        if (this._children.length>0) {
            spanP = document.createElement('span');
            spanP.id = 'p'+this.id;
            spanP.className = 'plus';
            //	spanP.addEventListener('click',plusEventHandler,false);
            spanP.onclick = plusEventHandler;
            spanP.innerHTML = myPlus;
        } 
        
	//The span that holds the label/caption
	spanL = document.createElement('span');
	spanL.id = 'l'+this.id;
	spanL.className = this.captionClass;
    //	spanL.addEventListener('click',captionEventHandler,false);
	if (this._children.length>0 || (this._children.length==0 && this.tipo==1) ) {
            spanL.ondblclick = captionClickEvent;
            spanL.innerHTML = this.caption;
        }else{
            divpersona=document.createElement("div");
            divpersona.id="contenido_persona";
            //Capa flotante 1
            divnombre=document.createElement("div");
            divnombre.id="nombre_cargo";
            img=new ImagenFlecha();
            divpersona.appendChild(img.imagen);
            divpersona.appendChild(divnombre);
            spanCargo=document.createElement("span");
            spanCargo.className="texto_negrita";
            spanCargo.appendChild(document.createTextNode(this.cargo));
            divnombre.appendChild(spanCargo);
            divnombre.appendChild(document.createElement("br"));
            span=document.createElement("span");
            span.appendChild(document.createTextNode(this.nombre));
            span.className="texto";
            divnombre.appendChild(span);
            spanL.appendChild(divpersona);
            //Capa flotante 2
            div=document.createElement("div");
            div.id="telefono_email";
            divpersona.appendChild(div);
            href=document.createElement("a");
            href.className="enlace_tree";
            href.setAttribute("href","mailto:"+this.email);
            href.appendChild(document.createTextNode(this.email));
            div.appendChild(href);
            div.appendChild(document.createElement("br"));
            span=document.createElement("span");
            img=new ImagenTelefono();
            span.appendChild(img.imagen);
            span.appendChild(document.createTextNode(" "+this.telefono));
            span.className="texto";
            div.appendChild(span);
            spanL.appendChild(divpersona);
            //Capa flotante 3
            div=document.createElement("div");
            div.id="pagina_personal";
            divpersona.appendChild(div);
            img=new ImagenIconoPersonal();
            div.appendChild(img.imagen);
            href=document.createElement("a");
            href.className="enlace_pagina_personal";
            href.setAttribute("href","/personal/curriculum.jsp?id="+this.id.substring(1,this.id.length)+"&nombre="+this.nombre);
            href.appendChild(document.createTextNode(this._myTree.idioma==0?"pàgina personal ":(this._myTree.idioma==1)?"página personal":"Page person"));
            div.appendChild(href);
            spanL.appendChild(divpersona);
          
        }
	captionOnClickEvent = this._myTree.name+'.getNodeById(\''+this.id+'\')._select(); ';
	/*if (this.onClick) { //FIXME when onclick && url
        captionOnClickEvent += this.onClick;
		spanL.onclick = captionEventHandler;
		spanL.onDblClick
	}else {
            spanL.innerHTML = this.caption;
       
	}*/
    
    //The div that holds the children
	divCH = document.createElement('div');
	divCH.id = 'ch'+this.id;
        divCH.className = myClass;
        
    //contenedor para la imagen + titulo
	contenedor = document.createElement('div');
	contenedor.className="son";
	contenedor.style.marginLeft= 10 * this.profundidad + "px";
	
    //separador entre las pestañas(blanco)
	separador = document.createElement('div');
        separador.className="separador";//necesario
	separador.style.height="2px";
	separador.style.background="transparent url(/99_img/fondo_contenido_med.gif) repeat scroll 0%";

	//insertar en contenedor
	if(this.profundidad > 0){//if para evitar que se pinte arrel
            if(this._children.length>0)contenedor.appendChild(spanP);
            contenedor.appendChild(spanL);
	}
	//insertar en nodo
	divN.appendChild(separador);
	if(this.profundidad > 0){//if para evitar que se pinte arrel
		divN.appendChild(contenedor); 
	}       
	divN.appendChild(divCH);
    
    
	if (this._parent != null) 	{
		parentChildrenDiv = getObjectById("ch"+this._parent.id);
	}	else {//is root	
		parentChildrenDiv = getObjectById("dftree_"+this._myTree.name);
               
        //		append = false;
	}
	if (parentChildrenDiv) 	{
		parentChildrenDiv.appendChild(divN);
              
        /*		if (append)		{
			parentChildrenDiv.innerHTML += str;
		}	else 	{
			parentChildrenDiv.innerHTML  = str;
		}*/
	}
     
       
}
//****************************************************************************************
//****************************************************************************************
//****************************************************************************************
// OBJETO TREE
//t = new dFTree({name:t, caption:'tree root', url:'http://www.w3.org'});
//****************************************************************************************
function dFTree(arrayProps) {
	//Parametros obligatorios
	this.name;      				//Identificador del objeto arbol que debe ser unico
	this.markchk = false; 				//Define si va a tener checkbox los elementos o no
	this.onClick;					//Javascript que se ejecutará en todos los nodos. En caso de que uno tenga esta propiedad definida se ejecutará la suya
	this.verroot = false;				//Define si se visualiza la raiz
	this.colores;					//Array de colores por profundidad
	//Parametros opcionales
	this.is_dynamic = true;   		//Si el arbol es dinamico se puede actualizar en el acto, sin recargar la página
	this.useIcons = true;     		//Determina si se usan icionos o los caracteres de texto + y -
	iconPath = (arrayProps['icondir'] != null)? arrayProps['icondir'] : '';
    this.icons = {
		root        : iconPath+'/foldertree_base.gif',
		folder      : iconPath+'/foldertree_folder.gif',
		folderOpen  : iconPath+'/foldertree_folderopen.gif',
		node        : iconPath+'/foldertree_folder.gif',
		empty       : iconPath+'/foldertree_empty.gif',
		line        : iconPath+'/foldertree_line.gif',
		join        : iconPath+'/foldertree_pagina.gif',
		link        : iconPath+'/foldertree_empty.gif',
		joinBottom  : iconPath+'/foldertree_joinbottom.gif',
		plus        : iconPath+'/foldertree_plus.gif',
		plusBottom  : iconPath+'/foldertree_plusbottom.gif',
		minus       : iconPath+'/foldertree_minus.gif',
		minusBottom : iconPath+'/foldertree_minusbottom.gif',
		nlPlus      : iconPath+'/f_nlin_plus_snps.gif',
		nlMinus     : iconPath+'/f_nlin_minus_snps.gif',
		nlEmpty     : iconPath+'/f_nlin_empty_snps.gif'
	};
	//Parametros privados
	this._root; 					//Puntero al nodo raiz
	this._aNodes = [];				//Colección de todos los nodos del arbol
	this._lastSelected; 			//Puntero al ultimo nodo seleccionado
	this._selected; 				//Puntero al nodo seleccionado actualmente
	for (i in arrayProps)	{
		if (i.charAt(0) != '_')		{
			eval('this.'+i+' = arrayProps[\''+i+'\'];');
		}
	}
}
//****************************************************************************************
//****************************************************************************************
dFTree.prototype.draw = function() {
	if (!getObjectById("dftree_"+this.name))	{
		document.write('<div id="dftree_'+this.name+'"></div>');
	}
	if (this._root != null) 	{        
            this._root._draw();
            this._drawBranch(this._root._children);
	}
}
//****************************************************************************************
//Funcion recursiva para pintar todos los nodos hijos
//****************************************************************************************
dFTree.prototype._drawBranch = function(childrenArray) {
	var a=0;
	for (a;a<childrenArray.length;a++)	{
		childrenArray[a]._draw();
		this._drawBranch(childrenArray[a]._children);
	}
}
//****************************************************************************************
//Añade un nodo
//****************************************************************************************
dFTree.prototype.add = function(node,pid) {
	var auxPos;
	var addNode = false;
	//Compruebo que no exista un nodo con el mismo id
	if (typeof (auxPos = this._searchNode(node.id)) != "number") 	{
		// Busco el padre en el array de nodos
		if (typeof (auxPos = this._searchNode(pid)) == "number")		{
			node._parent = this._aNodes[auxPos]; //Asigno el padre
			if (!node.onClick) {
				node.onClick = this.onClick; //Comprobamos que el nodo no tenga evento y le asignamos el del arbol por defecto
			}
			node.profundidad = node._parent.profundidad + 1;
			this._aNodes[auxPos]._children[this._aNodes[auxPos]._children.length] = node; //Añado el nodo en la lista de los hijos del nodo padre
			addNode = true;
		}	else  {
			//if parent cannot be found and there is a tree root, ignores node
			if (this._root == null)	{
				this._root = node;
				this.profundidad = 1;
				addNode = true;
			}
		}
		if (addNode) {
			this._aNodes[this._aNodes.length] = node; //Añado el nodo a la lista de nodos del arbol
			/*
				Se supone que dicho nodo se añade dos veces, una dentro de la lista de los nodos hijos y otra dentro de la lista de los nodos del arbol
				!!SE PODRÏA VER LA POSIBILIDAD DE METER SOLO EN EL HIJO LA REFERENCIA A LA POSICIÖN QUE OCUPA DENTRO DEL ARRAY TOTAL Y ASÏ AHORRAR MEMORIA
				DADO QUE SOLO GUARDARIAMOS UN NUMERO Y NO UN NODO. AUNQUE A LO MEJOR NO MERECE LA PENA EL AHORRO Y EL CURRO QUE SUPONE
			*/
			node._myTree = this;
			if (this.is_dynamic)	{
				node._draw();
			}
		}
	} 
}
//****************************************************************************************
//Obtiene un nodo dado su id
//****************************************************************************************
dFTree.prototype.getNodeById = function(nodeid) {
	return this._aNodes[this._searchNode(nodeid)];
}
//****************************************************************************************
//Busca un nodo en la colección de nodos del arbol y devuelve su id
//****************************************************************************************
dFTree.prototype._searchNode = function(id) {
	var a=0;
	for (a;a<this._aNodes.length;a++) 	{
		if (this._aNodes[a].id == id) 	{
			return a;
		}
	}
	return false;
}
//****************************************************************************************
//****************************************************************************************
//****************************************************************************************
//Funciones axuiliares
//****************************************************************************************
//For multi-browser compatibility
//****************************************************************************************
function getObjectById(name) {   
    if (document.getElementById)   {
        return document.getElementById(name);
    }   else if (document.all)   {
        return document.all[name];
    }  else if (document.layers)   {
        return document.layers[name];
    }
    return false;
}
//****************************************************************************************
function imageHTML(src,attributes) {
	if (attributes != null)	{
		attributes = '';
	}
	return "<img "+attributes+" src=\""+src+"\">";
}
