function RouteMap(dir, editable) {
	//window.map = map;
	this.markers = [];
	this.overlay = null;
	this.highlight = null;
	this.stops = [];
	this.editable = editable;
	this.lastdrag = null;
	
	//ex: ../.. or .. number of directories to get to root (/CoM/)
	this.dir = dir;
	
	this.buses = [];
}

//action is "alert" or "hide" depending if fleet view from admin view (alert) or customer interface (hide)
//could make boolean, but this allows for more than 2 options if required later
RouteMap.prototype.refreshBuses = function(xml, action) {

	if(this.lastdrag == null || new Date().getTime() - this.lastdrag > 5000)
	{
		this.destroyBuses();	
		thismap = this;
		var numbuses = 0;
		
		$('vehicle', xml).each(function (i) { 
			var id = $(this).attr('id');
			
			var lat = $(this).attr('lat');
			var lng = $(this).attr('lng');
			var lastupdate = $(this).attr('lastupdate');
			var icon = $(this).attr('icon');
			
			//updated more than 5 minutes ago
			if(action == "alert" && lastupdate > 5*60)
			{
				thismap.addBus(id, lat, lng, icon, true, action);
			}
			else
			{
				thismap.addBus(id, lat, lng, icon, false, action);
			}
		});
	}
	
}

RouteMap.prototype.destroyBuses = function() {

	for(var i = 0; i < this.buses.length; i++) {
		//this.buses[i].destroy();
		GEvent.clearInstanceListeners(this.buses[i]);
		window.map.removeOverlay(this.buses[i]);
		if(this.buses[i].polyline != null)
			window.map.removeOverlay(this.buses[i].polyline);
		this.buses[i] = null;
	}
	this.buses = [];
}

RouteMap.prototype.addBus = function(id, lat, lng, iconText, toAlert, action) {

	var icon = this.getBusIcon(iconText, toAlert);
  
	var draggable = action == "alert";
  	var marker = new GMarker(new GLatLng(lat, lng), {icon: icon, draggable: draggable});
	marker.type = "bus";
	marker.vehid = id;
	thismap = this;
	
	if(action == "alert")
	{
		GEvent.addListener(marker, "dragstart", function() {
			  thismap.lastdrag = new Date().getTime();
		});
		
	
		GEvent.addListener(marker, "drag", function() {
	
			if(this.polyline != null)
				map.removeOverlay(this.polyline);
	
			this.polyline = new GPolyline([
		                              new GLatLng(lat, lng),
		                              marker.getPoint()
		                            ], "#000000", 3, 1)
			map.addOverlay(this.polyline);
		});
	}
		
	//way to know that admin is wanting to click on the marker
	if(action == "alert")
		GEvent.bind(marker, "click", this, GEvent.callbackArgs(this, this.clickBus, marker));
	
	window.map.addOverlay(marker);
	
	this.buses[this.buses.length] = marker;
}

RouteMap.prototype.clickBus = function(marker) {
	window.open(this.dir+"/admin/info.php?vehID="+marker.vehid, 'InfoWindow', 'width=400,height=250,scrollbars=yes');
}

RouteMap.prototype.getBusIcon = function(id, toAlert) {	
	
	var icon = new GIcon();

	if(toAlert)
		icon.image = this.dir+"/icons/busIcon.php?id=" + id + "&alert=true";
	else
  		icon.image = this.dir+"/icons/busIcon.php?id=" + id;
  		
  	icon.iconSize = new GSize(60,60);
  	icon.iconAnchor = new GPoint(5,55);
  	icon.infoWindowAnchor = new GPoint(35,0);
  	
	return icon;
}

RouteMap.prototype.followBus = function(veh) {

	var thismap = this;
	
	$.ajax({
		type: "GET",
		url: this.dir+"/admin/actions.php",
		data: "action=getVehicleInfo&q="+veh,
		success: function(xml) {
						
			//clear other buses
			thismap.destroyBuses();
			
			$('marker', xml).each(function (i) {
					
				var id = $(this).attr('vehicleID');
				var lat = $(this).attr('lat');
				var lng = $(this).attr('lng');
				var lastupdate = $(this).attr('lastupdate');
				var icon = $(this).attr('icon');
				
				
				//check if we need to alert about the bus we are following
				if(lastupdate > 5*60) {
					thismap.addBus(id, lat, lng, icon, true, "alert");
				}
				else {
					thismap.addBus(id, lat, lng, icon, false, "alert");
				}
		
				
				window.map.setCenter(new GLatLng(lat, lng));
			});
		}
	});
}

