/**
*	Constructor
*/
function NContent(w,h,baseURLImages) {
	if ( arguments.length === 1 )
		this.init2(arguments[0]);
	else
		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;

	this.showIdentifyButtons=false;//ens serveix per saber si hem de posar el boto d'identify a cadascun dels layers.
};

/**
*	Constructor
*	@private
*/
NContent.prototype.init2 = function(t) {
	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=t.FIRSTCOLWIDTH;
	this.BUTTONCOLWIDTH=t.BUTTONCOLWIDTH;
	this.TEXTWIDTH=t.TEXTWIDTH;
	this.ACCORDIONCONTENTWIDTH=t.ACCORDIONCONTENTWIDTH;
	this.TABLEWIDTH=t.TABLEWIDTH;
	this.ACCORDIONCONTENTHEIGHT=t.ACCORDIONCONTENTHEIGHT;
	
	this.baseURLImages=t.baseURLImages;

	this.showIdentifyButtons=t.showIdentifyButtons;

};

/**
*	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");

	replaceArray=this.evalReplaceArray(replaceArray);
	
	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");

	replaceArray=this.evalReplaceArray(replaceArray);
	
	Legend.getLegendWithBaseXML(servletUrl,replaceArray,false,this.processDWRLegendResponse);

};

/**
*	Mira els services que tenen definida l'atribut configurl i fa la pa petició als que la tenen.
*/
NContent.prototype.queryConfigUrls = function(){
	
	// mirem quantes peticions hem de fer
	this.queryConfigCount=0;
	for (var i=0;i<this.services.length ;i++ ){
		var service=this.services[i];
		if (typeof(service.configurl)!="undefined" && service.configurl!=null){
			this.queryConfigCount++;
		}
	}
	
	var peticionsEnviades=false;

	// muntem peticions
	var scope=new Object();
	scope.tree=this;

	for (var i=0;i<this.services.length ;i++ ){
		var service=this.services[i];
		
		var scope=new Object();
		scope.tree=this;
		scope.service=service;

		if (typeof(service.configurl)!="undefined" && service.configurl!=null){

			var names=this.getLayerValueByAttributeValue(service.id,"name",",",null,null);
			if (names.length===0){// si no te layers definits no fem petició perque retorna error.
				this.queryConfigCount--;
			} else {
				peticionsEnviades=true;
				var request = OpenLayers.Request.GET({
					url: service.configurl,
					params: {
						userid: unescape(userId),
						//request: "GetURLConfig",
						layers: names
					},
					scope:scope,
					success:this.queryConfigUrlSuccess,
					failure:this.queryConfigUrlFailure
				});
			}
		}
	}//for

	if (!peticionsEnviades) { // no s'ha fet cap petició. Ja podem seguir.
		this.eventTreeLoadedCall();
	}
};

/**
*	Tractament de la resposta de configurl. Afegeix els atributs retornats a la url i a l'array d'urls.
*/
NContent.prototype.queryConfigUrlSuccess = function(r){
	try{		
		//alert("asdf: queryConfigUrlSuccess("+this.service.id+")\n"+r.responseText);
		var xml=r.responseXML;

		var nodes=xml.getElementsByTagName("URLConfig");
		for (var i=0;i<nodes.length ;i++ ){
			var param=nodes[i].attributes[0].nodeName;
			var value=nodes[i].attributes[0].nodeValue;

			// fem un reset de les originals, per si hem demanat x 2a vegada el configurl. ex: aplicar un filtre a un tema
			this.service.url=""+this.service.urlOriginal;
			this.service.urlArray=[].concat(this.service.urlArrayOriginal);

			// apliquen a la url
			if (	this.service.url.indexOf("?")>-1 
				||	this.service.url.charAt(this.service.url.length-1) !=="&") this.service.url+="&";
			this.service.url+=param+"="+value;

			// també apliquem a l'array d'urls
			for (var j=0;j<this.service.urlArray.length ;j++ ){
				if (	this.service.urlArray[j].indexOf("?")>-1 
					||	this.service.urlArray[j].charAt(this.service.urlArray[j].length-1) !=="&") this.service.urlArray[j]+="&";
				this.service.urlArray[j]+=param+"="+value;
			}
		}

		this.tree.queryConfigCount--;
		if (this.tree.queryConfigCount===0){
			this.tree.eventTreeLoadedCall();
		}
	}
	catch (e){
		alert("Error tractant configuració estàtica del service '"+this.service.id+"'. S'Utilitzarà la configuració per defecte.\n");
	}
};

