
/******************************************************************************\
*  geoxml.js		                               by Lance Dyas          *
*  A Google Maps API Extension  GeoXml parser                                 *
*  GeoXml Parser based on my maps kml parser by Mike Williams called egeoxml  *
*  Additions include:   GML/WFS/GeoRSS/GPX expanded GE KML style support      *                                            
\******************************************************************************/

//var taggedName; // holds the <h2> tagged name or title for use in the info box
//		// other tags are removed otherwise they appear in the tooltip!

 function getIconLocation(datatype, clustered) {
         iconlocation = "../images/single.png";
         
 	if (clustered == true) {
 		iconlocation = "../images/"+datatype;
 		iconlocation = iconlocation + "Cluster.png";
 	}
 	else  {
 		iconlocation = "../images/"+datatype;
 		iconlocation = iconlocation + ".png";
 	}
 	
 	return iconlocation;
}

// Constructor
function doCloseInfoWindow() {
	document.getElementById('opaquetext').innerHTML = "";
	//document.getElementById('container2').style.left = "-4000px";
	document.getElementById('container2').style.display = "none";
}


function createInfo(layername,taggedName,desc) {
	// we assume that all the html has been done on the server
	
	
	//		document.getElementById('container2').style.height = document.getElementById('map-canvas').style.height;*/

  var theWdth = parseInt(document.getElementById('map-canvas').style.width);
   theWdth = theWdth * (80/100);


var  html = "<div style=\"height:85%\">";
html += "<INPUT TYPE=\"image\" SRC=\"../images/addline.png\" VALUE=\"Close\"";
html += "ALT=\"Close\" title=\"close\" NAME=\"Close\" onclick=\"doCloseInfoWindow()\" style=\"height:20px;width:20px;float:right;\">"; 
  html += "<div style=\"height:5px;width:100%\">";
  html += "</div>"; // end of the gap div at the top of the table
  html += "<div style=\"margin-left:70px;width:"+ theWdth+ "px;height:90%\">";
  html +="<h1>"+layername +"</h1>";
  html += "<div style=\"overflow-y:auto;overflow-x:hidden;margin-left:20px;";
  html += "margin-right:20px;width:"+ theWdth+ "px;height:85%\">";
  html += taggedName + desc;
  html += "</div>"; // the actual data
  html += "<div style=\"height:10px;width:100%\"></div>";  // a gap before the close button
  html += "<button id=\"closeinfowindow\" type=\"button\" name=\"closeinfowindow\" ";
  html += " onclick=\"doCloseInfoWindow()\">Close</button>";
  html += "</div></div>";
  html += "</div>";


 
  return html;


}

function KMLObj(title,desc) {
	this.title = title;
  	this.description = escape(desc);
  	this.marks = [];
	this.folders = [];
	this.groundOverlays = [];
	}

function getColour(datatype) {
	// return the colour to be used for drawing lines and polygons
	// this is called both from the data capture and the data display
	// processes
	
	var colour = "#ff00ff" // this is pink?
	switch (datatype) {
		case "user_datas" :
			colour = "#FF0000"; // red
			break;
		case "events" :
			//colour = "#808000"; //forest green
			colour = "#01DF01"; // brighter green
			break;
		case "organisations" :
			colour = "#0000A0"; // dark blue
			break;
		case "large_projects" :
			//colour = "#C0C0C0"; // grey
			colour = "#0B3B24"; // dark green
			break;
		case "gainsborough" :
			colour = "#FF8040"; //orange
			break;
		case "classes" :
			colour = "#FF8040"; //orange
			break;
		case "historical" :
			colour = "#FFFF00"; //YELLOW
			break;
		case "cycleroute" :
			colour = "#FF8040"; //orange
			break;
		case "historic" :
			colour = "#FF8040"; //orange
			break;
		case "greenareas" :
			colour = "#336600"; //orange
			break;
		case "reuserecycle" :
			colour = "#FF8040"; //orange
			break;
		case "madeinarchway" :
			colour = "#FF8040"; //orange
			break;



		case "minisites" :
			//colour = "#408080"; //grass green
			colour = "#F5EFFB"; // off white
			break;
		
	}
	
	
	return colour;
}

function getCustomIcon (datatype, clustered) {

	switch (datatype) {
		case "user_datas" :
			if (clustered == true) {
				return user_datasClusterIcon;
			}
			else {
				return user_datasIcon;
			}
			
			break;
		case "events" :
			if (clustered == true ) {
				return eventsClusterIcon;
			}
			else {
				return eventsIcon;
			}
			break;
		case "organisations" :
			if (clustered == true) {
				return organisationsClusterIcon;
			}
			else {
				return organisationsIcon;
			}
		case "large_projects" :
			if (clustered == true) {
				return large_projectsClusterIcon;
			}
			else {
				return large_projectsIcon;
			}
		case "gainsborough" :
			if (clustered == true) {
				return gainsboroughIcon;
			}
			else {
				return gainsboroughIcon;
			}
		case "classes" :
			if (clustered == true) {
				return classesIcon;
			}
			else {
				return classesIcon;
			}
		case "historical" :
			if (clustered == true) {
				return historicalIcon;
			}
			else {
				return historicalIcon;
			}
		case "historic" :
			if (clustered == true) {
				return historicIcon;
			}
			else {
				return historicIcon;
			}
		case "cycleroute" :
			if (clustered == true) {
				return cyclerouteIcon;
			}
			else {
				return cyclerouteIcon;
			}
		case "greenareas" :
			if (clustered == true) {
				return greenareasIcon;
			}
			else {
				return greenareasIcon;
			}
		case "reuserecycle" :
			if (clustered == true) {
				return reuserecycleIcon;
			}
			else {
				return reuserecycleIcon;
			}
		case "madeinarchway" :
			if (clustered == true) {
				return madeinarchwayIcon;
			}
			else {
				return madeinarchwayIcon;
			}



		case "minisites" :
			break;
	}	

}




function GeoXml(myvar,layername, layerType, sourceIsKML,showlayer,map, url, opts){
  // store the parameters
  this.layerType = layerType;
  
  this.sourceIsKML = sourceIsKML; // this is to allow us to use kml files as well as the database.  the kml files won't have [cdata] tags
  this.myvar = myvar;
  this.layername = layername;
  this.showlayer = showlayer;
  this.opts = opts || {};
  //this.mb = new MessageBox(map,this,"mb",opts.messagebox);
  this.map = map;
  this.url = url;
  if (typeof url == "string") {
    this.urls = [url];
  } else {
    this.urls = url;
  }
 
  //this.mb.style = this.opts.messagestyle || { backgroundColor: "silver"};

  // infowindow styles
  this.titlestyle = this.opts.titlestyle || 'style = "font-family: arial, sans-serif;font-size: medium;font-weight:bold;font-size: 100%;"';
  this.descstyle = this.opts.descstyle || 'style = "font-family: arial, sans-serif;font-size: small;padding-bottom:.7em;"';
  this.directionstyle = this.opts.directionstyle || 'style="font-family: arial, sans-serif;font-size: small;padding-left: 1px;padding-top: 1px;padding-right: 4px;"';
  // sidebar
  this.sidebarfn = this.opts.sidebarfn || GeoXml.addSidebar;
  this.dropboxfn = this.opts.dropboxfn || GeoXml.addDropdown;
  // elabel options 
  this.pointlabelopacity = this.opts.pointlabelopacity || 100;
  this.polylabelopacity = this.opts.polylabelopacity || 100;
   // other useful "global" stuff
  this.hilite  = this.opts.hilite || { color:"#aaffff",opacity: 0.3, textcolor:"#000000" };
  this.latestsidebar = "";
  this.forcefoldersopen = false;
  if(typeof this.opts.allfoldersopen !="undefined"){ this.forcefoldersopen = this.opts.allfoldersopen;}
  this.clickablepolys = true;
  this.clickablelines = true;
  if(typeof this.opts.clickablepolys !="undefined"){ this.clickablepolys = this.opts.clickablepolys;}
  if(typeof this.opts.clickablelines !="undefined"){ this.clickablelines = this.opts.clickablelines;}
  this.nolegend = false;
  if(typeof this.opts.nolegend !="undefined"){
		this.nolegend = true;
		}
  this.hideall = false;
  if(typeof proxy!="undefined")this.proxy = proxy;
  if(typeof getcapproxy !="undefined")this.proxy = getcapproxy+"url=";
  if(this.opts.hideall){ this.hideall = this.opts.hideall; }
  if(top.publishdirectory){ this.publishdirectory = top.publishdirectory; }
  else {this.publishdirectory = "http://www.dyasdesigns.com/TNTmap/";}
  if(top.standalone){this.publishdirectory = "";}
  this.kmlicon =  this.publishdirectory +"images/ge.png";
  this.docicon = this.publishdirectory +"images/ge.png";
  this.foldericon = this.publishdirectory + "images/folder.png";
  this.gmlicon = this.publishdirectory + "images/geo.gif";
  this.rssicon = this.publishdirectory + "images/rssb.png";
  this.globalicon = this.publishdirectory + "images/geo.gif"; 
  this.WMSICON = "<img src=\""+this.publishdirectory+"images/geo.gif\" style=\"border:none\" />";
  GeoXml.WMSICON = this.WMSICON;
  this.baseLayers = [];
  this.bounds = new GLatLngBounds();
  this.style = {width:2,opacity:0.75,fillopacity:0.4};
  this.style.color = this.randomColor();
  this.style.fillcolor = this.randomColor();
  this.iwwidth = this.opts.iwwidth || 250;
  this.lastmarker = {};   
  this.verySmall = 0.0000001;
  this.progress = 0;
  this.ZoomFactor = 2;
  this.NumLevels = 18;
  this.maxtitlewidth = 0;
  this.styles = []; // associative array
  this.kml = [new KMLObj("GeoXML","")];
  this.jsdocs = [];
  this.jsonmarks = [];
  this.polyset = []; /* used while rendering */
  this.polygons = []; /*stores indexes to multi-polygons */ 
  this.polylines = []; /*stores indexes to multi-line */ 
  this.multibounds = []; /*stores extents of multi elements */
  this.overlayman = new Clusterer(map, this);
  this.allMarkers = [];
  this.overlayman.rowHeight = 20;
  if(this.opts.sidebarid){ this.basesidebar = this.opts.sidebarid; }
  this.overlayman.folders.push([]);
  this.overlayman.subfolders.push([]);
  this.overlayman.folderhtml.push([]);
  this.overlayman.folderhtmlast.push(0);
  this.overlayman.folderBounds.push(new GLatLngBounds()); 
  this.wmscount = 0;
  this.labels = new GTileLayerOverlay(G_HYBRID_MAP.getTileLayers()[1]);
  }
function $(mid){ return document.getElementById(mid);}

GeoXml.prototype.clear = function(idx) {
	for(var m=0;m<this.overlayman.markers.length;m++){
		this.overlayman.RemoveMarker(this.overlayman.markers[m]);
		}
	this.kml = [new KMLObj("GeoXML","")];
 	this.maxtitlewidth = 0;
  	this.styles = []; // associative array
  	this.jsdocs = [];
  	this.jsonmarks = [];
  	this.polyset = []; /* used while rendering */
  	this.polylines = [];
  	this.multibounds = []; 
	this.bounds = new GLatLngBounds();
  	this.overlayman = new Clusterer(map, this);
  	this.overlayman.rowHeight = 20;
	$(this.basesidebar).innerHTML = "";
  	this.overlayman.folders.push([]);
  	this.overlayman.subfolders.push([]);
  	this.overlayman.folderhtml.push([]);
  	this.overlayman.folderhtmlast.push(0);
  	this.overlayman.folderBounds.push(new GLatLngBounds()); 
 	this.wmscount = 0;
	}

GeoXml.prototype.createMarker = function(point,name,taggedName, desc,style,idx,instyle,visible) {
   var myvar=this.myvar;
      
	// if this is a cluster, then desc will be "c";
	var clustered = false;
	if (desc == "c") {
	clustered = true;
	}

   var icon = getCustomIcon(this.myvar, clustered) ; 

 
  var iwoptions = this.opts.iwoptions || {};
  var markeroptions = this.opts.markeroptions || {};

  if (!markeroptions.icon) {
    markeroptions.icon = icon;
  }
//  taggedName = name;
//  var newName = name.replace("<h2>","");
//  newName = newName.replace("</h2>","");
//  newName = newName.replace("<h3>","");
//  newName = newName.replace("</h3>","");
  if (clustered == true) {
  	markeroptions.title = name;
  }
  else {
  	markeroptions.title = name + ". Click on the point for more information";
  }
  
  //markeroptions.cursor = "help";
  var m = new GMarker(point, markeroptions);
  

  // strip the header texts from the name string
  
m.title = name;
  //var obj = {"type":"point","title":name,"description":escape(desc),"href":href,"shadow": shadow,"visibility":visible,"x":point.x,"y": point.y};
  var obj = {"type":"point","title":name,"description":escape(desc),"visibility":visible,"x":point.x,"y": point.y};
  this.kml[idx].marks.push(obj);
  if (this.opts.pointlabelclass) {
    var l = new ELabel(point, name, this.opts.pointlabelclass, this.opts.pointlabeloffset, this.pointlabelopacity, true);
    this.map.addOverlay(l);
  }

  var html1 = createInfo(this.layername,taggedName,desc);
  
// listener behaviour will differ depending on the nature of
// the point - is it a cluster?
if (name == "Click to Zoom in for Details") {
  GEvent.addListener(m, "click", function() {
    // this should only work if we are not capturing data ..
    if (startCapture == false ) {
             // if this is a cluster marker, offer the user the opportunity to zoom in
    	var answer = confirm ("There are multiple points in this area. Zoom in to see more details?")
		if (answer) {
			// centre on the point
			if (map.getZoom() < 13) {
				map.setCenter(this.getPoint(), map.getZoom()+ 3 );
			}
			else {
				map.setCenter(this.getPoint(), map.getZoom()+1 );
			}
		}
		else {
			// do nothing for now
		}
	
    } // startcapture = false
  });

} // this is a cluster point
else  {
	GEvent.addListener(m, "click", function() {
	    if (startCapture == false ) {
		    document.getElementById('opaquetext').innerHTML = "";
		    eval(myvar+".lastmarker = m");
			document.getElementById('container2').style.left = "0px";
			document.getElementById('container2').style.top = "0px";
			document.getElementById('container2').style.width = document.getElementById('map-canvas').style.width;
			document.getElementById('container2').style.height = "100%"; //document.getElementById('map-canvas').style.height;

		    document.getElementById('opaquetext').innerHTML = html1;
		    document.getElementById('container2').style.display = "block";
	     } // startcapture = false
	}); // end of the listener function
} // this is not a cluster point



  //if(this.opts.domouseover){
	//m.mess = html1+"</div>";
	//m.geoxml = this;
	//this.cursor = "help";
  	GEvent.addListener(m,"mouseover", function(point) {
  		//alert("mouseover");
		try {if(!point){ point=this.getPoint(); } }
		catch (e) {}
  		//m.geoxml.mb.showMess(m.mess,5000); 
  		//map.draggableCursor = "help";
  		//document.getElementById('map-canvas').style.cursor="help";
  	} );
	GEvent.addListener(m,"mouseout", function(point) {
		//alert("mouseover");
		try {if(!point){ point=this.getPoint(); } }
		catch (e) {}
		//m.geoxml.mb.showMess(m.mess,5000); 
		//document.getElementById('map-canvas').style.cursor="hand";
		//map.draggableCursor = "hand";
	} );

 //} // domouseover

  var nhtml = "";
  var parm;
  /*if (this.opts.sidebarid) {
    	var folderid = this.myvar+"_folder"+idx;    
    	var n = this.overlayman.markers.length; 
	var blob = "&nbsp;<img style=\"vertical-align:text-top;padding:0;margin:0\" height=\"16\" border=\"0\" src=\""+href+"\">&nbsp;";
 	parm =  this.myvar+"$$$" +name + "$$$marker$$$" + n +"$$$" + blob + "$$$" +visible+"$$$null"; 
		
	m.sidebarid = this.myvar+"sb"+n;
	m.hilite = this.hilite;
	m.geoxml = this;
	GEvent.addListener(m,"mouseover", function() {
		$(this.sidebarid).style.backgroundColor = this.hilite.color;
		$(this.sidebarid).style.color = this.hilite.textcolor;
		} 
		);
	GEvent.addListener(m,"mouseout", function() {
			$(this.sidebarid).style.background = "none"; 
			$(this.sidebarid).style.color = "";
			});

  	} */

 // if (!!this.opts.addmarker) {
 // 	
 //   this.opts.addmarker(m, name,idx, parm, visible);
 // } else {
  	
     this.overlayman.AddMarker(m, name,idx, parm, visible);
 // }

};