RouteMap.prototype.loadRoute = function(route) {

	var thismap = this;
	$.ajax({
		type: "GET",
		url: this.dir+"/admin/actions.php",
		data: "action=getRouteMap&d="+route,
		success: function(data) { thismap.load(data); }
	});

}


RouteMap.prototype.load = function(xml) {

	this.destroy();
	
	var encoded_route = $('encoded_route', xml).text();
	var encoded_level = $('encoded_level', xml).text();
	var color = $('color', xml).text();
	var zoom = $('zoom', xml).text();
	var center = $('center', xml).text();
	
	var enc_points = this.decodeLine(encoded_route);
	var enc_levels = this.decodeLevels(encoded_level);
	
	for(var i=0;i<enc_points.length; i++) { 
		this.addRouteMarker(new GLatLng(enc_points[i][0], enc_points[i][1]), false); 
		if(this.editable)
			window.map.addOverlay(this.markers[this.markers.length - 1].getMarker());
	}
	this.highlightMarker(this.markers[this.markers.length - 1]);

	if(center != null && center != '')
		window.map.setCenter(new GLatLng(center.split(",")[0], center.split(",")[1]));
	
	if(zoom != null && zoom != '')
		window.map.setZoom(parseInt(zoom));
	
	var thismap = this;
	
	//draw it first to set the polyline and when we add the stops, the polyline will already exist
	this.draw();
	
}

RouteMap.prototype.destroy = function() {

	if(this.overlay != null) {
		window.map.removeOverlay(this.overlay);
		this.overlay = null;
	}
	
	//first, destroy any other polylines, markers in this object
	while(this.markers.length > 0) {
		this.deleteMarker(this.markers[0], false);
	}
	//alert('after delete, size is ' + this.markers.length);
	
	//first, destroy any other polylines, markers in this object
	//while(this.stops.length > 0) {
	//	this.deleteMarker(this.stops[0], true);
	//}
	//alert('after delete, size is ' + this.stops.length);
	
	this.overlay = null;
	this.highlight = null;
	
	//
	this.markers = [];
	this.stops = [];
	
	this.destroyBuses();
	this.buses = [];
	//
}

RouteMap.prototype.addRouteMarker = function(point,redraw) {
	var marker = new RouteMarker(point, this);
	this.addMarker(marker,redraw);
}

RouteMap.prototype.getMap = function() {
	return window.map;
}

RouteMap.prototype.getOverlay = function() {
	return this.overlay;
}

/*
RouteMap.prototype.addStopMarker = function(point) {
	var title = prompt("Stop title: ", "N/A");
	if(title != null)
	{
		var marker = new BusStop(point, title, this);
		this.addMarker(marker);
	}
}
*/

RouteMap.prototype.highlightMarker = function(marker) {

	if(marker instanceof RouteMarker)
	{
		if(this.highlight != null)
		{
			window.map.removeOverlay(this.highlight.getMarker());
			this.highlight.highlight(false);
			window.map.addOverlay(this.highlight.getMarker());
		}
		
		if(this.markers.indexOf(marker) > -1)
			window.map.removeOverlay(marker.getMarker());
		
		marker.highlight(true);
		this.highlight = marker;
		
		window.map.addOverlay(marker.getMarker());
		
	}
}

RouteMap.prototype.addMarker = function(marker, redraw) {

	if(redraw)
	{
		if(marker instanceof RouteMarker)
		{		
			if(this.highlight == null || this.markers.length == 0)
			{
				this.highlightMarker(marker);
				this.markers.push(marker);
			}
			else if(this.highlight != null)
			{
				var index = this.markers.indexOf(this.highlight);
				this.highlightMarker(marker);			
				this.markers.splice(index+1, 0, marker);
				
			}
			
			
		
		}
		this.draw();
	}
	else
	{
		this.markers.push(marker);
	}
	/*
	else if(marker instanceof BusStop)
	{
		if(!this.editable) {
			GEvent.clearListeners(marker.getMarker());
		}
			
		this.stops.push(marker);
		window.map.addOverlay(marker.getMarker());
	}
	*/
}

