/*
	Copyright Scott Penrose 2007
	http://www.dd.com.au/
	scottp@dd.com.au
*/

/* 
	Debug & Compatibility Notes

	IE Issues
		- List entries, like 'glidermaps' or 'markers' must not have a final "," entry

	Javascript Libraries ?
		- Which to use?
		- Ext - large, special data containers for datagrid (tables), no obvious sort example
		- Tool-man - tiny (40K total), good for sortable, and editable list items

	Undo
		- Markers only ?
		- ID 
			- might be NO good as what if you 'delete' one
			- might be OK, as delete might be just a flag on a marker !
			- might be NO, due to re-order
			- might be OK, as sort may be a integer on the points
		- What can you do that can be undone
			- move - keep old position
				- .marker has new lat/lng
				- .point has new lat/lng		(redundant info - use .marker.getPoint())
				- .latitude changed			(redundant info - use .marker.getPoint().lat)
				- .longitude changed			(redundant info - use .marker.getPoint().lng)
			- create - delete it
			- modify - other non,move content such as Title (could be same as move)
			- delete - put it back
		- 'Modified' array 
			- seems that that text string is duplicate of some of this info?
			- this object can keep the reference to the modified array to remove that too
	Redo - not this version - could be done with array above

	undo[1] = {
		marker: 37,					// Marker effected
		action: 'create' | 'delete' | 'change'		// What was done
			// create - delete it by marking delete, but not putting in undo list
			// delete - unmark the delete flag
			// change - put field below back how it was
			//	Issue with this is multiple changes, e.g. undo should
			//	put back latitude and longitude, or all changes in a form.
			//	Fixed with 'another' being true
			//	e.g. adding these, you put in multiple entries
		field: 'latitude',				// Which field, if 'change'
		value: 13.27742,				// Previous value
		another: true,					// Do the next undo automatically
	}

		

*/

// ToolMan dragable list items ! - not working yet ! Try Ext versions
// var dragsort = ToolMan.dragsort();