/**
*
*/
NContent.prototype.queryConfigUrlFailure = function(r){
	try{
		alert("Error generant configuració estàtica del service '"+this.service.id+"'. S'Utilitzarà la configuració per defecte.");
		this.tree.queryConfigCount--;
		if (this.tree.queryConfigCount===0){
			this.tree.eventTreeLoadedCall();
		}
	}
	catch (e){
		alert("Error a queryConfigUrlFailure()\n"+e.message);
	}
};

/**
*	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");

	replaceArray=this.evalReplaceArray(replaceArray);
	
	Legend.getLegendWithBaseXML(servletUrl,replaceArray,false,this.processDWRLegendResponse);

};

/**
*	@private
*/
NContent.prototype.evalReplaceArray = function(replaceArray) {
	for (var i=0; i<replaceArray.length; i++){
		if (typeof(replaceArray[i][1])=="function") {
			var func=replaceArray[i][1];
			replaceArray[i][1]=func(userId);
		}
	}
	return replaceArray;
}


/**
*	
*	@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 {
		
		//DEBUGOFF: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 {
		
		var mainNode = responseXML.getElementsByTagName('main')[0];
		for (var i=0;i<mainNode.childNodes.length ;i++ ){
			if (mainNode.childNodes[i].nodeName=="error") {
				var code=mainNode.childNodes[i].getAttribute("code");
				var desc=mainNode.childNodes[i].getAttribute("descripcio");
				alert("Llegenda:\n"+desc);
				window.location.href=window.location.href;
				return;
			}
		}
		ncontent.load(mainNode);
		ncontent.queryConfigUrls();
		//abans de posar el configurl es cridava directament aquí: 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);
				objContent.load(contentNode);
				this.addChild(objContent);
			} else if (contentNode.nodeName=="services") {
				this.loadServices(contentNode);
			} else if (contentNode.nodeName=="edition") {
				this.loadEdition(contentNode);
			} else if (contentNode.nodeName=="map") {
				this.loadMapConfig(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);
				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);
				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);
	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;
}

/**
*	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);
	}
}

/**
*	loads the map configuration from the xml node.
*	@private
*/
NContent.prototype.loadMapConfig = function(node) {
	try{
		// declare vars in case some of them not in xml.
		this.map_projection=null;
		this.map_projection_units=null;

		this.map_tilesize_x=null;
		this.map_tilesize_y=null;

		this.map_scalesArray=new Array();

		this.map_restrictedExtent_xmin=null;
		this.map_restrictedExtent_ymin=null;
		this.map_restrictedExtent_xmax=null;
		this.map_restrictedExtent_ymax=null;

		this.map_maxExtent_xmin=null;
		this.map_maxExtent_ymin=null;
		this.map_maxExtent_xmax=null;
		this.map_maxExtent_ymax=null;

		this.map_tileOrigin_x=null;
		this.map_tileOrigin_y=null;

		this.map_baseServices=new Array();// emplenem amb els layers OL (service al legend) que han de ser de tipus baseLayer OL.


		for (var i=0;i<node.childNodes.length ;i++ ) {
			var c=node.childNodes[i];
			switch (c.nodeName.toLowerCase()) {
			case "projection":
				this.map_projection="EPSG:"+c.getAttribute("epsg");
				this.map_projection_units=c.getAttribute("units");
				break;
			case "tilesize":
				this.map_tilesize_x=parseFloat(c.getAttribute("x"));
				this.map_tilesize_y=parseFloat(c.getAttribute("y"));
				break;
			case "scalelevels":
				this.map_scalesArray=new Array();
				for (var j=0;j<c.childNodes.length ;j++ ) {
					var c2=c.childNodes[j];
					if (c2.nodeName=="scale"){
						this.map_scalesArray.push(parseFloat(c2.firstChild.nodeValue));
					}
				}
				// sort array descending
				this.map_scalesArray.sort(function(a,b){return b - a});
				break;
			case "scale":
				this.map_maxScale=parseFloat(c.getAttribute("max"));
				this.map_minScale=parseFloat(c.getAttribute("min"));
				break;
			case "restrictedextent":
				this.map_restrictedExtent_xmin=parseFloat(c.getAttribute("xmin"));
				this.map_restrictedExtent_ymin=parseFloat(c.getAttribute("ymin"));
				this.map_restrictedExtent_xmax=parseFloat(c.getAttribute("xmax"));
				this.map_restrictedExtent_ymax=parseFloat(c.getAttribute("ymax"));
				break;
			case "maxextent":
				this.map_maxExtent_xmin=parseFloat(c.getAttribute("xmin"));
				this.map_maxExtent_ymin=parseFloat(c.getAttribute("ymin"));
				this.map_maxExtent_xmax=parseFloat(c.getAttribute("xmax"));
				this.map_maxExtent_ymax=parseFloat(c.getAttribute("ymax"));
				break;
			case "tileorigin":
				this.map_tileOrigin_x=parseFloat(c.getAttribute("x"));
				this.map_tileOrigin_y=parseFloat(c.getAttribute("y"));
				break;
			case "controls":
				this.map_controls_coordinates_active=false;
					this.map_controls_coordinates_epsg=null;
					this.map_controls_coordinates_prefix=null;
					this.map_controls_coordinates_separator=null;
					this.map_controls_coordinates_suffix=null;
					this.map_controls_coordinates_numDigits=null;
					this.map_controls_coordinates_tooltip=null;
				this.map_controls_scalebar_active=false;
				this.map_controls_overview_active=false;
				this.map_controls_baseButtonsArray=new Array();
				this.map_controls_identifyButtonsArray=new Array();
				
				for (var j=0;j<c.childNodes.length ;j++ ) {
					var c2=c.childNodes[j];
					if (c2.nodeName==="coordinates"){
						this.map_controls_coordinates_active=c2.getAttribute("visible")=="1";
						this.map_controls_coordinates_epsg=c2.getAttribute("epsg");
						this.map_controls_coordinates_prefix=c2.getAttribute("prefix");
						this.map_controls_coordinates_separator=c2.getAttribute("separator");
						this.map_controls_coordinates_suffix=c2.getAttribute("suffix");
						this.map_controls_coordinates_numDigits=c2.getAttribute("numDigits");
						this.map_controls_coordinates_tooltip=c2.getAttribute("tooltip");
					}
					if (c2.nodeName==="scalebar"){
						this.map_controls_scalebar_active=c2.getAttribute("visible")=="1";
					}
					if (c2.nodeName==="overview"){
						this.map_controls_overview_active=c2.getAttribute("visible")=="1";
						this.map_controls_overview_open=c2.getAttribute("open")=="1";
						
						this.map_controls_overview_imageSource=c2.getAttribute("imageSource");
						this.map_controls_overview_xmin=c2.getAttribute("xmin");
						this.map_controls_overview_ymin=c2.getAttribute("ymin");
						this.map_controls_overview_xmax=c2.getAttribute("xmax");
						this.map_controls_overview_ymax=c2.getAttribute("ymax");

						this.map_controls_overview_service=c2.getAttribute("service");
						this.map_controls_overview_layers=c2.getAttribute("layers");
						this.map_controls_overview_format=c2.getAttribute("format");
					}
					if (c2.nodeName==="baseButtons") {
						for (var k=0;k<c2.childNodes.length ;k++ ) {
							var c3=c2.childNodes[k];
							if (c3.nodeName=="button"){
								var b=new Object();
								b.id=c3.getAttribute("id");
								b.title=c3.getAttribute("title");
								b.desc=c3.getAttribute("desc");
								b.service=c3.getAttribute("service");
								this.map_controls_baseButtonsArray[this.map_controls_baseButtonsArray.length]=b;
								this.map_baseServices[this.map_baseServices.length]=b.service;
							}
						}
					}
					if (c2.nodeName==="identifyButtons"){
						
						for (var k=0;k<c2.childNodes.length ;k++ ) {
							var c3=c2.childNodes[k];
							if (c3.nodeName=="button"){
								var b=new Object();
								b.target=c3.getAttribute("target");
								b.usercontrol=c3.getAttribute("usercontrol");
								b.targetdivid=c3.getAttribute("targetdivid");
								b.service=c3.getAttribute("service");
								this.map_controls_identifyButtonsArray[this.map_controls_identifyButtonsArray.length]=b;

								this.showIdentifyButtons=b.usercontrol.toLowerCase()==="tocbutton";

							}
						}
					}
				}
				break;
			}
		}
	}
	catch (e){
		alert("Error a NContent.prototype.loadMapConfig()\n"+e.message);
	}
}