RouteMap.prototype.deleteMarker = function(marker, redraw) {
	
	if(marker instanceof GMarker)
	{
		//try to find it in markers and stops array
		var isMarker = this.getMarkerIndex(this.markers, marker) > -1 ? true : false;
		var isStop = this.getMarkerIndex(this.stops, marker) > -1 ? true : false;
		
		if(isMarker)
			marker = this.markers[this.getMarkerIndex(this.markers,marker)];
		else if (isStop)
			marker = this.stops[this.getMarkerIndex(this.stops, marker)];
		else
			marker = null;
	}
	
	if(marker != null)
		this.deleteMarker_(marker);
	
	if(redraw)
		this.draw();
	
}

RouteMap.prototype.deleteMarker_ = function(marker) {

	if(marker instanceof RouteMarker)
	{
		var index = this.markers.indexOf(marker);
	
		window.map.removeOverlay(marker.getMarker());
		
		GEvent.clearInstanceListeners(marker);
		
		this.markers.splice(index, 1);
		
		if(this.highlight == marker)
		{
			this.highlight = null;
			
			if(index == 0 && this.markers.length > 1) {
				this.highlightMarker(this.markers[1]);
			}
			else {
				this.highlightMarker(this.markers[index - 1]);
			}
		}
		
	
	}
	/*
	else if(marker instanceof BusStop)
	{
		window.map.removeOverlay(marker.getMarker());
		GEvent.clearInstanceListeners(marker);
		var index = this.stops.indexOf(marker);
		this.stops.splice(index, 1);
	}
	*/
}

RouteMap.prototype.getMarkerIndex = function(arr, marker) {
	for(var i = 0; i < arr.length; i++) {
		if(arr[i].getMarker() == marker)
			return i;
	}
	
	return -1;
}

RouteMap.prototype.draw = function() {

	if(this.overlay != null) {
		window.map.removeOverlay(this.overlay);
	}
	
	var points = [];
	
	for(var i=0; i<this.markers.length; i++) {
		points[points.length] = this.markers[i].getMarker().getLatLng();
		
		if(!this.editable) {
			window.map.removeOverlay(this.markers[i].getMarker());
		}
	}
	
	this.overlay = new GPolyline(points);
	
	map.addOverlay(this.overlay);		
	
	/*
	//update all bus markers
	for(var i=0; i<this.stops.length; i++) {
		//update the bus stop to closest point on the polyline
		this.stops[i].updateOverlay(this.overlay);
		var newpoint = this.stops[i].getSnapper().getClosestLatLng(this.stops[i].getMarker().getLatLng());
		this.stops[i].getMarker().setLatLng(newpoint);
	}
	*/
}

RouteMap.prototype.decodeLine = function(encoded) {
	var len = encoded.length;
	var index = 0;
  	var array = [];
  	var lat = 0;
  	var lng = 0;

	while (index < len) {
    	var b;
    	var shift = 0;
    	var result = 0;
    	do {
    		b = encoded.charCodeAt(index++) - 63;
      		result |= (b & 0x1f) << shift;
      		shift += 5;
    	} while (b >= 0x20);
    	var dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
    	lat += dlat;

    	shift = 0;
    	result = 0;
    	do {
      		b = encoded.charCodeAt(index++) - 63;
      		result |= (b & 0x1f) << shift;
      		shift += 5;
    	} while (b >= 0x20);
    	var dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
    	lng += dlng;

    	array.push([lat * 1e-5, lng * 1e-5]);
  	}

	return array;
}

// Decode an encoded levels string into a list of levels.
RouteMap.prototype.decodeLevels = function(encoded) {
	var levels = [];

	for (var pointIndex = 0; pointIndex < encoded.length; ++pointIndex) {
		var pointLevel = encoded.charCodeAt(pointIndex) - 63;
		levels.push(pointLevel);
  	}

	return levels;
}

//put this here for IE
//TODO move this to a utility.js file instead
if(!Array.indexOf){
	Array.prototype.indexOf = function(obj){
		for(var i=0; i<this.length; i++){
			if(this[i]==obj){
		    	return i;
		    }
		}
		return -1;
	}
}