// Main object !
var glidermaps = {

	// Configuration !
	startZoom: 10,

	// undo
	undo: [],

	// The Google map object
	map: "",
	enableNew: false,
	deselectCurrent: false,

	// icons - Consider moving these to a data file
	icons: {
		home: 0,
		airport: 0,
		landpoint: 0,
		start: 0,
		finish: 0,
		turnpoint: 0,
		restricted: 0,
		waypointflag: 0
	},

	// toggleNew - Can we add new waypoints with a click?
	toggleNew: function() {
		if (glidermaps.enableNew) {
			glidermaps.enableNew = false;
			return false;
		} else {
			glidermaps.enableNew = true;
			return true;
		}
	},

	// init - First time load of whole map - call once !
	init: function() {
		if (GBrowserIsCompatible()) {
			// Setup icons - consider moving this to a setup/config file !
			for (var t in glidermaps.icons) {
				glidermaps.icons[t] = new GIcon();
				glidermaps.icons[t].image = 'http://www.glidingmaps.com/flags/' + t + '.png';
				glidermaps.icons[t].shadow = 'http://www.glidingmaps.com/flags/shadow.png';
				glidermaps.icons[t].iconSize = new GSize(20,34);
				glidermaps.icons[t].shadowSize = new GSize(20,34);
				glidermaps.icons[t].iconAnchor = new GPoint(10, 34); 
				glidermaps.icons[t].infoWindowAnchor = new GPoint(20, 3); 
			}

			// INIT Map
			glidermaps.map = new GMap2(document.getElementById("map")); 
			// XXX First location ?
			glidermaps.map.setCenter(new GLatLng (markers[0].latitude, markers[0].longitude), glidermaps.startZoom); 

			// Scroll Wheel 
			glidermaps.map.enableDoubleClickZoom();
			glidermaps.map.enableScrollWheelZoom();
			var wheelevent = function() {
				var e;
				if (!e){ e = window.event }
				if (e.preventDefault){ e.preventDefault() }
				e.returnValue = false;
			}
			GEvent.addDomListener(glidermaps.map.getContainer(), "DOMMouseScroll", wheelevent);
			glidermaps.map.getContainer().onmousewheel = wheelevent; 

			// Add controls (always after center)
			glidermaps.map.addControl(new GLargeMapControl()); 
			glidermaps.map.addControl(new GMapTypeControl()); 

			// Map Type Button
			//var MyMapType = new GMapType( 
			//	[MyTileLayer1, MyTileLayer2], 
			//	MyProjection, 
			//	'My Map Type',
			//	{
			//		shortName:'Mine', 
			//		tileSize:256, 
			//		maxResolution:5, 
			//		minResolution:0 
			//	}
			//); 

			// Load default markers (TODO probably remove based on using Load/Save etc)
			glidermaps.loadMarkers();

			// Listen to any click on the map
			GEvent.addListener(glidermaps.map, 'click', glidermaps.newMarker);

			// Update body class - to remove loading image
			document.body.className = document.body.className.replace('loading', 'standby');
		} 
		else {
			alert("Sorry, this browser does not support Google Maps");
		}
	},

	// XXX should we pass the Object or the ID to all of these?
	//	e.g. use marker[id].* or just mark.* or both?

	// initMarker - init the content for a marker !
	initMarker: function(id) {

		// Google point
		markers[id].point = new GLatLng(markers[id].latitude, markers[id].longitude); 

		// Google marker (map flag)
		var i = G_DEFAULT_ICON;
		var iUrl = "http://www.glidingmaps.com/flags/default.png";
		if (glidermaps.icons[markers[id].type]) {
			i = glidermaps.icons[markers[id].type];
			iUrl = "http://www.glidingmaps.com/flags/" + markers[id].type + ".png";
		}
		markers[id].marker = new GMarker(markers[id].point, {draggable: true, title: markers[id].title, icon: i} );

		// Corosponding listNode
		markers[id].listItem = document.createElement('li'); 
		var listItemLink = markers[id].listItem.appendChild(document.createElement('a')); 
		listItemLink.href = "#"; 
		listItemLink.innerHTML = ''
			+ '<img src="' + iUrl + '"/>'
			+ '<strong>' + markers[id].title + '</strong>'
			+ '<br />' + markers[id].flag
			+ '<br />' + markers[id].other
		;

		// Info window
		var focusPoint = function() { 
			if (glidermaps.deselectCurrent) {glidermaps.deselectCurrent(); }
			markers[id].listItem.className = 'current';
			markers[id].listItem.focus();
			glidermaps.deselectCurrent = function() { markers[id].listItem.className = ''; }
			markers[id].marker.openInfoWindowTabsHtml([
				new GInfoWindowTab("Info", '' 
					+ '<div class="infowindow">'
					+ '<img src="' + iUrl + '"/>'
					+ '<div class="title">' + markers[id].title + '</div>'
					+ '<div class="type">' + markers[id].type + '</div>'
					+ '<div class="other">' + markers[id].other + '</div>'
					+ '<div class="latitude">' + markers[id].latitude + '</div>'
					+ '<div class="longitude">' + markers[id].longitude + '</div>'
					+ '</div>'
				),
				new GInfoWindowTab("Edit", '' 
					+ 'TODO'
				)
				// TODO Consider adding little map !
			]);

			glidermaps.map.panTo(markers[id].point); 

			// Scroll the list (TODO better offset code than guess of 25)
			glidermaps.sidebarEl.dom.scrollTop = listItemLink.offsetTop - 25;

			return false; 
		}
		GEvent.addListener(markers[id].marker, 'click', focusPoint); 
		listItemLink.onclick = focusPoint; 

		// Drabable Markers - simple version for now (XXX) (note drabable: true above)
		GEvent.addListener(markers[id].marker, "dragstart", function() {
			glidermaps.map.closeInfoWindow();
		});
		GEvent.addListener(markers[id].marker, "dragend", function() {
			// Keep last values for undo
			// 	'flase' (last undo) entry must ALWAYS be first !
			glidermaps.undoField(id, 'longitude', markers[id].longitude, false);
			glidermaps.undoField(id, 'latitude', markers[id].latitude, true);
				
			// Get current point
			markers[id].point = markers[id].marker.getPoint();
			markers[id].latitude = markers[id].point.lat();
			markers[id].longitude = markers[id].point.lng();

			markers[id].marker.openInfoWindowHtml("XXX Just bouncing along..."
				+ markers[id].point.lat() 
				+ " "
				+ markers[id].point.lng() 
			);

			// History (XXX may not need this with undo now !)
			markers[id].modified.push("Moved"
				+ " to " 
				+ markers[id].latitude
				+ " "
				+ markers[id].longitude
			);
		});

		// XXX Other defaults - assume not new flag_new = false
		// if (! markers[id].flag_new) 
			
		markers[id].show = false;

		// Keep what changes made (text array) for Saving - empty array = no changes.
		markers[id].modified = [];
	},

	// addMarker - Add a new entry ot the Markers array
	addMarker: function(latitude, longitude, description) {
		// XXX is markers.length reliable?
		id = markers.length;
		markers[id] = {
			latitude: latitude,
			longitude: longitude,
			title: description
		};
		glidermaps.initMarker(id);
		return id;
	},

	// removeMarker - remove it - permenantly from the array ?

	// showMarker - in the interface - map and list
	showMarker: function(id) {
		if (!markers[id].show) {
			document.getElementById('sidebar-list').appendChild(markers[id].listItem); 
			glidermaps.map.addOverlay(markers[id].marker); 
			markers[id].show = true;
		}
	},

	// hideMarker - in the interface - map and list
	hideMarker: function(id) {
		if (markers[id].show) {
			glidermaps.map.removeOverlay(markers[id].marker); 
			markers[id].listItem.parentNode.removeChild(markers[id].listItem);
			markers[id].show = false;
		}
	},

	// newMarker - a box to allow a new marker to be created
	newMarker: function(overlay, latlong) {
		//var marker = new GMarker(latlong);
		// glidermaps.map.addOverlay(marker);
		//glidermaps.map.openInfoWindow(latlong, document.createTextNode("Hello world!"));

		// Get rid of broken clics (e.g. when clicking Save)
		if (!latlong) { return }

		// Is it enabled?
		if (!glidermaps.enableNew) { return }

		if (glidermaps.deselectCurrent) {glidermaps.deselectCurrent(); }

		//create an HTML DOM form element 
		var inputForm = document.createElement("form"); 
		inputForm.setAttribute("action",""); 
		inputForm.onsubmit = function() {glidermaps.storeMarker(); return false;}; 
		//retrieve the longitude and lattitude of the click point 
		var longitude = latlong.lng(); 
		var latitude = latlong.lat(); 
		// TODO Move this HTML to somewhere else ! - e.g. Variable loaded
		inputForm.innerHTML = 
			'<fieldset style="width:150px;">' 
			+ '<legend>New Marker</legend>' 
			+ '<label for="wp_title">Title</label>' 
			+ '<input type="text" id="wp_title" style="width:100%;"/>' 
			+ '<label for="wp_longitude">Longitude</label>' 
			+ '<input id="wp_longitude" value="' + longitude + '"/>' 
			+ '<label for="wp_latitude">Latitude</label>' 
			+ '<input id="wp_latitude" value="' + latitude + '"/>' 
			+ '<input type="submit" value="Save"/>' 
			+ '</fieldset>'
		;
		glidermaps.map.openInfoWindow (latlong,inputForm); 
	},

	// editMarker
	editMarker: function() {
		// NOTE this should be the same code as newMarker
		//	Only passes in existing "id"
		//	storeMarker then needs to remove the old and add it again, or change details
	},

	// storeMarker -  on the server and add to map
	storeMarker: function() {
		// var id = document.getElementById("wp_id").value;			// Existing Waypoint entry (else new)
		var lng = document.getElementById("wp_longitude").value; 
		var lat = document.getElementById("wp_latitude").value; 
		var title = document.getElementById("wp_title").value; 

		/* 

		XXX TODO The actual call to the server !

		var getVars =  "?found=" + document.getElementById("found").value 
			+ "&left=" + document.getElementById("left").value 
			+ "&lng=" + lng 
			+ "&lat=" + lat ; 
		var request = GXmlHttp.create(); 

		//open the request to storeMarker.php on your server 
		request.open('GET', 'storeMarker.php' + getVars, true); 
		request.onreadystatechange = function() {
			if (request.readyState == 4) {
				//the request is complete 
				var xmlDoc = request.responseXML; 
				//retrieve the root document element (response) 
				var responseNode = xmlDoc.documentElement; 
				//retrieve the type attribute of the node 
				var type = responseNode.getAttribute("type"); 
				//retrieve the content of the responseNode 
				var content = responseNode.firstChild.nodeValue; 
				//check to see if it was an error or success 
				if(type!='success') { 
					alert(content); 
				} else { 
					//create a new marker and add its info window 
					XXX glidermaps.addMarker !
					map.closeInfoWindow(); 
				} 
			} 
		} 
		request.send(null); 
		*/

		/*

			// Simpler version of GXmlHttp - but less control (may be fine)
			GDownloadUrl('storeMarker.php' + getVars,  function(data,responseCode)) { 
				//Do something with the data 
			}); 

		*/

		var id = glidermaps.addMarker(lat, lng, "New - " + title);
		glidermaps.showMarker(id);
		glidermaps.map.closeInfoWindow(); 

		markers[id].modified.push("New Marker");

		return false; 
	}, 


	// Load the markers
	//	Could be a file was uploaded, new selection made from a set of markers
	loadMarkers : function() {
		// Markers ! - Centre point followed by list of markers
		for (var id = 0; id < markers.length; ++id) {
			glidermaps.initMarker(id);
			glidermaps.showMarker(id);
		} 
		glidermaps.updateCount(markers.length);
		glidermaps.zoomAll();
	},

	// zoomAll - zoom and move center to show all visible markers
	zoomAll: function() {
		var bounds = new GLatLngBounds();
		for (var id = 0; id < markers.length; ++id) {
			if (markers[id].show) {
				bounds.extend(markers[id].marker.getPoint());
			}
		} 
		glidermaps.map.setCenter(bounds.getCenter(), glidermaps.map.getBoundsZoomLevel(bounds));
	},

	// filterMarkers - show only those that match
	//	title = Substring
	//	flag = ? probably substring?
	//	Both = restrict where both match
	//	Neither = show all
	filterMarkers : function(title, flag) {
		var title_re = new RegExp(title, "i");
		var flag_re = new RegExp(flag, "i");
		var count = 0;
		for (var id = 0; id < markers.length; ++id) {
			if (
				(
					!title
					|| (markers[id] && markers[id].title && markers[id].title.match(title_re))
				)
				&& (
					!flag
					|| (markers[id] && markers[id].flag && markers[id].flag.match(flag_re))
				)
			) {
				count++;
				glidermaps.showMarker(id);
			}
			else {
				glidermaps.hideMarker(id);
			}
		} 
		glidermaps.updateCount(count);
	},

	// UNDO CODE - XXX document !

	undoCreate: function (id) {
		glidermaps.undo.push({
			marker: id,
			action: 'create'
		});
	},

	undoDelete: function (id) {
		glidermaps.undo.push({
			marker: id,
			action: 'delete'
		});
	},

	undoField: function (id, field, value, another) {
		glidermaps.undo.push({
			marker: id,
			action: 'change',
			field: field,
			value: value,
			another: another
		});
	},

	undoUndo: function () {
		var undo;
		while (undo = glidermaps.undo.pop()) {
			if (undo.action == 'change') {
				markers[undo.marker][undo.field] = undo.value;
			}

			if (! undo.another) {
				// Hack for lat/lng
				markers[undo.marker].point = new GLatLng(markers[undo.marker].latitude, markers[undo.marker].longitude); 
				markers[undo.marker].marker.setPoint(markers[undo.marker].point);
				// End of this undo cycle
				glidermaps.hideMarker(undo.marker);	// Cheap update marker !
				glidermaps.showMarker(undo.marker);	// XXX Removes and adds to list - looks crap !
				return true;
			}
		}
		return false;
	},

	// XXX document
	updateCount: function(count) {
		document.getElementById("count").innerHTML = "Count: " + count + " of " + markers.length;
	}

};

// Set "load" and "unload" events required for all maps !
window.onload = glidermaps.init; 
window.onunload = GUnload; 

