/**
 * Map Class
**/
 
var MapClass = Class.create (
{
	initialize: function ()
	{
		google.load('maps', 2);
		Event.observe(window, 'load', function () { Maps.initialise(); });
		Event.observe(window, 'resize', function () { Maps.resize(); });
	},
	initialise: function ()
	{
		if (!GBrowserIsCompatible())
		{
			alert('Browser is not compatible for maps.');
			return;
		}
 
		// resize the map
		Maps.resize();
		Maps.map = new google.maps.Map2($('map'));
		Maps.map.setCenter(new google.maps.LatLng(-37.872784, 145.088196), 10);
		Maps.map.addControl(new google.maps.LargeMapControl());
		Maps.map.addControl(new google.maps.MapTypeControl());
		Maps.markerManager = new MarkerManager(Maps.map);
		//Maps.map.addControl(new google.maps.OverviewMapControl());

		// setup Markers
		Maps.createMarkers();

		// Dev stuff
/*		google.maps.Event.addListener(Maps.map, 'click', function (o, p)
		{
			if (p)
			{
				var marker = new google.maps.Marker(p, { draggable: true });
				google.maps.Event.addListener(marker, 'click', function ()
				{
					marker.openInfoWindowHtml('' + marker.getLatLng().lat() + ', ' + marker.getLatLng().lng());
				});
				Maps.map.addOverlay(marker);
			} 
		}); */
	},
	resize: function ()
	{
		$('map').setStyle
		({
			width: '' + ($('content').getDimensions().width - $('controls').getDimensions().width - 20) + 'px',
			height: '' + [$('controls').getDimensions().height, ($('main').getDimensions().height - 10 - $('map').cumulativeOffset().top)].max() + 'px'
		});
//		if ($('main').getDimensions().height < 768)
//			$('main').setStyle({ height: '768px' });
	},
 
	addLine: function (lines)
	{
		if (arguments.length > 1)
			var cb = arguments[1];
		else
			var cb = Maps.showLine;
 
		lines = $A(lines);
		// retrieve lines that are not cached
		Maps.toCache = [];
		lines.each (function (line)
		{
			if (!Maps.isCached(line))
				Maps.toCache.push(line);
		});
		Maps.cacheLines(function (x) { Maps.addLine([x], cb); });
 
		lines.each (function (line)
		{
			cb(line);
		});
	},
	
	isCached: function (line)
	{
		if (Maps.lineCache == null)
		{
			Maps.lineCache = [];
			return false;
		}
		if (Maps.lineCache.any(function (cache) { return cache.shortname == line; }))
			return true;
		return false;
	},
	getCache: function (line)
	{
		return Maps.lineCache.find(function (l) { return l.shortname == line; });
	},
	cacheLines: function (cb)
	{
		if (Maps.toCache.length == 0)
			return;
 
		new Ajax.Request ('/bam/get_lines/' + Maps.toCache.join(';'),
		{
			method: 'GET',
			onSuccess: function (t) { Maps.addCache(t, cb); }
		});
	},
	cacheLine: function (line, cb)
	{
		new Ajax.Request ('/bam/get_lines/' + line,
		{
			method: 'GET',
			onSuccess: function (t) { Maps.addCache(t, cb); }
		});
	},
	addCache: function (t, cb)
	{

		$A(t.responseJSON).each (function (line)
		{
			if (line.polyline.match('<!@#>'))
			{
				line.polyline = line.polyline.split('<!@#>');
				line.levels = line.levels.split('<!@#>');
			} else
			{
				line.polyline = [line.polyline];
				line.levels = [line.levels];
			}
			line.polygonObject = Maps.createPolygon(line);
			line.polylineObject = Maps.createPolyline(line);
			Maps.lineCache.push(Object.extend(line,
			{
				shown: false,
				visible: function ()
				{
					return this.shown;
				}
			}));
			cb(line.shortname);
		});
		Maps.toCache = [];
	},
	getStations: function (line)
	{
		return !Maps.stationCache || !Maps.stationCache[line.shortname] ? false : Maps.stationCache[line.shortname];
	},
	
	cacheStations: function (line, cb)
	{
		if (!Maps.stationCache)
			Maps.stationCache = [];

		if (line.type == 1)
			var url = '/bam/get_stations/';
		else if (line.type == 2)
			var url = '/bam/get_stops/';

		new Ajax.Request (url + line.stations.join(';'),
		{
			method: 'GET',
			onSuccess: function (t) { Maps.addStations(line, t.responseJSON, cb); }
		});
	},
	addStations: function (line, stations, cb)
	{
		Maps.stationCache[line.shortname] = stations.collect(function (station)
		{
			station = Object.extend(station,
			{
				marker: new google.maps.Marker(new google.maps.LatLng(station.lat, station.long),
				{
					icon: Maps.markers[line.type]
				})
			});
			if (line.type == 1)
				var url = '/bam/get_station_info/';
			else if (line.type == 2)
				var url = '/bam/get_stop_info/';

			google.maps.Event.addListener(station.marker, 'click', function (s)
			{
				new Ajax.Request(url + station.id,
				{
					method: 'GET',
					onSuccess: function (t)
					{
						station.marker.openInfoWindowHtml(t.responseText);
					}
				});
			}); 
			return station;
		});
		cb(line, true);
	},
	
	showStations: function (line)
	{
		if (!Maps.stationCache || !Maps.stationCache[line.shortname])
		{
			if (arguments.length <= 1 || !arguments[1])
				Maps.cacheStations(line, Maps.showStations);
			return false;
		}

		stations = Maps.getStations(line);
		if (!stations)
			return false;

		// go ahead and place markers over..everything
		stations.each(function (station)
		{
			//Maps.map.addOverlay(station.marker);
			Maps.markerManager.addMarker(station.marker, station.zoom);
		});
	},
	
	hideStations: function (line)
	{
		if (!Maps.stationCache || !Maps.stationCache[line.shortname])
			return false;
		Maps.stationCache[line.shortname].each(function (station)
		{
			Maps.markerManager.removeMarker(station.marker);
		});
	},

	
	createPolyline: function (line)
	{
		highlight = false;
		if (arguments.length > 1)
			highlight = arguments[1];
 
		return new google.maps.Polyline.fromEncoded
		({
			color: highlight ? '#ff0000' : (line.type == 1 ? '#0099cc' : '#66cc33'),
			weight: 4,
			opacity: 1.0,
			points: line.polyline[0],
			levels: line.levels[0],
			zoomFactor: 2,
			numLevels: 18,
			clickable: false
		});
	},
 
	createPolygon: function (line)
	{
		highlight = false;
		if (arguments.length > 1)
			highlight = arguments[1];
 
		var polygon = line.polyline.collect(function (p, k)
		{
			return {
				weight: 4,
				opacity: 1.0,
				color: highlight ? '#ff0000' : (line.type == 1 ? '#0099cc' : '#66cc33'),
				points: p,
				levels: line.levels[k],
				zoomFactor: 2,
				numLevels: 18
			};
		});
		var p = new google.maps.Polygon.fromEncoded (
		{
			polylines: polygon,
			fill: false,
			outline: true,
			clickable: false
		});
		/*if (!highlight)
		{
			google.maps.Event.addListener(p, 'click', function ()
			{
				Maps.highlightLine(line.shortname);
			});
		} */
		return p;
	},
	
	showLine: function (line)
	{
		line = Maps.getCache(line);
		if (!line)
			return;
 
		// show this line only if its not already highlighted, if it is just change the status
		if (!Maps.isHighlightedLine(line.shortname))
		{
			if (line.polyline.length > 1)
				Maps.map.addOverlay(line.polygonObject);
			else
				Maps.map.addOverlay(line.polylineObject);
		}
		$(line.shortname).removeClassName('off');
		$(line.shortname).removeClassName('on');
		$(line.shortname).addClassName('on');
		line.shown = true;
 
		Maps.toggleAllLink();
	},
	hideLine: function (line)
	{
		line = Maps.getCache(line);
		if (!line)
			return;
		if (line.polyline.length > 1)
			Maps.map.removeOverlay(line.polygonObject);
		else
			Maps.map.removeOverlay(line.polylineObject);
		$(line.shortname).removeClassName('off');
		$(line.shortname).removeClassName('on');
		$(line.shortname).addClassName('off');
		line.shown = false;
		Maps.toggleAllLink();
	},
	visibleLine: function (line)
	{
		line = Maps.getCache(line);
		if (!line)
			return false;
		return line.visible();
	},
	
	
	enableControls: function ()
	{
		// go through the controls table and find all of our lines
		var lines = $$('#controls > table > tbody > tr');
		
		lines.each(function (line)
		{
			if (line.down().tagName.toLowerCase() == 'th')
				return;
			line.down().observe('click', Maps.highlightLine);
			line.down().next().observe('click', Maps.toggleLine);
		});
		
		$$('#controls > table > tbody > tr > th').each (function (header)
		{
			header.observe('click', function () { Maps.setControlTab($w(header.className).without('active').join('')); });
		});
		
		$$('#showhide > a').invoke('observe', 'click', Maps.toggleAll);
	},
	
	toggleLine: function (e)
	{
		if (!e.element().up())
			return false;
		var line = e.element().up().identify();
		if (Maps.visibleLine(line))
			Maps.hideLine(line);
		else if (Maps.isCached(line))
			Maps.showLine(line);
		else
			Maps.addLine([line]);
	},
	
	highlightLine: function (line)
	{
		var fromEvent = false;
		if (line instanceof Event)
		{
			line = line.element().up('tr').identify();
			fromEvent = true;
		}

		if (Maps.highlightedLine && Maps.highlightedLine.shortname == line)
		{
			Maps.clearHighlight();
			if (Maps.savedPosition)
			{
				Maps.map.setZoom(Maps.savedPosition.zoom);
				Maps.map.panTo(Maps.savedPosition.center);
				Maps.savedPosition = false;
			}
			return;
		}
		if (!Maps.highlightedLine)
		{
			Maps.savedPosition = { center: Maps.map.getCenter(), zoom: Maps.map.getZoom() };
		}

		// highlight this line!
		if (!Maps.getCache(line))
		{
			if (fromEvent)
				Maps.cacheLine(line, Maps.highlightLine);
			return false;
		}
		line = Maps.getCache(line);
		Maps.clearHighlight();

		if (!line.highlight)
		{
			if (line.polyline.length > 1)
				line.highlight = Maps.createPolygon(line,true);
			else
				line.highlight = Maps.createPolyline(line,true);
		}
 
		// draw our highlight
		Maps.map.addOverlay(line.highlight);
		Maps.map.setZoom(Maps.map.getBoundsZoomLevel(line.highlight.getBounds()));
		Maps.map.panTo(line.highlight.getBounds().getCenter());
		Maps.highlightedLine = line;
		$(line.shortname).addClassName('highlighted');
 
		// if the old line is shown, silently hide it
		if (line.visible())
		{
			// line was just added but not previously shown, remove it again
			if (line.polyline.length > 1)
				Maps.map.removeOverlay(line.polygonObject);
			else
				Maps.map.removeOverlay(line.polylineObject);
		}

		// show the information window
		Maps.showInfo(line);

		// show stations/stops on the highlighted line
		Maps.showStations(line);
 	},
	clearHighlight: function ()
	{
		var line = Maps.highlightedLine;
		if (!line)
			return false;
		Maps.hideStations(line);
		Maps.clearInfo();
		Maps.map.removeOverlay(line.highlight);
		Maps.highlightedLine = false;
 
		// is the line shown? restore it to its shown state
		$(line.shortname).removeClassName('highlighted');
		if (line.visible())
			Maps.showLine(line);
	},
	isHighlightedLine: function (line)
	{
		if (!Maps.highlightedLine)
			return false;
		return Maps.highlightedLine.shortname == line;
	},
	
	setControlTab: function (tab)
	{
		// is this tab already active?
		if ($$('#controls > table > tbody > tr > th.' + tab)[0].hasClassName('active'))
			return true;
 
		// mark both tabs inactive, then mark active our one
		$$('#controls > table > tbody > tr > th').invoke('removeClassName', 'active');
		$$('#controls > table > tbody > tr > th.' + tab).invoke('addClassName', 'active');
 
		// make them all hidden!
		$$('#controls > table > tbody > tr').invoke('hide');
 
		// reshow our header
		$$('#controls > table > tbody > tr > th')[0].up().show();
 
		// show all the ones that are ours
		$$('#controls > table > tbody > tr.' + tab).invoke('show');
 
		// resize the map + viewport to make sure it all fits still
		Maps.resize();
		Maps.toggleAllLink();
	},
	
	showAll: function ()
	{
		// show all of the currently visible lines
		$$('#controls > table > tbody > tr > td:first-child').each(function (x)
		{
			if (x.up().visible() && !Maps.visibleLine(x.up().identify()))
				Maps.addLine([x.up().identify()]);
		});
	},
 
	hideAll: function ()
	{
		// show all of the currently visible lines
		$$('#controls > table > tbody > tr > td:first-child').each(function (x)
		{
			if (x.up().visible() && Maps.visibleLine(x.up().identify()))
				Maps.hideLine([x.up().identify()]);
		});
	},
	
	toggleAll: function ()
	{
		if ($('showhide').down('a').innerHTML.match('Hide'))
			Maps.hideAll();
		else
			Maps.showAll();
	},
	toggleAllLink: function ()
	{
		// update the show/hide all link
		if ($$('#controls > table > tbody > tr > td:first-child').any(function (x)
		{
			return x.up().visible() && !Maps.visibleLine(x.up().identify());
		}))
			$('showhide').down('a').update('Show All');
		else
			$('showhide').down('a').update('Hide All');
	},
	
	// Create Marker Icons
	createMarkers: function ()
	{
		Maps.markers = [null];

		Maps.markers.push(new MapIconMaker.createMarkerIcon({ width: 26, height: 26, primaryColor: '#0000ff', cornerColor: '#8888ff' }));
		Maps.markers.push(new MapIconMaker.createMarkerIcon({ width: 26, height: 26, primaryColor: '#008000', cornerColor: '#88ff88' }));
/*
		var icon = new GIcon();
		icon.image = '/misc/images/stationsign.png';
		icon.shadow = '/misc/images/stationsignshadow.png';
		icon.iconSize = new GSize(40.0, 27.0);
		icon.shadowSize = new GSize(54.0, 27.0);
		icon.iconAnchor = new GPoint(18.0, 25.0);
		icon.infoWindowAnchor = new GPoint(20.0, 15.0);
		icon.imageMap = [16, 26, 16, 18, 0, 18, 0, 2, 16, 2, 16, 0, 20, 0, 20, 26, 16, 26]; 
		Maps.markers.push(icon);*/
	},
	
	clearInfo: function ()
	{
		$('lineinfo').update('');
	},
	showInfo: function (line)
	{
		if (line.type == 1)
		{
		/*	$('lineinfo').insert(new Element('h4').update(line.name + ' Line'));
			var table = new Element('table').insert(new Element('tbody'));
			var kms = line.polylineObject.inject(0, function (a, l) { return a + l.getLength(); }) / 1000;
			kms = kms.toFixed(2); 
			table.insert(new Element('tr').insert(new Element('td').update('Distance')).insert(new Element('td').update('' + kms + ' kms')));
			table.insert(new Element('tr').insert(new Element('td').update('Stations')).insert(new Element('td').update(line.stations.length)));
			$('lineinfo').insert(table); */
		} else if (line.type == 2)
		{
/*			$('lineinfo').insert(new Element('h4').update('Route ' + line.route + ': ' + line.name));
			var table = new Element('table').insert(new Element('tbody'));
			var kms = line.polylineObject.inject(0, function (a, l) { return a + l.getLength(); }) / 1000;
			kms = kms.toFixed(2); 
			table.insert(new Element('tr').insert(new Element('td').update('Distance')).insert(new Element('td').update('' + kms + ' kms')));
			table.insert(new Element('tr').insert(new Element('td').update('Stops')).insert(new Element('td').update(line.stations.length)));
			$('lineinfo').insert(table); */
		}
		Maps.resize();
	}
});
 
var Maps = new MapClass();

