/**
*	Constructor
*/
function NContent(w,h,baseURLImages) {
	//if ( arguments.length > 0 )
	this.init(w,h,baseURLImages);
}

/**
*	Constructor
*	@private
*/
NContent.prototype.init = function(width,contentHeight,baseURLImages) {
	if (typeof(width)=="undefined") width=244;
	if (typeof(contentHeight)=="undefined") contentHeight=200;
	if (typeof(baseURLImages)=="undefined") baseURLImages="";

	this.childrenArrayCount=0;
	this.childrenArray=new Array();

	// list of attribute names from this content node.
	this.attributeNames=new Array();
	this.attributeNamesCount=0;

	// list of ranges 
	this.rangesArray=new Array();
	this.rangesArrayCount=0;

	// Widths of generated tables in accordion
	this.FIRSTCOLWIDTH=16;
	this.BUTTONCOLWIDTH=30;
	this.TEXTWIDTH=145;
	this.ACCORDIONCONTENTWIDTH=width;
	this.TABLEWIDTH=this.ACCORDIONCONTENTWIDTH-16;
	this.ACCORDIONCONTENTHEIGHT=contentHeight;
	
	this.baseURLImages=baseURLImages;

};

/**
*	Carrega el toc.
*	@param {String} servletUrl La url del toc xml.
*	@param {String} targetDiv id del div on s'ha de posar el toc.
*	@param {String} backColor color de fons del toc.
*	@param {String} baseURLImages la url parcial on hi ha les imatges especificades que es mostraran al toc.
*/
NContent.prototype.loadToc = function(servletUrl,targetDiv,backColor,baseURLImages) {

	this.servletUrl=servletUrl;
	this.initToc(targetDiv,backColor,baseURLImages);

	this.sendRequest(this.servletUrl,this.processLegendResponse);

};

/**
*	Carrega el toc.
*	@param {String} servletUrl La url del toc xml.
*	@param {String} targetDiv id del div on s'ha de posar el toc.
*	@param {String} backColor color de fons del toc.
*	@param {String} baseURLImages la url parcial on hi ha les imatges especificades que es mostraran al toc.
*/
NContent.prototype.loadTocRemote = function(servletUrl,replaceArray,targetDiv,backColor,baseURLImages) {

	this.servletUrl=servletUrl;
	this.initToc(targetDiv,backColor,baseURLImages);

	if (typeof(Legend)=="undefined") alert("Falta script de DWR");
	
	Legend.getLegend(servletUrl,replaceArray,this.processDWRLegendResponse);

};

/**
*	Carrega el toc.
*	@param {String} servletUrl La url del toc xml.
*	@param {String} targetDiv id del div on s'ha de posar el toc.
*	@param {String} backColor color de fons del toc.
*	@param {String} baseURLImages la url parcial on hi ha les imatges especificades que es mostraran al toc.
*/
NContent.prototype.loadTocRemoteWithBase = function(servletUrl,replaceArray,targetDiv,backColor,baseURLImages) {

	this.servletUrl=servletUrl;
	this.initToc(targetDiv,backColor,baseURLImages);

	if (typeof(Legend)=="undefined") alert("Falta script de DWR");
	
	Legend.getLegendWithBaseXML(servletUrl,replaceArray,false,this.processDWRLegendResponse);
	

};

/**
*	Carrega el toc.
*	@param {String} servletUrl La url del toc xml.
*	@param {String} targetDiv id del div on s'ha de posar el toc.
*	@param {String} backColor color de fons del toc.
*	@param {String} baseURLImages la url parcial on hi ha les imatges especificades que es mostraran al toc.
*/
NContent.prototype.loadTocBaseWithRemote = function(servletUrl,replaceArray,targetDiv,backColor,baseURLImages) {

	this.servletUrl=servletUrl;
	this.initToc(targetDiv,backColor,baseURLImages);

	if (typeof(Legend)=="undefined") alert("Falta script de DWR");
	
	Legend.getLegendWithBaseXML(servletUrl,replaceArray,false,this.processDWRLegendResponse);

};

/**
*	
*	@private
*/
NContent.prototype.processDWRLegendResponse = function(data) {
	//alert("response\n"+data.xml);
	treeContent.processLegendResponse(treeContent,data);
}



/**
*	Inicialitza el toc.
*	@param {String} targetDiv id del div on s'ha de posar el toc.
*	@param {String} backColor color de fons del toc.
*	@param {String} baseURLImages la url parcial on hi ha les imatges especificades que es mostraran al toc.
*	@private
*/
NContent.prototype.initToc = function(targetDiv,backColor,baseURLImages) {
	
	if (typeof(baseURLImages)=="undefined") baseURLImages="";
	
	this.services=new Array(); // urls dels serveis wms i wfs

	this.setBackGroundcolor(backColor);
	this.baseURLImages=baseURLImages;
	this.targetDiv=targetDiv;

	this.deferredEvents = new Array();
	global_NContent_deferredEvents=this.deferredEvents;// global per no passar a tots els nodes

};

/**
*	NContent sendRequest
*	@private
*/
NContent.prototype.sendRequest = function(servletPath,processResponse) {
	try {
		
		DebugOut("NContent.sendRequest() "+servletPath ,INFO);
		var req = newXMLHttpRequest();

		// Set the handler function to receive callback notifications from the request object
		var handlerFunction = getReadyStateHandler(req, this, processResponse);
		req.onreadystatechange = handlerFunction;

		// Open an HTTP POST connection. Third parameter specifies request is asynchronous.
		req.open("GET", servletPath, true);

		// Specify that the body of the request contains form data
		req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		req.send("");
		
	}
	catch (e) {
		alert("Error a NContent.sendRequest()\n"+e.message);
	}
};


/**
*	Rep la resposta amb l'xml de la llegenda a carregar.
*	@private
*/
NContent.prototype.processLegendResponse = function(ncontent, responseXML) {
	try {
		//	DebugOut("NContent.processResponse XML:\n"+Sarissa.serialize(responseXML),DEBUG);
		
		var mainNode = responseXML.getElementsByTagName('main')[0];
		if (mainNode.childNodes[0].nodeName=="error") {
			alert("Error carregant llegenda:\n"+mainNode.childNodes[0].getAttribute("descripcio"));
		} else {
			ncontent.load(mainNode);
			ncontent.eventTreeLoadedCall();
		}
		
	}
	catch (e) {
		alert("Error a NContent.processLegendResponse()\n"+e.message);
	}
};

/**
*	loop through all the items in the init array and execute any functions
*	@private
*/
NContent.prototype.deferredEventsExecute = function(){
	try {
		for( var i=0; i < this.deferredEvents.length; i++ ){
			if( typeof this.deferredEvents[i] == "function" ) this.deferredEvents[i](this);
		}
	}
	catch (e) {
		alert("Error a NContent.deferredEventsExecute()\n"+e.message);
	}
}
 
/**
*	S'executa despres de carregar-se l'arbre a memòria.
*	@private
*/
NContent.prototype.eventTreeLoadedCall = function() {
	try {
		treeContent.populateToc(this.targetDiv);
		this.deferredEventsExecute();
		this.eventTreeLoaded();
	}catch (e) {
		alert("Error a NContent.eventTreeLoadedCall()\n"+e.message);
	}
};

/**
*	Metode que s'ha de sobreescriure per fer algun event abans de generar el codi html, però despres de carregar el toc a memòria.
*/
NContent.prototype.eventBeforePopulateToc = function() {};

 
/**
*	S'executa abans de generar l'html del toc.
*	@private
*/
NContent.prototype.eventPopulateTocCall = function() {
	try {
		this.loadConfigParams();
		this.eventBeforePopulateToc();
	}catch (e) {
		alert("Error a NContent.eventPopulateTocCall()\n"+e.message);
	}
};

/**
*	Metode que s'ha de sobreescriure si es vol executar algun event quan s'ha carregat l'arbre.
*/
NContent.prototype.eventTreeLoaded = function() {};

