
/*********************************************************************\
*																																		 *
* 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						*
*																																		 *
***********************************************************************
*																																		 *
*	 This Javascript is provided by Mike Williams											*
*	 Blackpool Community Church Javascript Team												*
*	 http://www.commchurch.freeserve.co.uk/														*
*	 http://econym.googlepages.com/index.htm													 *
*																																		 *
*	 This work is licenced under a Creative Commons Licence						*
*	 http://creativecommons.org/licenses/by/2.0/uk/										*
*																																		 *
\*********************************************************************/

// Version 0.0	 17 Apr 2007 - Initial testing, just markers
// Version 0.1	 17 Apr 2007 - Sensible shadows, and a few general improvements
// Version 0.2	 18 Apr 2007 - Polylines (non-clickable, no sidebar)
// Version 0.3	 18 Apr 2007 - Polygons (non-clickable, no sidebar)
// Version 0.4	 18 Apr 2007 - Sidebar entries for polygons
// Version 0.5	 19 Apr 2007 - Accept an array of XML filenames, and add the {sortbyname} option
// Version 0.6	 19 Apr 2007 - Sidebar entries for polylines, get directions and search nearby
// Version 0.7	 20 Apr 2007 - Info Window Styles
// Version 0.8	 21 Apr 2007 - baseicon
// Version 0.9	 21 Apr 2007 - iwoptions and markeroptions
// Version 1.0	 21 Apr 2007 - Launched
// Version 1.1	 25 Apr 2007 - Bugfix - would crash if no options were specified
// Version 1.2	 25 Apr 2007 - If the description begins with "http://" make it into a link.
// Version 1.3	 30 Apr 2007 - printgif, dropbox
// Version 1.4	 14 May 2007 - Elabels
// Version 1.5	 17 May 2007 - Default values for width, fill and outline
// Version 1.6	 21 May 2007 - GGroundOverlay (needs API V2.79+)
// Version 1.7	 22 May 2007 - Better icon positioning for MyMaps icons
// Version 1.8	 31 May 2007 - polyline bugfix
// Version 1.9	 23 Jun 2007 - add .parseString() method
// Version 2.0	 23 Jun 2007 - .parseString() handles an array of strings
// Version 2.1	 25 Jul 2007 - imagescan
// Version 2.2	 10 Aug 2007 - Support new My Maps icons
// Version 2.3	 25 Nov 2007 - Clear variables used by .parse() so that it can be rerun
// Version 2.4	 08 Dec 2007 - polylineoptions and polygonoptions
// Version 2.5	 11 Dec 2007 - EGeoXml.value() trims leading and trailing whitespace
// Version 2.6	 08 Feb 2008 - Trailing whitespace wasn't removed in the previous change

// 2007.10.16 - update Tomazov

// Constructor
var myviton;
var oberton;
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 || 'style="font-size:13px; font-weight:bold;"';
	this.descstyle = this.opts.descstyle || 'style="font-size:10px;"';
	this.allstyle = this.opts.allstyle || 'style="font-family:Tahoma; padding:11px; font-size:10px; line-height:13px"';
	// sidebar/dropbox functions
	this.sidebarfn = this.opts.sidebarfn || EGeoXml.addSidebar;
	this.findnamefn = this.opts.findnamefn || EGeoXml.addFindname;
	this.dropboxfn = this.opts.dropboxfn || EGeoXml.addDropdown;
	this.centerfn = this.opts.centerfn || EGeoXml.linkCenter;
	// elabel options
	this.elabelopacity = this.opts.elabelopacity || 90;
	// 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;

	if(this.opts.findname) this.centerfn();
}