/**
*	Carrega la configuració del mapa de situació.
*	@private
*/
NContent.prototype.loadOverviewMapConfig = function(node) {
	alert("legend.xml:\nnode '/main/overviewMap' deprecated. Utilitza '/main/controls/overview'");
	try {
		this.overviewMap_service=null;
		this.overviewMap_layers=null;
		this.overviewMap_format=null;
		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 datasets editables
*	@private
*/
NContent.prototype.loadEdition = function(node) {
	try {
		var count=0;
		this.editionDatasets=new Array();

		for (var i=0;i<node.childNodes.length ;i++) {
			var c=node.childNodes[i];
			if (c.nodeType==1 && (c.nodeName==="dataset")) {
				var dataset=new Object();
				dataset.id=c.getAttribute("id");
				dataset.title=c.getAttribute("title");
				dataset.wfsUrl=c.getAttribute("wfsurl");
				dataset.wmsUrl=c.getAttribute("wmsurl");
				dataset.typeName=c.getAttribute("typename");
				dataset.layerName=c.getAttribute("layername");
				dataset.featureNS=c.getAttribute("featurens");
				dataset.geometryColumn=c.getAttribute("geometrycolumn");
				dataset.geometryType=c.getAttribute("geometrytype");
				dataset.addEditLog=c.getAttribute("addeditlog")=="1";
				dataset.editUserColumn=c.getAttribute("editUserColumn");
				dataset.editOriginColumn=c.getAttribute("editOriginColumn");
				dataset.editDateColumn=c.getAttribute("editDateColumn");
				dataset.addUrl=c.getAttribute("addurl");
				dataset.modifyUrl=c.getAttribute("modifyurl");
				dataset.showUrl=c.getAttribute("showurl");
				dataset.searchUrl=c.getAttribute("searchurl");
				dataset.associatedLayerName="";
				
				this.editionDatasets[count]=dataset;
				count++;
			}
		}
		return;
	} catch(e) {
		alert("Error a NContent.prototype.loadUserConfig()\n"+e.message);
		return;
	}
}
/**
*	Carrega la informació dels serveis de l'xml
*	@private
*/
NContent.prototype.loadServices = function(node) {
	try {
		var count=0;
		this.services=new Array();
		this.servicesTimedOut=new Array();
		for (var i=0;i<node.childNodes.length ;i++) {
			var c=node.childNodes[i];
			if (c.nodeType==1 && (c.nodeName==="service" || c.nodeName==="serviceTimedOut")) {
				var id=c.getAttribute("id");
				var type=c.getAttribute("type");
				var url=c.getAttribute("url");// afegim multiplicitat
				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");
				var show=c.getAttribute("show");
				var splitquery=c.getAttribute("splitquery");
				var tiled=c.getAttribute("tiled");
				var identifyurl=c.getAttribute("identifyurl");
				var configurl=c.getAttribute("configurl");
				
				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=="wmsc" || type=="wfs" || type=="ags92" || type=="ags93" || type=="tilecache") {
						//DEBUGOFF:DebugOut("> NContent.services id: "+ id + " type: " + type + " url: " + url,DEBUG );
						var theService;
						if (c.nodeName==="serviceTimedOut"){
							var len=this.servicesTimedOut.length;
							this.servicesTimedOut[len]=new Object();
							theService=this.servicesTimedOut[len];
						}else {
							this.services[count]=new Object();
							theService=this.services[count];
							count++;
						}
						theService.id=id;
						theService.type=type;
						theService.url=url;
						theService.urlOriginal=""+url;// backup per si tenim configurl guardar la original.
						theService.transparency=transparency;
						theService.querylayers=querylayers;
						theService.printlayers=printlayers;
						theService.printdpi=printdpi;
						theService.printurl=printurl;
						theService.desc=desc;
						theService.order=count;
						theService.url_transparent=url_transparent;
						theService.url_bgcolor=url_bgcolor;
						theService.url_exception=url_exception;
						theService.url_style=url_style;
						theService.show=show;
						theService.tiled=tiled=="1";
						theService.identifyurl=identifyurl;
						theService.configurl=configurl;

						// generem un array amb les urls
						theService.urlArray=new Array();
						theService.urlArray.push(theService.url);
						var j=2;
						while (c.getAttribute("url"+j)!=null) {
							theService.urlArray.push(c.getAttribute("url"+j));
							j++;
						}
						theService.urlArrayOriginal=[].concat(theService.urlArray);// backup per si tenim configurl guardar la original.
					
					} else if (type=="info") {// service de tipus info.
						this.serviceInfo=new Object();
						this.serviceInfo.id=id;
						this.serviceInfo.type=type;
						this.serviceInfo.url=url;
						this.serviceInfo.querylayers=querylayers;
						this.serviceInfo.splitquery=splitquery;
					}
				}
			}
		}
		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+'">');
	//if (this.showIdentifyButtons) str.push('		<img src="img/treeview/empty.gif" alt="" width="4" height="1">');
	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 (this.queryable=="2") {
		identifyImg="identify_on.gif";
	} else if (this.queryable=="1") {
		identifyImg="identify_off.gif";
	} else {
		identifyImg="identify_empty.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;
	}
	//DEBUGOFF: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"/>');
	//	if (this.showIdentifyButtons) str.push('		<img id="node_'+nodeId+'_identify" src="img/treeview/'+identifyImg+'" onClick="javascript: treeIdentifyClick(this,\'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 {		
		var d=new Date();
		var str=treeContent.getHTMLTree(1);
		//DEBUGOFF:DebugOut("TIME: populateToc " + (new Date()-d),INFO);
		d=new Date();
		document.getElementById(divId).innerHTML = str;
		//DEBUGOFF:DebugOut("TIME: innerHTML " + (new Date()-d),INFO);
		
	}
	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 {
			var langAux="";
			if (typeof(lang)=="undefined") langAux="";
			else langAux=lang;

			// important: hem de passar-ho amb un var local pq sino seria undefined.
			if (this.sourceurl.indexOf("?")>-1) var sourceurl=this.sourceurl+"&lang="+langAux;
			else  var sourceurl=this.sourceurl+"?lang="+langAux;
			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" ) {
				var estil="";
				if (child.show == "0") estil=' style="visibility: hidden; display:none;"';
				str.push('<dt id="dt_'+i+'" onmousedown="treeBlockClick('+i+');" '+estil+'><div class="dt_text">'+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" style="height:'+this.ACCORDIONCONTENTHEIGHT+'px; width:'+this.ACCORDIONCONTENTWIDTH+'px; padding:2px;">');
					}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" style="height:'+this.ACCORDIONCONTENTHEIGHT+'px; width:'+this.ACCORDIONCONTENTWIDTH+'px; padding:2px;">');
					}
				} 
				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 a getContentNodeByName\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;
}