/**
*	Carrega l'xml i genera l'estructura de memòria.
*	@private
*/
NContent.prototype.load = function(xmlNode) {
	
	if(xmlNode.nodeName=="main") {
		// traverse childs recursively and adding them to array list
		this.type="main";
		for (var i=0;i<xmlNode.childNodes.length;i++) {
			var contentNode=xmlNode.childNodes[i];
			if (contentNode.nodeName=="persona") {
				this.loadUserConfig(contentNode);
			} else if (contentNode.nodeName=="block") {
				var objContent = new NContent(this.ACCORDIONCONTENTWIDTH,this.ACCORDIONCONTENTHEIGHT,this.baseURLImages);
				objContent.load(contentNode);
				this.addChild(objContent);
			} else if (contentNode.nodeName=="services") {
				this.loadServices(contentNode);
			} else if (contentNode.nodeName=="overviewMap") {
				this.loadOverviewMapConfig(contentNode);
			}
		}
	} else if(xmlNode.nodeName=="block") {
		//alert("block");
		// traverse childs recursively and adding them to array list
		this.type="block";
		// traverse attributes
		var attr=xmlNode.attributes;
		for (var i=0;i<attr.length;i++){
			this.addAttribute(attr[i].nodeName,attr[i].nodeValue);
		}
		for (var i=0;i<xmlNode.childNodes.length;i++) {
			var contentNode=xmlNode.childNodes[i];
			if (contentNode.nodeType == 4) {//CDATA
				this.cdata=contentNode.nodeValue;
				
			}else if (contentNode.nodeType != 3) {//TEXT_NODE
				var objContent = new NContent(this.ACCORDIONCONTENTWIDTH,this.ACCORDIONCONTENTHEIGHT,this.baseURLImages);
				objContent.load(contentNode);
				this.addChild(objContent);
			}
			
		}

	} else if(xmlNode.nodeName=="content") {

		// traverse attributes
		var attr=xmlNode.attributes;
		for (var i=0;i<attr.length;i++){
			this.addAttribute(attr[i].nodeName,attr[i].nodeValue);
		}

		// traverse childs(layers and ranges are treated the same!). GROUP.children->LAYER. LAYER.children->RANGE
		for (var i=0;i<xmlNode.childNodes.length;i++) {
			var contentNode=xmlNode.childNodes[i];
			if (contentNode.nodeType == 4) {//CDATA
				this.cdata=contentNode.nodeValue;

			}else if (contentNode.nodeType != 3) {//TEXT_NODE
				var objContent = new NContent(this.ACCORDIONCONTENTWIDTH,this.ACCORDIONCONTENTHEIGHT,this.baseURLImages);
				objContent.load(contentNode);
				this.addChild(objContent);
			} 
		}

	} else return null;
	
	
};

/**
*	NContent addChild
*	@private
*/
NContent.prototype.addChild = function(ncontent) {
	this.childrenArray[this.childrenArrayCount]=ncontent;
	ncontent.parentNodeRef=this; // save reference to the parent node!
	this.childrenArrayCount=this.childrenArrayCount+1;
};

/**
*	NContent addSiblingBefore
*	@private
*/
NContent.prototype.addSiblingBefore = function(ncontent) {
	this.addSibling(ncontent,false);
}

/**
*	NContent addSiblingAfter
*	@private
*/
NContent.prototype.addSiblingAfter = function(ncontent) {
	this.addSibling(ncontent,true);
}

/**
*	NContent addSibling
*	isAfter==true :: insert after
*	isAfter==false :: insert before
*	@private
*/
NContent.prototype.addSibling = function(ncontent,isAfter) {

	var p=this.parentNode();

	// busquem la posicio on ha d'anar el nou
	var i=0;
	var trobat=false;
	while ((i<p.childrenArrayCount) && (!trobat)) {
		if (p.childrenArray[i].equals(this)) {
			trobat=true;
		} else i++;
	}

	if (isAfter) i++;

	// afegim element buit al final
	var empty =new NContent(this.ACCORDIONCONTENTWIDTH,this.ACCORDIONCONTENTHEIGHT,this.baseURLImages);
	p.addChild(empty);

	// recorrem de l'ultim fins a la posicio del nou
	for (var j=p.childrenArrayCount-1; (j>=i && j>0); j--) {
		//DebugOut(">>for j=" + j + "\t" + p.childrenArray[j] + "  <--  " + p.childrenArray[j-1] , DEBUG);
		p.childrenArray[j].replace(p.childrenArray[j-1].clone());
	}

	// actualitzem el nou
	p.childrenArray[i].replace(ncontent);
	
};


/**
*	Compara si dos NContents tenen el mateix nom i titol.
*/
NContent.prototype.equals = function(ncontent) {
	if (this.name!=ncontent.name) return false;
	if (this.title!=ncontent.title) return false;
	return true;
}

/**
*	Retorna la referencia al node pare.
*/
NContent.prototype.parentNode = function() {
	return this.parentNodeRef;
};

/**
*	Retorna el numero de fills del node actual.
*/
NContent.prototype.getChildCount = function() {
	return this.childrenArrayCount;
}

/**
*	NContent loadUserConfig(contentNode);
*		loads the user privileges from the xml node

*  <persona id="ADMDES" nom="Administrador desenvolupament" xmin="1" xmax="3" ymin="2" ymax="4">
*  <funcional id="ADM" nom="Administrador"/>
*  <organics>
*	<organic id="P2" nom="Departament 2"/>
*	<organic id="P3" nom="Departament 3"/>
*	<organic id="P4" nom="Departament 4"/>
*	<organic id="P5" nom="Departament 5"/>
*  </organics>
*  </persona>
*	@private
*/
NContent.prototype.loadUserConfig = function(node) {
	try {
		this.conf_UserId=node.getAttribute("id");
		this.conf_UserName=node.getAttribute("nom");

		this.conf_xmin=node.getAttribute("xmin");
		this.conf_xmax=node.getAttribute("xmax");
		this.conf_ymin=node.getAttribute("ymin");
		this.conf_ymax=node.getAttribute("ymax");

		for (var i=0;i<node.childNodes.length ;i++ ) {
			var c=node.childNodes[i];
			switch (c.nodeName)
			{
			case "funcional":
				this.conf_UserType=c.getAttribute("id");
				this.conf_UserTypeName=c.getAttribute("nom");
				break;
			case "organics":
				break;
			}
		}
		return;
	}
	catch (e) {
		alert("Error a NContent.prototype.loadUserConfig()\n"+e.message);
	}
}

/**
*	Carrega la configuració del mapa de situació.
*	@private
*/
NContent.prototype.loadOverviewMapConfig = function(node) {
	try {
		this.overviewMap_service=node.getAttribute("service");
		this.overviewMap_layers=node.getAttribute("layers");
		this.overviewMap_format=node.getAttribute("format");

	}
	catch (e) {
		alert("Error a loadOverviewMapConfig()\n"+e.message);
	}
}

/**
*	Carrega la informació dels serveis de l'xml
*	@private
*/
NContent.prototype.loadServices = function(node) {
	try {
		var count=0;
		this.services=new Array();
		for (var i=0;i<node.childNodes.length ;i++ ) {
			var c=node.childNodes[i];
			if (c.nodeType==1 && c.nodeName=="service") {
				
				var id=c.getAttribute("id");
				
				var type=c.getAttribute("type");
				var url=c.getAttribute("url");
				var transparency=c.getAttribute("transparency");
				var querylayers=c.getAttribute("querylayers");
				var printlayers=c.getAttribute("printlayers");
				var printdpi=c.getAttribute("printdpi");
				var printurl=c.getAttribute("printurl");
				var desc=c.getAttribute("desc");
				var url_transparent=c.getAttribute("url_transparent");
				var url_bgcolor=c.getAttribute("url_bgcolor");
				var url_exception=c.getAttribute("url_exception");
				var url_style=c.getAttribute("url_style");
				
				if (id!="DEFAULT" && id!="default") { // quan l'id sigui DEFAULT no volem que surti
					if (printurl==null || typeof(printurl)=="undefined") printurl="";
					if (printdpi==null || typeof(printdpi)=="undefined") printdpi="";
					
					if (type=="wms" || type=="wfs") {
						DebugOut("> NContent.services id: "+ id + " type: " + type + " url: " + url,DEBUG );
						this.services[count]=new Object();
						this.services[count].id=id;
						this.services[count].type=type;
						this.services[count].url=url;
						this.services[count].transparency=transparency;
						this.services[count].querylayers=querylayers;
						this.services[count].printdpi=printdpi;
						this.services[count].printurl=printurl;
						this.services[count].desc=desc;
						this.services[count].order=count;
						this.services[count].url_transparent=url_transparent;
						this.services[count].url_bgcolor=url_bgcolor;
						this.services[count].url_exception=url_exception;
						this.services[count].url_style=url_style;
						count++;
					
					} else if (type=="info") {
						this.serviceInfo=new Object();
						this.serviceInfo.id=id;
						this.serviceInfo.type=type;
						this.serviceInfo.url=url;
						this.serviceInfo.querylayers=querylayers;
					}
				}
			}
		}
		return;
	}
	catch (e) {
		alert("Error a NContent.prototype.loadUserConfig()\n"+e.message);
	}
}

/**
*	Reordena els serveis a partir del valor de "order".
*/
NContent.prototype.sortServices = function() {
	try {
		var compareFunc=function(a,b) {
			if (a.order<b.order) return -1;
			if (a.order>b.order) return 1;
			return 0;
		}
		this.services.sort(compareFunc);

	}
	catch (e) {
		alert("Error a NContent.sortServices()\n"+e.message);
	}
}

