/**
* Script for loading a map
*/

var DEFAULT_ZOOM = 9;

var markers = new Array();
var gmap;
var initialZoom;

// current line
var currentLine;
var polylines = new Array();


var BASE_URL = "http://www.bybeck.com/";

// map icons
var DEFAULT_MARKER_ICON = new GIcon();
DEFAULT_MARKER_ICON.image = BASE_URL + "images/ltblue-dot.png";
DEFAULT_MARKER_ICON.shadow = BASE_URL + "images/blank.gif";
DEFAULT_MARKER_ICON.iconSize = new GSize(32, 32);
DEFAULT_MARKER_ICON.shadowSize = new GSize(18, 31);
DEFAULT_MARKER_ICON.iconAnchor = new GPoint(10, 35);
DEFAULT_MARKER_ICON.infoWindowAnchor = new GPoint(7, 2);


/**
* Loads the map
* @param htmlElemId the HTML element with the id where the map should be loaded
* @param url the url to load the map XML from
*/
function loadMap(htmlElemId,url) {
	gmap = new GMap2(document.getElementById(htmlElemId));
	var request = GXmlHttp.create();
	request.open("GET", url, true);
	request.onreadystatechange = function() {  
		if (request.readyState == 4) {
			callback_loadMap(request);	
		}
	};

	request.send(null);
}

/**
* Loads the map: callback function
* @param request 
*/
function callback_loadMap(request) {
	var xmlDoc = request.responseXML;

	// load map properties
	var lon = parseFloat(xmlDoc.documentElement.getAttribute("lon"));
	var lat = parseFloat(xmlDoc.documentElement.getAttribute("lat"));
	var zoom = parseInt(xmlDoc.documentElement.getAttribute("zoom"));
	var mapType = parseInt(xmlDoc.documentElement.getAttribute("mapType"));

	// save the zoom
	if (zoom == null || zoom == "") {
		initialZoom = DEFAULT_ZOOM;
	} else {
		initialZoom = zoom;
	}

	// add controls and view
	var type = G_DEFAULT_MAP_TYPES[mapType];
	gmap.setCenter(new GLatLng(lat,lon),  zoom,  type);
	gmap.addControl(new GLargeMapControl());
	gmap.addControl(new GMapTypeControl());
	
	// load markers
	var markersElem = xmlDoc.documentElement.getElementsByTagName("markers");
	var markerElems = markersElem[0].getElementsByTagName("marker");
	for (var i=0; i<markerElems.length; i++) {
		var id = parseFloat(markerElems[i].getAttribute("id"));
		var lon = parseFloat(markerElems[i].getAttribute("lon"));
		var lat = parseFloat(markerElems[i].getAttribute("lat"));
		var title = markerElems[i].getAttribute("title");
		var imgUrl = markerElems[i].getAttribute("imgUrl");
		var imgWidth = markerElems[i].getAttribute("imgWidth");
		var imgHeight = markerElems[i].getAttribute("imgHeight");
		
		var html = "";
		if (markerElems[i].firstChild != null && markerElems[i].firstChild.nodeValue) {
			html = markerElems[i].firstChild.nodeValue;
		} 

		// load the point data locally
		var marker = new Marker();
		marker.id = id;
		marker.lat = lat;
		marker.lon = lon;
		marker.title = title;
		marker.html = html;
		if (imgUrl != null && trim(imgUrl) != "") {
			marker.imgUrl = imgUrl;
			marker.imgWidth = imgWidth;
			marker.imgHeight = imgHeight;
		}

		marker.draw();
		markers.push(marker);
	}

	// load the polylines

	var polylinesElem = xmlDoc.documentElement.getElementsByTagName("polylines");
	var polylineElems = polylinesElem[0].getElementsByTagName("polyline");
	for (var i=0; i<polylineElems.length; i++) {

		var id = parseInt(polylineElems[i].getAttribute("id"));
		var title = trim(polylineElems[i].getAttribute("title"));
		var color = trim(polylineElems[i].getAttribute("color"));
		var opacity = parseFloat(polylineElems[i].getAttribute("opacity"));
		var weight = polylineElems[i].getAttribute("weight");
				
		var html = "";
		var contentElems = polylineElems[i].getElementsByTagName("content");
		if (contentElems.length == 1) {
			if (contentElems[0].firstChild != null && contentElems[0].firstChild.nodeValue) {
				html = contentElems[0].firstChild.nodeValue;
			} 
		}

		// load the polyline data locally
		var polyline = new Polyline();
		polyline.id = id;
		polyline.title = title;
		polyline.html = html;
		polyline.setColor(color);
		polyline.setWeight(weight);
		polyline.setOpacity(opacity);

		// load the points
		var pointElems = polylineElems[i].getElementsByTagName("point");
		for (var j=0; j<pointElems.length; j++) {
			var lon = parseFloat(pointElems[j].getAttribute("lon"));
			var lat = parseFloat(pointElems[j].getAttribute("lat"));
			var linePoint = new LinePoint(lat,lon);
			polyline.addPoint(linePoint);
		}
		
		polyline.draw();
		polyline.addEndGMarker();
		polyline.addBeginGMarker();
		polylines.push(polyline);
	}

}


