
/*********************************************************************\
*																																		 *
* egeoxml.js																				 by Mike Williams *
*																																		 *
* A Google Maps API Extension																				 *
*																																		 *
* Renders the contents of a My Maps (or similar) KML file						 *
*																																		 *
* Documentation: http://econym.googlepages.com/egeoxml.htm						*
*																																		 *
\*********************************************************************/

// Version 2.2	 10 Aug 2007 - Support new My Maps icons
// 2007.10.16 - update Tomazov

// Constructor

function EGeoXml(myvar, map, url, opts){
	// store the parameters
	this.myvar = myvar;
	this.map = map;
	this.url = url;
	if(typeof url == "string"){
		this.urls = [url];
	} else {
		this.urls = url;
	}
	this.opts = opts || {};
	// infowindow styles
	this.titlestyle = this.opts.titlestyle || 'font-size:12px; font-weight:bold;';
	this.descstyle = this.opts.descstyle || '';
	this.allstyle = this.opts.allstyle || 'font-family:Tahoma; padding:10px; font-size:11px; line-height:15px;';
	// sidebar/dropbox functions
	this.sidebarfn = this.opts.sidebarfn || EGeoXml.addSidebar;
	this.findnamefn = this.opts.findnamefn || EGeoXml.addFindname;
	this.dropboxfn = this.opts.dropboxfn || EGeoXml.addDropdown;
	// elabel options
	this.elabelopacity = this.opts.elabelopacity || 100;
	// other useful "global" stuff
	this.bounds = new GLatLngBounds();
	this.gmarkers = [];
	this.gpolylines = [];
	this.gpolygons = [];
	this.groundoverlays = [];
	this.side_bar_html = "";
	this.side_bar_list = [];
	this.styles = []; // associative array
	this.iwwidth = this.opts.iwwidth || 250;
	this.progress = 0;
	this.lastmarker = {};
	this.myimages = [];
	this.imageNum =0;
}

// uses GXml.value, then removes leading and trailing whitespace
EGeoXml.value = function(e){
	a = GXml.value(e);
	a = a.replace(/^\s*/,"");
	a = a.replace(/\s*$/,"");
	return a;
}

// Create Marker