// Create Polyline



GeoXml.prototype.processLine = function (pnum, lnum, idx,taggedName,desc,name){
	var op = this.polylines[pnum];
	var line = op.lines[lnum];
	if(!line)return;
        var thismap = this.map;
	var iwoptions = this.opts.iwoptions || {};
	var polylineEncoder = new PolylineEncoder(this.NumLevels,this.ZoomFactor,this.verySmall,true);
	if(line.length >2) {
		
		var result = polylineEncoder.dpEncode(line);
		obj = { points: result.encodedPoints,
			levels: result.encodedLevels,
			color: op.color,
			weight: op.width,
			opacity: op.opacity,
			zoomFactor: this.ZoomFactor,
			numLevels: this.NumLevels,
			type: "polyline" 
	 		};
		var p = new GPolyline.fromEncoded(obj);	
		}
	else {
 		obj = { points:line, color:op.color, weight:op.width, opacity:op.opacity, type:"line" };
		var p = new GPolyline(line,op.color,op.width,op.opacity);
		}
	p.bounds = op.pbounds;
	var nhtml = "";
	var n = this.overlayman.markers.length;
	this.polylines[pnum].lineidx.push(n);
	var parm;
	//taggedName = op.name;
		//  var newName = op.name.replace("<h2>","");
		//  newName = newName.replace("</h2>","");
		//  newName = newName.replace("<h3>","");
		//  newName = newName.replace("</h3>","");
		
		//op.Name = newName;
		//p.title = name;
	  	p.title = op.name;
	  	//op.name = newName + ". Click for more details";
	  	//p.title = newName + ". Click for more details";

	var html = "<div style='font-weight: bold; font-size: medium; margin-bottom: 0em;'>"+op.name;
  	html += "</div>"+"<div style='font-family: Arial, sans-serif;font-size: small;width:"+this.iwwidth+"px'>"+op.description+"</div>";

	if(lnum ==0){
	 	if(this.opts.sidebarid) {
    			var blob = '&nbsp;&nbsp;<span style=";border-left:'+op.width+'px solid '+op.color+';">&nbsp;</span> ';
			parm =  this.myvar+"$$$" +op.name + "$$$polyline$$$" + n +"$$$" + blob + "$$$" +op.visible+"$$$"+pnum+"$$$";
			this.latestsidebar = this.myvar +"sb"+n;
 			}
		}

	if(lnum < line.length){
		setTimeout(this.myvar+".processLine("+pnum+","+(lnum+1)+",'"+idx+"','"+taggedName+"','"+desc+"','"+name+"');",15);
		if(this.opts.sidebarid) { p.sidebar = this.latestsidebar; }
		}
		
	if(this.opts.domouseover){
		//p.mess = html;
		}
		
		
        p.geoxml = this;
        p.strokeColor = op.color;
        p.strokeWeight = op.width;
	p.strokeOpacity = op.opacity;
	p.hilite = this.hilite;
	p.mytitle = p.title;
	p.map = this.map;
	p.idx = pnum;
  	
  	// events for line data ..!
  	p.onOver = function(){
		var pline = this.geoxml.polylines[this.idx];
		for(var l=0;l<pline.lineidx.length;l++){
			var mark = this.geoxml.overlayman.markers[pline.lineidx[l]];
			mark.realColor = mark.strokeColor; 
			mark.setStrokeColor(this.hilite.color);
			}
		$(this.sidebar).style.backgroundColor = this.hilite.color;
		$(this.sidebar).style.color = this.hilite.textcolor;
	//	if(this.mess) { this.geoxml.mb.showMess(this.mess,5000); } else { this.title = "Click for more information about "+this.mytitle; }
		};
  	p.onOut = function(){ 
		var pline = this.geoxml.polylines[this.idx];
		for(var l=0; l < pline.lineidx.length; l++){
			var mark = this.geoxml.overlayman.markers[pline.lineidx[l]];
			mark.setStrokeColor(mark.realColor);
			}
//		this.geoxml.mb.hideMess();
		$(this.sidebar).style.background = "none";
		$(this.sidebar).style.color = "";
		};


  var html1 = createInfo(this.layername,taggedName,desc);
  
  

  	/*GEvent.addListener(p,"click", function(point) 
  	{var doit=false; if(!point) { point = this.getPoint();doit=true; } 
  	if(this.geoxml.clickablelines|doit)this.map.openInfoWindowHtml(point, html, iwoptions); });*/
  	
  	GEvent.addListener(p, "click", function(point) {
	    // this should only work if we are not capturing data ..
	    if (startCapture == false ) {
		document.getElementById('opaquetext').innerHTML = "";
		document.getElementById('container2').style.left = "0px";
		document.getElementById('container2').style.top = "0px";
		document.getElementById('container2').style.width = document.getElementById('map-canvas').style.width;
		document.getElementById('container2').style.height = "100%"; //document.getElementById('map-canvas').style.height;
		document.getElementById('opaquetext').innerHTML = html1;
		document.getElementById('container2').style.display = "block";
	    } // startcapture = false
	  });

	obj.name = op.name;
	//obj.name = newName;
	
        obj.description = escape(op.description);
	obj.visibility = op.visibility;
 	this.kml[idx].marks.push(obj);
 	//this.overlayman.AddMarker(p, op.name, idx, parm, op.visibility);
 	
 	this.overlayman.AddMarker(p, op.name, idx, parm, op.visibility);
};

GeoXml.prototype.createPolyline = function(lines,color,desc,taggedName,width,opacity,pbounds,name,desc,idx, visible) {
	
    	var p = {};
   	if(!color){p.color = this.randomColor();}
   	
  	else { p.color = color; }
  	if(!opacity){p.opacity= 0.45;}
		else p.opacity = opacity;
  	if(!width){p.width = 2;}
 		 else{  p.width = width; }
  	p.idx = idx;
	p.visibility = visible;
	if(this.hideall)p.visibility = false;
	//taggedName = name;
	p.name = name;
	//alert(p.name);
	p.description = desc;
 	p.lines = lines;
        p.lineidx = [];
 	this.polylines.push(p);
	setTimeout(this.myvar+".processLine("+(this.polylines.length-1)+",0,'"+idx+"','"+taggedName+"','"+desc+"','"+name+"');",15);
	};

// Create Polygon

GeoXml.prototype.processPLine = function(taggedName,pnum,linenum,idx) {
        
	var p = this.polyset[pnum];
	var line = p.lines[linenum];
	var obj = {};
	
	if(line && line.length){
		var polylineEncoder = new PolylineEncoder(18,2,0.00001,true);
		var result = polylineEncoder.dpEncode(line);
		obj = {};
		obj.points = result.encodedPoints;
		obj.levels = result.encodedLevels;
		obj.color = p.color;
		obj.weight = p.weight;
		obj.numLevels = 18;
		obj.zoomFactor = 2;
		obj.opacity = p.opacity;
		p.obj.polylines.push(obj);
		}
	if(linenum == p.lines.length-1){	
		this.finishPolygon(taggedName,p.obj,idx);
		}
	else {
	    setTimeout(this.myvar+".processPLine('"+taggedName + "',"+pnum+","+(linenum+1)+",'"+idx+"');",5);
	    }
	};	

GeoXml.prototype.finishPolygon = function(taggedName, op,idx) {
  op.type = "polygon";
  
  this.finishPolygonJSON(taggedName, op,idx,false);
   };

GeoXml.prototype.finishPolygonJSON = function(taggedName, op,idx,updatebound,lastpoly) {
	
  var that = this;
  var iwoptions = that.opts.iwoptions || {};
  if(typeof op.visibility == "undefined")op.visibility=true;
  if(that.hideall)op.visibility = false;
  var desc = unescape(op.description);
  var p = new GPolygon.fromEncoded(op);

//taggedName = op.name;
//newName = op.name.replace("<h2>","");
//newName = newName.replace("</h2>","");
//newName = newName.replace("<h3>","");
//newName = newName.replace("</h3>","");
//op.name = newName;
  var html = "<div style='font-weight: bold; font-size: medium; margin-bottom: 0em;'>"+op.name+"</div>"
             +"<div style='font-family: Arial, sans-serif;font-size: small;width:"+this.iwwidth+"px'>"+desc+"</div>";
 var newgeom = (lastpoly != "p_"+op.name);
  if(newgeom){
	this.latestsidebar = that.myvar +"sb"+  this.overlayman.markers.length;
	}
  //if(that.opts.domouseover){
  
  	//p.mess = name;
//	}

  p.strokeColor =  getColour(this.myvar); //"#ff00ff"; // op.polylines[0].color;
  //p.mb = that.mb;
  p.hilite = that.hilite;
  p.strokeOpacity = 1;   //op.polylines[0].opacity;
  p.fillopacity =  1; //op.opacity;
  if(that.domouseover){
	//p.mess = html;
	}
  p.geoxml = that;
  
  
  p.title = op.name;
 
 //p.title = newName; 
 var n = this.overlayman.markers.length;
  if(newgeom){
	that.multibounds.push(new GLatLngBounds());
 	that.polygons.push([])
	}
  var len = that.multibounds.length-1;
  that.multibounds[len].extend(p.getBounds().getSouthWest());
  that.multibounds[len].extend(p.getBounds().getNorthEast()); 
  that.polygons[that.polygons.length-1].push(n);
  p.polyindex = that.polygons.length-1;
  p.geomindex = len;
  p.sidebarid = this.latestsidebar;
  
  // these are the tooltip functions for polygons
  p.onOver = function(){ 
		// make this into a tooltip
		try {if(!point){ point=this.getPoint(); } }
		catch (e) {}
	}; // end of onover function
  p.onOut = function(){ 
		try {if(!point){ point=this.getPoint(); } }
		catch (e) {}
	}; // end of onout function
  op.description = escape(desc);
  this.kml[idx].marks.push(op);
  p.map = this.map;
  name = op.name;
  //alert(taggedName + "  " +desc + " "+ this.layername);
  var html = createInfo(this.layername, taggedName,desc);

  GEvent.addListener(p,"click", function(point, overlay) {
  	
      if (startCapture == false ) {
      	
      	    document.getElementById('opaquetext').innerHTML = "";
  		document.getElementById('container2').style.left = "0px";
  		document.getElementById('container2').style.top = "0px";
  		document.getElementById('container2').style.width = document.getElementById('map-canvas').style.width;
  		document.getElementById('container2').style.height = "100%"; //document.getElementById('map-canvas').style.height;
  		document.getElementById('container2').style.display = "block";
  	    document.getElementById('opaquetext').innerHTML = html;
  	    
  
      } // startcapture = false
    });

  
  


if(this.opts.polylabelclass && newgeom ) {
 	var epoint =  p.getBounds().getCenter();
        var off = this.opts.polylabeloffset;
	if(!off)off= new GSize(0,0);
	off.x = -(op.name.length * 6);
 	var l = new ELabel(epoint, " "+op.name+" ", this.opts.polylabelclass, off, this.polylabelopacity, true);
	this.map.addOverlay(l);
	}

  var nhtml ="";
  var parm;
 
  if (this.basesidebar &&  newgeom) {
   
    var folderid = this.myvar+"_folder"+idx;
    var blob = '<span style="background-color:' + op.color + ';border:2px solid '+op.fillcolor+';">&nbsp;&nbsp;&nbsp;&nbsp;</span> ';
    parm =  this.myvar+"$$$" +op.name + "$$$polygon$$$" + n +"$$$" + blob + "$$$" +op.visibility+"$$$null"; 
    }
   if(updatebound) {
  	var ne = p.getBounds().getNorthEast();
   	var sw = p.getBounds().getSouthWest()
   	this.bounds.extend(ne);
   	this.bounds.extend(sw);
   	this.overlayman.folderBounds[idx].extend(sw);
   	this.overlayman.folderBounds[idx].extend(ne);
	}

   this.overlayman.AddMarker(p,op.name,idx, parm, op.visibility);
   return op.name;
   };

GeoXml.prototype.finishLineJSON = function(po, idx, lastlinename){
	var m;
	var that = this;
	var thismap = this.map;
	if(po.type == "line"){ m = new GPolyline(po.points,po.color,po.weight,po.opacity); }
	else { m = new GPolyline.fromEncoded(po); }
	m.mytitle = po.name;
	m.title = po.name;
        m.geoxml = this;
        m.strokeColor = po.color;
        m.strokeWeight = po.weight;
	m.strokeOpacity = po.opacity;
        m.hilite = this.hilite;
	var n = that.overlayman.markers.length;
	var lineisnew = false;
	if(("l_"+po.name) != lastlinename){
		lineisnew = true;
		that.polylines.push(po);
		var pnum = that.polylines.length-1;
		that.polylines[pnum].lineidx = [];
		that.latestsidebar = that.myvar +"sb"+n;
		}
	else {
		var pnum = that.polylines.length-1;
		that.polylines[pnum].lineidx.push(n);
		}
	m.sidebarid = that.latestsidebar;

	  m.onOver = function(){ 
			// make this into a tooltip
			//if(!point){ point=this.getPoint(); } 
		}; // end of onover function
	  m.onOut = function(){ 
	  		//if(!point){ point=m.getPoint(); } 
		}; // end of onout function



	var parm = "";
	that.kml[idx].marks.push(po);
	var desc = unescape(po.description);
	var html = "<div style='font-weight: bold; font-size: medium; margin-bottom: 0em;'>"+po.name;
  	html += "</div>"+"<div style='font-family: Arial, sans-serif;font-size: small;width:"+that.iwwidth+"px'>"+desc+"</div>";
	m.map = this.map;
	if(this.clickablelines){
  		GEvent.addListener(m,"click", function(point) {if(!point){ point=m.getPoint(); } this.map.openInfoWindowHtml(point,html,that.opts.iwoptions);} );
		}

	if(that.basesidebar && lineisnew) {
    		var blob = '&nbsp;&nbsp;<span style=";border-left:'+po.weight+'px solid '+po.color+';">&nbsp;</span> ';
		if(typeof po.visibility == "undefined")po.visibility = true;
		parm =  that.myvar+"$$$" +po.name + "$$$polyline$$$" + n +"$$$" + blob + "$$$" +po.visibility+"$$$"+(that.polylines.length-1)+"$$$";
 		}	
	
	var ne = m.getBounds().getNorthEast();
	var sw = m.getBounds().getSouthWest()
	that.bounds.extend(ne);
	that.bounds.extend(sw);
	that.overlayman.folderBounds[idx].extend(sw);
	that.overlayman.folderBounds[idx].extend(ne);
	
    	that.overlayman.AddMarker(m, po.name, idx, parm, po.visibility);	
	return(po.name);	
	};
	
GeoXml.prototype.handlePlaceObj = function(num, max, idx, lastlinename, depth){
	var that = this;
	var po = that.jsonmarks[num];
	var lastlinename;
	var name = po.name;
	if(po.title)name = po.title;
	if(name.length+depth > that.maxtitlewidth)that.maxtitlewidth = name.length+depth;
	switch (po.type) {
			case "polygon" :
				lastlinename = "p_"+ that.finishPolygonJSON(po,idx,true,lastlinename);
				break;
			case "line" :  
			case "polyline" :
				lastlinename = "l_"+ that.finishLineJSON(po,idx,lastlinename);		
				break;
			case "point":
          			that.createMarkerJSON(po,idx);
				lastlinename = "";
				break;
		 	}
	if (num < max-1){
		setTimeout(that.myvar+".handlePlaceObj("+(num+1)+","+max+","+idx+",'"+lastlinename+"',"+depth+");",1);
		}
	else {
		lastlinename = "";		
		if(num == that.jsonmarks.length-1){
			that.progress--;
    			if (that.progress <= 0) {
      		 	// Shall we zoom to the bounds?
      				//if (!that.opts.nozoom) {
        			//	that.map.setZoom(that.map.getBoundsZoomLevel(that.bounds));
        			//	that.map.setCenter(that.bounds.getCenter());
      				//	}
      				GEvent.trigger(that,"parsed");
      				if(!that.opts.sidebarid){
					//that.mb.showMess("Finished Parsing",1000);
					}
				}
	 		}
		}
	};