/******************
* Marker object
******************/
function Marker() {
	this.id = null;
	this.lat;
	this.lon;
	this.title = "";
	this.html = "";
	this.imgUrl = "";
	this.imgWidth = "";
	this.imgHeight = "";
	this.gmarker = null;
	
	// methods
	this.draw = drawMarker;
	this.open = openMarker;
	this.erase = eraseMarker;
	this.save = saveMarker;
	this.destroy = destroyMarker;
	this.getTab1Html = getTab1Html;

	this.toString = function() {
		var s = "Marker: id:" + this.id + " title: " + this.title + " lat:" + this.lat + " lon:" + this.lon + " html:" + this.html + " imgUrl:" + this.imgUrl;
		return s;
	}
}

/**
* Method: draws the marker
*/
function drawMarker() {
	//GLog.write("marker.draw()");
	var gicon = DEFAULT_MARKER_ICON;
	
	if (this.imgUrl != null && this.imgUrl != "") {	
		gicon = new GIcon(DEFAULT_MARKER_ICON);
		gicon.image = this.imgUrl;	
		gicon.iconSize = new GSize(this.imgWidth, this.imgHeight);
		gicon.iconAnchor = new GPoint(Math.round(this.imgWidth/2), Math.round(this.imgHeight));
	}
	
	// if marker exists, erase first
	if (this.gmarker != null) {	
		gmap.removeOverlay(this.gmarker);
	}

	// draw using GMap objects
	var gmarker = new GMarker(new GPoint(this.lon,this.lat),gicon);
	gmap.addOverlay(gmarker);
	this.gmarker = gmarker;
	
	GEvent.addListener(gmarker, "click", function() {
		//GLog.write("marker clicked");
		var gLatLng = this.getPoint();
		//GLog.write("marker latLng:" + gLatLng);
		var marker = getMarkerByLatLon(gLatLng.lat(),gLatLng.lng());
		//GLog.write("marker:" + marker);
		marker.open();
	});
		
	GEvent.addListener(this.gmarker,"infowindowclose",function() { 
		var gLatLng = this.getPoint();
		var marker = getMarkerByLatLon(gLatLng.lat(),gLatLng.lon());
		marker.close();
	});
}

/**
* Method: erases the marker
*/
function eraseMarker() {
	//GLog.write("marker.erase()");
	// if marker exists, erase first
	if (this.gmarker != null) {	
		//GLog.write("marker.erase(): removing overlay");
		gmap.removeOverlay(this.gmarker);
	}
}

/**
* Method: opens the marker
*/
function openMarker() {
	//GLog.write("marker.open()");
	var tab1 = this.getTab1Html();
	var infoTabs = [
		new GInfoWindowTab("Basic", tab1)
	];
	this.gmarker.openInfoWindowTabsHtml(infoTabs);
}

/**
* Method: saves a marker
*/
function saveMarker() {
	if (this.id == null || this.id == "") {
		call_addPoint(this);
	} else {
		call_editPoint(this);
	}
}