// 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,id,link){
	// Check merkers
	for(var i in this.map.Ab) if(this.map.Ab[i].Hr=='marker'+id){this.gmarkers[id]=this.map.Ab[i]; return false;}

	var icon = G_DEFAULT_ICON;
	var myvar=this.myvar;
	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);
	m.Hr = 'marker'+id;

	// 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++;
				}
			}
		}
	}

	var html = "<div style = 'width:"+ this.iwwidth +"px'"+ this.allstyle +">"
							 + "<div "+ this.titlestyle +">"+ name +"</div>"
							 +"<div "+ this.descstyle +">"+ desc +"</div>";

	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);
	}

	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(){
		if(l) l.show();
		m.setImage(icon.iimage);
	});
	GEvent.addListener(m, "mouseover", function(){
		if(l) l.show();
		m.setImage(icon.iimage);
		if(l) return false;
		m.openInfoWindowHtml(html,iwoptions);
	});
	GEvent.addListener(m, "click", function(){
		if(l) l.show();
		if(link) document.location=link;
		m.setImage(icon.iimage);
		if(l) return false;
//		openClose();
//		eval(myvar+".lastmarker.setImage(icon.image);");
		m.openInfoWindowHtml(html,iwoptions);
		eval(myvar+'.lastmarker = m;');
	});

	GEvent.addListener(m, "blur", function(){
		if(l) l.show();
		m.setImage(icon.image);
	});
	GEvent.addListener(m, "mouseout", function(){
		if(l) l.hide();
		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[id] = m;
	if(this.opts.sidebarid || this.opts.dropboxid || this.opts.findnameid){
		//var n = this.gmarkers.length-1;
		this.side_bar_list.push (name + "$$$marker$$$" + id +"$$$" );
	}
}

// Create Polyline

EGeoXml.prototype.createPolyline = function(points,color,width,opacity,pbounds,name,desc,id,link){
	// Check merkers
	//for(var i in this.map.Ab) if(this.map.Ab[i].ID=='polyline'+id) return false;

	var cz = this.centerZoom(points);
	this.map.setCenter(cz['center'], Math.round(cz['zoom']));

	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[id] = p;

	this.midArrows(points);
	//p.ID = 'polyline'+id;

	if(this.opts.elabelclass){
		var l = new ELabel(cz['center'], name, this.opts.elabelclass, this.opts.elabeloffset, this.elabelopacity, true);
		l.hidden=true;
		this.map.addOverlay(l);
	}
/*
	var thismap = this.map;
	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$$$" + id +"$$$" + blob );
	}
}

// Create Polygon

EGeoXml.prototype.createPolygon = function(points,color,width,opacity,fillcolor,fillopacity,pbounds,name,desc,id,link){
	// Check merkers
	for(var i in this.map.Ab) if(this.map.Ab[i].ID=='polygon'+id) return false;

	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);
	p.ID = 'polygon'+id;
	this.gpolygons[id] = 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$$$" + id +"$$$" + blob );
	}
}

EGeoXml.prototype.deleteMarkersOutsideSection = function(section,mark){
	if(this.map&&this.map.Ab&&!this.map.Ab.length) return;
	var markersByIds = this.map.Ab;

	if(!mark){
		var delta=10;
		var deltaLat = delta*(section.ne_lat-section.sw_lat)/this.map.getSize().height;
		var deltaLng = delta*(section.ne_lng-section.sw_lng)/this.map.getSize().width;
	}
	for(var i in markersByIds) if(markersByIds[i]){
		var marker = markersByIds[i];
		if(!mark){
				if(!this.isMarkerInSection(marker, section, deltaLat, deltaLng))
					this.map.removeOverlay(marker);
		} else {
			if(!marker.Hr) continue;
			id = marker.Hr.replace(/marker/i,'');
			if(id&&!this.gmarkers[id]){
				this.map.removeOverlay(marker);
			}
		}
	}
}

EGeoXml.prototype.isMarkerInSection = function(marker, section, deltaLat, deltaLng){
		var ll = marker.getLatLng();
		return ll.lat() >= section.sw_lat-deltaLat && ll.lat() <= section.ne_lat+deltaLat &&
					 ll.lng() >= section.sw_lng-deltaLng && ll.lng() <= section.ne_lng+deltaLng;
}

// 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;
	var that = this;
	var selhid = 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++)/*if(alls[x].href.length>3)*/{
		var find = 0;
		//if(pos = alls[x].innerHTML.indexOf('г.Прилуки, Другие регионы') != -1 ) alert_r(alls[x]);
		if(!alls[x].onmouseover && alls[x].title && alls[x].title.length>0 && alls[x]['name']!='nomap' && (pos = alls[x].title.indexOf(name.replace(/[&]/,'&amp;'))) != -1) find = 1;
		else if(!alls[x].onmouseover && alls[x]['name'] && alls[x]['name'].length>0 && alls[x]['name']!='nomap' && (pos = alls[x]['name'].indexOf(name.replace(/[&]/,'&amp;'))) != -1) find = 1;
		else if(!alls[x].onmouseover && alls[x].innerHTML.length>0 && alls[x]['name']!='nomap' && (pos = alls[x].innerHTML.indexOf(name.replace(/[&]/,'&amp;'))) != -1) find = 1;
		if(find){
			var da = document.createElement("A");
			da.href = "#maps";
      if(this.href) da.onclick = new Function('document.location=this.href;GEvent.trigger(' + myvar+ '.'+atype+'['+i+'],"click");return false;');	else 
      da.onclick = new Function('window.scroll(0, document.getElementById(\'map\').offsetTop);GEvent.trigger(' + myvar+ '.'+atype+'['+i+'],"click");return false;');
			var dimg = document.createElement("IMG");
			dimg.src="/img/showmap.gif";dimg.border=0;dimg.alt="";dimg.title="Показать на карте.";dimg.align="absmiddle";dimg.width=15;dimg.height=15;
			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;
			return true;
		}
	}
	if(selhid && typeof document.getElementById("selhid") != "undefined"){
		document.getElementById("selhid").blur();
		document.getElementById("selhid").focus();
	}
}

EGeoXml.linkCenter = function(){
	if(typeof(myviton)!="undefined"&&typeof(oberton)!="undefined") return;
	var that = this;//javacript:alert(typeof(myviton));void(0);
	var s = document.createElement('script');
	s.type = 'text/javascript';
	s.id = 'smo';
	s.onreadystatechange = function(){
		//if(s.readyState=='complete'&&s.status==200)
			that.Centeris();
	}
	s.src = this.urls[0]+'&s=1';
	s.onload = function(){that.Centeris();};
	document.getElementsByTagName('head')[0].appendChild(s);
	//document.body.appendChild(s);
	//alert(typeof(myviton)+' '+typeof(oberton));
}

EGeoXml.prototype.Centeris = function(){
	//alert(typeof(myviton)+' '+typeof(oberton)+' '+typeof(document.createElement("smo")));
	if((typeof(myviton)=="undefined"||typeof(oberton)=="undefined")||this.markers) return;
	//alert('ok');
	var that = this;
	var selhid=0;
	// Search data
	if(myviton){
		if(oberton) for(var i=0;i<oberton.length;i++){
			var els = document.getElementById('lt'+oberton[i][0]);
			if(els && els.innerHTML.search(/<a/)<0){
				var da = document.createElement("A");
				da.id = 'm'+i;
				da.href = "#maps";
				da.onclick=function(e){return that.selMap(e,false)};//
				//da.onclick= new Function('return EGeoXml.prototype.selMap(this.id);');
				var dimg = document.createElement("IMG");
				dimg.src="/img/showmap.gif";dimg.border=0;dimg.alt="";dimg.title="Показать на карте!";dimg.align="absmiddle";dimg.width=15;dimg.height=15;
				da.appendChild(dimg);
				if(els.innerHTML.search(/<a/)) els.innerHTML=els.innerHTML+' ';
				els.appendChild(da);
				if(this.opts.selhid==oberton[i][0]) var selhid=i;
			}
		}
	}
	this.markers=oberton.length;
	if(this.opts.selhid && selhid && typeof document.getElementById('m'+selhid) != "undefined"){
		that.selMap(false,'m'+selhid);
	}
}

EGeoXml.prototype.selMap = function(e,id){
	if(!id){
		e=e||event;
		var target=e.target||e.srcElement;
	} else if(document.getElementById(id)) target = document.getElementById(id).firstChild;
	else return false;

	if(target.tagName!='IMG'||target.parentNode.tagName!='A') return false;
	var i = target.parentNode.id.replace(/[m]/,'');

	var that = this;
	if(!i.length||!oberton||!myviton||!that.map) return false;
	var lat = oberton[i][1];
	var lng = oberton[i][2];
	var zom = oberton[i][3];
//alert(lat+'('+lat.length+')='+myviton[lat]+';'+lng+'('+lng.length+')='+myviton[lng]+';'+zom+'=('+zom.length+')'+myviton[zom]);
	if(!myviton[lat]||!myviton[lng]||!myviton[zom]) return false;
//alert(lat+'='+myviton[lat]+';'+lng+'='+myviton[lng]+';'+zom+'='+myviton[zom]);
	if(that.opts&&that.map.j) that.map.j.style.display='';

	selmarker=oberton[i][0];
	that.map.setCenter(new GLatLng(myviton[lat],myviton[lng]), Math.round(myviton[zom]));

	that.gotomarker();
	if(document.getElementById('openClose')) document.getElementById('openClose').focus();
	else if(document.getElementById('map')) {
    if(document.all) window.document.getElementById('map').focus();
    else window.scroll(0, document.getElementById('map').offsetTop);
  }

	return false;
}

EGeoXml.prototype.gotomarker = function(){
	if(!selmarker||!this.gmarkers[selmarker]) return false;
	GEvent.trigger(this.gmarkers[selmarker],'mouseover');
	selmarker = false;
	return false;
}
// 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(marker){

	// 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;

	this.setmarker = marker;

	var that = this;
	//if(that.opts.data) that.deleteMarkersOutsideSection(that.opts.data,false);

	this.progress = this.urls.length;
	for(u=0; u<this.urls.length; u++){
		var request = GXmlHttp.create();
		request.open("GET", this.urls[u], true);
		request.onreadystatechange = function(){
			if(request.readyState == 4){
				that.processing(request.responseXML, request.status);
			}
		}
		request.send(null);
		//GDownloadUrl(this.urls[u], function(doc, responseCode){ that.processing(doc, responseCode); });
	}
}


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, responseCode){
	if(responseCode!=200) return false;

		var that = this;
    
		var fParsed = false;
		var xmlDoc = doc;
/* это для GDownloadUrl
		try {
		 if(ActiveXObject){
			xmlDoc = GXml.parse(doc);
			fParsed = xmlDoc.parsed;
		 }
		} catch(e){
		 //displayError(e);
		 if(window.DOMParser){
			var parser=new DOMParser();
			xmlDoc=parser.parseFromString(doc,"text/xml");
			fParsed = true;
		 }
		}
*/
		//if(fParsed) if(typeof(xmlDoc)=="undefined" /* || !xmlDoc.firstChild || !xmlDoc.firstChild.tagName || xmlDoc.firstChild.tagName=='parsererror'*/) fParsed = false;
		// Read through the Styles
		try {
			var styles = xmlDoc.documentElement.getElementsByTagName("Style");
			fParsed = true;
		} catch(e){
			//displayError(e);
			fParsed = false;
		}

		if(!fParsed){
			//document.getElementById('map').style.display='none';
			//if(document.getElementById('openClose')) document.getElementById('openClose').parentNode.style.display='none';
			return false;
		}


		if(typeof(styles)=="undefined")	return false;
		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,1);
						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
							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("/pink.png")>-1
							 || href.indexOf("/orange.png")>-1
							 || href.indexOf("-dot.png")>-1 ){
									that.styles["#"+styleID].shadow="http://maps.google.com/mapfiles/ms/micons/msmarker.shadow.png";
							}
							else if(href.indexOf("-pushpin.png")>-1){
									that.styles["#"+styleID].shadow="http://maps.google.com/mapfiles/ms/micons/pushpin_shadow.png";
							} else {
								that.styles["#"+styleID].shadow="/img/icons/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 reid=EGeoXml.value(placemarks[i].getElementsByTagName("id")[0]);
			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\t]+/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; 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 createpolyline 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,reid,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 createpolygon 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,reid,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,reid,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");
		}

		if(that.opts.data&&!that.opts.noreload) that.deleteMarkersOutsideSection(that.opts.data,true);
		if(that.opts.findname&&this.setmarker) this.gotomarker();

		return true;
}