GeoXml.prototype.createPolygon = function(taggedName,lines,color,width,opacity,fillcolor,fillopacity, pbounds, name, desc, folderid, visible,fill,outline) {
  var thismap = this.map;
  var p = {};	
  
  // get rid of all the tags from name as this is used by ie to do the
  // tooltip!
  
  
  
  // this is the bit that sets the tooltip !
  //var newName = name.replace("<h2>","");
  //newName = newName.replace("</h2>","");
  //newName = newName.replace("<h3>","");
  //newName = newName.replace("</h3>","");
  
  
  p.obj = {"description":desc,"name":name };
  
  
  //p.obj = {"description":desc,"name" : newName};
  p.obj.polylines = []; 
  p.obj.visibility = visible;
  p.obj.fill = fill;
  p.obj.outline = outline; 
  p.fillcolor = fillcolor;
  p.obj.strokecolor = color; 
  if(!color){p.color = this.style.color;}
  else { p.color = color; }

  if(!fillcolor){ p.obj.color = this.randomColor(); }
  else {p.obj.color = fillcolor;}

  if(!opacity){p.obj.opacity= this.style.opacity;}
	else{ p.obj.opacity = opacity; }

  if(!fillopacity){p.obj.fillopacity = this.style.fillopacity}
   else { p.obj.fillopacity = fillopacity;}

  if(!width){p.weight = this.style.width;}
  else{  p.weight = width; }

  p.bounds = pbounds;
  p.lines = lines;
  p.sidebarid = this.opts.sidebarid;
  this.polyset.push(p);
  setTimeout(this.myvar+".processPLine('"+taggedName + "',"+ (this.polyset.length-1)+",0,'"+folderid+"')",5);
};


GeoXml.prototype.toggleFolder = function(i){

// we don't want to see subfolders

/*	var f = $(this.myvar+"_folder"+i);
	var tb = $(this.myvar+"TB"+i);
	if(f.style.display=="none"){
			f.style.display="";
			if(tb)tb.style.fontWeight = "normal";
			}
		else{ 
			f.style.display ="none"; 
			if(tb)tb.style.fontWeight = "bold";
			} */
	}

GeoXml.prototype.saveJSON = function(){

	if(top.standalone){
		var fpath = browseForSave("Select a directory to place your json file","JSON Data Files (*.js)|*.js|All Files (*.*)|*.*","JSON-DATA");
 		if(typeof fpath!="undefined")saveLocalFile (fpath+".js", this.kml.toJSONString());
		return;
		}

	if(this.kml.toJSONString){
		if(typeof serverBlessJSON!="undefined"){
			serverBlessJSON(escape(this.kml.toJSONString()),"MyKJSON"); 
			}
		else {
			showIt(this.kml.toJSONString());
			}
		}
	else {
		alert("No JSON methods currently available");
		}
	}

function showIt (str, h, w) {
	var features = "status=yes,resizable=yes,toolbar=0,height=" + h + ",width=" + h + ",scrollbars=yes";
	var myWin;
 
	if (top.widget) {
		//showMess(str);
		}
	else {
		myWin = window.open("", "_blank", features);
		myWin.document.open("text/xml");
		myWin.document.write(str);
		myWin.document.close();
		}
	}

GeoXml.prototype.toggleContents = function(i,show){
 	
// test - simply get all markers and remove from the map or add to the map?
if (show) {
	for (var i = 0; i < this.allMarkers.length; i++) {
		this.map.addOverlay(this.allMarkers[i]);
	}
}
else {
	for (var i = 0; i < this.allMarkers.length; i++) {
		try  {
			this.map.removeOverlay(this.allMarkers[i]);
		}
		catch (e) {
		}
	}
}
 	
 	
/* 	var f = this.overlayman.folders[i];
	var cb;
	if(show){
	for (var j=0;j<f.length;j++){
			var m = this.overlayman.markers[f[j]];
			
		        m.hidden = false;	
			cb = $(this.myvar+''+f[j]+'CB');
			if(cb)cb.checked = true;
				if(m.hide) { 
			//		alert("show");
					m.show(); 
				}
				else { 
					
					this.map.addOverlay(m); 
				}
			} // for
	} // if  
	else {
	   for (var j=0;j<f.length;j++){
			var m = this.overlayman.markers[f[j]];
			m.hidden = true;
			cb = $(this.myvar+''+f[j]+'CB');
			if(cb)cb.checked = false;
			
			if(m.hide) { 
				m.hide(); 
			}
			else {
				this.map.removeOverlay(m); 
			}
		} // end of for loop
	} // end of else ..

	var sf = this.overlayman.subfolders[i];
	if(typeof sf!="undefined"){
 		for (var j=0;j<sf.length;j++){
			if(sf[j]!=i){
	 			cb = $(this.myvar+''+sf[j]+'FCB');
				if(cb)cb.checked = (!!show);
				this.toggleContents(sf[j],show);
				} // end if
			} // end for
		 } // end if 
*/

	}; // end of function 


GeoXml.prototype.showHide = function(a,show, p){
 	if(a !== null){	
		if(show){ 
			this.overlayman.markers[a].show(); 
			this.overlayman.markers[a].hidden = false; 
			}	
		else  { this.overlayman.markers[a].hide(); 
			this.overlayman.markers[a].hidden = true; }
		}
	else {
		var ms = this.polylines[p];
		if(show){
			for(var i=0;i<ms.lineidx.length;i++){
				var m = this.overlayman.markers[ms.lineidx[i]];
				m.hidden = false;
				if(m.hide) { m.show(); }
				else { this.map.addOverlay(m); }
				}
		    }
		else {
			for(var i=0;i<ms.lineidx.length;i++){
				var m = this.overlayman.markers[ms.lineidx[i]]; 
				m.hidden = true;	
				if(m.hide) { m.hide(); }
					else { this.map.removeOverlay(m); }
				}
		    }
	    }
	};


GeoXml.prototype.toggleOff = function(a,show){
	if(show){ 
		this.map.addOverlay(this.overlayman.markers[a]); 
		this.overlayman.markers[a].hidden = false; 
		}	
	else  { this.map.removeOverlay(this.overlayman.markers[a]); 
		this.overlayman.markers[a].hidden = true; }

	if(this.labels.onMap){
		this.map.removeOverlay(this.labels);
 		this.map.addOverlay(this.labels); 
		}
	};

// Sidebar factory method One - adds an entry to the sidebar
GeoXml.addSidebar = function(myvar, name, type, e, graphic, ckd, i) {
   var check = "checked";
   if(ckd=="false")check = "";
    var h="";
    var mid = myvar+'sb'+e;
   switch(type) {
   case  "marker" :  h = '<li id="'+mid+'" onmouseout="GEvent.trigger(' + myvar+ '.overlayman.markers['+e+'],\'mouseout\');" onmouseover="GEvent.trigger(' + myvar+ '.overlayman.markers['+e+'],\'mouseover\');" ><input id="'+myvar+''+e+'CB" type="checkbox" style="vertical-align:middle" '+check+' onclick="'+myvar+'.showHide('+e+',this.checked)"><a href="#" onclick="GEvent.trigger(' + myvar+ '.overlayman.markers['+e+'],\'click\');return false;">'+ graphic + name + '</a></li>';
   break;
  case  "polyline" :  h = '<li id="'+mid+'"  onmouseout="'+myvar+ '.overlayman.markers['+e+'].onOut();" onmouseover="'+myvar+ '.overlayman.markers['+e+'].onOver();" ><input id="'+myvar+''+e+'CB" type="checkbox" '+check+' onclick="'+myvar+'.showHide(null,this.checked,'+i+')"><span style="margin-top:6px;"><a href="#" onclick="GEvent.trigger(' + myvar+ '.overlayman.markers['+e+'],\'click\');return false;">&nbsp;' + graphic + name + '</a></span></li>';
  break;
  case "polygon": h = '<li id="'+mid+'"  onmouseout="'+myvar+ '.overlayman.markers['+e+'].onOut();" onmouseover="'+myvar+ '.overlayman.markers['+e+'].onOver();" ><input id="'+myvar+''+e+'CB" type="checkbox" '+check+' onclick="'+myvar+'.showHide('+e+',this.checked)"><span style="margin-top:6px;"><a href="#" onclick="GEvent.trigger(' + myvar+ '.overlayman.markers['+e+'],\'click\');return false;">&nbsp;' + graphic + name + '</a></span></nobr></li>';
  break;
 case "groundoverlay": h = '<li id="'+mid+'"><input id="'+myvar+''+e+'CB" type="checkbox" '+check+' onclick="'+myvar+'.showHide('+e+',this.checked)"><span style="margin-top:6px;"><a href="#" onclick="GEvent.trigger(' + myvar+ '.overlayman.markers['+e+'],\'zoomto\');return false;">&nbsp;' + graphic + name + '</a></span></li>';
   break;
case "tiledoverlay": h = '<li id="'+mid+'"><nobr><input id="'+myvar+''+e+'CB" type="checkbox" '+check+' onclick="'+myvar+'.toggleOff('+e+',this.checked)"><span style="margin-top:6px;"><a href="#" oncontextMenu="'+myvar+'.upgradeLayer('+i+');return false;" onclick="GEvent.trigger(' + myvar+ '.overlayman.markers['+e+'],\'zoomto\');return false;">'+GeoXml.WMSICON +'&nbsp;'+ name + '</a><br />'+ graphic +'</span></li>';
   break;
}
return h;
};

// Dropdown factory method
GeoXml.addDropdown = function(myvar,name,type,i,graphic) {
    return '<option value="' + i + '">' + name +'</option>';
};

// Request to Parse an XML file

GeoXml.prototype.parse = function(titles) {
 
 var that = this;
 var names =[];
 if(typeof titles !="undefined"){
 if(typeof titles!= "string") {
 	names = titles;
	}
 else {
	// we have more than one type of data in the returned document?? cde
	names = titles.split(",");
	}
}
 that.progress += that.urls.length;
 for ( var u=0; u<that.urls.length; u++) {
   var title = names[u];
  if(typeof title =="undefined" || !title || title =="null" ){
  	var segs = that.urls[u].split("/");
	title = segs[segs.length-1];
	}
   //that.mb.showMess("Loading "+title);
   var re = /\.js$/i;
   if(that.urls[u].search(re) != -1){
	that.loadJSONUrl(this.urls[u], title);
	}
   else {
 	that.loadXMLUrl(this.urls[u], title);	}
 }
};