/**
*	Retorna el service d'aquest node.
*	@return NContent
*/
NContent.prototype.getLayerService = function() {
	try {
		return this.getLayerServiceRecursive();
	} catch (e) {
		alert("error a getLayerService\n"+e.message);
	}
}

/**
*	Busca recursivament un atribut de service.
*	@return NContent
*	@private
*/
NContent.prototype.getLayerServiceRecursive = function() {
	try {
		if (this.attributeExists("service")) {
			return this.getAttributeValue("service");
		} else {
			if (this.getAttributeValue("type")=="main") return "";
			else return this.parentNodeRef.getLayerServiceRecursive();
		}
	} catch (e) {
		alert("error a getLayerService\n"+e.message);
	}
}

/**
*	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";
		if (this.queryable=="2") this.queryable="1";// quan desactiven visibilitat tb desactivem identify
	}

	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.
*	@param {String} separador el separador a utilitzar entre els noms dels services.
*	@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 "";
}


/**
*	Retorna una llista amb els valors de l'atribut demanat.
*
*	exemple: treeContent.getLayerValueByAttributeValue(id,"name" ,"#","queryable","2");
*				retorna el valor de l'atribut name de tots els layers del servei amb l'id passat i que tinguin el queryable a "2".
*	exemple: treeContent.getLayerValueByAttributeValue("AGSCACHE","format" ,"#","visible","1"); 
*				retorna l'atribut format de tots els layers del servei AGSCACHE que estiguin a visibles.
*
*	@param {String} service Si és un string, retorna els layers d'aquest servei, si es undefined retorna els de tots.
*	@param {String} returnAttributeName el nom de l'atribut que volem obtenir.
*	@param {String} separador el separador de 'string amb els valors
*	@param {String} attributeName el nom de l'atribut a filtrar. si volem obtenir sense filtrar passem attributeName==null
*	@param {String} attributeValue el valor de l'atribut que busquem.
*	@return {String} llista separada per comes amb els valors de l'atribut.
*/
NContent.prototype.getLayerValueByAttributeValue = function(service,returnAttributeName,separador,attributeName,attributeValue) {
	if (typeof(separador)=="undefined") separador=",";

	var str=this.getLayerValueByAttributeValueRecursive(service,returnAttributeName,separador,attributeName,attributeValue);

	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.getLayerValueByAttributeValueRecursive = function(service,returnAttributeName,separador,attributeName,attributeValue,blockService) {

	var thisService=this.getAttributeValue("service");

	if (this.type=="layer" 
		&& ( (blockService==service && thisService==null)	// layer sense service però coincideix el del block
			 || (service==thisService && thisService!=null) // el service del layer coincideix amb el demanat.
			 || (blockService==null && service==null && thisService!=null) // quan es busca des d'un node que es tipus group i volem tots els services que conté.	 						
		   ) 
		) {
		//console.log("getLayerValueByAttributeValueRecursive",attributeName,this[attributeName]);
		if ( attributeName==null																		// si volem obtenir sense filtrar passem attributeName==null
			 || (this[attributeName]==attributeValue && this.attributeExists(returnAttributeName))
		) {
			if (typeof(this[returnAttributeName])!="undefined") // cal que l'atribut existeixi, sinò retornariem un undefined.
				return this[returnAttributeName]+separador;	
		} 
		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].getLayerValueByAttributeValueRecursive(service,returnAttributeName,separador,attributeName,attributeValue,blockService);
		}
		return str;
		
	} else return "";
}