/**
* Method: removes a marker
*/
function destroyMarker() {
	//GLog.write("marker.destroy()");
	if (this.id != null && this.id != "") {
		call_deletePoint(this.id);
	}
	this.erase();
}

/**
* Method: gets HTML for a tab for this marker
*/
function getTab1Html() {
	var s = "<div id='markerInfoWin'>";		
	s += "<h2>"+this.title+"</h2>";
	s += "<p>"+this.html+"</p>";
	s += "</div>";
	return s;
}


/************
 End Marker
*************/



/**
* Returns the marker at the given point
* @param lat
* @param lon
*/
function getMarkerByLatLon(lat,lon) {
	for (var i=0;i<markers.length; i++) {
		if (markers[i].lat == lat && markers[i].lon == lon) {
			return markers[i];
		}
	}
	return null;
}

/**
* Cancels the marker provided
*/
function closeInfoWin(gmarker) {
	gmap.closeInfoWindow();
}

/**
* Loads the info window
*/
function loadInfoWin(lat,lon,gmarker) {
	var gp = new GPoint(lon,lat);
	var html = getInfoWindowHtml(gp);
	gmarker.openInfoWindowHtml(html);
}



/*********************
* LINE-HANDLING CODE
*********************/

/**
* LinePoint class 
*/
function LinePoint(lat,lon) {
	this.lat = lat;
	this.lon = lon;
}

/** 
* Polyline class 
*/
function Polyline() {
	this.id = null;
	this.title = "";
	this.html = "";
	this.color = "#FF0000";
	this.weight = 1;
	this.opacity = 1;
	this.points = new Array();
	this.gPolyline;  	// reference to the Google Polyline
	this.beginGMarker = null;
	this.endGMarker = null;
	
	// settors
	this.setColor = setColor;
	this.setWeight = setWeight;
	this.setOpacity = setOpacity;
	this.setEndGMarker = setEndGMarker;
	this.setBeginGMarker = setBeginGMarker;
	// methods
	this.addPoint = addPoint;
	this.addEndGMarker = addEndGMarker;
	this.addBeginGMarker = addBeginGMarker;
	this.getMarkerIcon = getMarkerIcon;
	this.draw = drawPolyline;
	this.remove = removePolyline;
	this.save = savePolyline;
	
	this.toString = function() {
		return "Polyline:" +id+ "," +color+ "," +weight+ "," +opacity+ "," +points.length;	
	}
}

/**
* Sets the color
*/
function setColor(v) {
	//GLog.write("setColor("+v+")");
	v = trim(v);
	if (v != "" && v != null) {
		this.color = v;
	}
}

/**
* Sets the weight
*/
function setWeight(v) {
	if (v != "" && v != null && !isNaN(v)) {
		this.weight = v;
	}
}

/**
* Sets the opacity
*/
function setOpacity(v) {
	if (v != "" && v != null && !isNaN(v)) {
		this.opacity = v;
	}
}

/**
* Sets the end GMarker
*/
function setEndGMarker(v) {
	if (v != null) {
		this.endGMarker = v;
	}
}

/**
* Sets the begin GMarker
*/
function setBeginGMarker(v) {
	if (v != null) {
		this.beginGMarker = v;
	}
}

/**
* Polyline method: adds a point to the line
*/
function addPoint(lp) {
	this.points.push(lp);
}

/**
* Polyline method: saves this line
*/
function savePolyline() {
	if (this.id == null || this.id == "") {
		call_savePolyline(this);
	} else {
		call_editPolyline(this);
	}
}

/**
* Polyline method: removes the line
*/
function removePolyline() {
	if (this.beginGMarker != null) {
		gmap.removeOverlay(this.beginGMarker);
	}
	if (this.endGMarker != null) {
		gmap.removeOverlay(this.endGMarker);
	}
	if (this.gPolyline != null) {
		gmap.removeOverlay(this.gPolyline);
	}
	call_deletePolyline(this);
}