/**
*	Retorna l'user id.
*/
NContent.prototype.getUserId = function() {
	try{
		return this.conf_UserId;
	}
	catch (e) {alert("Error: "+e);}
}

/**
*	Retorna el nom de l'usuari.
*/
NContent.prototype.getUserName = function() {
	try{
		return this.conf_UserName;
	}
	catch (e) {alert("Error: "+e);}
}

/**
*	Retorna el nivell funcional de l'usuari
*/
NContent.prototype.getUserType = function() {
	try{
		return this.conf_UserType;
	}
	catch (e) {alert("Error NContent.prototype.getUserType()\n "+e);}
}

/**
*	Retorna un fill.
*	@private
*/
NContent.prototype.getChild = function(num) {
	if (num>=this.childrenArrayCount) {
		alert("Error: NContent.prototype.getChild.\nItem out of range");
		return null;
	}
	return this.childrenArray[num];
}


/**
*	Afegeix un atribut al node actual.
*	@private
*/
NContent.prototype.addAttribute = function(attrName,attrValue) {
	try {
		
		eval("this." + attrName + "='" + attrValue.replace(/\'/g,"&#39;") + "';");
		this.attributeNames[this.attributeNamesCount]=attrName;
		this.attributeNamesCount++;
	}
	catch (e) {
		alert("Error a NContent.addAttribute()\n"+e.message);
	}
}

/**
*	Indica si l'atribut amb el nom del parametre existeix.
*	@param {String} attrName nom de l'atribut
*	@return {boolean}
*/
NContent.prototype.attributeExists = function(attrName) {
	var ret=eval("this."+attrName);
/*	alert("attributeExists\nattrName: " +attrName 
					   + "\nvalue: " + ret
					   + "\ntypeof(ret)!=undefined: " + (typeof(ret)!="undefined"));*/
	if (typeof(ret)!="undefined") return true;
	else return false;
};

/**
*	NContent getAttributeValue
*/
NContent.prototype.getAttributeValue = function(attrName) {
	if (this.attributeExists(attrName)) return eval("this."+attrName);
	else return null;
};

/**
*	Fa el mateix que getAttributeValue pero si l'atribut no existeix retorna un string "0".
*	@private
*/
NContent.prototype.getAttributeValueNotUndefined = function(attrName) {
	var v=this.getAttributeValue(attrName);
	if (typeof(v)=="undefined" || v==null) return "0";
	else return v;
};

/**
*	NContent toString
*/
NContent.prototype.toString = function() {
	return "(" + this.title + ") TYPE:" + this.type + " OPEN:" + this.open;
};

/**
*	NContent toStringTree
*
*	Creates a string with the structure of the tree.
*
*/
NContent.prototype.toStringTree = function(depth) {
	if (typeof(depth)=="undefined") depth=0;
	var spaces=this.getSpaces(depth,"  ");

	var str="\n"+spaces+"<NODE>";
	// list attributes and its values
	for (var j=0;j<this.attributeNamesCount;j++){
		str+="\n"+spaces+spaces+this.attributeNames[j]+" = "+eval("this."+this.attributeNames[j]);
	}
	// traverse childs
	for (var j=0;j<this.childrenArrayCount;j++){
		str+=this.getChild(j).toStringTree(depth+1);
	}

	str+="\n"+spaces+"</NODE>";

	return str;
};

/**
*	NContent getSpaces
*	@private
*/
NContent.prototype.getSpaces = function(depth,spaceChar) {
	var ret="";
	for (var i=0;i<=depth;i++) ret+=spaceChar;
	return ret;
}


/**
*	NContent getHTMLGroup_init
*	@private
*	nodeLevel:	level of this node. Used to create unique div ids.
*	nodeId:		the id of the div, fex: node_0_1_21
*	nodeTitle:	The text to be shown.
*	nodeDesc:	A description of this group.
*	isOpen:		Boolean than indicates if the group must be open or closed.
*	visible:	Boolean than indicates is visible by default.
*	@private
*/
NContent.prototype.getHTMLGroup_init = function(nodeLevel,nodeId,nodeTitle,nodeDesc,isOpen,visible) {
	var visibleStyles="";
	if (visible=="on") var visibleImg="checked_on.gif";
	else if (visible=="mid") var visibleImg="checked_mid.gif";
	else if (visible=="dis") {
		var visibleImg="checked_disabled.gif";
		visibleStyles="visibility:hidden;";
	}else var visibleImg="checked_off.gif";

	if (isOpen) {
		var openImg="expanded.gif";
		var display="inline";
	} else {
		var openImg="collapsed.gif";
		var display="none";
	}

	if (typeof(nodeDesc)=='undefined') nodeDesc=nodeTitle;
	
	var str=new Array();
	str.push('<div id="node_'+nodeId+'" style="display:inline;" >');
	str.push('<table border="0" cellspacing="0" cellpadding="0" width="'+this.TABLEWIDTH+'px"><tr>');
	str.push('	<td width="'+this.FIRSTCOLWIDTH+'px">');
	str.push('		<img id="node_'+nodeId+'_open" src="img/treeview/'+openImg+'" alt="" onClick="javascript: treeNodeClick(\'node_'+nodeId+'\');" style="cursor:pointer">');
	str.push('	</td>');
	str.push('	<td width="20px" align="center">');
	str.push('		<img id="node_'+nodeId+'_image" src="img/treeview/folder.gif" alt="">');
	str.push('	</td>');
	str.push('	<td>');
	//str.push('		<font class="treeGroupTitle">'+nodeTitle+'</font>');
	str.push('		<div onClick="javascript:showTooltipGroup(event,\'node_'+nodeId+'\');" class="treeGroupTitle" style="text-overflow:ellipsis;overflow:hidden;white-space:nowrap; width:'+this.TEXTWIDTH+'px" class="treeLevelTitle" title="'+nodeDesc+'">'+nodeTitle+'</div>');//TODO: Width fixat perque talli text llarg. Alternatives?
	str.push('	</td>');
	str.push('	<td align="right" width="'+this.BUTTONCOLWIDTH+'px">');
	str.push('		<img id="node_'+nodeId+'_visible" src="img/treeview/'+visibleImg+'" onClick="javascript: treeVisibleClick(\'node_'+nodeId+'\');" style="cursor:pointer; '+visibleStyles+'">');
	str.push('<img src="img/treeview/empty.gif" alt="" width="4" height="1">');
	//str.push('		<img id="node_'+nodeLevel+'_config" src="img/treeview/config.gif" alt="configurar" onClick="javascript: treeConfigClick(\'node_'+nodeLevel+'\');">');
	str.push('	</td>');
	str.push('</tr></table>');
	str.push('');
	str.push('<div id="node_'+nodeId+'_content" style="display:'+display+';">');
	return str.join("");
}

/**
*	Creates a layer node that will have ranges inside.
*				
*	nodeLevel:	level of this node. Used to create unique div ids.
*	nodeTitle:	The text to be shown.
*	nodeDesc:	A description of this group.
*	isOpen:		Boolean than indicates if the group must be open or closed.
*	isVisible:	Boolean than indicates is visible by default.
*	@private
*
*/
NContent.prototype.getHTMLLayer_init = function(nodeLevel,nodeId,nodeTitle,nodeDesc,isOpen,isVisible,isConf,geometry,geomColor,imagepath) {
	//DebugOut("getHTMLLayer_init imagepath:"+imagepath,DEBUG);
	var teFiltreComu=this.getAttributeValueNotUndefined("commonfilter_set")=="1" && this.getAttributeValue("commonfilter_value")!="";
	var teFiltrePers=this.getAttributeValueNotUndefined("personalfilter_set")=="1" && this.getAttributeValue("personalfilter_value")!="";
	var teFilterCols=this.getAttributeValueNotUndefined("filtercolumns")>0;
	
	var visibleImg="checked";
	if (isVisible) visibleImg+="_on";
	else visibleImg+="_off";
	if (teFiltreComu || teFiltrePers) visibleImg+="_filtered";
	else {
		if (teFilterCols) visibleImg+="_filtrable";
		else visibleImg+="";
	}
	visibleImg+=".gif";

	if (isOpen) var display="inline";
	else var display="none";

	if (isConf) var configImg="config.gif"; 
	else var configImg="noconfig.gif";

	/* BEFORE USING SAME SYMBOL 4 ALL LAYERS WITH RANGES
	switch (geometry){
		case "point": var geomImg="img/treeview/point.gif";break;
		case "line": var geomImg="img/treeview/line.gif";break;
		case "polygon": var geomImg="img/treeview/polygon.gif";break;
		default:var geomImg="img/treeview/layer.gif";break;
	}

	// if no color is defined show white bg.
	if (typeof(geomColor)!="undefined") var bgcolor=geomColor;
	else var bgcolor="#FFFFFF";
	*/
	var geomImg="img/treeview/layer_theme.gif";
	var bgcolor=this.getBackGroundcolor();

	if (typeof(nodeDesc)=='undefined') nodeDesc=nodeTitle;

	var str=new Array();
	str.push('<div id="node_'+nodeId+'" style="display:inline;" >');
	str.push('<table border="0" cellspacing="0" cellpadding="0" width="'+this.TABLEWIDTH+'px"><tr>');
	str.push('	<td width="'+eval(this.FIRSTCOLWIDTH*nodeLevel)+'px">');
	str.push('		<img id="node_'+nodeId+'_open" src="img/treeview/empty.gif" alt="" width="'+eval(this.FIRSTCOLWIDTH*nodeLevel)+'px" height="1px">');
	str.push('	</td>');
	str.push('	<td width="20px" align="center">');
	str.push('		<table border="0" cellspacing="0" cellpadding="0" width="15px" height="15px" bgcolor="'+bgcolor+'"><tr><td align="center"><img id="node_'+nodeId+'_image" src="'+geomImg+'" style="max-width:15px; max-height:15px;" alt="" onClick="javascript: treeNodeClick(\'node_'+nodeId+'\');" style="cursor:pointer"></td></tr></table>');
	str.push('	</td>');
	str.push('	<td>');
	str.push('		<div onClick="javascript:showTooltipGroup(event,\'node_'+nodeId+'\');" style="text-overflow:ellipsis;overflow:hidden;white-space:nowrap; width:'+this.TEXTWIDTH+'px" class="treeLevelTitle" title="'+nodeDesc+'">'+nodeTitle+'</div>');//TODO: Width fixat perque talli text llarg. Alternatives?
	str.push('	</td>');
	str.push('	<td align="right" width="'+this.BUTTONCOLWIDTH+'px">');
	str.push('		<img id="node_'+nodeId+'_visible" src="img/treeview/'+visibleImg+'" onClick="javascript: treeVisibleClick(\'node_'+nodeId+'\');" style="cursor:pointer">');
	str.push('<img src="img/treeview/empty.gif" alt="" width="4" height="1">');
	//str.push('		<img id="node_'+nodeLevel+'_config" src="img/treeview/config.gif" alt="configurar" onClick="javascript: treeConfigClick(\'node_'+nodeLevel+'\');">');
	str.push('	</td>');
	str.push('</tr></table>');
	str.push('<div id="node_'+nodeId+'_content" style="display:'+display+';">');
	return str.join("");
}

/**
*	NContent getHTMLGroup_end
*	@private
*/
NContent.prototype.getHTMLGroup_end = function() {
	var str='';
	str+='</div>';// el de node_1_content
	str+='</div>';// el de node_1
	return str;
}

/**
*	Genera l'html d'un node layer sense rangs, o bé un node que representa un rang.
*	@private
*	@param {boolean} layerIsRange Boolean that indicates if this is a range or only a layer
*/
NContent.prototype.getHTMLLayer = function(nodeLevel,nodeId,layerIsRange,nodeTitle,nodeDesc,isVisible,isConf,geometry,geomColor,imagepath) {

	var teFiltreComu=this.getAttributeValueNotUndefined("commonfilter_set")=="1";
	var teFiltrePers=this.getAttributeValueNotUndefined("personalfilter_set")=="1";
	var teFilterCols=this.getAttributeValueNotUndefined("filtercolumns")>0;
	
	var visibleImg="checked";
	if (isVisible) visibleImg+="_on";
	else visibleImg+="_off";
	if (teFiltreComu || teFiltrePers) visibleImg+="_filtered";
	else {
		if (teFilterCols) visibleImg+="_filtrable";
		else visibleImg+="";
	}
	visibleImg+=".gif";

	if (isConf) {
		var configImg="config.gif";
		var imgStyle='style="cursor:pointer"';
	}else{
		var configImg="empty.gif";
		var imgStyle='';
	}

	// if no color is defined show white bg.
	if (typeof(geomColor)!="undefined") var bgcolor=geomColor;
	else var bgcolor=this.getBackGroundcolor();

	switch (geometry){
		case "point": var geomImg="img/treeview/point.gif";break;
		case "line": var geomImg="img/treeview/line.gif";break;
		case "polygon": var geomImg="img/treeview/polygon.gif";break;
		//case "raster": var geomImg="raster.gif";break;
		default:var geomImg="img/treeview/layer.gif";break;
	}
	if (layerIsRange) {
		var geomImg="img/treeview/range.gif";
		var jsTooltip='';
	} else {
		var jsTooltip='onClick="javascript:showTooltipGroup(event,\'node_'+nodeId+'\');"';
	}

	if (imagepath!="") {
		bgcolor=this.getBackGroundcolor();// canviem color per evitar que si és més petit de 15x15 es vegi al voltant un color raro.

		if (imagepath.indexOf("/")==0 || imagepath.indexOf("http:")==0) geomImg=imagepath;
		else geomImg=this.baseURLImages+imagepath;
	}
	DebugOut("this.baseURLImages: "+this.baseURLImages+"    geomImg: " + geomImg,DEBUG);
	if (typeof(nodeDesc)=='undefined') nodeDesc=nodeTitle;
	
	var str=new Array();
	str.push('<div id="node_'+nodeId+'" style="display:inline;">');
	str.push('<table border="0" cellspacing="0" cellpadding="0" width="'+this.TABLEWIDTH+'px"><tr>');
	str.push('	<td width="'+eval(this.FIRSTCOLWIDTH*nodeLevel)+'px">');
	str.push('		<img id="node_'+nodeId+'_open" src="img/treeview/empty.gif" alt="">');
	str.push('	</td>');
	str.push('	<td width="20px" align="center">');
	// to paint the object we set the color to the table bg and adjust it to the image size.
	str.push('		<table border="0" cellspacing="0" cellpadding="0" width="15px" height="15px" bgcolor="'+bgcolor+'"><tr><td align="center"><img id="node_'+nodeId+'_image" src="'+geomImg+'" style="max-width:15px; max-height:15px;" alt=""></td></tr></table>');
	str.push('	</td>');
	str.push('	<td>');
	//str.push('		<font class="treeLevelTitle">'+nodeTitle+'</font>');
	str.push('		<div '+jsTooltip+' style="text-overflow:ellipsis;overflow:hidden;white-space:nowrap; width:'+this.TEXTWIDTH+'px" class="treeLevelTitle" title="'+nodeDesc+'">'+nodeTitle+'</div>');//TODO: Width fixat perque talli text llarg. Alternatives?
	str.push('	</td>');
	str.push('	<td align="right" width="'+this.BUTTONCOLWIDTH+'px">');
	if (!layerIsRange) {
		str.push('		<img id="node_'+nodeId+'_visible" src="img/treeview/'+visibleImg+'" onClick="javascript: treeVisibleClick(\'node_'+nodeId+'\');" style="cursor:pointer">');
	}
	//BOTO CONFIGURAR:str.push('<img id="node_'+nodeId+'_config" src="img/treeview/'+configImg+'" alt="configurar" onClick="javascript: treeConfigClick(\'node_'+nodeId+'\');" '+imgStyle+'>');
	str.push('<img src="img/treeview/empty.gif" alt="" width="4" height="1">');
	str.push('	</td>');
	str.push('</tr></table>');

	str.push('</div>');

	return str.join("");
}

/**
*	Genera el toc html i el posa al div passat per paràmetre.
*	@param {String} divId l'id del div.
*/
NContent.prototype.populateToc = function(divId) {
	this.eventPopulateTocCall();
	try {		
		document.getElementById(divId).innerHTML = treeContent.getHTMLTree(1);
	}
	catch (e) {
		alert("Error a NContent.populateToc()\n"+e.message);
	}
}

/**
*	Genera el codi html per l'arbre d'aquest node i els seus descendents.
*	@param {Number}	level identation level
*	@param {String}	parentNodeId path to this node. format: 0_0, 0_0_0, 0_0_1, 0_0_1_5,... 
*	@param {Number}	openBlockId [number|undefined]: block number forced to be open. If undefined then uses the xml open attribute of the block
*	@param {boolean}	isMultivalue [true/false]: boolean than indicates if this block is multivalue
*	@private
*/
NContent.prototype.getHTMLTree = function(level,parentNodeId,openBlockId,isMultivalue) {
	if (typeof(level)=="undefined") level=0;
	if (typeof(parentNodeId)=="undefined") parentNodeId="";
	if (typeof(isMultivalue)=="undefined") isMultivalue=false;
	
	var str=new Array();

	if (this.type=="group") {

		var groupIsOpen=(this.open=="1");
		// special case: if multivalue then checkbox disabled:
		if (!isMultivalue) var groupVisible="dis";
		else var groupVisible=this.getVisibility();
		str.push(this.getHTMLGroup_init(level+1,parentNodeId,this.title,this.desc,groupIsOpen,groupVisible));

		for (var i=0;i<this.childrenArrayCount;i++){
			var child=this.getChild(i);
			str.push(child.getHTMLTree(level+1,parentNodeId+"_"+i,null,isMultivalue));
		}
		str.push(this.getHTMLGroup_end());
	}
	
	else if (this.type=="layer") {

		if (this.childrenArrayCount==0) {//without ranges/tematic.
			var layerIsVisible=(this.visible=="1");
			var layerIsConf=(this.configurable=="1");
			this.interfaceDivId="node_"+parentNodeId;// save div id of this node
			str.push(this.getHTMLLayer(level,parentNodeId,false,this.title,this.desc,layerIsVisible,layerIsConf,this.geometry,this.color,this.imagepath));

		} else {//with ranges
			var layerIsOpen=(this.open=="1");
			var layerIsVisible=(this.visible=="1");
			var layerIsConf=(this.configurable=="1");
			this.interfaceDivId="node_"+parentNodeId;// save div id of this node
			str.push(this.getHTMLLayer_init(level,parentNodeId,this.title,this.desc,layerIsOpen,layerIsVisible,layerIsConf,this.geometry,this.color,this.imagepath));

			for (var i=0;i<this.childrenArrayCount;i++){
				var child=this.getChild(i);
				str.push(child.getHTMLTree(level+1,parentNodeId+"_"+i,null,isMultivalue));
			}
			str.push(this.getHTMLGroup_end());
		}
	}

	else if (this.type=="range") {

		var layerIsVisible=(this.visible=="1");
		var layerIsConf=(this.configurable=="1");
		if (this.title!="") var theTitle=this.title;
		else var theTitle=this.minvalue+".."+this.maxvalue;
		str.push(this.getHTMLLayer(level+1,parentNodeId,true,theTitle,this.desc,layerIsVisible,layerIsConf,this.geometry,this.color,this.imagepath));
	}

	else if (this.type=="html") {
		
		str.push('<div id="'+this.divid+'" style="display:inline;">');
		str.push(this.cdata);
		str.push('</div>');

		try {
			// important: hem de passar-ho amb un var local pq sino seria undefined.
			var sourceurl=this.sourceurl;
			var targetdiv=this.divid;
			var obj=this;

			// guardem l'event de carregar el contingut
			global_NContent_deferredEvents[global_NContent_deferredEvents.length] = function(rootNode) {
				//alert("deferred " + sourceurl + "  to Div: "+ targetdiv);

				obj.sendRequest(sourceurl,loadResponseToDiv);
			}
		}
		catch (e) { alert("error creating deferred call:\n"+e.message);
		}
		
	} 

	else if (this.type=="info") {
		
		str.push('<div id="'+this.divid+'" style="display:inline;">');
		str.push(this.cdata);
		str.push('</div>');
	} 

	else if (this.type=="config") {
		
		str.push('<div id="'+this.divid+'" style="display:inline;">');
		str.push(this.cdata);
		str.push('</div>');

		var targetdiv=this.divid;
		var obj=this;
		// guardem l'event de carregar el contingut
		global_NContent_deferredEvents[global_NContent_deferredEvents.length] = function(rootNode) {

			obj.initLayersConfig(rootNode,targetdiv);
		}
	} 

	else if (this.type=="block") {
		var isMultivalue=this.getAttributeValue("multivalue")=="1";

		for (var i=0;i<this.childrenArrayCount;i++){
			var child=this.getChild(i);	
			str.push(child.getHTMLTree(level,parentNodeId+i,null,isMultivalue));
		}
	} 

	else if (this.type=="main") {
		var hasOpen=false;
		str.push('<dl class="accordion" style="width:100%;">');
		for (var i=0;i<this.childrenArrayCount;i++){
			var child=this.getChild(i);
			if (child.type=="block" || child.type=="html" || child.type=="info" || child.type=="config" ) {
				str.push('<dt id="dt_'+i+'" onmousedown="treeBlockClick('+i+');"><div class="">'+child.title+'</div>');
				if (child.attributeExists("buttonUrl")) str.push('<div class="dt_button" onclick="javascript:window.open(\''+child.getAttributeValue("buttonUrl")+'\');"><img src="'+child.getAttributeValue("buttonImageUrl")+'" alt="" title="'+child.getAttributeValue("buttonTitle")+'"/></div>');
				str.push('</dt>');
				
				ui_accordion.contentHeight=this.ACCORDIONCONTENTHEIGHT+"px";
				if (typeof(openBlockId)!='undefined') {
					// passed a block number that has to be opened
					if (openBlockId!=i || hasOpen) {
						str.push('<dd id="node_'+i+'" style="overflow:visible; height:0px; display:none; padding:2px;" class="default_close">');
					}else {
						str.push('<dd id="node_'+i+'" style="overflow:auto; overflow-x: hidden; display:block; height:'+this.ACCORDIONCONTENTHEIGHT+'px; width:'+this.ACCORDIONCONTENTWIDTH+'px; padding:2px;">');
						hasOpen=true;
					}
				} else {
					if (child.open=="1" && !hasOpen) {
						str.push('<dd id="node_'+i+'" style="overflow:auto; overflow-x: hidden; display:block; height:'+this.ACCORDIONCONTENTHEIGHT+'px; width:'+this.ACCORDIONCONTENTWIDTH+'px; padding:2px;">');
						hasOpen=true;
					}else {
						str.push('<dd id="node_'+i+'" style="overflow:visible; height:0px; display:none; padding:2px;" class="default_close">');
					}
				} 
				var divHeight=this.ACCORDIONCONTENTHEIGHT;
				if (child.type=="block") {
					//str.push('<div class="transpDiv">transparència:<img alt="" src="library/slider/sliderbg.gif" onMouseOver="javascript:transparencyShow(this,'+i+');"/></div>');
					//divHeight=divHeight-30;// ajustar-ho segons les mides de lo de transp. pq no surti scroll
				}

			//	str.push('<div style="height:'+divHeight+'px; width:'+this.ACCORDIONCONTENTWIDTH+'px; overflow:auto; display:block;">');
				str.push('<div style="height:'+divHeight+'px; width:100%; overflow:auto; overflow-x: hidden; display:block;" class="colorScrollbar">');
				if (child.attributeExists("msg")) str.push('	<small>'+child.getAttributeValue("msg")+'</small>');
				str.push(child.getHTMLTree(level,""+i+"_",null,isMultivalue));
				str.push('</div>');
				
				str.push('</dd>');
			} //else alert("iep!: " + child + child.type);
		}
		str.push('</dl>');

	
	} //else alert("Tipus desconegut: "+this.toString());

	return str.join("");
}

/**
*	Retorna un boolea que indica si aquest NContent te un paràmetre de multivalue a 1. 
+
*	multivalue=1 : Dins d'aquest bloc, hi pot haver més d'un layer actiu a la vegada.
*	multivalue=0 : Dins d'aquest bloc només pot haver-hi un layer actiu a la vegada.
*	@return {boolean}
*/
NContent.prototype.isMultiValue = function() {
	var ret=this.getAttributeValue("multivalue");
	if (ret!=null && ret=="1") return true;
	else return false;
}

/**
*	Retorna el block al que pertany el node amb l'id passat per parametre.
*	@param {String} nodeId L'identificador del node.
*/
NContent.prototype.getBlockNode = function(nodeId) {
	var pathArray=nodeId.split('_');
	return this.getChild(pathArray[1]);
}

/**
*	Retorna el block al que pertany el node amb l'id passat per parametre.
*	@param {String} nodeId L'identificador del node.
*/
NContent.prototype.getNextSiblingBlockNode = function(nodeId) {
	var pathArray=nodeId.split('_');
	return this.getChild(parseInt(pathArray[1])+1);
}

/**
*	Retorna el block al que pertany el node amb l'id passat per parametre.
*	@param {String} nodeId L'identificador del node.
*/
NContent.prototype.getPreviousSiblingBlockNode = function(nodeId) {
	var pathArray=nodeId.split('_');
	return this.getChild(parseInt(pathArray[1])-1);
}

/**
*	Returns the node corresponding to the id path "nodeId". Ex: 0_0_3.
*	@return {NContent}
*/
NContent.prototype.getContentNode = function(nodeId) {
	var pathArray=nodeId.split('_');
	return this.getContentNodeRecursive(pathArray,1);
}

/**
*	NContent getContentNode
*	@private
*/
NContent.prototype.getContentNodeRecursive = function(pathArray,index) {
	//alert(pathArray + "\nindex: " + index + "\n" + pathArray[index]);
	if (pathArray.length==index) return this;//end condition of the recursive call
	else return this.getChild(pathArray[index]).getContentNodeRecursive(pathArray,index+1);
}

/**
*	Retorna el node de l'arbre que el valor de l'atribut 'name' coincideix amb el parametre donat.
*	@param {String} nodeName Nom de l'atribut name a buscar
*	@return NContent
*/
NContent.prototype.getContentNodeByName = function(nodeName) {
	try {	
		return this.getContentNodeByNameRecursive(nodeName);
	}
	catch (e) {
		alert("error\n"+e.message);
		return null;
	}
}

/**
*	NContent getContentNodeByNameRecursive
*	@return NContent
*	@private
*/
NContent.prototype.getContentNodeByNameRecursive = function(nodeName) {
	//DebugOut("getContentNodeByNameRecursive: "+nodeName+"\n\n" + this.getAttributeValue('name'),INFO);
	if (this.getAttributeValue("name")==nodeName) return this;//end condition of the recursive call
	else {
		var found=false; var i=0;
		while (!found && i<this.getChildCount()) {
			var c=this.getChild(i).getContentNodeByNameRecursive(nodeName);
			if (c!=null) return c; 
			i++;
		}
	}
	return null;
}

/**
*	Especifica si el bloc actual esta desplegat.
*	@param {boolean} isOpen
*/
NContent.prototype.setOpen = function(isOpen) {
	if (isOpen) this.open="1";
	else  this.open="0";
}

/**
*	Modifica la visibilitat d'aquest node i tots els seus descendents.
*	@param {boolean} isVisible Nou valor de la visibilitat
*/
NContent.prototype.setVisible = function(isVisible) {
	this.setVisibleRecursive(isVisible);
}

/**
*	Modifica la visibilitat d'aquest node i tots els seus descendents. Crida recursiva.
*	@private
*/
NContent.prototype.setVisibleRecursive = function(isVisible) {
	//DebugOut("setVisibleRecursive: "+this.toString());
	
	if (this.type=="range") return;

	if (isVisible) this.visible="1";
	else this.visible="0";

	for (var i=0;i<this.childrenArrayCount;i++) {
		this.childrenArray[i].setVisibleRecursive(isVisible);
	}
	return;
}

/**
*	Modifica la visibilitat d'aquest node i tots els seus descendents. Posa tots els nodes a no visible excepte els que
*	el nom coincideixi amb algun dels de la llista que ens passen per paràmetre.
*	@param {String} nameList llista de noms.
*	@param {String} separador de la llista de noms. Per defecte utilitza el caràcter '#'.
*/
NContent.prototype.setVisibility = function(nameList,separador) {
	if (typeof(separador)=="undefined") separador="#";
	var nameListArray=nameList.split(separador);
	this.setVisibilityRecursive(nameListArray);
}

/**
*	Modifica la visibilitat d'aquest node i tots els seus descendents. Posa tots els nodes a no visible excepte els que
*	el nom coincideixi amb algun dels de la llista que ens passen per paràmetre.
*	@param {String} nameList llista de noms.
*	@param {String} separador de la llista de noms. Per defecte utilitza el caràcter '#'.
*/
NContent.prototype.setVisibilityRecursive = function(nameListArray) {
	try {
		if (this.type=="range") return;

		if (this.type=="layer") {
		
			var isVisible=false;
			var i=0;
			while (i<nameListArray.length && !isVisible) {
				if (nameListArray[i]==this.name) {
					isVisible=true;
				} else {
					i++;
				}
			}
			if (isVisible) this.visible="1";
			else this.visible="0";

		}
		for (var i=0;i<this.childrenArrayCount;i++) {
			this.childrenArray[i].setVisibilityRecursive(nameListArray);
		}
		return;	
	}
	catch (e) {
		alert("Error a setVisibilityRecursive()\n"+e.message);
	}
}

/**
*	Retorna la visibilitat del node actual, tenint en compte els seus fills.
*	@return {String} Valors possibles: "on", "off", "mid".
*/
NContent.prototype.getVisibility = function() {
	return this.getVisibilityRecursive();
};

/**
*	Retorna la visibilitat del node actual, tenint en compte els seus fills. Crida recursiva.
*	@private
*/
NContent.prototype.getVisibilityRecursive = function() {
	if (this.type=="layer") {
		return this.visible;

	} else if (this.type=="group") {
		var str="";
		for (var i=0;i<this.childrenArrayCount;i++) {
			str+=this.childrenArray[i].getVisibilityRecursive();
		}
		var hasOn=(str.indexOf("1")>-1);
		var hasOff=(str.indexOf("0")>-1);
		if (hasOn && hasOff) return "mid";
		else if(hasOn && !hasOff) return "on";
		else if(!hasOn && hasOff) return "off";
		else return "off";
	} else return "off"; 
};

/**
*	Retorna l'estat de la personalització.
*	@return {String} valors possibles: disabled, off, mid, on.
*/
NContent.prototype.getEstatPersonalitzacio = function() {
	var str=this.getEstatPersonalitzacioRecursive();
	
	var hasEnabled=str.indexOf("enabled")>-1;
	var hasDisabled=str.indexOf("disabled")>-1;
	var hasUnavailable=str.indexOf("unavailable")>-1;

	if		( !hasEnabled && !hasDisabled && hasUnavailable	) return "disabled"; 
	else if ( !hasEnabled &&  hasDisabled && hasUnavailable	) return "off"; 
	else if (  hasEnabled &&  hasDisabled					) return "mid"; 
	else if (  hasEnabled && !hasDisabled					) return "on"; 

};

/**
*	Retorna l'estat de la personalització. Crida recursiva.
*	@return {String} una llista amb valors(enabled|disabled|unavailable) separats per comes.
*	@private
*/
NContent.prototype.getEstatPersonalitzacioRecursive = function() {

	if (this.type=="layer") {
		return this.getAttributeValue("personal");
	} else if (this.type=="group" || this.type=="block" || this.type=="main") {
		var str="";
		for (var i=0;i<this.childrenArrayCount;i++) {
			str+=this.childrenArray[i].getEstatPersonalitzacioRecursive()+",";
		}
		return str;

	} else return "";
};

/**
*	Retorna el número de serveis utilitzats en els blocs.
*	@return {Integer}
*/
NContent.prototype.getServiceCount = function() {
	if (this.type=="main") {
		return this.services.length;
	}
	else return 0;
}

/**
*	Retorna l'id del servei de la posició i.
*	@param {Integer} i el número de servei.
*	@return {String}
*	@private
*/
NContent.prototype.getServiceId = function(i) {
	if (this.type=="main") {
		
		return this.services[i].id;
	}
	else return "";
};

/**
*	Retorna el servei amb el nom/id donat.
*	@param {Integer} i el número de servei.
*	@return {Object}//TODO explicar parametres de l'objecte
*/
NContent.prototype.getServiceById = function(id) {
	if (this.type=="main") {
		
		var i=0;
		while (i<this.services.length) {
			if (this.services[i].id==id) return this.services[i];
			else i++;
		}
		return "";
	}
	else return "";
};

/**
*	Retorna l'atribut "querylayers" del servei de la posició i.
*	@param {Integer} i el número de servei
*	@return {String}
*/
NContent.prototype.getServiceQueryLayers = function(i) {
	if (this.type=="main") {
		return this.services[i].querylayers;
	}
	else return "";
};

/**
*	Retorna una llista amb els layers visibles d'un servei.
*
*	@param {String} service Si és un string, retorna els layers d'aquest servei, si es undefined retorna els de tots.
*	@return {String} llista separada per comes amb els noms dels layers.
*/
NContent.prototype.getVisibleLayersNames = function(service,separador) {
	if (typeof(separador)=="undefined") separador=",";

	var str=this.getVisibleLayersNamesRecursive(service,separador);

	if (str.length>0) return str.substr(0,str.length-1);//remove last comma
	else return "";
}

/**
*	Retorna una llista amb els layers visibles d'un servei. Crida recursiva.
*
*	@param {String} service Si és un string, retorna els layers d'aquest servei, si es undefined retorna els de tots.
*	@return {String} llista separada per comes amb els noms dels layers.
*	@private
*/
NContent.prototype.getVisibleLayersNamesRecursive = function(service,separador,blockService) {

	var thisService=this.getAttributeValue("service");

	if (this.type=="layer" && ( (blockService==service && thisService==null)  || service==thisService ) ) {
		if (this.visible=="1") return this.name+separador;
		else return "";

	} else if (this.type=="group" || this.type=="block" || this.type=="main") {
		
		if (this.type=="block") blockService=thisService;
		var str="";
		for (var i=0;i<this.childrenArrayCount;i++) {
			str+=this.childrenArray[i].getVisibleLayersNamesRecursive(service,separador,blockService);
		}
		return str;
		
	} else return "";
}


/**
*
*/
NContent.prototype.getWFSConfigArray = function(serviceId) {
	var array=new Array();
	this.getWFSConfigArrayRecursive(serviceId,array);
	return array;
}

/**
*
*/
NContent.prototype.getWFSConfigArrayRecursive = function(service,retArray) {

	if (this.type=="layer") {

		var o=new Array();
		o.push(retArray.length);// un identificador unic
		o.push(this.imagepath);
		o.push(this.imagewidth);
		o.push(this.imageheight);
		o.push(this.name);
		retArray[retArray.length]=o;

	} else if (this.type=="group" || this.type=="block" || this.type=="main") {

		if (this.type=="block" && typeof(service)!='undefined' && service!=this.getAttributeValue("service") ) {
			return;

		} else {

			for (var i=0;i<this.childrenArrayCount;i++) {
				this.childrenArray[i].getWFSConfigArrayRecursive(service,retArray);
			}

			return;
		}
		
	} else return;
}


/**
*	Retorna el format d'imatge més adient per el servei donat. 
*	@param {String} service 
+	@return {String} Pot retornar "image/jpeg" o "image/png".
*/
/*
NContent.prototype.getBestFormat = function(service) {
	var str=this.getBestFormatRecursive(service);
	if (str.length>0) {
		if (str.toLowerCase().indexOf("jpg")>-1) return "image/jpeg";
		else return "image/gif";
	}
	else return "image/jpeg";
}
*/
NContent.prototype.getBestFormat = function(service) {
	var str=this.getBestFormatRecursive(service);
	if (str.length>0) {
		if (str.toLowerCase().indexOf("jpg")>-1) return "image/jpeg";
		else if (str.toLowerCase().indexOf("png")>-1) return "image/png";
		else return "image/gif";
	}
	else return "image/jpeg";
}
/**
*	Crida recursiva.
*	@private
*/
NContent.prototype.getBestFormatRecursive = function(service, blockService) {

	var thisService=this.getAttributeValue("service");

	if (this.type=="layer" && ( (blockService==service && thisService==null)  || service==thisService ) ) {
		if (this.visible=="1") return this.format+",";
		else return "";

	} else if (this.type=="group" || this.type=="block" || this.type=="main") {
		
		if (this.type=="block") blockService=thisService;
		var str="";
		for (var i=0;i<this.childrenArrayCount;i++) {
			str+=this.childrenArray[i].getBestFormatRecursive(service,blockService);
		}
		return str;
		
	} else return "";//important! sino retorna undefined

}

/**
*	Retorna informació sobre els layers que són queriables, que es pot demanar informació.
*
*	@option {boolean} retList [true/false]: true= retorna una llista, false= retorna tags <option>. list like: name1#title1#desc1$name2#title2#desc2$...
*	@option {Integer} retType [0/1/2]: 0=tots, 1=només visibles, 2=només no visibles
*	@return 
*
*/
NContent.prototype.getQueryableLayersNames = function(retList,retType) {
	var str=this.getQueryableLayersNamesRecursive(retList,retType);
	return str;
}

/**
*	Crida recursiva.
*	@private
*/
NContent.prototype.getQueryableLayersNamesRecursive = function(retList,retType) {
	//alert(">>"+this.type);
	if (this.type=="layer") {

		if (this.queryable=="1" && ( (retType==0) || (retType==1 && this.visible=="1") || (retType==2 && this.visible=="0") ) ) {
			if (retList==true) return this.name+'#'+this.title+'#'+this.desc+'$';
			else return '<option value="'+this.name+'">'+this.title+'</option>';
		}
		else return "";

	} else if (this.type=="group" || this.type=="block" || this.type=="main") {
		var str="";
		for (var i=0;i<this.childrenArrayCount;i++) {
			str+=this.childrenArray[i].getQueryableLayersNamesRecursive(retList,retType);
		}
		return str;
	} else return "";//important! sino retorna undefined
}

/**
*	Replaces this node with the values of c
*/
NContent.prototype.replace = function(c) {

	this.init();	

	// copy attributes
	for (var i=0; i<c.attributeNamesCount ;i++ ) {
		this.addAttribute(c.attributeNames[i],eval("c."+c.attributeNames[i]));
	}

	// copy children
	for (var i=0; i<c.childrenArrayCount ;i++ ) {
		this.childrenArray[i]=c.childrenArray[i];
	}
	this.childrenArrayCount=c.childrenArrayCount;

	// copy ranges
	for (var i=0; i<c.rangesArrayCount ;i++ ) {
		this.rangesArray[i]=c.rangesArray[i];
	}
	this.rangesArrayCount=c.rangesArrayCount;

	return false;
}

/**
*	Clones this node and its children
*/
NContent.prototype.clone = function() {

	var c = new NContent(this.ACCORDIONCONTENTWIDTH,this.ACCORDIONCONTENTHEIGHT,this.baseURLImages);

	// attributes
	for (var i=0; i<this.attributeNamesCount ;i++ ) {
		try {c.addAttribute(this.attributeNames[i],eval("this."+this.attributeNames[i]));
		}catch (e){ alert("error cloning attribute '"+this.attributeNames[i]+"'\n"+e);}
		
	}

	// children
	for (var i=0; i<this.childrenArrayCount ;i++ ) {
		c.childrenArray[i]=this.childrenArray[i].clone();
	}
	c.childrenArrayCount=this.childrenArrayCount;

	// ranges
	for (var i=0; i<this.rangesArrayCount ;i++ ) {
		c.rangesArray[i]=this.rangesArray[i].clone();
	}
	c.rangesArrayCount=this.rangesArrayCount;
	return c;
}

/**
*	Removes this node from the object tree
*	@private
*/
NContent.prototype.remove = function() {

	var p=this.parentNode();

	// remove this from parents chindren array
	var i=0;
	var trobat=false;
	while ((i<p.childrenArrayCount) && (!trobat)) {
		if (p.childrenArray[i].name==this.name) {
//			p.childrenArray[i].remove();
			trobat=true;
		} else i++;
	}	
	while ( (i+1)<p.childrenArrayCount ) {
		p.childrenArray[i]=p.childrenArray[i+1];
		i++;
	}	
	p.childrenArray[i]=null;
	p.childrenArrayCount--;


}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
			

/**
*	Guarda al servidor la posició i propietats dels nodes
*	@param {String} servletPath where to send the xml
*	@param {String} userid user send in the url as a parameter
*	@param {String} useridTarget userid send inside the xml.(to who the changes are applied)
*	@param {String} blockTarget blockid send inside the xml.(the only block that has been changed)
*/
NContent.prototype.saveContentPositions = function(servletPath,userid,useridTarget,blockTarget) {
	var doc=newObjectXML();
	
	var node=this.getContentPositionsXmlRecursive(doc,useridTarget,blockTarget);
	doc.appendChild(node);

	//prompt('NOMES VISIBLE AMB IE!!',doc.xml);
//	DebugOut("NContent saveContentPositions XML:\n"+Sarissa.serialize(doc),INFO);

	//send xml to server

	// Obtain an XMLHttpRequest instance
	var req = newXMLHttpRequest();

	// Set the handler function to receive callback notifications from the request object
	var handlerFunction = getReadyStateHandler(req, "res", this.processSaveContentPositionsResponse);
	req.onreadystatechange = handlerFunction;

	// Open an HTTP POST connection. Third parameter specifies request is asynchronous.
	DebugOut("NContent.saveContentPositions() URL: "+ servletPath+"userid="+userid, DEBUG);
	req.open("POST", servletPath+"userid="+userid, true);

	// Specify that the body of the request contains form data
//	req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	req.setRequestHeader("Content-Type", "text/xml;charset=UTF-8;");

	req.send(doc);

	return;
}

/**
*	processSaveContentPositionsResponse
*	@private
*/
NContent.prototype.processSaveContentPositionsResponse = function(obj, responseXML) {
	DebugOut("NContent.processSaveContentPositionsResponse()", DEBUG);

	try{
		var node = responseXML.getElementsByTagName('ok')[0];
		var text=node.getAttribute("descripcio");
		//alert(text);
	}
	catch (e) {
		var node = responseXML.getElementsByTagName('error')[0];
		var text=node.getAttribute("descripcio");
		alert("Error guardant configuració:\n"+text);
	}
	
}

/**
*	getContentPositionsXmlRecursive
*	@private
*/
NContent.prototype.getContentPositionsXmlRecursive = function(doc,userTarget,blockTarget) {
	try {
			
		if (this.type=="layer") {
			var layer=doc.createElement("content");
			layer.setAttribute("id", this.getAttributeValue("name"));
			layer.setAttribute("type", "layer");
			layer.setAttribute("desplegat", this.getAttributeValueNotUndefined("open"));
			layer.setAttribute("ocult", this.getAttributeValueNotUndefined("hidden"));
			layer.setAttribute("visible", this.getAttributeValueNotUndefined("visible"));
			return layer;

		} else if (this.type=="group") {
			var group=doc.createElement("content");
			group.setAttribute("id", this.getAttributeValue("name"));
			group.setAttribute("type", "group");
			group.setAttribute("desplegat", this.getAttributeValueNotUndefined("open"));
			group.setAttribute("ocult", this.getAttributeValueNotUndefined("hidden"));
			//group.setAttribute("visible", this.getAttributeValueNotUndefined("visible"));
			for (var i=0;i<this.childrenArrayCount;i++) {
				var retNode=this.childrenArray[i].getContentPositionsXmlRecursive(doc);
				if (retNode!=undefined)	group.appendChild(retNode);
			}
			return group;

		} else if (this.type=="block") {
			var block=doc.createElement("block");
			block.setAttribute("id", this.getAttributeValue("name"));
			block.setAttribute("desplegat", this.getAttributeValueNotUndefined("open"));
			//block.setAttribute("ocult", this.getAttributeValueNotUndefined("hidden"));
			for (var i=0;i<this.childrenArrayCount;i++) {
				var retNode=this.childrenArray[i].getContentPositionsXmlRecursive(doc);
				if (retNode!=undefined)	block.appendChild(retNode);
			}
			return block;

		} else if (this.type=="main") {
			var main=doc.createElement("main");
			main.setAttribute("persona_id", userTarget);
			if (typeof(blockTarget)!='undefined') main.setAttribute("block_id", blockTarget);
			for (var i=0;i<this.childrenArrayCount;i++) {
				var retNode=this.childrenArray[i].getContentPositionsXmlRecursive(doc);
				if (retNode!=undefined)	main.appendChild(retNode);
			}
			return main;

		} else return undefined;
		
	}
	catch (e) {
		alert("Error a NContent.getContentPositionsXmlRecursive()\n"+e.message);
	}
}

/**
*	Sets the background color for the content tree html. Per no tenir que posar-ho a cada node ho guardem com a variable global.
*/
NContent.prototype.setBackGroundcolor = function(colorHex) {
	NContent_backGroundColor=colorHex;
}


/**
*	Gets the background color for the content tree html
*/
NContent.prototype.getBackGroundcolor = function() {
	if (typeof(NContent_backGroundColor)=="undefined") return "#FFFFFF";
	else return NContent_backGroundColor;
}




/**
*	Genera un array amb els estils que es passaran al proxywfs. amb dwr.
*	format de l'array: 
*	stylesArray[i][0]=identificador de l'estil. Ha de ser únic.
*	stylesArray[i][1]=url de la imatge
*	stylesArray[i][2]=width de la imatge
*	stylesArray[i][3]=height de la imatge
*	stylesArray[i][4]=nom del layer
*	@private
*/
NContent.prototype.getWFSStyles = function(array) {
	if (typeof(array)=="undefined") array=new Array();

	if (this.type=="layer" && this.format.toLowerCase()=="wfs") {
		array.push(new Array(array.length, this.imagepath, this.imagewidth, this.imageheight, this.name));
		return;

	} else if (this.type=="group" || this.type=="block" || this.type=="main") {
		
		for (var i=0;i<this.childrenArrayCount;i++) {
			this.childrenArray[i].getWFSStyles(array);
		}
		return array;
		
	} else return array;

}

/**
*	Retorna les metadades del node actual.
*	exemple: treeContent.getContentNode("node_2_0").getMetadata();
*	@return {String}
*/
NContent.prototype.getMetadata = function() {
	try {	
		for (var i=0;i<this.childrenArrayCount;i++) {
			var cdata=this.childrenArray[i].cdata;
			if (typeof(cdata)!="undefined") {
				return cdata;
			}
		}
		return "";
	}
	catch (e) {
	}
}

/**
*	Retorna la url a les metadades del node actual.
*	exemple: treeContent.getContentNode("node_2_0").getMetadataUrl();
*	@return {String}
*/
NContent.prototype.getMetadataUrl = function() {
	try {	
		for (var i=0;i<this.childrenArrayCount;i++) {
			var cdata=this.childrenArray[i].cdata;
			if (typeof(cdata)!="undefined") {
				return this.childrenArray[i].url;
			}
		}
		return "";
	}
	catch (e) {
	}
}

/**
*
*/
function loadResponseToDiv(ncontent, responseXML, req) {

	document.getElementById(ncontent.divid).innerHTML=req.responseText;

	/*var mainNode = responseXML.getElementsByTagName('main')[0];
	if (mainNode.childNodes[0].nodeName=="error") {
		alert("Error carregant llegenda:\n"+mainNode.childNodes[0].getAttribute("descripcio"));
	} else {
		ncontent.load(mainNode);
		ncontent.eventTreeLoadedCall();
	}*/
};



/**
*	Genera el codi per configurar el mapa: ordre, transparencies i galetes.
*/
NContent.prototype.initLayersConfig = function(rootNode,targetDivId) {
	try {
		var obj=document.getElementById(targetDivId);

		var str=new Array();
		str.push('<div style="float:left; margin-top:5px; margin-bottom:10px;margin-left:10px;"><b>Ordre de les capes:</b></div>');
		str.push('<select id="'+targetDivId+'_sel" size="'+rootNode.services.length+'" onclick="javascript: configLayerChange(this);" onmousedown="javascript: planolSelectIndex=this.options.selectedIndex;">');

		rootNode.sortServices();
		for (var i=0; i<rootNode.services.length; i++) {
			var service=rootNode.services[i];
			str.push('<option value="'+service.id+'">'+service.desc+'</option>');
		}

		str.push('</select>');

		str.push('<div style="float:left; margin:3px;">');
		str.push('	<a><img src="img/config_amunt.gif" alt="" onClick="javascript: configMoveUp();"/></a>');
		str.push('	<br/>');
		str.push('	<a><img src="img/config_avall.gif" alt="" onClick="javascript: configMoveDown();"/></a>');
		str.push('<div style="float:left; margin-top:5px;"><img src="img/icon_eye.gif" alt="" style="cursor:pointer;" onmouseover="javascript:layerConfigShow();" onmouseout="javascript:layerConfigHide();" /></div>');
		str.push('</div>');

		str.push('<br/>');
		
		//str.push('<br/>');
		str.push('<div style="float:left; margin-left: 14px; margin-top:15px;"><img alt="" src="library/slider/transp_icon.gif"/></div>');
		str.push('<div style="float:left; margin-left: 4px; margin-top:15px;">Transparència:</div>');
		str.push('<div style="float:left; margin-left: 2px; margin-top:15px;"><img id="transparencyImgId" width="70" alt="" src="library/slider/sliderbg.gif"/></div>');
		str.push('<br/>');
		str.push('<br/>');
//		str.push('<center><img style="padding-bottom:5px;" src="img/botones/boto_guardar.gif" onmouseover="this.src=\'img/botones/boto_guardar_p.gif\'" onmouseout="this.src=\'img/botones/boto_guardar.gif\'" value="guarda" onclick="javascript: saveConfig();"/></center>');
//		str.push('<center><img style="padding-bottom:5px;" src="img/botones/boto_cargar.gif" onmouseover="this.src=\'img/botones/boto_cargar_p.gif\'" onmouseout="this.src=\'img/botones/boto_cargar.gif\'" value="carrega" onclick="javascript: loadConfig();"/></center>');
//		str.push('<center><img src="img/botones/boto_eliminar.gif" onmouseover="this.src=\'img/botones/boto_eliminar_p.gif\'" onmouseout="this.src=\'img/botones/boto_eliminar.gif\'" value="elimina" onclick="javascript: deleteConfig();"/></center>');

		obj.innerHTML=str.join("");
	}
	catch (e) {
		alert("Error a NContent.initLayersConfig()\n"+e.message);
	}
}

/**
*	Carrega la configuració de la url i dels cookies en aquest ordre de preferencia.
*	Es carrega la info de: services, layers i extent.
*/
NContent.prototype.loadConfigParams = function() {
	try {
		var separador="~";
			
		// agafem valors de cookie
		var services=readCookie("services");
		var layers=readCookie("layers");
		var extent=readCookie("extent");

		// agafem els valors de la url
		var p= new UrlParser(window.location.href);
		var names=p.getNameArray();
		var values=p.getValueArray();

		for (var i=0; i<p.getMaxVars(); i++) {

			if (names[i].toLowerCase()=="extent") {
				extent=values[i];

			} else if (names[i].toLowerCase()=="services") {
				var services=values[i];
				
			} else if (names[i].toLowerCase()=="layers") {
				layers=values[i];
			} 
		}
		
		// apliquem els valors obtinguts
		if (extent!=null) urlExtent=new NExtent(extent);

		if (services!=null) {
			var lArray=services.split(separador);
			for (var i=0;i<lArray.length ;i++ ) {
				var one=lArray[i].split(":");
				
				treeContent.getServiceById(one[0]).order=i;
				treeContent.getServiceById(one[0]).transparency=one[1];
			}
		}

		if (layers!=null) this.setVisibility(layers,separador);
		
	}
	catch (e) {
		alert("Error a NContent.loadConfigParams()\n"+e.message);
	}
}