EGeoXml.prototype.createMarker = function(point,name,desc,style,link){
	var icon = G_DEFAULT_ICON;
	var myvar=this.myvar;
	var map=this.map;
	var iwoptions = this.opts.iwoptions || {};
	var markeroptions = this.opts.markeroptions || {};
	var icontype = this.opts.icontype || "style";
	if(icontype == "style"){
		if(!!this.styles[style]){
			icon = this.styles[style];
		}
	}
	if(!markeroptions.icon){
		markeroptions.icon = icon;
	}
	var m = new GMarker(point, markeroptions);

	// Attempt to preload images
	if(this.opts.preloadimages){
		var text = desc;
		var pattern = /<\s*img/ig;
		var result;
		var pattern2 = /src\s*=\s*[\'\"]/;
		var pattern3 = /[\'\"]/;

		while((result = pattern.exec(text)) != null){
			var stuff = text.substr(result.index);
			var result2 = pattern2.exec(stuff);
			if(result2 != null){
				stuff = stuff.substr(result2.index+result2[0].length);
				var result3 = pattern3.exec(stuff);
				if(result3 != null){
					var imageUrl = stuff.substr(0,result3.index);
					this.myimages[this.imageNum] = new Image();
					this.myimages[this.imageNum].src = imageUrl;
					this.imageNum++;
				}
			}
		}
	}

	if(this.opts.elabelclass){
		var l = new ELabel(point, name, this.opts.elabelclass, this.opts.elabeloffset, this.elabelopacity, true);
		l.hidden=true;
		this.map.addOverlay(l);
	}

	var html = "<div style='width:"+ this.iwwidth +"px; "+ this.allstyle +"'>"+ "<div style='"+ this.titlestyle +"'>"+ name +"</div>"+"<div style='"+ this.descstyle +"'>"+ desc +"</div></div>";
  
	GEvent.addListener(m, "focus", function(){
		if(l) l.show();
		m.setImage(icon.iimage);
		if(l) return false;
		m.openInfoWindowHtml(html,iwoptions);
	});
	GEvent.addListener(m, "mouseover2", function(){
    map.panTo(point);
		eval('last='+myvar+'.lastmarker;')
		if(l&&m!=last) l.show();
		m.setImage(icon.iimage);
		eval('lastimage='+myvar+'.lastimage;')
    if(last&&lastimage) last.setImage(lastimage);
	});
	GEvent.addListener(m, "mouseover", function(){
		if(l) l.show();
		m.setImage(icon.iimage);
		eval('last='+myvar+'.lastmarker;')
		eval('lastimage='+myvar+'.lastimage;')
    if(last&&lastimage) last.setImage(lastimage);
		if(l) return false;
		m.openInfoWindowHtml(html,iwoptions);
	});
	GEvent.addListener(m, "click", function(){
    //map.panTo(point);
		m.openInfoWindowHtml(html,iwoptions);
		if(l) l.hide();
		//if(link) document.location=link;
		m.setImage(icon.iimage);
		eval(myvar+'.lastmarker = m;');
		eval(myvar+'.lastimage = icon.image;');
	});
	GEvent.addListener(m, "click2", function(){
    if(document.all) document.getElementById("maps").focus();
    else document.getElementById("map").scrollIntoView(true);
    map.panTo(point);
		m.openInfoWindowHtml(html,iwoptions);
		if(l) l.hide();
		//if(link) document.location=link;
		m.setImage(icon.iimage);
		eval(myvar+'.lastmarker = m;');
		eval(myvar+'.lastimage = icon.image;');
	});

	GEvent.addListener(m, "blur", function(){
		if(l) l.show();
		m.setImage(icon.image);
	});
	GEvent.addListener(m, "mouseout", function(){
		if(l) l.hide();
		eval('last='+myvar+'.lastmarker;')
		if(m!=last) m.setImage(icon.image);
	});
	if(!!this.opts.addmarker){
		this.opts.addmarker(m,name,desc,icon.image,this.gmarkers.length)
	} else {
		this.map.addOverlay(m);
	}
	this.gmarkers.push(m);
	if(this.opts.sidebarid || this.opts.dropboxid || this.opts.findnameid){
		var n = this.gmarkers.length-1;
		this.side_bar_list.push (name + "$$$marker$$$" + n +"$$$" );
	}
}

// Create Polyline

EGeoXml.prototype.createPolyline = function(points,color,width,opacity,pbounds,name,desc,link){
	var thismap = this.map;
	var iwoptions = this.opts.iwoptions || {};
	var polylineoptions = this.opts.polylineoptions || {};
	var p = new GPolyline(points,color,width,opacity,polylineoptions);
	this.map.addOverlay(p);
	this.gpolylines.push(p);
	var html = "<div style='font-weight: bold; font-size: medium; margin-bottom: 0em;'>"+name+"</div>"
						 +"<div style='font-family: Arial, sans-serif;font-size: small;width:"+this.iwwidth+"px'>"+desc+"</div>";
	GEvent.addListener(p,"click", function(){
		thismap.openInfoWindowHtml(p.getVertex(Math.floor(p.getVertexCount()/2)),html,iwoptions);
	} );
	if(this.opts.sidebarid){
		var n = this.gpolylines.length-1;
		var blob = '&nbsp;&nbsp;<span style=";border-left:'+width+'px solid '+color+';">&nbsp;</span> ';
		this.side_bar_list.push (name + "$$$polyline$$$" + n +"$$$" + blob );
	}
}

// Create Polygon

EGeoXml.prototype.createPolygon = function(points,color,width,opacity,fillcolor,fillopacity,pbounds, name, desc,link){
	var thismap = this.map;
	var iwoptions = this.opts.iwoptions || {};
	var polygonoptions = this.opts.polygonoptions || {};
	var p = new GPolygon(points,color,width,opacity,fillcolor,fillopacity,polygonoptions)
	this.map.addOverlay(p);
	this.gpolygons.push(p);
	var html = "<div style='font-weight: bold; font-size: medium; margin-bottom: 0em;'>"+name+"</div>"
						 +"<div style='font-family: Arial, sans-serif;font-size: small;width:"+this.iwwidth+"px'>"+desc+"</div>";
	GEvent.addListener(p,"click", function(){
		thismap.openInfoWindowHtml(pbounds.getCenter(),html,iwoptions);
	} );
	if(this.opts.sidebarid){
		var n = this.gpolygons.length-1;
		var blob = '<span style="background-color:' +fillcolor + ';border:2px solid '+color+';">&nbsp;&nbsp;&nbsp;&nbsp;</span> ';
		this.side_bar_list.push (name + "$$$polygon$$$" + n +"$$$" + blob );
	}
}


// Sidebar factory method One - adds an entry to the sidebar
EGeoXml.addSidebar = function(myvar,name,type,i,graphic){
	if(type == "marker"){
		return '<a href="javascript:GEvent.trigger(' + myvar+ '.gmarkers['+i+'],\'click\')">' + name + '</a><br>';
	}
	if(type == "polyline"){
		return '<div style="margin-top:6px;"><a href="javascript:GEvent.trigger(' + myvar+ '.gpolylines['+i+'],\'click\')">' + graphic + name + '</a></div>';
	}
	if(type == "polygon"){
		return '<div style="margin-top:6px;"><a href="javascript:GEvent.trigger(' + myvar+ '.gpolygons['+i+'],\'click\')">' + graphic + name + '</a></div>';
	}
}

// Sidebar factory method One - adds an entry to the sidebar
EGeoXml.addFindname = function(myvar,name,type,i,graphic){
	if(this.opts.noalink) return false;
	if(type == "marker") atype = 'gmarkers';
	if(type == "polyline") atype = 'gpolylines';
	if(type == "polygon") atype = 'gpolygons';
	alls = document.getElementsByTagName("A");
	for(x=0; x<alls.length; x++){
	  var selhid = false;
		if(!alls[x].onmouseover && (pos = alls[x].innerHTML.indexOf(name.replace(/[&]/,'&amp;'))) != -1){
			var da = document.createElement("A");
			da.href = "#maps";da.onclick = new Function('document.location=this.href;GEvent.trigger(' + myvar+ '.'+atype+'['+i+'],\'click2\');return false;');
			var dimg = document.createElement("IMG");
			dimg.src="http://img.otpusk.com/img/showmap.gif";dimg.border=0;dimg.alt="";dimg.title="Показать на карте";dimg.align="absmiddle";
			da.appendChild(dimg);
			alls[x].innerHTML+=' '; alls[x].appendChild(da);
			alls[x].onmouseover = new Function('GEvent.trigger(' + myvar+ '.'+atype+'['+i+'],\'mouseover2\')');
			alls[x].onmouseout = new Function('GEvent.trigger(' + myvar+ '.'+atype+'['+i+'],\'mouseout\')');
			alls[x].onfocus = new Function('GEvent.trigger(' + myvar+ '.'+atype+'['+i+'],\'focus\')');
			alls[x].onblur = new Function('GEvent.trigger(' + myvar+ '.'+atype+'['+i+'],\'blur\')');
			if(alls[x].id=='selhid') selhid = true;
      if(selhid && document.location.href.search(/hid=(\d+)/i) && RegExp.$1>0){
        da.id = 'hid'+RegExp.$1;
      }
			return true;
		}
	}
	if(selhid && typeof document.getElementById("selhid") != "undefined"){
		document.getElementById("selhid").blur();
		document.getElementById("selhid").focus();
	}
}

// Dropdown factory method
EGeoXml.addDropdown = function(myvar,name,type,i,graphic){
		return '<option value="' + i + '">' + name +'</option>';
}


// Request to Parse an XML file

EGeoXml.prototype.parse = function(){
	// clear some variables
	this.gmarkers = [];
	this.gpolylines = [];
	this.gpolygons = [];
	this.groundoverlays = [];
	this.side_bar_html = "";
	this.side_bar_list = [];
	this.styles = []; // associative array
	this.lastmarker = {};
	this.myimages = [];
	this.imageNum =0;
	var that = this;
	this.progress = this.urls.length;
	for(u=0; u<this.urls.length; u++){
		GDownloadUrl(this.urls[u], function(doc){that.processing(doc)});
	}
  if(document.location.href.search(/hid=(\d+)/i) && RegExp.$1>0){
    setTimeout(hId,3600);
    //if(document.getElementById('hid'+RegExp.$1)) document.getElementById('hid'+RegExp.$1).click();
  }
}
function hId(){
  if(document.location.href.search(/hid=(\d+)/i) && RegExp.$1>0){
    if(!document.getElementById('hid'+RegExp.$1)) {
      setTimeout(hId,3600);
      return false;
    }
    //alert('hid'+RegExp.$1);
    if(document.all) document.getElementById('hid'+RegExp.$1).click();
    else document.getElementById('hid'+RegExp.$1).onclick();
  }
}
EGeoXml.prototype.parseString = function(doc){
	// clear some variables
	this.gmarkers = [];
	this.gpolylines = [];
	this.gpolygons = [];
	this.groundoverlays = [];
	this.side_bar_html = "";
	this.side_bar_list = [];
	this.styles = []; // associative array
	this.lastmarker = {};
	this.myimages = [];
	this.imageNum =0;
	if(typeof doc == "string"){
		this.docs = [doc];
	} else {
		this.docs = doc;
	}
	this.progress = this.docs.length;
	for(u=0; u<this.docs.length; u++){
		this.processing(this.docs[u]);
	}
}


EGeoXml.prototype.processing = function(doc){
		var that = this;
		var xmlDoc = GXml.parse(doc)
		// Read through the Styles
		var styles = xmlDoc.documentElement.getElementsByTagName("Style");
		for(var i = 0; i <styles.length; i++){
			var styleID = styles[i].getAttribute("id");
			var icons=styles[i].getElementsByTagName("Icon");
			// This might not be am icon style
			if(icons.length > 0){
				var href=EGeoXml.value(icons[0].getElementsByTagName("href")[0]);
				if(!!href){
					if(!!that.opts.baseicon){
						that.styles["#"+styleID] = new GIcon(that.opts.baseicon,href);
					} else {
						that.styles["#"+styleID] = new GIcon(G_DEFAULT_ICON,href);
						that.styles["#"+styleID].iconSize = new GSize(14,20);
						that.styles["#"+styleID].shadowSize = new GSize(16,19);
						//that.styles["#"+styleID].dragCrossAnchor = new GPoint(2,8);
						that.styles["#"+styleID].infoWindowAnchor = new GPoint(5,10);
						that.styles["#"+styleID].iconAnchor = new GPoint(6,20);
						if(that.opts.printgif){
							var bits = href.split("/");
							var gif = bits[bits.length-1];
							gif = that.opts.printgifpath + gif.replace(/.png/i,".gif");
							that.styles["#"+styleID].printImage = gif;
							that.styles["#"+styleID].mozPrintImage = gif;
						}
						if(!!that.opts.noshadow){
							that.styles["#"+styleID].shadow="";
						} else {
							// Try to guess the shadow image
							that.styles["#"+styleID].shadow="http://img.otpusk.com/img/map/shadow.png";
						}
					}
				}
				var hrefover=GXml.value(icons[0].getElementsByTagName("hrefover")[0]);
				if(!!hrefover) that.styles["#"+styleID].iimage = hrefover;
				else that.styles["#"+styleID].iimage = that.styles["#"+styleID].image;
			}
			// is it a LineStyle ?
			var linestyles=styles[i].getElementsByTagName("LineStyle");
			if(linestyles.length > 0){
				var width = parseInt(GXml.value(linestyles[0].getElementsByTagName("width")[0]));
				if(width < 1){width = 5;}
				var color = EGeoXml.value(linestyles[0].getElementsByTagName("color")[0]);
				var aa = color.substr(0,2);
				var bb = color.substr(2,2);
				var gg = color.substr(4,2);
				var rr = color.substr(6,2);
				color = "#" + rr + gg + bb;
				var opacity = parseInt(aa,16)/256;
				if(!that.styles["#"+styleID]){
					that.styles["#"+styleID] = {};
				}
				that.styles["#"+styleID].color=color;
				that.styles["#"+styleID].width=width;
				that.styles["#"+styleID].opacity=opacity;
			}
			// is it a PolyStyle ?
			var polystyles=styles[i].getElementsByTagName("PolyStyle");
			if(polystyles.length > 0){
				var fill = parseInt(GXml.value(polystyles[0].getElementsByTagName("fill")[0]));
				var outline = parseInt(GXml.value(polystyles[0].getElementsByTagName("outline")[0]));
				var color = EGeoXml.value(polystyles[0].getElementsByTagName("color")[0]);

				if(polystyles[0].getElementsByTagName("fill").length == 0){fill = 1;}
				if(polystyles[0].getElementsByTagName("outline").length == 0){outline = 1;}
				var aa = color.substr(0,2);
				var bb = color.substr(2,2);
				var gg = color.substr(4,2);
				var rr = color.substr(6,2);
				color = "#" + rr + gg + bb;

				var opacity = parseInt(aa,16)/256;
				if(!that.styles["#"+styleID]){
					that.styles["#"+styleID] = {};
				}
				that.styles["#"+styleID].fillcolor=color;
				that.styles["#"+styleID].fillopacity=opacity;
				if(!fill) that.styles["#"+styleID].fillopacity = 0;
				if(!outline) that.styles["#"+styleID].opacity = 0;
			}
		}

		// Read through the Placemarks
		var placemarks = xmlDoc.documentElement.getElementsByTagName("Placemark");
		for(var i = 0; i < placemarks.length; i++){
			var name=EGeoXml.value(placemarks[i].getElementsByTagName("name")[0]);
			var desc=EGeoXml.value(placemarks[i].getElementsByTagName("description")[0]);
			var link=EGeoXml.value(placemarks[i].getElementsByTagName("link")[0]);
			if(desc.match(/^http:\/\//i)){
				desc = '<a href="' + desc + '">' + desc + '</a>';
			}
			if(desc.match(/^https:\/\//i)){
				desc = '<a href="' + desc + '">' + desc + '</a>';
			}
			var style=EGeoXml.value(placemarks[i].getElementsByTagName("styleUrl")[0]);
			var coords=GXml.value(placemarks[i].getElementsByTagName("coordinates")[0]);
			coords=coords.replace(/\s+/g," "); // tidy the whitespace
			coords=coords.replace(/^ /,"");		// remove possible leading whitespace
			coords=coords.replace(/ $/,"");		// remove possible trailing whitespace
			coords=coords.replace(/, /,",");	 // tidy the commas
			var path = coords.split(" ");

			// Is this a polyline/polygon?
			if(path.length > 1){
				// 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);
					that.bounds.extend(point);
					pbounds.extend(point);
				}
				var linestring=placemarks[i].getElementsByTagName("LineString");
				if(linestring.length){
					// it's a polyline grab the info from the style
					if(!!that.styles[style]){
						var width = that.styles[style].width;
						var color = that.styles[style].color;
						var opacity = that.styles[style].opacity;
					} else {
						var width = 5;
						var color = "#0000ff";
						var opacity = 0.45;
					}
					// Does the user have their own createmarker function?
					if(!!that.opts.createpolyline){
						that.opts.createpolyline(points,color,width,opacity,pbounds,name,desc);
					} else {
						that.createPolyline(points,color,width,opacity,pbounds,name,desc,link);
					}
				}

				var polygons=placemarks[i].getElementsByTagName("Polygon");
				if(polygons.length){
					// it's a polygon grab the info from the style
					if(!!that.styles[style]){
						var width = that.styles[style].width;
						var color = that.styles[style].color;
						var opacity = that.styles[style].opacity;
						var fillopacity = that.styles[style].fillopacity;
						var fillcolor = that.styles[style].fillcolor;
					} else {
						var width = 5;
						var color = "#0000ff";
						var opacity = 0.45;
						var fillopacity = 0.25;
						var fillcolor = "#0055ff";
					}
					// Does the user have their own createmarker function?
					if(!!that.opts.createpolygon){
						that.opts.createpolygon(points,color,width,opacity,fillcolor,fillopacity,pbounds,name,desc);
					} else {
						that.createPolygon(points,color,width,opacity,fillcolor,fillopacity,pbounds,name,desc,link);
					}
				}


			} else {
				// It's not a poly, so I guess it must be a marker
				var bits = path[0].split(",");
				var point = new GLatLng(parseFloat(bits[1]),parseFloat(bits[0]));
				that.bounds.extend(point);
				// Does the user have their own createmarker function?
				if(!!that.opts.createmarker){
					that.opts.createmarker(point, name, desc, style);
				} else {
					that.createMarker(point, name, desc, style, link);
				}
			}
		}

		// Scan through the Ground Overlays
		var grounds = xmlDoc.documentElement.getElementsByTagName("GroundOverlay");
		for(var i = 0; i < grounds.length; i++){
			var url=EGeoXml.value(grounds[i].getElementsByTagName("href")[0]);
			var north=parseFloat(GXml.value(grounds[i].getElementsByTagName("north")[0]));
			var south=parseFloat(GXml.value(grounds[i].getElementsByTagName("south")[0]));
			var east=parseFloat(GXml.value(grounds[i].getElementsByTagName("east")[0]));
			var west=parseFloat(GXml.value(grounds[i].getElementsByTagName("west")[0]));
			var sw = new GLatLng(south,west);
			var ne = new GLatLng(north,east);
			var ground = new GGroundOverlay(url, new GLatLngBounds(sw,ne));
			that.bounds.extend(sw);
			that.bounds.extend(ne);
			that.groundoverlays.push(ground);
			that.map.addOverlay(ground);
		}

		// Is this the last file to be processed?
		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());
			}
			// Shall we display the sidebar?
			if(that.opts.sortbyname){
				that.side_bar_list.sort();
			}
			if(that.opts.sidebarid){
				for(var i=0; i<that.side_bar_list.length; i++){
					var bits = that.side_bar_list[i].split("$$$",4);
					that.side_bar_html += that.sidebarfn(that.myvar,bits[0],bits[1],bits[2],bits[3]);
				}
				document.getElementById(that.opts.sidebarid).innerHTML += that.side_bar_html;
			}
			if(that.opts.dropboxid){
				for(var i=0; i<that.side_bar_list.length; i++){
					var bits = that.side_bar_list[i].split("$$$",4);
					if(bits[1] == "marker"){
						that.side_bar_html += that.dropboxfn(that.myvar,bits[0],bits[1],bits[2],bits[3]);
					}
				}
				document.getElementById(that.opts.dropboxid).innerHTML = '<select onChange="var I=this.value;if(I>-1){GEvent.trigger('+that.myvar+'.gmarkers[I],\'click\'); }">'
					+ '<option selected> - Select a location - </option>'
					+ that.side_bar_html
					+ '</select>';
			}

			if(that.opts.findnameid){
				for(var i=0; i<that.side_bar_list.length; i++){
					var bits = that.side_bar_list[i].split("$$$",4);
					that.findnamefn(that.myvar,bits[0],bits[1],bits[2],bits[3]);
				}
			}
			GEvent.trigger(that,"parsed");
		}
}
EGeoXml.prototype.alert_r = function(d){
  var text;
  for(var k in d) if(d[k]) text+='\t'+(k+' = "'+d[k])+'"\n';
  alert(text);
}