/**
* Polyline method: draws the line
*/
function drawPolyline() {
	var linePoints = this.points;
	var gPoints = new Array();
	for (var i=0;i < linePoints.length; i++) {
		var gPoint = new GPoint(linePoints[i].lon,linePoints[i].lat); 
		gPoints.push(gPoint);
	}
	
	var newGPolyline =  new GPolyline(gPoints,this.color,this.weight,this.opacity);
	if (this.gPolyline != null) {	// if line exists, erase first
		gmap.removeOverlay(this.gPolyline);
	}
	this.gPolyline = newGPolyline;
	gmap.addOverlay(newGPolyline);
}

/**
* Method: returns the icon for this line
*/
function getMarkerIcon() {
	var gIcon = new GIcon(DEFAULT_LINE_ICON);
	var iconUrl = this.color.replace("#","");
	gIcon.image = BASE_URL + "/images/line/" + iconUrl + ".png";
	gIcon.shadow = BASE_URL + "/images/line/" + iconUrl + ".png";
	return gIcon;
}

/**
* Method for adding the ending marker
*/
function addEndGMarker() {
	var lastPoint = this.points[this.points.length-1];
	var firstPoint = this.points[0];
	
	var gIcon = this.getMarkerIcon();
		
	// add a marker to the LAST point and save
	var gmarker = new GMarker(new GPoint(lastPoint.lon,lastPoint.lat),gIcon);
	this.setEndGMarker(gmarker);
	gmap.addOverlay(gmarker);
	
	// add listener to marker
	GEvent.addListener(gmarker, "click", function() {
		var polyline = getLineByLatLon(lastPoint.lat,lastPoint.lon);
		var html = getLineHtml(polyline);
		gmarker.openInfoWindowHtml(html);
	});
}

/**
* Method for adding the begin marker
*/
function addBeginGMarker() {
	var lastPoint = this.points[this.points.length-1];
	var firstPoint = this.points[0];
	
	var gIcon = this.getMarkerIcon();
		
	// add a marker to the FIRST point and save
	var gmarker = new GMarker(new GPoint(firstPoint.lon,firstPoint.lat),gIcon);
	this.setBeginGMarker(gmarker);
	gmap.addOverlay(gmarker);
	
	// add listener to marker
	GEvent.addListener(gmarker, "click", function() {
		var polyline = getLineByLatLon(lastPoint.lat,lastPoint.lon); // the LAST point
		var html = getLineHtml(polyline);
		gmarker.openInfoWindowHtml(html);
	});
}

/**************
  End Polyline
***************/



/**
* Adds a point to the current line
* @param gpoint the GPoint to add
*/
function addLinePoint(gpoint) {
	if (currentLine == null) {
		currentLine = new Polyline();
		updateCurrentLineProps();
	}
	var linePoint = new LinePoint(gpoint.y,gpoint.x);
	currentLine.addPoint(linePoint)
	currentLine.draw();
}


/**
* Gets the HTML form/input for adding this lines data
* @return the HTML
*/
function getLineHtml(polyline) {
	var lastPoint = polyline.points[polyline.points.length-1];
	
	s = "";
	s += "<div id='markerInfoWin'>";		
	s += "<h2>"+polyline.title+"</h2>";
	s += "<p>";
	s += trim(polyline.html);
	s += "</p>";
	s += "</div>";
	return s;
}

/**
* Gets the line for which the last point matches the given lat and lon
*/
function getLineByLatLon(lat,lon) {
	for (var i=0; i<polylines.length; i++) {
		if (polylines[i].points.length > 0) {
			var lastPoint = polylines[i].points[polylines[i].points.length - 1];
			if (lastPoint.lat == lat && lastPoint.lon == lon) {
				return polylines[i];
			}
		}
	}
	return null;
}

/**
* Trims a string
* @param s the string
*/
function trim(s) {
	if (s == null || s == "") {
		return "";	
	}
	while ((s.substring(0,1) == ' ') || (s.substring(0,1) == '\n') || (s.substring(0,1) == '\r')) {
		s = s.substring(1,s.length);
	}
	while ((s.substring(s.length-1,s.length) == ' ') || (s.substring(s.length-1,s.length) == '\n') || (s.substring(s.length-1,s.length) == '\r')) {
		s = s.substring(0,s.length-1);
	}
	return s;
}