EGeoXml.prototype.centerZoom = function(points){
		var numpoints = points.length - 1;
		var points2 = points.slice();
		points2.sort(function(p1, p2){
			return p1.lng() - p2.lng();
		});
		var west = points2[0].x;
		var east = points2[numpoints].x;
		points2.sort(function(p1, p2){
			return p1.lat() - p2.lat();
		});
		var north = points2[numpoints].y;
		var south = points2[0].y;
		var sw = new GLatLng(south,west);
		var ne = new GLatLng(north,east);
		var bounds = new GLatLngBounds(sw, ne);
		var centerpoint = new GLatLng((north + south)/2, (east + west)/2);
		var zoomlevel = this.map.getBoundsZoomLevel(bounds);
	return {'center':centerpoint,'zoom':zoomlevel};
}

EGeoXml.prototype.bearing = function( from, to ){
	// See T. Vincenty, Survey Review, 23, No 176, p 88-93,1975.
	// Convert to radians.
	var degreesPerRadian = 180.0 / Math.PI;
	var lat1 = from.latRadians();
	var lon1 = from.lngRadians();
	var lat2 = to.latRadians();
	var lon2 = to.lngRadians();
	// Compute the angle.
	var angle = - Math.atan2( Math.sin( lon1 - lon2 ) * Math.cos( lat2 ), Math.cos( lat1 ) * Math.sin( lat2 ) - Math.sin( lat1 ) * Math.cos( lat2 ) * Math.cos( lon1 - lon2 ) );
	if( angle < 0.0 )	angle	+= Math.PI * 2.0;
	// And convert result to degrees.
	angle = angle * degreesPerRadian;
	angle = angle.toFixed(1);
	return angle;
}