/**
*	Genera i retorna un array multidimensional amb la definició dels layers WFS.
*	array[0][0]: identificador únic
*	array[0][1]: path de la imatge a mostrar.
*	array[0][2]: amplada de la imatge.
*	array[0][3]: alçada de la imatge.
*	array[0][4]: nom del layer. El que s'ha de demanar a la petició WFS.
*	@return {Array}
*/
NContent.prototype.getWFSConfigArray = function(serviceId) {
	var array=new Array();
	this.getWFSConfigArrayRecursive(serviceId,array);
	return array;
}

/**
*	la crida recursiva
*	@private
*/
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 || str.toLowerCase().indexOf("jpeg")>-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 i que estan activats. L'atribut queryable ara te 3 valors possibles: 0->no queryable, 1->queryable però desactivat, 2->queryable i activat.
*
*	@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 dels layers visibles, 2=només dels layers 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=="2" && ( (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);

	// 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.
	//DEBUGOFF: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) {
	//DEBUGOFF: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" && this.attributeExists("dynamic") && this.getAttributeValue("dynamic")=="1") {
			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 l'html del bloc de  configuració
*/
NContent.prototype.initLayersConfig = function(rootNode,targetDivId) {
	try {
		var obj=document.getElementById(targetDivId);
		var len=rootNode.services.length;

		if (len>10) len=10;

		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="'+len+'" 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];
			
			// mirem si és un mapa de base per no posar-lo. Tampoc el volem posar si és el mapa de situació o si te el show a 0
			var trobat=false;
			
			if (rootNode.map_controls_overview_service===service.id // service de situació no el posem
					|| service.show==="0"							// si no volem que el servei surt, posem un show a 0 
			)trobat=true;
			else {
				// mirem si és un mapa de base per no posar-lo. Tampoc el volem posar si és el mapa de situació.
				var j=0;
				while (rootNode.map_baseServices!=null && j<rootNode.map_baseServices.length && !trobat){
					if (
						rootNode.map_baseServices[j]===service.id
					) 
						trobat=true;
					else j++;
				}
			}

			if (!trobat) str.push('<option value="'+service.id+'" title="'+service.desc+'">'+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++) {
//
//			//Afegim unescape pq al enviar per correu sino no funciona. (sisq)
//			if (names[i].toLowerCase()=="extent") {
//				extent=unescape(values[i]);
//
//			} else if (names[i].toLowerCase()=="services") {
//				var services=unescape(values[i]);
//				
//			} else if (names[i].toLowerCase()=="layers") {
//				layers=unescape(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);
	}
}


/**
 * Retorna true si la capa està activada en el menú, false en cas contrari 
 * @param {String} wfsVisibleLayers Llista dels ID's de capes visibles separades per comes.
 * @param {String} layerID ID del layer que volem comprobar.
 * @return {boolean}
 */
NContent.prototype.isLayerVisible = function (wfsVisibleLayers, layerID){
	if (("," + wfsVisibleLayers + ",").indexOf(","+layerID+",") >= 0){
		return true;
	} else {
		return false;
	}
}