var currdeschead = "";
GeoXml.prototype.makeDescription = function(elem, title, depth) {
         var d = ""; 
	 var len = elem.childNodes.length;
	 var ln = 0;
	 while (len--) {
		var subelem = elem.childNodes.item(ln);
		var nn = subelem.nodeName;
		var sec = nn.split(":");
		var base = "";
		if(sec.length>1){ 
			base = sec[1];
			}
		else { base = nn;}
 	
		if(base.match(/^(boundedBy|StyleMap|styleUrl|posList|coordinates|Style|Polygon|LineString|Point|LookAt|Envelope|Box|MultiPolygon)/)){
 			currdeschead = ""; 
			}
		else {
		
			if(base.match(/#text|the_geom/)){}
			else {	
				currdeschead = "<b>"+base+"</b> :";
				}
			val = subelem.nodeValue;
			if(base.match(/(\S)*(name|title)(\S)*/i)){
			 	if(!val)val = GXml.value(subelem);
				title = val;
				if(val && typeof title!="undefined" && title.length > this.maxtitlewidth){
					this.maxtitlewidth = title.length;
					}
				currdeschead="";
				}
			else {
				 if(val && val.match(/(\S)+/)){		
					if (val.match(/^http:\/\/|^https:\/\//i)) {
        	    				val = '<a href="' + val + '">' + val + '</a>';
      		    				}
					else {
						if(!title || title==""){
							title = val;	
							if(val && typeof title!="undefined" && title.length > this.maxtitlewidth){
								this.maxtitlewidth = title.length;
								}
							}
						}
				
					}
			   if(val) { d += currdeschead + "<span>"+val+"</span><br />"; currdeschead = ""}
			
				if(subelem.childNodes.length){
		 			var con = this.makeDescription(subelem, title);
					if(con){
						d += con.desc;
						if(typeof con.title!="undefined" && con.title){
						 	title = con.title;
							if(title.length > this.maxtitlewidth){
								this.maxtitlewidth = title.length + depth;
								}
							}
						}
					}
				}

			}
		
		ln++;
		}
	var dc = {};
	dc.desc = d;
	dc.title = title;
	return dc;
	};

GeoXml.prototype.randomColor = function(){ 
	var hex="0123456789abcdef";
	var color="#";
	for ( var i=0;i<6;i++){
		var idx = parseInt(Math.random()*16);
		color += hex.substring(idx,idx+1);
		}
	return color;
	};


GeoXml.prototype.handlePlacemark = function (mark, idx, depth, fullstyle) {
     var that = this;
     var desc, title, name, style;
     title = "";
     desc = "";
     var styleid = 0;
     var lat, lon;
     
     //alert(this.layername + " "+this.sourceIsKML);
     
     //var visible = true;
     	var visible = true;
     	// depending on whether the layer is on or off ..!
     		// now switch layers on or off as required...
     		// should the layer be on or off?
     		if (this.showlayer == false) {
     			//alert(this.myvar + " " + this.showlayer);
     			//document.getElementById(this.myvar).checked = false;
     			//document.getElementById(this.myvar).click(); // = false;
     			//this.myvar.toggleContents(1,false);
     			visible = false;
     		}
     		else  {
     			visible = true;
     		}

     var newcoords = false;
     var l = mark.getAttribute("lat");
     if(typeof l!="undefined")lat = l;
     l = mark.getAttribute("lon");
     if(typeof l!="undefined"){
		newcoords = true;
		lon = l;
		}

     var coordset=mark.getElementsByTagName("coordinates");
	if(coordset.length <1){
	    coordset=mark.getElementsByTagName("gml:coordinates");
	    }
	if(coordset.length <1){
	   	coordset = [];
	    	var poslist =mark.getElementsByTagName("gml:posList");
		for(var l =0;l<poslist.length;l++){
			var coords = " ";
			var plitem = GXml.value(poslist.item(l)) + " ";
			var cor = plitem.split(' ');
			for(var cc=0;cc<(cor.length-1);cc++){
					if(cor[cc] && cor[cc]!=" " && !isNaN(parseFloat(cor[cc]))){
						coords += ""+parseFloat(cor[cc])+","+parseFloat(cor[cc+1]);
						coords += " ";
						}
					cc++;
					}
			if(coords){
 				if(poslist.item(l).parentNode && (poslist.item(l).parentNode.nodeName == "gml:LineString") )line_count++;
					else poly_count++;
				var cm = "<coordinates>"+coords+"</coordinates>";
				var node = GXml.parse(cm);
				if(coordset.push)coordset.push(node); 
				}
			}

		var pos = mark.getElementsByTagName("gml:pos");
		if(pos.length <1)pos = mark.getElementsByTagName("gml:pos");
		if(pos.length){
			for(var p=0;p<pos.length;p++){
				var nv = GXml.value(pos.item(p))+" ";
				var cor = nv.split(' ');
				var node = GXml.parse("<coordinates>"+cor[0]+","+cor[1]+"</coordinates>");
				if(coordset.push)coordset.push(node); 
				}
			}
	    }


	var coords = "";
	var point_count =0;
	var box_count=0;
	var line_count=0;
	var poly_count=0;
 	for (var ln = 0; ln < mark.childNodes.length; ln++) {
		var nn = mark.childNodes.item(ln).nodeName;
		var nv = GXml.value(mark.childNodes.item(ln));
		var ns = nn.split(":");
		var base;
		if(ns.length>1)base = ns[1].toLowerCase();
			else base = ns[0].toLowerCase();	
		
		processme = false;
		switch(base){
			case "name": 
				name = nv;
				// strip the CDATA stuff
				if (this.sourceIsKML == false ) {
					name = name.substr(9,name.length - 9); 
					name = name.substr(0, name.length - 3);
					// strip any h2 stuff
					var taggedName = name;


					// strip the H2 stuff
					  var newName = name.replace("<h2>","");
					  newName = newName.replace("</h2>","");
					  newName = newName.replace("<h3>","");
					  newName = newName.replace("</h3>","");
					name = newName;
					if(name.length+depth > this.maxtitlewidth)this.maxtitlewidth = name.length+depth;
				} else {
					taggedName = "<h2>Name</h2>"+name;
				}
				
				break;
			case "title":
				
				//?? appears that firefox uses title to identify an object
				// whereas IE uses name???
				title = nv;
				// strip the CDATA stuff
				title = title.substr(9,name.length - 9); 
				title = title.substr(0, name.length - 3);
				
				var taggedName = title;
				
				
				// strip the H2 stuff
				  var newName = title.replace("<h2>","");
				  newName = newName.replace("</h2>","");
				  newName = newName.replace("<h3>","");
				  newName = newName.replace("</h3>","");
				title = newName;
				if(title.length+depth > this.maxtitlewidth)this.maxtitlewidth = title.length+depth;
				break;
			case "desc":
			case "description":
				desc += nv;
				// strip out the CDATA tags that we added to 
				// allow us to process invalid HTML data 
				// replace(RegExp("<","g"),'&lt;');
				if (this.sourceIsKML == false) {
					desc = desc.substr(9,desc.length - 9); 
					desc = desc.substr(0, desc.length - 3);
				} else {
					desc = "<h3>Description</h3>"+desc;
				
				}
				
				
				if(desc.match(/<(\s)*img/i)){
					var preload = document.createElement("span");
     					preload.style.visibility = "visible";
					preload.style.position = "absolute";
					preload.style.left = "-1200px";
					preload.style.top = "-1200px";
					preload.style.zIndex = this.overlayman.markers.length; 
     					document.body.appendChild(preload);
					preload.innerHTML = desc;
					}	
				break;
			case "visibility":
 				if(nv == "0")visible = false;
				break;
			case "href":
			case "link":
				desc += "<p><a target='_blank' href='"+nv+"'>link</a></p>";
				break;
			case "author":
				desc += "<p><b>author:</b>"+nv+"</p>";
				break;
			case "time":
				desc += "<p><b>time:</b>"+nv+"</p>";
				break;
			case "lat":
				lat=nv; 
				break; 
			case "long":
				lon=nv; 
				newcoords = true;
				break;
			case "point":
				point_count++;
                                processme = true;
				break;
			case "line":
				line_count++;processme = true;break;
			case "box":
				box_count++;processme = true;break;
			case "polygon":
				poly_count++;processme = true;break;
				break;
			case "styleurl":
				styleid = nv;
			 	break;
			case "stylemap" :
				/*var found = false;
				var node = mark.childNodes.item(ln);
				for(var j=0;(j<node.childNodes.length && !found);j++){ 
					var pair = node.childNodes[j];
					for(var k =0;(k<pair.childNodes.length && !found);k++){
						var pn = pair.childNodes[k].nodeName;
						if(pn == "Style"){
							style = this.handleStyle(pair.childNodes[k]);
							found = true;
							}
						}
					}*/
				break;

			case "style":
				/*style = this.handleStyle(mark.childNodes.item(ln));*/
				break;
			}
			if(processme){
				var cor = nv.split(' ');
				coords = "";
				for(var cc=0;cc<(cor.length-1);cc++){
					if(cor[cc] && cor[cc]!=" " && !isNaN(parseFloat(cor[cc]))){
						coords += ""+parseFloat(cor[cc+1])+","+parseFloat(cor[cc]);
						if(cc>1 && cc<(cor.length-2)) coords += " ";
						}
					cc++;
					}
				if(coords !=""){
					var node = GXml.parse("<coordinates>"+coords+"</coordinates>");
					if(coordset.push)coordset.push(node); 
					}
				}

		}
	
      if(!name && title)name = title; 

      if(fullstyle){
		style = fullstyle;
		}
      if(styleid){
		style = this.styles[styleid];
		}

      if(typeof desc == "undefined" || !desc  ){
	    var dc = that.makeDescription(mark,"");
	    desc = "<ul>"+dc.desc+"</ul>";
	    if(!name && dc.title){
			name = dc.title;
			if((name.length +depth) > this.maxtitlewidth){
				this.maxtitlewidth = name.length + depth;
				}
			}
	    }
      
     if(newcoords && typeof lat!="undefined"){
        if(lat){
		    var cs = ""+lon+","+lat+" ";
		    var node = GXml.parse("<coordinates>"+cs+"</coordinates>");
		    coordset.push(node);
		    }
		}
    
     var lines = [];
     for(var c=0;c<coordset.length;c++){
      var skiprender =false;
     if(coordset[c].parentNode && (coordset[c].parentNode.nodeName.match(/^(gml:Box|gml:Envelope)/i))){
	skiprender = true;
	};

      var coords = GXml.value(coordset[c]);
      coords += " ";
      coords=coords.replace(/\s+/g," "); // tidy the whitespace
      coords=coords.replace(/^ /,"");    // remove possible leading whitespace
      //coords=coords +" "; //ensure trailing space
      coords=coords.replace(/, /,",");   // tidy the commas
      var path = coords.split(" ");
      // Is this a polyline/polygon?
      
      if (path.length == 1 || path[1]== "") {
        var bits = path[0].split(",");
        var point = new GLatLng(parseFloat(bits[1]),parseFloat(bits[0]));
        this.overlayman.folderBounds[idx].extend(point);
        // Does the user have their own createmarker function?
	//if(!skiprender){
	//	if(!name)name="un-named place";
        //	if (!!that.opts.createmarker) {
        //  		that.opts.createmarker(point, name, desc, styleid, idx, style, visible);
        //		} 
	//	else {
          		that.createMarker(point, name, taggedName, desc, styleid, idx, style, visible);
        //		}
	//	}
	} // path.length = 1
      else {
        // Build the list of points
        var points = [];
        var pbounds = new GLatLngBounds();
       		for (var p=0; p<path.length-1; p++) {
         	 var bits = path[p].split(",");
         	 var point = new GLatLng(parseFloat(bits[1]),parseFloat(bits[0]));
         	 points.push(point);
         	 pbounds.extend(point);
         	 }
		this.overlayman.folderBounds[idx].extend(pbounds.getSouthWest());
	 	this.overlayman.folderBounds[idx].extend(pbounds.getNorthEast());
		if(!skiprender) lines.push(points);
	    }
	}
 	if(!lines || lines.length <1) return;
        var linestring=mark.getElementsByTagName("LineString");
	if(linestring.length <1){
		linestring=mark.getElementsByTagName("gml:LineString");
		}
        if (linestring.length || line_count>0) {
          // its a polyline grab the info from the style
          if (!!style) {
            var width = style.width; 
            var color = style.color; 
            var opacity = style.opacity; 
          } else {
            /*var width = this.style.width;
            var color = this.style.color;
            var opacity = this.style.opacity;*/
            // PUT CODE IN HERE DEPENDING ON TYPE OF LINE
            var width = 5;
	    var color = getColour(this.myvar);  //"#ff00ff";
            var opacity = 1;
            
          }
          // Does the user have their own createmarker function?
	if(!name)name="un-named path";
          if (!!that.opts.createpolyline) {
            that.opts.createpolyline(lines,color,desc,taggedName, width,opacity,pbounds,name,desc,idx,visible);
          } else {
            that.createPolyline(lines,color,desc,taggedName, width,opacity,pbounds,name,desc,idx,visible);
          }
        }
        var polygons=mark.getElementsByTagName("Polygon");
	if(polygons.length <1){
		polygons=mark.getElementsByTagName("gml:Polygon");
		}
        if (polygons.length || poly_count>0) {
          // its a polygon grab the info from the style
          if (!!style) {
            var width = style.width; 
            var color = style.color; 
            var opacity = style.opacity; 
            var fillopacity = style.fillopacity; 
            var fillcolor = style.fillcolor;
	    var fill = style.fill;
	    var outline = style.outline; 
          } 
          else {
          	// put code in here depending on type of polygon
		    var width = 4; 
		    var color = getColour(this.myvar); //"#C0C0C0"; 
		    var opacity = 0.5; 
		    var fillopacity = 0.5; 
		    var fillcolor = getColour(this.myvar); "#C0C0C0";
		    var fill = true; //style.fill;
		    var outline = true; //style.outline; 
          } // !! style
	if(!name)name="un-named area";
 	if (!!that.opts.createpolygon) {
            that.opts.createpolygon(taggedName,lines,color,width,opacity,fillcolor,fillopacity,pbounds,name,desc,idx,visible,fill,outline);
          } else {
            that.createPolygon(taggedName,lines,color,width,opacity,fillcolor,fillopacity,pbounds,name,desc,idx,visible,fill,outline);
          }
      }  
    };

GeoXml.prototype.makeIcon = function(tempstyle, href){
	
	if (!!href) {
          if (!!this.opts.baseicon) {
           tempstyle = new GIcon(this.opts.baseicon,href);
	   tempstyle.href = href;
          } else {
            tempstyle = new GIcon(G_DEFAULT_ICON,href);
            tempstyle.iconSize = new GSize(32,32);
            tempstyle.shadowSize = new GSize(59,32);
            tempstyle.dragCrossAnchor = new GPoint(2,8);
            tempstyle.iconAnchor = new GPoint(16,32);
  	    tempstyle.href = href;
            if (this.opts.printgif) {
              var bits = href.split("/");
              var gif = bits[bits.length-1];
              gif = this.opts.printgifpath + gif.replace(/.png/i,".gif");
              tempstyle.printImage = gif;
              tempstyle.mozPrintImage = gif;
            }
            if (!!this.opts.noshadow) {
              tempstyle.shadow="";
            } else {
              // Try to guess the shadow image
              if (href.indexOf("/red.png")>-1 
               || href.indexOf("/blue.png")>-1 
               || href.indexOf("/green.png")>-1 
               || href.indexOf("/yellow.png")>-1 
               || href.indexOf("/lightblue.png")>-1 
               || href.indexOf("/purple.png")>-1
		|| href.indexOf("/orange.png")>-1 
               || href.indexOf("/pink.png")>-1 
		|| href.indexOf("-dot.png")>-1 ) {
                  tempstyle.shadow="http://maps.google.com/mapfiles/ms/icons/msmarker.shadow.png";
              }
              else if (href.indexOf("-pushpin.png")>-1  
		|| href.indexOf("/pause.png")>-1 
		|| href.indexOf("/go.png")>-1    
		|| href.indexOf("/stop.png")>-1     ) {
                  tempstyle.shadow="http://maps.google.com/mapfiles/ms/icons/pushpin_shadow.png";
              }
              else {
                var shadow = href.replace(".png",".shadow.png");
                tempstyle.shadow=shadow;
              }
            }
          }
        }
	return tempstyle;
	};
GeoXml.prototype.processKML = function(node, marks, title, sbid, depth) {  
	var that = this;
	//if (node.nodeName == "kml")icon = this.docicon;
        //if (node.nodeName == "Document" )icon = this.kmlicon;
	//if (node.nodeName == "Folder")icon = this.foldericon;
	
	// use the same icon as on screen for the layer
	icon = getCustomIcon(this.myvar, false);
	
	var pm = [];
	var sf = [];
	var desc= "";
	var desc = that.layername;
	var snip ="";
	var i;
	var open = that.forcefoldersopen;
	var visible = true;
	// depending on whether the layer is on or off ..!
		// now switch layers on or off as required...
		// should the layer be on or off?
		if (this.showlayer == false) {
			//alert(this.myvar + " " + this.showlayer);
			//document.getElementById(this.myvar).checked = false;
			//document.getElementById(this.myvar).click(); // = false;
			//this.myvar.toggleContents(1,false);
			visible = false;
		}
		else  {
			visible = true;
		}

	//var visible = true;
	var boundsmodified = false;
        networklink = false;
	var url;
	var ground = null;
	var opacity = 1.0;
	var wmsbounds;
	var makewms = false;
	var wmslist = [];
	for (var ln = 0; ln < node.childNodes.length; ln++) {
		var nextn = node.childNodes.item(ln);
		var nn = nextn.nodeName;
		var nv = nextn.nodeValue;
		switch (nn) {
		 	case "name":  
			case "title": 
				var title = GXml.value(nextn);
				if(title.length + depth > this.maxtitlewidth){ this.maxtitlewidth = title.length+depth;	}
			 	break;
			case "Folder" :
			
			case "Document" :
				sf.push(nextn); 
				break;
			case  "Description":
				var desc = GXml.value(nextn);
				break;
			case "open":
				if(GXml.value(nextn) == "1") open = true;
				if(GXml.value(nextn) == "0") open = this.forcefoldersopen;
				break;
			case "visibility":
				if(GXml.value(nextn) == "0") visible = false;
				break;
			default:
				for(var k=0;k<marks.length;k++){
					if(nn == marks[k]){
						pm.push(nextn);
					}	// nn == makrs
				} // marks.length
		} // switch
} // nodes.childnode.length	

	var folderid;
	var idx = this.overlayman.folders.length;


	if(sf.length > 1 || pm.length > 0) {    //|| ground || makewms ){
        	this.overlayman.folders.push([]);
   		this.overlayman.subfolders.push([]);
    		this.overlayman.folderhtml.push([]);
    		this.overlayman.folderhtmlast.push(0);
		this.overlayman.folderBounds.push(new GLatLngBounds());
  		this.kml.push(new KMLObj(title,desc));
  		folderid = this.createFolder(idx, title, sbid, icon, desc, snip, open, visible);
		} 
	else {
  		folderid = this.createFolder(idx, title, sbid, icon, desc, snip, open, visible);
		//folderid = sbid;
		}  
 

	for(var i=0;i<pm.length;i++) {
		this.handlePlacemark(pm[i], idx, depth+1);
		}
	var fc = 0;


	// this is the bit that loads the actual data for display!
		for(i=0;i<sf.length;i++) {
				var fid = this.processKML(sf[i], marks, title, folderid, depth+1);
				if(typeof fid =="number"){
					//this.overlayman.subfolders[idx].push(fid);
					//this.overlayman.folderBounds[idx].extend(this.overlayman.folderBounds[fid].getSouthWest());
					//this.overlayman.folderBounds[idx].extend(this.overlayman.folderBounds[fid].getNorthEast());
					if(fid!=idx){ this.kml[idx].folders.push(fid); }
					fc++;
				}
		}
	if(fc || pm.length || boundsmodified){
		//this.bounds.extend(this.overlayman.folderBounds[idx].getSouthWest());
		//this.bounds.extend(this.overlayman.folderBounds[idx].getNorthEast());
		}
	return idx;
	};


GeoXml.prototype.processing = function(xmlDoc,title, latlon, desc, sbid) {


// the processing here will depend if it is a map layer or a search query


if (this.layerType == "map" ) {
	
    this.overlayman.miStart = new Date();
    if(!desc)desc = title;
    var that = this;
    if(!sbid)sbid = 0;

    var root = xmlDoc.documentElement;
    if(!root){ 
    	alert("We are sorry but we were unable to download data for: "+ this.layername +"\n\nMove the map to try again"); 
    	var sb = $(sbid);	
    	if(sb){ sb.innerHTML = "";} // + sb.innerHTML; }
    	return 0; 
    }  // no document found
    var placemarks = [];
    basename = root.nodeName;
    var bases = basename.split(":");
    if(bases.length>1){basename = bases[1];
    }  // bases length greater than 1
    if(basename == "kml") {	
	if(!title)title = name;
	this.title = title;
	if(title.length >this.maxtitlewidth){
		this.maxtitlewidth = title.length;
	} // this.maxtitlewidth
	var marknames = ["Placemark"];

	var bar = $(this.basesidebar);
	if(bar)bar.style.display="";
	var idx = this.overlayman.folders.length;
	var fid = this.processKML(root, marknames, title, this.basesidebar, 0);	
	this.kml[0].folders.push(idx);
	
	
    }  // basename = "kml"


    // Is this the last file to be processed?
    this.progress--;
    if (that.progress == 0) {
      // Shall we zoom to the bounds?
      //if (!that.opts.nozoom) {
//	that.map.setZoom(that.map.getBoundsZoomLevel(that.bounds));
//	that.map.setCenter(that.bounds.getCenter());
//      } // opts nozoom

      GEvent.trigger(that,"parsed");
      	// now switch layers on or off as required...
      	// should the layer be on or off?
      	if (this.showlayer == false) {
      		//alert(this.myvar + " " + this.showlayer);
      		document.getElementById(this.myvar).checked = false;
      		//document.getElementById(this.myvar).click(); // = false;
      		//this.myvar.toggleContents(1,false);
      		}

      if(!this.opts.sidebarid){
	//this.mb.showMess("Finished Parsing",1000);
      }  // not this.opts.sidebarid
    } // that.progress = 0
} //layertype is not map
else  {
	
	
	this.processSearchResults(xmlDoc);
}
};

GeoXml.prototype.processSearchResults = function(xmlDoc) {

// we need to put an entry for each result, with a hotlink that moves the map
// to centre the map on the point


    var root = xmlDoc.documentElement;
    if(!root){ alert("We are sorry but we were unable to download data for: "+ this.layername); return 0; 
    }  // no document found
    var placemarks = [];
    basename = root.nodeName;
    var bases = basename.split(":");
    if(bases.length>1){basename = bases[1];
    }  // bases length greater than 1
    if(basename == "kml") {	
    
    	//document.getElementById("searchresults").style.display = "inline";

	var node=root;
	// now process the search results
		var that = this;
		var resultsHTML = "";
		
		//get the next level node down ..
		node = node.childNodes.item(0);
		for (var ln = 0; ln < node.childNodes.length; ln++) {
			var nextn = node.childNodes.item(ln);
			var nn = nextn.nodeName;
			var nv = nextn.nodeValue;
			
			// only add the result if it has coordinate information with it...
			var coordString = nextn.childNodes.item(2).childNodes.item(0).childNodes.item(0).nodeValue;
			if (coordString != ",") {
				// add the result onto the list
				// add as a text item
				// build up the parameter string to pass to goto result
				// we need the layer name and the coordinates
				var resultName = nextn.childNodes.item(0).childNodes.item(0).nodeValue;
				// now strip the CDATA tags away
				resultName = resultName.substr(9,resultName.length - 9); 
				resultName = resultName.substr(0, resultName.length - 3);

				//a href=\"javascript:gotoLoginPage()\">
				
				resultString = coordString ;
				//resultsHTML = resultsHTML + "<div id='result"+ln +"'";
				//resultsHTML = resultsHTML + "onclick=\"gotoResult("+ resultString+",'layername')\">";
				//resultsHTML = resultsHTML + "<a>"+resultName;
				//resultsHTML = resultsHTML +  "</a>";	
				//resultsHTML = resultsHTML + "</div>";	
				
				
				//resultsHTML = resultsHTML + "<a href=\"javascript:gotoResult("+resultString+",'layername')\">";
				//resultsHTML = resultsHTML + "<a href=\"#\" onclick=\"gotoResult("+resultString+",'layername');return false;\">";
				resultsHTML = resultsHTML + "<a href=\"#\" onclick=\"gotoResult("+resultString+",'"+ this.layername+"');return false;\">";
				//<a href="#" onClick="some_function('pagename');return false;">
				
				
				//resultsHTML = resultsHTML + "<a href=\"#\" onclick=\"gotoResult("+resultString+",'layername')\">";
				// trim the _search of the myvar value to get the right icon
				iconstring  = this.myvar.substr(0,this.myvar.length - 7);
				
				resultsHTML = resultsHTML + "<img style=\"width:12px;height:12px\" src='"+getIconLocation(iconstring,false)+"'/>";
				resultsHTML = resultsHTML + "<span style=\"font:12px Helvetica, sans-serif;\">" + resultName+ "</span></a><br>";
				
				
				// this code required due to long response time for ie7 whereas firefox displays
				// immediate results
				

			} // nodevalue is not null			
		} // nodes.childnode.length	
		if (resultsHTML == "") {
			resultsHTML = "No matches found";
		}
		
	document.getElementById("searchresults").innerHTML = document.getElementById("searchresults").innerHTML+"<h3>"+ this.layername + " </h3>" + resultsHTML;
	
	// now display the search results!
	//document.getElementById("searchresults").style.display = "inline";
	
    }  // basename = "kml"
    else {
    	alert("We are sorry but we were unable to download data for: "+ this.layername);
    } // basename not kml
}

 
GeoXml.prototype.createFolder = function(idx, title, sbid, icon, desc, snippet, keepopen, visible){ 	      
		var sb = $(sbid);	
	 	folderid = this.myvar+'_folder'+ idx;
                var checked ="";
		if(visible){ checked = " checked " }
		this.overlayman.folderhtml[folderid]="";
		var disp="display:block";
		var fw= "font-weight:normal";
 		if(typeof keepopen == "undefined" || !keepopen){
			disp ="display:none";
			fw = "font-weight:bold";
	 		}
	 	
	 	iconlocation = getIconLocation(this.myvar,false);
		if(!desc || desc ==""){
			desc = title;
			}
		//desc = escape(desc);
		//var htm = '<ul><input type="checkbox" id="'+this.myvar+''+idx+'FCB" style="vertical-align:middle" ';
		var htm = '<ul><input type="checkbox" id="'+this.myvar+'" style="vertical-align:middle" ';
		
		
		
		htm += checked;
		//alert(this.myvar + " "+ idx);
		htm += 'onclick="'+this.myvar+'.toggleContents('+idx+',this.checked)">';
		htm += '&nbsp;<span title="'+snippet+'" id="'+this.myvar+'TB'+idx+'" oncontextmenu=\"'+this.myvar+'.saveJSON('+idx+');\" onclick="'+this.myvar+'.toggleFolder('+idx+')" style=\"'+fw+'\">';
		htm += '<img style=\"vertical-align:text-top;padding:0;margin:0\" height=\"16\" border=\"0\" src="'+iconlocation+'" /></span>&nbsp;';
		htm +=  desc + '<br><span id=\"'+folderid+'\" style="height:14px;'+disp+'"></span></ul>';

		
		//if(sb){ sb.innerHTML = htm + sb.innerHTML; }
		if(sb){ sb.innerHTML = htm;} // + sb.innerHTML; }
		
		return folderid;
	    };
	    

GeoXml.prototype.processGML = function(root,title, latlon, desc) {
    var that = this;
    var isWFS = false;
    var placemarks = [];
    var srsName;
    var isLatLon = false;
    var xmin = 0;
    var ymin = 0;
    var xscale = 1;
    var yscale = 1;
    	for (var ln = 0; ln < root.childNodes.length; ln++) {
		var kid = root.childNodes.item(ln).nodeName;
		var n = root.childNodes.item(ln);
		if(kid == "gml:boundedBy" || kid  == "boundedBy"){
			 for (var j = 0; j < n.childNodes.length; j++) {
				var nn = n.childNodes.item(j).nodeName;
				var llre = /CRS:84|(4326|4269)$/i;
				if(nn == "Box" || nn == "gml:Box"){
					var box =  n.childNodes.item(j);
					srsName = n.childNodes.item(j).getAttribute("srsName");
					if(srsName.match(llre)){
						isLatLon = true;
						} 
					else {
						alert("SRSname ="+srsName+"; attempting to create transform");
						 for (var k = 0; k < box.childNodes.length; k++) {
							var coor = box.childNodes.item(k);
							if(coor.nodeName =="gml:coordinates" ||coor.nodeName =="coordinates" ){
								var coorstr =  GXml.value(coor);
								var pts = coorstr.split(" ");
								var pt1 = pts[0].split(",");
								var pt2 = pts[1].split(",");
								xscale = (parseFloat(pt2[0]) - parseFloat(pt1[0]))/(latlon.xmax - latlon.xmin);
								yscale = (parseFloat(pt2[1]) - parseFloat(pt1[1]))/(latlon.ymax - latlon.ymin);
								xmin = pt1[0]/xscale - latlon.xmin;
								ymin = pt1[1]/yscale - latlon.ymin;
								}
							}
						}
					break;
					}
				if(nn == "Envelope" || nn == "gml:Envelope"){
					var box =  n.childNodes.item(j);
					srsName = n.childNodes.item(j).getAttribute("srsName");
					if(srsName.match(llre)){
						isLatLon = true;
						} 
					else {
						alert("SRSname ="+srsName+"; attempting to create transform");
						 for (var k = 0; k < box.childNodes.length; k++) {
							var coor = box.childNodes.item(k);
							if(coor.nodeName =="gml:coordinates" ||coor.nodeName =="coordinates" ) {
								var pts = coor.split(" ");
								var b = {"xmin":100000000,"ymin":100000000,"xmax":-100000000,"ymax":-100000000};
								for(var m = 0;m<pts.length-1;m++){
									var pt = pts[m].split(",");
									var x = parseFloat(pt[0]);
									var y = parseFloat(pt[1]);
									if(x<b.xmin)b.xmin = x;
									if(y<b.ymin)b.ymin = y;
									if(x>b.xmax)b.xmax = x;
									if(y>b.ymax)b.ymax = y;
									}
								xscale = (b.xmax - b.xmin)/(latlon.xmax - latlon.xmin);
								yscale = (b.ymax - b.ymin)/(latlon.ymax - latlon.ymin);
								xmin = b.xmin/xscale - latlon.xmin;
								ymin = b.ymin/yscale - latlon.ymin;
								}
							}
						}
					
						}
						break;
					}
				}
		if(kid == "gml:featureMember" || kid == "featureMember"){
			placemarks.push(n);
			}
		}
 
     var folderid;
     if(!title)title = name;
       this.title = title;
       if(placemarks.length<1){
		alert("No features found in "+title);
		//this.mb.showMess("No features found in "+title,3000);
		} 
	else {
	    //this.mb.showMess("Adding "+placemarks.length+" features found in "+title);
            this.overlayman.folders.push([]);
            this.overlayman.folderhtml.push([]);
	    this.overlayman.folderhtmlast.push(0);
	    this.overlayman.folderBounds.push(new GLatLngBounds());
	    this.kml.push(new KMLObj(title,desc));
	    var idx = this.overlayman.folders.length-1;
    	if(this.basesidebar) {    
	 	    folderid = this.createFolder(idx,title,this.basesidebar,this.gmlicon,desc,null,true,true);
		    } 
	
	if(isLatLon){
    		for (var i = 0; i < placemarks.length; i++) {
     			this.handlePlacemark(placemarks[i],idx,0);
    			}
		}
	else {
	     var trans = {"xs":xscale,"ys":yscale,"x":xmin, "y":ymin };
	    for (var i = 0; i < placemarks.length; i++) {
		        this.handleGeomark(placemarks[i],idx,trans,0);
		        }
	    	}
	}

    // Is this the last file to be processed?
    this.progress--;
    if (that.progress == 0) {
      // Shall we zoom to the bounds?
      if (!that.opts.nozoom) {
	that.bounds = that.overlayman.folderBounds[idx];
        that.map.setZoom(that.map.getBoundsZoomLevel(that.bounds));
        that.map.setCenter(that.bounds.getCenter());
      }

      GEvent.trigger(that,"parsed");
      if(!this.opts.sidebarid){
		//this.mb.showMess("Finished Parsing",1000);
		}
    }
};

// PolylineEncoder.js copyright Mark McClure  April/May 2007
//
// This software is placed explicitly in the public
// domain and may be freely distributed or modified.
// No warranty express or implied is provided.

PolylineEncoder = function(numLevels, zoomFactor, verySmall, forceEndpoints) {
  var i;
  if(!numLevels) {
    numLevels = 18;
  }
  if(!zoomFactor) {
    zoomFactor = 2;
  }
  if(!verySmall) {
    verySmall = 0.0000001;
  }
  if(!forceEndpoints) {
    forceEndpoints = true;
  }
  this.numLevels = numLevels;
  this.zoomFactor = zoomFactor;
  this.verySmall = verySmall;
  this.veryTiny = verySmall * verySmall;
  this.forceEndpoints = forceEndpoints;
  this.zoomLevelBreaks = new Array(numLevels);
  for(i = 0; i < numLevels; i++) {
    this.zoomLevelBreaks[i] = verySmall*Math.pow(zoomFactor, numLevels-i-1);
    this.zoomLevelBreaks[i] *= this.zoomLevelBreaks[i];
  }
}

// The main function.  Essentially the Douglas-Peucker
// algorithm, adapted for encoding. Rather than simply
// eliminating points, we record their from the
// segment which occurs at that recursive step.  These
// distances are then easily converted to zoom levels.
PolylineEncoder.prototype.dpEncode = function(points) {
  var absMaxDist = 0;
  var stack = [];
  var dists = new Array(points.length);
  var maxDist, maxLoc, temp, first, last, current;
  var i, encodedPoints, encodedLevels;
  var segmentLength;
  
  
 // if(points.length > 2) {
    stack.push([0, points.length-1]);
    while(stack.length > 0) {
      current = stack.pop();
      maxDist = 0;
      segmentLength = Math.pow(points[current[1]].lat()-points[current[0]].lat(),2) + Math.pow(points[current[1]].lng()-points[current[0]].lng(),2);
      for(i = current[0]+1; i < current[1]; i++) {
        temp = this.distance(points[i], points[current[0]], points[current[1]], segmentLength);
        if(temp > maxDist) {
          maxDist = temp;
          maxLoc = i;
          if(maxDist > absMaxDist) {
            absMaxDist = maxDist;
          }
        }
      }
      if(maxDist > this.veryTiny ) {
        dists[maxLoc] = maxDist;
        stack.push([current[0], maxLoc]);
        stack.push([maxLoc, current[1]]);
      }
    }
 // }
   
  encodedPoints = this.createEncodings(points, dists);
  encodedLevels = this.encodeLevels(points, dists, absMaxDist);
  return {
    encodedPoints: encodedPoints,
    encodedLevels: encodedLevels,
    encodedPointsLiteral: encodedPoints.replace(/\\/g,"\\\\")
  }
}

PolylineEncoder.prototype.dpEncodeToJSON = function(points,
  color, weight, opacity) {
  var result;

  result = this.dpEncode(points);
  return {
    color: color,
    weight: weight,
    opacity: opacity,
    points: result.encodedPoints,
    levels: result.encodedLevels,
    numLevels: this.numLevels,
    zoomFactor: this.zoomFactor,
    literals: result.encodePointsLiteral
  }
}

PolylineEncoder.prototype.dpEncodeToGPolyline = function(points, color, weight, opacity) {
  return new GPolyline.fromEncoded(
    this.dpEncodeToJSON(points, color, weight, opacity));
}

PolylineEncoder.prototype.dpEncodeToGPolygon = function(pointsArray,
  boundaryColor, boundaryWeight, boundaryOpacity,
  fillColor, fillOpacity, fill, outline) {
  var i, boundaries;

  boundaries = new Array(0);
  for(i=0; i<pointsArray.length; i++) {
    boundaries.push(this.dpEncodeToJSON(pointsArray[i],
      boundaryColor, boundaryWeight, boundaryOpacity));
  }
  return new GPolygon.fromEncoded({
    polylines: boundaries,
    color: fillColor,
    opacity: fillOpacity,
    fill: fill,
    outline: outline
  });
}

// distance(p0, p1, p2) computes the square distance between the point p0
// and the segment [p1,p2].  This could probably be replaced with
// something that is a bit more numerically stable.
PolylineEncoder.prototype.distance = function(p0, p1, p2, segLength) {
  var u, out;
   var dlat2 = p2.lat() - p1.lat();
   var dlong1 = p2.lng() - p1.lng();
  if(dlat2 === 0 && dlong1 === 0) {
    out = Math.pow(p2.lat()-p0.lat(),2) + Math.pow(p2.lng()-p0.lng(),2);
  }
  else {
   var dlat0 = p0.lat() - p1.lat();
   var dlong0 = p0.lng() - p1.lng();
    u = ((dlat0)*(dlat2)+(dlong0)*(dlong1))/segLength;
    if(u <= 0) {
      out = Math.pow(dlat0,2) + Math.pow(dlong0,2);
    }
    if(u >= 1) {
      out =  Math.pow(p0.lat() - p2.lat(),2) + Math.pow(p0.lng() - p2.lng(),2);
    }
    if(0 < u && u < 1) {
      out = Math.pow(dlat0-u*(dlat2),2) + Math.pow(dlong0-u*(dlong1),2);
    }
  }
  return out;
}

// The createEncodings function is very similar to Googles
// http://www.google.com/apis/maps/documentation/polyline.js
// The key difference is that not all points are encoded, 
// since some were eliminated by Douglas-Peucker.
PolylineEncoder.prototype.createEncodings = function(points, dists) {
  var i;
  var j;
  var floor = Math.floor;
  var len = points.length-2;
  var late5;
  var lnge5;
  var dlat = floor(points[0].lat() * 1e5);
  var dlng = floor(points[0].lng() * 1e5);
  var plat = dlat;
  var plng = dlng;
  var encoded_points = this.encodeSignedNumber(dlat) + this.encodeSignedNumber(dlng);
  for(j = len; j >0; j--) {
    var i = len - j+1;
    if(dists[i] != undefined) {
      late5 = floor(points[i].lat() * 1e5);
      lnge5 = floor(points[i].lng() * 1e5);
      dlat = late5 - plat;
      dlng = lnge5 - plng;
      plat = late5;
      plng = lnge5;
      encoded_points += this.encodeSignedNumber(dlat) + this.encodeSignedNumber(dlng);
    }
  }
   dlat = floor(points[len+1].lat() * 1e5) - plat;
   dlng = floor(points[len+1].lng() * 1e5) - plng;
   encoded_points += this.encodeSignedNumber(dlat) + this.encodeSignedNumber(dlng);
  return encoded_points;
}

// This computes the appropriate zoom level of a point in terms of its 
// distance from the relevant segment in the DP algorithm.  Could be done
// in terms of a logarithm, but this approach makes it a bit easier to
// ensure that the level is not too large.
PolylineEncoder.prototype.computeLevel = function(dd) {
  var lev;
  if(dd > this.veryTiny) {
    lev=0;
    while(dd < this.zoomLevelBreaks[lev]) {
      lev++;
    }
    return lev;
  }
}

// Now we can use the previous function to march down the list
// of points and encode the levels.  Like createEncodings, we
// ignore points whose distance (in dists) is undefined.
PolylineEncoder.prototype.encodeLevels = function(points, dists, absMaxDist) {
  var i;
  var encoded_levels = "";
  if(this.forceEndpoints) {
    encoded_levels += this.encodeNumber(this.numLevels-1)
  } else {
    encoded_levels += this.encodeNumber(
      this.numLevels-this.computeLevel(absMaxDist)-1)
  }
  for(i=1; i < points.length-1; i++) {
    if(dists[i] != undefined) {
      encoded_levels += this.encodeNumber(
        this.numLevels-this.computeLevel(dists[i])-1);
    }
  }
  if(this.forceEndpoints) {
    encoded_levels += this.encodeNumber(this.numLevels-1)
  } else {
    encoded_levels += this.encodeNumber(
      this.numLevels-this.computeLevel(absMaxDist)-1)
  }
  return encoded_levels;
}

// This function is very similar to Googles, but I added
// some stuff to deal with the double slash issue.
PolylineEncoder.prototype.encodeNumber = function(num) {
  var encodeString = "";
  var nextValue, finalValue;
  while (num >= 0x20) {
    nextValue = (0x20 | (num & 0x1f)) + 63;
//     if (nextValue == 92) {
//       encodeString += (String.fromCharCode(nextValue));
//     }
    encodeString += (String.fromCharCode(nextValue));
    num >>= 5;
  }
  finalValue = num + 63;
//   if (finalValue == 92) {
//     encodeString += (String.fromCharCode(finalValue));
//   }
  encodeString += (String.fromCharCode(finalValue));
  return encodeString;
}

// This one is Googles verbatim.
PolylineEncoder.prototype.encodeSignedNumber = function(num) {
  var sgn_num = num << 1;
  if (num < 0) {
    sgn_num = ~(sgn_num);
  }
  return(this.encodeNumber(sgn_num));
}


// The remaining code defines a few convenience utilities.
// PolylineEncoder.latLng
PolylineEncoder.latLng = function(y, x) {
	this.y = y;
	this.x = x;
}
PolylineEncoder.latLng.prototype.lat = function() {
	return this.y;
}
PolylineEncoder.latLng.prototype.lng = function() {
	return this.x;
}

// PolylineEncoder.pointsToLatLngs
PolylineEncoder.pointsToLatLngs = function(points) {
	var i, latLngs;
	latLngs = new Array(0);
	for(i=0; i<points.length; i++) {
		latLngs.push(new PolylineEncoder.latLng(points[i][0], points[i][1]));
	}
	return latLngs;
}

// PolylineEncoder.pointsToGLatLngs
PolylineEncoder.pointsToGLatLngs = function(points) {
	var i, gLatLngs;
	gLatLngs = new Array(0);
	for(i=0; i<points.length; i++) {
		gLatLngs.push(new GLatLng(points[i][0], points[i][1]));
	}
	return gLatLngs;
}



GPolyline.prototype.getPoint = function () { return (this.getVertex(Math.round(this.getVertexCount()/2))); };
GPolyline.prototype.computeBounds = function() {
  var bounds = new GLatLngBounds();
  for (var i=0; i < this.getVertexCount() ; i++) {
	var v = this.getVertex(i);
	if(v) bounds.extend(v);
  	}
  this.bounds = bounds;
  return bounds;
}


GTileLayerOverlay.prototype.getBounds = function(){return this.bounds; };


GPolyline.prototype.getBounds = function() {
  if(typeof this.bounds!="undefined") return this.bounds;
   else return (this.computeBounds());
  }

GPolyline.count = 0;  
GPolyline.prototype.myredraw = GPolyline.prototype.redraw;
GPolyline.prototype.myinit = GPolyline.prototype.initialize;


GPolyline.prototype.initialize = function(force) {
   GPolyline.count++;
   this.dash = "";
   //this.cursor = "help";
   this.domid = "GLine"+GPolyline.count;
   this.myinit(force); //original method
   this.className = "";
}

GPolyline.prototype.redraw = function(force) {
   this.myredraw(force); //original method
}

//event handlers
//GPolyline.prototype.onClick = function(){
 //   GEvent.trigger(this,"click");
//}
GPolyline.prototype.onOver = function(){
    GEvent.trigger(this,"mouseover");
}
GPolyline.prototype.onOut = function(){
    GEvent.trigger(this,"mouseout");
}

//once the shape has been drawn, we can modify it with these setX functions;

GPolyline.prototype.setStrokeColor = function(color) {
    this.strokeColor = color;
    var dom = $(this.domid); 
    if(navigator.userAgent.indexOf("MSIE") != -1){
        dom.stroke.color = this.strokeColor;
    }
    else{
        dom.setAttribute("stroke",this.strokeColor);
    }
}
GPolyline.prototype.getStrokeColor = function() {
    return this.strokeColor;
}
GPolyline.prototype.setStrokeDash = function(dash) {
    this.dash = dash;
    var dom = $(this.domid); 
    if(typeof dom=="undefined")return;
    if(navigator.userAgent.indexOf("MSIE") != -1){
        if(this.dash == "dash")
            dom.stroke.dashstyle = "dash";       
        else if (this.dash == "dot")
            dom.stroke.dashstyle = "dot";    
        else 
            dom.stroke.dashstyle = "";    
    }
    else{
        if(this.dash == "dash")
            dom.setAttribute("stroke-dasharray","10,10");
        else if (this.dash == "dot")
            dom.setAttribute("stroke-dasharray","3,17");
        else
            dom.setAttribute("stroke-dasharray","none");
    }
}
GPolyline.prototype.getStrokeDash = function() {
    return this.dash;
}
GPolyline.prototype.setStrokeWeight = function(weight) {
    this.strokeWeight = weight;
    var dom = $(this.domid); 
if(typeof dom=="undefined")return;
    if(navigator.userAgent.indexOf("MSIE") != -1){
        dom.stroke.weight = this.strokeWeight.toString()+"px";   
    }
    else{
        dom.setAttribute("stroke-width",this.strokeWeight.toString()+"px");
    }
}

GPolyline.prototype.setTitle = function(str) {
    this.title = str;
    var dom = $(this.domid); 
if(typeof dom=="undefined")return;
    if(navigator.userAgent.indexOf("MSIE") != -1){
        dom.title = this.title;   
    }
    else{
        dom.setAttribute("title",str);
    }
}

GPolyline.prototype.getStrokeWeight = function() {
    return this.strokeWeight;
}
GPolyline.prototype.setStrokeOpacity = function(opacity) {
	if (opacity == undefined) {
		opacity = 0.5;
	}
    this.strokeOpacity = opacity;
    var dom = $(this.domid); 
if(typeof dom=="undefined") {
	return;
}
    if(navigator.userAgent.indexOf("MSIE") != -1){
        dom.stroke.opacity = this.strokeOpacity;
    }
    else{
        dom.setAttribute("stroke-opacity",this.strokeOpacity);
    }
}

GPolyline.prototype.getStrokeOpacity = function() {
    return this.strokeOpacity;
 	}

GTileLayer.prototype.getBounds = function(){
	return this.bounds;
	}

/* Extension to GPolygon over-ride to provide mouse events and dashed styles etc for polygons */
GPolygon.count = 0;
GPolygon.prototype.getPoint = function() { return (this.getBounds().getCenter()); };
GPolygon.prototype.myredraw = GPolygon.prototype.redraw;
GPolygon.prototype.myinit = GPolygon.prototype.initialize;

GPolygon.prototype.initialize = function(force) {
   GPolygon.count++;
   this.strokeWeight = 2;
   this.dash = "";
   this.fillColor = this.color;
   this.fillOpacity = 0.4;
   this.strokeOpacity = this.strokeOpacity || 0.6;
   //this.cursor = "help";
   this.domid = "gpoly"+GPolygon.count;
   this.myinit(force); //original method
   this.className = "";
}


// we are using this funcition!!
GPolygon.prototype.redraw = function(force) {
   this.myredraw(force); //original method
   var dom;
   if(navigator.userAgent.indexOf("MSIE") != -1){
       var shps = document.getElementsByTagName("shape"); 
       dom = shps[shps.length-1];//assume ours is the most recently added by the superclass redraw
       //dom.style.cursor = "help";//to show mouseover 
       if(this.title)dom.title = this.title;
       dom.id = this.domid;//assign unique DOM id so we can modify attributes later
        }
   else{
        var shps = document.getElementsByTagName("path"); 
	if(shps.length){
       		dom = shps[shps.length-1];//assume ours is the most recently added by the superclass redraw
 		//dom.style.cursor = "help";//to show mouseover
 		// this is the tooltip?
 		//  var newName = this.title.replace("<h2>","");
		//  newName = newName.replace("</h2>","");
		//  newName = newName.replace("<h3>","");
		//  newName = newName.replace("</h3>","");
        	if(this.title)dom.setAttribute("title",this.title);
		}
        }
   if(dom){
   	dom.setAttribute("id",this.domid);//assign unique DOM id so we can modify attributes later
   //set up the appearance of our polygon
   	this.setStrokeColor(this.strokeColor);
   	this.setStrokeDash(this.dash);
   	this.setStrokeOpacity(this.strokeOpacity);
   	this.setStrokeWeight(this.strokeWeight);
   	this.setFillColor(this.fillColor);
   	this.setFillOpacity(this.fillOpacity);
   //set up event handlers
   	if(this.onClick){
    		var cclick = GEvent.callback(this,this.onClick);
    	}
   	var cover = GEvent.callback(this,this.onOver);
   	var cout = GEvent.callback(this,this.onOut);
   	GEvent.clearInstanceListeners(dom);//safety 
   	if(this.onClick) GEvent.addDomListener(dom,"click",function(event){cclick();});
   	GEvent.addDomListener(dom,"mouseover",function(){cover();});
   	GEvent.addDomListener(dom,"mouseout",function(){cout();});
	}
}

//event handlers
GPolygon.prototype.onClick = function(){
    GEvent.trigger(this,"click");
}
GPolygon.prototype.onOver = function(){
    GEvent.trigger(this,"mouseover");
}
GPolygon.prototype.onOut = function(){
    GEvent.trigger(this,"mouseout");
}

//once the shape has been drawn, we can modify it with these setX functions;

GPolygon.prototype.setStrokeColor = function(color) {
    this.strokeColor = color;
    var dom = $(this.domid); if(typeof dom=="undefined")return;
    if(navigator.userAgent.indexOf("MSIE") != -1){
        dom.stroke.color = this.strokeColor;
    }
    else{
        dom.setAttribute("stroke",this.strokeColor);
    }
}
GPolygon.prototype.getStrokeColor = function() {
    return this.strokeColor;
}
GPolygon.prototype.setStrokeDash = function(dash) {
    this.dash = dash;
    var dom = $(this.domid); if(typeof dom=="undefined")return;
    if(navigator.userAgent.indexOf("MSIE") != -1){
        if(this.dash == "dash")
            dom.stroke.dashstyle = "dash";       
        else if (this.dash == "dot")
            dom.stroke.dashstyle = "dot";    
        else 
            dom.stroke.dashstyle = "";    
    }
    else{
        if(this.dash == "dash")
            dom.setAttribute("stroke-dasharray","10,10");
        else if (this.dash == "dot")
            dom.setAttribute("stroke-dasharray","3,17");
        else
            dom.setAttribute("stroke-dasharray","none");
    }
}
GPolygon.prototype.getStrokeDash = function() {
    return this.dash;
}
GPolygon.prototype.setStrokeWeight = function(weight) {
    this.strokeWeight = weight;
    var dom = $(this.domid); if(typeof dom=="undefined")return;
    if(navigator.userAgent.indexOf("MSIE") != -1){
        dom.stroke.weight = this.strokeWeight.toString()+"px";   
    }
    else{
        dom.setAttribute("stroke-width",this.strokeWeight.toString()+"px");
    }
}

GPolygon.prototype.getStrokeWeight = function() {
    return this.strokeWeight;
}
GPolygon.prototype.setStrokeOpacity = function(opacity) {
    this.strokeOpacity = opacity;
    var dom = $(this.domid); if(typeof dom=="undefined")return;
    if(navigator.userAgent.indexOf("MSIE") != -1){
        dom.stroke.opacity = this.strokeOpacity;
    }
    else{
        dom.setAttribute("stroke-opacity",this.strokeOpacity);
    }
}
GPolygon.prototype.getStrokeOpacity = function() {
    return this.strokeOpacity;
}
GPolygon.prototype.setFillColor = function(color) {
    this.fillColor = color;
    var dom = $(this.domid); if(typeof dom=="undefined")return;
    if(navigator.userAgent.indexOf("MSIE") != -1){
        dom.fill.color = this.fillColor;
    }
    else{
        dom.setAttribute("fill",this.fillColor);
    }
}
GPolygon.prototype.getFillColor = function() {
    return this.fillColor;
}

GPolygon.prototype.setFillOpacity = function(opacity) {
    this.fillOpacity = opacity;
    var dom = $(this.domid); if(typeof dom=="undefined")return;
    if(navigator.userAgent.indexOf("MSIE") != -1){
        dom.fill.opacity = this.fillOpacity;
    }
    else{
        dom.setAttribute("fill-opacity",this.fillOpacity);
    }
}
GPolygon.prototype.getFillOpacity = function() {
    return this.fillOpacity;
}




// Augment GMarker so it handles markers that have been created but
// not yet addOverlayed.

GMarker.prototype.setMap = function ( map )
    {
    this.map = map;
    };

GMarker.prototype.addedToMap = function ()
    {
    this.map = null;
    };

GMarker.prototype.origOpenInfoWindow = GMarker.prototype.openInfoWindow;
GMarker.prototype.openInfoWindow = function ( node, opts )
    {
    if ( this.map != null )
	return this.map.openInfoWindow( this.getPoint(), node, opts );
    else
	return this.origOpenInfoWindow( node, opts );
    };

GMarker.prototype.origOpenInfoWindowHtml = GMarker.prototype.openInfoWindowHtml;
GMarker.prototype.openInfoWindowHtml = function ( html, opts )
    {
    if ( this.map != null )
	return this.map.openInfoWindowHtml( this.getPoint(), html, opts );
    else
	return this.origOpenInfoWindowHtml( html, opts );
    };

GMarker.prototype.origOpenInfoWindowTabs = GMarker.prototype.openInfoWindowTabs;
GMarker.prototype.openInfoWindowTabs = function ( tabNodes, opts )
    {
    if ( this.map != null )
	return this.map.openInfoWindowTabs( this.getPoint(), tabNodes, opts );
    else
	return this.origOpenInfoWindowTabs( tabNodes, opts );
    };

GMarker.prototype.origOpenInfoWindowTabsHtml = GMarker.prototype.openInfoWindowTabsHtml;
GMarker.prototype.openInfoWindowTabsHtml = function ( tabHtmls, opts )
    {
    if ( this.map != null )
	return this.map.openInfoWindowTabsHtml( this.getPoint(), tabHtmls, opts );
    else
	return this.origOpenInfoWindowTabsHtml( tabHtmls, opts );
    };

GMarker.prototype.origShowMapBlowup = GMarker.prototype.showMapBlowup;
GMarker.prototype.showMapBlowup = function ( opts )
    {
    if ( this.map != null )
	return this.map.showMapBlowup( this.getPoint(), opts );
    else
	return this.origShowMapBlowup( opts );
    }; 



MessageBox = function(map,paren,myvar,mb){
	this.map = map;
	this.paren = paren;
	this.myvar = paren.myvar+"."+myvar;
	this.eraseMess = null;
	this.centerMe = null;
	//this.mb = null;
	//if(mb)this.mb = mb;
	this.id = this.myvar + "_message"
	};

MessageBox.prototype.hideMess = function(){
  	//this.mb.style.visiblity ="hidden"; 
	//this.mb.style.left = "-1200px";
	//this.mb.style.top = "-1200px";
	};

MessageBox.prototype.centerThis = function(){
	var c = this.map.getObjCenter();
	//if(!this.mb)this.mb = $(this.id);
	//if(this.centerMe){ clearTimeout(this.centerMe);}
	//if(this.mb){
	//	var nw = this.mb.clientWidth;
	//	if(nw > this.map.getSize().width){
	//		var nw = parseInt(2*this.map.getSize().width/3);
	//		this.mb.style.width = nw +"px";
	//		this.centerMe = setTimeout(this.myvar+".centerThis()",5);
	//		return; 
	//		}
	//	this.mb.style.left = (c.x - (nw/2)) +"px";
	//	this.mb.style.top = (c.y - 20 - (this.mb.clientHeight/2))+ "px";
	//	}
	//else {
	//	this.centerMe = setTimeout(this.myvar+".centerThis()",10);
	//	}
	};

//MessageBox.prototype.showMess = function (val,temp){};

GMap2.prototype.getObjCenter = function(){
	var container = obj = this.getContainer();
	var y = x = 0;
	if (obj.offsetParent) {
		x = obj.offsetLeft;
		y = obj.offsetTop;
		while (obj = obj.offsetParent) {
			x += obj.offsetLeft;
			y += obj.offsetTop;
		}
 	return new GPoint(x+parseInt(this.getSize().width)/2,y+parseInt(this.getSize().height)/2);
	}
	
	};


GeoXml.prototype.loadXMLUrl = function (url, title, latlon, desc, idx) {
var that = this;	

// this is the actual xmlhttp call ...!
  GDownloadUrl(url, function(doc) {
		// try and convert the text before sending it to the parser ...??
		// eliminaet unwanted characters ..
				  		//var thisDate = new Date();
						//alert(title + " before " + thisDate);

	//var newdoc = stripNonValidXMLCharacters(doc);
				  		//var thisDate = new Date();
						//alert(title + " after " + thisDate);
						var newdoc = doc;

		that.processing(GXml.parse(newdoc),title, latlon, desc, idx)
  	    	//that.processing(GXml.parse(doc),title, latlon, desc, idx)
  	});
}

function stripNonValidXMLCharacters(instring) {
        var out; // Used to hold the output.
        
        
        // to get the unicode code for a character
        //string.charCodeAt(index)
        // this should also give ascii for first 128 characters
        // so check and print out a list of any ascii beyond the first 128
        var extraChars ="";
        var theResult="";
        
        
        // from the lower values, keep:  tab - character 9, linefeed, character 10, cr character 13, 
        // then from 32 onwards, till 125 which is the }
        
        
        for (var i=0; i< instring.length;i++) {
        	var theText = instring.substring(i,i+1);
        	var theChar = theText.charCodeAt(0);
        	if ((theChar > 125) || (theChar < 9 ) || (theChar == 39) ||(theChar == 11) || (theChar == 12) || (theChar > 13 && theChar < 32)){
        		extraChars += theText;
        	}
        	else {
        		theResult += theText; // this is valid text
        	}
        }
       
        return theResult;
        
        
        var current; // Used to reference the current character.

        //if (instring == null || ("".equals(instring))) return ""; // vacancy test.
        /*for (var i = 0; i < instring.length; i++) {
        	
            current = instring.charAt(i); // NOTE: No IndexOutOfBoundsException caught here; it should not happen.
            if ((current == 0x9) ||
                (current == 0xA) ||
                (current == 0xD) ||
                ((current >= 0x20) && (current <= 0xD7FF)) ||
                ((current >= 0xE000) && (current <= 0xFFFD)) ||
                ((current >= 0x10000) && (current <= 0x10FFFF)))
                out += current;
        }
        
        return out;*/
    }    



GeoXml.prototype.upgradeLayer = function(n) {
	var mt = this.map.getMapTypes();
	var found = false;
	for(var i=0;i<mt.length;i++){
		if(mt[i] == this.baseLayers[n]){
			found = true;
			this.map.removeMapType(this.baseLayers[n])
			}
		}
	if(!found)this.map.addMapType(this.baseLayers[n]);
	};


GeoXml.prototype.makeWMSTileLayer = function(getmapstring, on, title, opac) {
	var that = this;
	getmapstring = getmapstring.replace("&amp;","&");
 	var args = getmapstring.split("?");
	baseurl = args[0]+"?";
	var version = "1.1.0";
	var format = "image/png";
	var styles = "";
	var layers = "";
	var bbox = "";
	var queryable = false;
	var opacity = 1.0;
	if(typeof opac!="undefined")opacity = opac;
	var bbox = "-180,-90,180,90";
	var pairs = args[1].split("&");
	var sld ="";
	var gmcrs = "";
	for(var i=0;i < pairs.length; i++){
		var dstr = pairs[i];
		var duo = pairs[i].split("=");
		var dl = duo[0].toLowerCase();
		switch(dl) {
			case "version" : version = duo[1];break;
			case "bbox": bbox = duo[1]; break;
			case "width":
			case "height":break;
			case "service":break;
			case "styles": styles = duo[1]; break;
			case "layers": layers = duo[1]; break;
			case "format": format = duo[1]; break;
			case "opacity":opacity = parseFloat(duo[1]); break;
			case "crs":
			case "srs":epsg = duo[1]; break;
			case "gmcrs":gmcrs = duo[1];break;
			case "queryable":queryable = duo[1];break;
			default : if(duo[0])baseurl += "&"+pairs[i]; break;
			}
		}

	if(gmcrs)epsg = gmcrs;
	var bbn = bbox.split(",");
	var bb = {"w":parseFloat(bbn[0]),"s":parseFloat(bbn[1]),"e":parseFloat(bbn[2]),"n":parseFloat(bbn[3])};
	
	var lon = (bb.n - bb.s);
	var z = 0; 
	var ex = 180;
 	while(ex >= lon){
		ex = ex/2;
		z++;
		}
	z--;
	if(z<1){ z=1; }
 
	var cr0 = new GCopyright(1, new GLatLngBounds(new GLatLng(bb.s,bb.w),new GLatLng(bb.n,bb.e)),0,"WMS");
    	var cc0 = new GCopyrightCollection("Base Map from:");
     	cc0.addCopyright(cr0);
 	var twms = new GTileLayer(cc0,z,19);
	twms.s = bb.s; twms.n = bb.n; twms.e = bb.e; twms.w = bb.w;
	twms.myBaseURL = baseurl;
	twms.publishdirectory = this.publishdirectory;
	twms.getTileUrl = function(a,b,c) {
		if (typeof(this.myStyles)=="undefined") {
			this.myStyles=""; 
			}
		var lULP = new GPoint(a.x*256,(a.y+1)*256);
		var lLRP = new GPoint((a.x+1)*256,a.y*256);
		var lUL = G_NORMAL_MAP.getProjection().fromPixelToLatLng(lULP,b,c);
		var lLR = G_NORMAL_MAP.getProjection().fromPixelToLatLng(lLRP,b,c);
		var west = lUL.x;
		var east = lLR.x;
		var north = lUL.y;
		var south = lLR.y;
		var ge = east;
		var gw = west;
		var gs = south;
		var gn = north;
		if(gn < gs){ gs = gn; gn = south; }
		if(this.epsg != "EPSG:4326") {
			west = GeoXml.merc2Lon(west);
			north = GeoXml.merc2Lat(north);
			east = GeoXml.merc2Lon(east);
			south = GeoXml.merc2Lat(south);
			}
		var w = Math.abs(east - west);
		var h = Math.abs(north - south);
		var s = h/w;
		h = Math.round((256.0 * s) + 0.5);
		w = 256;
		var sud = south; 
		if(north < south){
			south = north; north = sud; 
			}
 
		if(typeof this.s != "undefined"){
			if(gs>(this.n) || ge < (this.w) || gn < (this.s) || gw > (this.e)  ){
				var retstr = this.publishdirectory +"images/white.gif";
		 		if(this.myFormat=="image/jpeg" || this.myFormat == "JPEG" || this.myFormat == "JPG"){ return retstr; }
					return this.publishdirectory +"images/blank.gif";
					}
			}
    		var lBbox=west+","+south+","+east+","+north;
		var lSRS="EPSG:41001";
		if(typeof this.epsg != "undefined"){
    			lSRS=this.epsg;
			}
		
		var lURL=this.myBaseURL;
		if(typeof this.myVersion == "undefined"){ this.myVersion = "1.1.1"; }
		var ver = parseFloat(this.myVersion);
		lURL+="&SERVICE=WMS";
		if(this.myVersion !="1.0.0"){
			lURL+="&REQUEST=GetMap";
			}
		else {
			lURL+="&REQUEST=Map";
			}
		lURL+="&VERSION="+this.myVersion;
		if(this.myLayers) {
		lURL+="&LAYERS="+this.myLayers;
		lURL+="&STYLES="+this.myStyles; 
		}
		if(this.mySLD){
			lURL+="&SLD="+this.mySLD; 
			}
  		lURL+="&FORMAT="+this.myFormat;
		lURL+="&BGCOLOR=0xFFFFFF";
		lURL+="&TRANSPARENT=TRUE";
		if(this.myVersion == "1.1.1" || ver<1.3 ){
			lURL += "&SRS=" + lSRS;
			}
		else {
			lURL += "&CRS=" + lSRS;
			}
		lURL+="&BBOX="+lBbox;
		lURL+="&WIDTH="+w;
		lURL+="&HEIGHT="+h;
		this.requestCount++;
		return lURL;
		}
	twms.myFormat = format;
	twms.myVersion = version;
	twms.myExtents = bbox;
	twms.queryable = queryable;
	twms.opacity = opacity;
	twms.getOpacity = function() { return this.opacity; };
	if(sld){
		twms.mySLD = sld;
		}
	else {
		twms.myLayers = layers;
		twms.myStyles = styles;
		}
	twms.epsg = epsg;
	var ol = new GTileLayerOverlay(twms);
	ol.bounds = new GLatLngBounds();
	ol.bounds.extend(new GLatLng(bb.n,bb.e));ol.bounds.extend(new GLatLng(bb.s,bb.w));
 

 	var twms2 = new GTileLayer(cc0,z,19);
	twms2.s = bb.s; twms2.n = bb.n; twms2.e = bb.e; twms2.w = bb.w;
	twms2.myBaseURL = baseurl;
	twms2.publishdirectory = this.publishdirectory;
	twms2.getTileUrl = twms.getTileUrl;
	twms2.myFormat = "image/jpeg";
	twms2.myVersion = version;
	twms2.myExtents = bbox;
	twms2.queryable = queryable;
	twms2.opacity = 1.0;
	twms2.title = title;
	twms2.getOpacity = function() { return this.opacity; };
	if(sld){
		twms2.mySLD = sld;
		}
	else {
		twms2.myLayers = layers;
		twms2.myStyles = styles;
		}
	twms2.epsg = epsg;
	this.wmscount++;
	var layer = [twms2];
	var cmap = new GMapType(layer, G_HYBRID_MAP.getProjection(), "WMS ("+title+")", G_HYBRID_MAP);	
	that.baseLayers.push(cmap);
	return ol;
	}

GeoXml.SEMI_MAJOR_AXIS = 6378137.0;
GeoXml.ECCENTRICITY = 0.0818191913108718138;
GeoXml.DEG2RAD = 180.0/(Math.PI);
GeoXml.prototype.merc2Lon = function(lon) {
	return (lon*GeoXml.DEG2RAD)*GeoXml.SEMI_MAJOR_AXIS;
	}
GeoXml.prototype.merc2Lat = function(lat) {
	var rad = lat * DEG2RAD;
	var sinrad = Math.sin(rad);
	return (GeoXml.SEMI_MAJOR_AXIS * Math.log(Math.tan((rad + Math.PI/2) / 2) * Math.pow(((1 - GeoXml.ECCENTRICITY * sinrad) / (1 + GeoXml.ECCENTRICITY * sinrad)), (GeoXml.ECCENTRICITY/2))));
	}

GeoXml.prototype.toggleLabels = function(on) {
	if(!on) {this.removeLabels();
		}
	else { 
	  	this.addLabels();
		}
	}
GeoXml.prototype.addLabels = function() {
	this.labels.onMap = true;
 	this.map.addOverlay(this.labels); 
	}
 
GeoXml.prototype.removeLabels = function() {
	this.labels.onMap = false;
	this.map.removeOverlay(this.labels);
	}

Clusterer = function ( map , paren ) {
    this.myvar = paren.myvar;
    this.paren = paren;
    this.map = map;
    this.markers = [];
    this.clusters = [];
    this.timeout = null;
    this.folders = [];
    this.folderBounds = [];
    this.folderhtml = [];
    this.folderhtmlast = [];
    this.subfolders = [];
    this.currentZoomLevel = map.getZoom();

    this.maxVisibleMarkers = Clusterer.defaultMaxVisibleMarkers;
    this.gridSize = Clusterer.defaultGridSize;
    this.minMarkersPerCluster = Clusterer.defaultMinMarkersPerCluster;
    this.maxLinesPerInfoBox = Clusterer.defaultMaxLinesPerInfoBox;
    this.icon = Clusterer.defaultIcon;
   
   // GEvent.addListener( map, 'zoomend', Clusterer.MakeCaller( Clusterer.Display, this ) );
   // GEvent.addListener( map, 'moveend', Clusterer.MakeCaller( Clusterer.Display, this ) );
    GEvent.addListener( map, 'infowindowclose', Clusterer.MakeCaller( Clusterer.PopDown, this ) );
    };


Clusterer.defaultMaxVisibleMarkers =  650;
Clusterer.defaultGridSize = 15;
Clusterer.defaultMinMarkersPerCluster = 5;
Clusterer.defaultMaxLinesPerInfoBox = 15;
Clusterer.defaultIcon = new GIcon();
Clusterer.defaultIcon.image = 'http://www.acme.com/resources/images/markers/blue_large.PNG';
Clusterer.defaultIcon.shadow = 'http://www.acme.com/resources/images/markers/shadow_large.PNG';
Clusterer.defaultIcon.iconSize = new GSize( 30, 51 );
Clusterer.defaultIcon.shadowSize = new GSize( 56, 51 );
Clusterer.defaultIcon.iconAnchor = new GPoint( 13, 34 );
Clusterer.defaultIcon.infoWindowAnchor = new GPoint( 13, 3 );
Clusterer.defaultIcon.infoShadowAnchor = new GPoint( 27, 37 );


// Call this to change the cluster icon.
Clusterer.prototype.SetIcon = function ( icon )
    {
    this.icon = icon;
    };


// Changes the maximum number of visible markers before clustering kicks in.
Clusterer.prototype.SetMaxVisibleMarkers = function ( n )
    {
    this.maxVisibleMarkers = n;
    };


// Sets the minumum number of markers for a cluster.
Clusterer.prototype.SetMinMarkersPerCluster = function ( n )
    {
    this.minMarkersPerCluster = n;
    };


// Sets the maximum number of lines in an info box.
Clusterer.prototype.SetMaxLinesPerInfoBox = function ( n )
    {
    this.maxLinesPerInfoBox = n;
    };


// Call this to add a marker.
Clusterer.prototype.AddMarker = function (marker, title, idx, sidebar, visible, forcevisible) {
	//alert("add marker" + title);
    if (marker.setMap != null){
		marker.setMap( this.map );
		}
    marker.hidden = (!visible || this.hideall);
    marker.title = title;
    
   /* this.folders[idx].push(this.markers.length);
    var bounds = this.map.getBounds();
    var vis = false;
    if(typeof marker.getBounds =="undefined"){
		if (bounds.contains(marker.getPoint())) vis = true; 
		}
	else {
	     var b = marker.getBounds();
	     if(!b.isEmpty()){
	        if(bounds.intersects(b))vis = true;  
		}
	}
    if(forcevisible)vis = true; */
    var id = this.markers.length;
   // this.markers.push(marker);
    
    //if(vis){ 
	marker.onMap = true;
	if (visible) {
    		this.map.addOverlay(marker);
    	}
    	
    	// ====================================
    	// add the marker to the list of all markers for the layer
    		//this.allMarkers.push(marker);
    		this.paren.allMarkers.push(marker);
    	// ====================================
    	
	//if(marker.hidden)marker.hide();
 	//}
/* 	if (visible == false) {
 		marker.hide();
 	}
 	
    this.DisplayLater();
    if(sidebar){
	this.folderhtml[idx].push(sidebar);
	} */
    return id;
    };

Clusterer.prototype.zoomToFolder = function (idx) {
	var bounds = this.folderBounds[idx];
	this.map.setZoom(this.map.getBoundsZoomLevel(bounds));
    	this.map.panTo(bounds.getCenter());
	}


// Call this to remove a marker.
Clusterer.prototype.RemoveMarker = function ( marker ) {
    for ( var i = 0; i < this.markers.length; ++i )
	if ( this.markers[i] == marker )
	    {
	    if ( marker.onMap )
		this.map.removeOverlay( marker );
	    for ( var j = 0; j < this.clusters.length; ++j )
		{
		var cluster = this.clusters[j];
		if ( cluster != null )
		    {
		    for ( var k = 0; k < cluster.markers.length; ++k )
			if ( cluster.markers[k] == marker )
			    {
			    cluster.markers[k] = null;
			    --cluster.markerCount;
			    break;
			    }
		    if ( cluster.markerCount == 0 )
			{
			this.ClearCluster( cluster );
			this.clusters[j] = null;
			}
		    else if ( cluster == this.poppedUpCluster )
			Clusterer.RePop( this );
		    }
		}
	    this.markers[i] = null;
	    break;
	    } 
    this.DisplayLater();
    };



Clusterer.prototype.DisplayLater = function ()
    {
    if ( this.timeout != null )
	clearTimeout( this.timeout );
    this.timeout = setTimeout( Clusterer.MakeCaller( Clusterer.Display, this ), 50);
    };


Clusterer.Display = function (clusterer)
    {
    var i, j, k, marker, cluster;
    clearTimeout( clusterer.timeout );
     
    var update_side = false;
    var count = 0;
    for(k = 0; k< clusterer.folderhtml.length ; k++ ){	
	var curlen = clusterer.folderhtml[k].length;
	var con = clusterer.folderhtmlast[k];
	if(con < curlen){
		var destid = clusterer.paren.myvar+"_folder"+k;
		var dest = $(destid);
	
		if(dest){
			if(clusterer.paren.opts.sortbyname){
			
			        content = dest.innerHTML;
				var clon = clusterer.folderhtml[k].sort();
				for(var l=0; l<curlen; l++){
 					var bits = clon[l].split("$$$",7);
          				content += clusterer.paren.sidebarfn(bits[0],bits[1],bits[2],bits[3],bits[4],bits[5],bits[6]); 
					}
				}
			else {
	 		       content = dest.innerHTML;
				var clon = clusterer.folderhtml[k];
				for(var l=con; l<curlen; l++){
 					var bits = clon[l].split("$$$",7);
          				content += clusterer.paren.sidebarfn(bits[0],bits[1],bits[2],bits[3],bits[4],bits[5],bits[6]);  
					}
				}
				
			clusterer.folderhtmlast[k] = curlen;
			dest.innerHTML  = content;
		 	dest.style.height = (2+(clusterer.folderhtml[k].length*clusterer.rowHeight))+"px";
		 	if(clusterer.paren.forcefoldersopen){
	 			dest.style.display = "block";
	 			}
			update_side = true;
			count = curlen;
			}
		else {
			//alert("target folder not found "+destid);
			//don't need this warning as we won't have a target folder on our main maps page
			}
		}

	}
	

   	
	if(update_side && count>0){
		var mifinish = new Date();
		var sec = ((mifinish - clusterer.miStart)/1000+" seconds");
		//clusterer.paren.mb.showMess("Loaded "+count+"  GeoXML elements in "+sec,5000);
		
		}

    if (typeof resizeKML != "undefined"){
		resizeKML();
		} 

    var bounds, sw, ne, dx, dy;
    var newZoomLevel = clusterer.map.getZoom();
    if ( newZoomLevel != clusterer.currentZoomLevel )
	{
	// When the zoom level changes, we have to remove all the clusters.
	for ( var i = 0; i < clusterer.clusters.length; ++i )
	    if ( clusterer.clusters[i] != null )
		{
		clusterer.ClearCluster( clusterer.clusters[i] );
		clusterer.clusters[i] = null;
		}
	clusterer.clusters.length = 0;
	clusterer.currentZoomLevel = newZoomLevel;
	}

    // Get the current bounds of the visible area.
    bounds = clusterer.map.getBounds();

    // Expand the bounds a little, so things look smoother when scrolling
    // by small amounts.
    var sw = bounds.getSouthWest();
    var ne = bounds.getNorthEast();
    var dx = ne.lng() - sw.lng();
    var dy = ne.lat() - sw.lat();
    if ( dx < 300 && dy < 150 ){
	dx *= 0.05;
	dy *= 0.05;
	bounds = new GLatLngBounds(
	new GLatLng( sw.lat() - dy, sw.lng() - dx ),
	new GLatLng( ne.lat() + dy, ne.lng() + dx ) );
	}

    // Partition the markers into visible and non-visible lists.
    var visibleMarkers = [];
    var nonvisibleMarkers = [];
    var viscount = 0;
    for (var i = 0; i < clusterer.markers.length; ++i ) {
	marker = clusterer.markers[i];
	vis = false;
	if (marker != null ){
		var mid = clusterer.paren.myvar+"sb"+i;	
	    	if(typeof marker.getBounds =="undefined"){
			if (bounds.contains(marker.getPoint()) ) {
				vis = true; 
				if($(mid)){ 
					$(mid).className = "inView";
					}
				viscount++;
				}
			else {	if($(mid)){ 
					$(mid).className = "outView";
					}
				}
			}
	     	else {
			var b = marker.getBounds();
			 if($(mid)){ 
	            		if(bounds.intersects(b)){
					$(mid).className = "inView";
					}
				else {  $(mid).className = "outView"; }
					}
			vis = true;
			}
      		if(vis)visibleMarkers.push(i);
	            else nonvisibleMarkers.push(i);
	      
		}
	}

    // Take down the non-visible markers.
    for (var  i = 0; i < nonvisibleMarkers.length; ++i )
	{
	marker = clusterer.markers[nonvisibleMarkers[i]];
	if (marker.onMap){
	    clusterer.map.removeOverlay(marker);
	    marker.onMap = false;
	    }
	}

    // Take down the non-visible clusters.
    for (var i = 0; i < clusterer.clusters.length; ++i ) {
	cluster = clusterer.clusters[i];
	if(cluster != null && cluster.marker) {
		var vis = false;
			if(typeof cluster.marker.getBounds =="undefined"){
				if (bounds.contains(cluster.marker.getPoint()) ) vis = true; 
				}
	     	  	else {
		 		//if(bounds.intersects(cluster.marker.getBounds())) vis=true;
				vis = true;
		 		}
		if (!vis && cluster.onMap) {
	    		clusterer.map.removeOverlay(cluster.marker);
	   		    cluster.onMap = false;
	    		}
		}
	}

    // Clustering!  This is some complicated stuff.  We have three goals
    // here.  One, limit the number of markers & clusters displayed, so the
    // maps code doesnt slow to a crawl.  Two, when possible keep existing
    // clusters instead of replacing them with new ones, so that the app pans
    // better.  And three, of course, be CPU and memory efficient.

    if (viscount > clusterer.maxVisibleMarkers)
	{
	// Add to the list of clusters by splitting up the current bounds
	// into a grid.
	if(!update_side){
		//clusterer.paren.mb.showMess("Clustering on "+viscount+"  GeoXML elements");
		}

	var latRange = bounds.getNorthEast().lat() - bounds.getSouthWest().lat();
	var latInc = latRange / clusterer.gridSize;
	var lngInc = latInc / Math.cos( ( bounds.getNorthEast().lat() + bounds.getSouthWest().lat() ) / 2.0 * Math.PI / 180.0 );
	for (var  lat = bounds.getSouthWest().lat(); lat <= bounds.getNorthEast().lat(); lat += latInc )
	    for ( var lng = bounds.getSouthWest().lng(); lng <= bounds.getNorthEast().lng(); lng += lngInc )
		{
		cluster = new Object();
		cluster.clusterer = clusterer;
		cluster.bounds = new GLatLngBounds( new GLatLng( lat, lng ), new GLatLng( lat + latInc, lng + lngInc ) );
		cluster.markers = [];
		cluster.markerCount = 0;
		cluster.onMap = false;
		cluster.marker = null;
		clusterer.clusters.push( cluster );
		}

	// Put all the unclustered visible markers into a cluster - the first
	// one it fits in, which favors pre-existing clusters.
	for ( var i = 0; i < visibleMarkers.length; ++i ) {
	    marker = clusterer.markers[visibleMarkers[i]];
	    if (marker != null && !marker.inCluster ) {
		for (var j = 0; j < clusterer.clusters.length; ++j ) {
		    cluster = clusterer.clusters[j];
		    if(cluster != null){
		        var vis = false;
		        if(typeof marker.getBounds =="undefined"){ 
				    if (cluster.bounds.contains(marker.getPoint())) { vis = true;   }
				    }
		        if (vis){
				marker.inCluster = true;
			        clusterer.clusters[j].markers.push(marker);
			        ++clusterer.clusters[j].markerCount;
			        }
			    }
		    }   
		}
	    }

	// Get rid of any clusters containing only a few markers.
	for (var i = 0; i < clusterer.clusters.length; ++i ) {
	    if ( clusterer.clusters[i] != null && clusterer.clusters[i].markerCount < clusterer.minMarkersPerCluster )
		{
		clusterer.ClearCluster( clusterer.clusters[i] );
		clusterer.clusters[i] = null;
		}
	     }

	// Shrink the clusters list.
	for (var i = clusterer.clusters.length - 1; i >= 0; --i )
	    if ( clusterer.clusters[i] != null )
		break;
	    else
		--clusterer.clusters.length;
  
	// Ok, we have our clusters.  Go through the markers in each
	// cluster and remove them from the map if they are currently up.
	for (var i = 0; i < clusterer.clusters.length; ++i )
	    {
	    cluster = clusterer.clusters[i];
	    if ( cluster != null )
		{
		for (var j = 0; j < cluster.markers.length; ++j )
		    {
		    marker = cluster.markers[j];
		    if ( marker != null && marker.onMap )
			{
			clusterer.map.removeOverlay( marker );
			marker.onMap = false;
			}
		    }
		}
	    }

	// Now make cluster-markers for any clusters that need one.
	for (var i = 0; i < clusterer.clusters.length; ++i )
	    {
	    cluster = clusterer.clusters[i];
	    if ( cluster != null && cluster.marker == null )
		{
		// Figure out the average coordinates of the markers in this
		// cluster.
		var xTotal = 0.0, yTotal = 0.0;
		for (var j = 0; j < cluster.markers.length; ++j )
		    {
		    marker = cluster.markers[j];
		    if ( marker != null )
			{
			xTotal += ( + marker.getPoint().lng() );
			yTotal += ( + marker.getPoint().lat() );
			}
		    }
		var location = new GLatLng( yTotal / cluster.markerCount, xTotal / cluster.markerCount );
		marker = new GMarker( location, { icon: clusterer.icon } );
		cluster.marker = marker;
		GEvent.addListener( marker, 'click', Clusterer.MakeCaller( Clusterer.PopUp, cluster ) );
		}
	    }

	}

    if(!update_side && viscount){
		//clusterer.paren.mb.showMess("Showing "+viscount+"  GeoXML elements",500);
		}

    // Display the visible markers not already up and not in clusters.
    for (var i = 0; i < visibleMarkers.length; ++i )
	{
	marker = clusterer.markers[visibleMarkers[i]];
	if ( marker != null && ! marker.onMap && ! marker.inCluster) {
	    if (marker.addedToMap != null ) marker.addedToMap();
	    if(marker.hidden){
		if(marker.hide){ clusterer.map.addOverlay(marker); marker.hide(); }
		}
	    else { clusterer.map.addOverlay(marker);}
	    marker.onMap = true;
	    }
	}

    // Display the visible clusters not already up.
    for (var i = 0; i < clusterer.clusters.length; ++i ) {
	cluster = clusterer.clusters[i]; 
	if(cluster != null && cluster.marker) {
	    var vis = false;
	    if(typeof marker.getPoint !="undefined"){if (bounds.contains( cluster.marker.getPoint())) vis = true; }
	        else {if(bounds.intersects(cluster.marker.getBounds())) vis=true;}
	    if (!cluster.onMap && vis ) {
	        clusterer.map.addOverlay( cluster.marker );
	        cluster.onMap = true;
	        }
	    }
	}

 
    // In case a cluster is currently popped-up, re-pop to get any new
    // markers into the infobox.
   // if(addHilite)addHilite();
    Clusterer.RePop( clusterer );
    };


Clusterer.PopUp = function ( cluster )
    {
    var clusterer = cluster.clusterer;
    var html = '<table width="300">';
    var n = 0;
    for (var  i = 0; i < cluster.markers.length; ++i )
	{
	var marker = cluster.markers[i];
	if ( marker != null )
	    {
	    ++n;
	    html += '<tr><td>';
	    if (typeof marker.getIcon!="undefined" &&  marker.getIcon().smallImage != null )
		html += '<img src="' + marker.getIcon().smallImage + '">';
	    else
		html += '<img src="' + marker.getIcon().image + '" width="' + ( marker.getIcon().iconSize.width / 2 ) + '" height="' + ( marker.getIcon().iconSize.height / 2 ) + '">';
	    html += '</td><td>' + marker.title + '</td></tr>';
	    if ( n == clusterer.maxLinesPerInfoBox - 1 && cluster.markerCount > clusterer.maxLinesPerInfoBox  )
		{
		html += '<tr><td colspan="2">...and ' + ( cluster.markerCount - n ) + ' more</td></tr>';
		break;
		}
	    }
	}
    html += '</table>';
    clusterer.map.closeInfoWindow();
    cluster.marker.openInfoWindowHtml( html );
    clusterer.poppedUpCluster = cluster;
    };


Clusterer.RePop = function ( clusterer )
    {
    if ( clusterer.poppedUpCluster != null )
	Clusterer.PopUp( clusterer.poppedUpCluster );
    };


Clusterer.PopDown = function ( clusterer )
    {
    clusterer.poppedUpCluster = null;
    };


Clusterer.prototype.ClearCluster = function ( cluster )
    {
    var i, marker;

    for (var i = 0; i < cluster.markers.length; ++i )
	if ( cluster.markers[i] != null )
	    {
	    cluster.markers[i].inCluster = false;
	    cluster.markers[i] = null;
	    }
    cluster.markers.length = 0;
    cluster.markerCount = 0;
    if ( cluster == this.poppedUpCluster )
	this.map.closeInfoWindow();
    if ( cluster.onMap )
	{
	this.map.removeOverlay( cluster.marker );
	cluster.onMap = false;
	}
    };


// This returns a function closure that calls the given routine with the
// specified arg.
Clusterer.MakeCaller = function ( func, arg )
    {
    return function () { func( arg ); };
    };