// === A function to put arrow heads at intermediate points
EGeoXml.prototype.midArrows = function(points){
	var arrowIcon = new GIcon();
	arrowIcon.iconSize = new GSize(16,16);
	arrowIcon.shadowSize = new GSize(1,1);
	arrowIcon.iconAnchor = new GPoint(8,8); // цент картинки (половина размера)
	arrowIcon.infoWindowAnchor = new GPoint(0,0);

	for(var i=0; i < points.length-1; i++){
		var p1=points[i];
    //p1.x=p1.x-0.008;p1.y=p1.y-0.008;
		var p2=points[i+1];
    //p2.x=p2.x-0.008;p2.y=p2.y-0.008;
		var dir = this.bearing(p1,p2);
		// == round it to a multiple of 3 and cast out 120s
		var dir = Math.round(dir/3) * 3;
		while(dir >= 120){dir -= 120;}
		// == use the corresponding triangle marker
		arrowIcon.image = "http://www.google.com/intl/en_ALL/mapfiles/dir_"+dir+".png";
		var midx = p1.x+((p2.x-p1.x)/2);
		var midy = p1.y+((p2.y-p1.y)/2);
		var middlepoint = new GLatLng(midy, midx);
		this.map.addOverlay(new GMarker(middlepoint, arrowIcon));
	}
}

function alert_r(d){
	var text='';
	for(var k in d) if(d[k]) text+='\t'+(k+' = "'+d[k])+'"\n';
	alert(text);
}

function displayError(e){
	var txt="Javascript Ошибка.\n";
	txt+="Source: " + e.source + "\n";
	txt+="Name: " + e.name + "\n";
	txt+="Description: " + e.message + "\n";
	alert(txt);
	return false;
	if(document.getElementById('openClose')) document.getElementById('openClose').innerHTML=txt;
}
