
/*
 * Objects of this class are created by the MMDirections object to store information about
 * a single route in a directions result. 
 */
function MMRoute(startWaypoint, endWaypoint){ 	
			
	/**** Routing Properties ****/
	
	this.startWaypoint = startWaypoint;
	this.endWaypoint = endWaypoint;
	
	this.heightUp = 0;
	this.heightDown = 0;
	
	
	/** 1) Simple bike routing **/
	this.traffic = 1;
	if(window.location.href.search('netedit')==-1){ 	// Routen nach Wunsch
		this.difficulty = 0;
		this.surface = 20;	
		this.useElevation = 0;
		this.bikeResponseCache = null;
		this.traffic = 1;
	}else{											// Netzwerk Verwalten, bzw sonstiges
		this.difficulty = 0;
		this.surface = 0;	
		this.useElevation = 0;
		this.bikeResponseCache = null;
		this.traffic = 3;
	}
	
	this.costfree = false;
	

	/** 2) ÖPNV Transportation **/
	this.useOpnv = false;
	this.regionalbahn = true;
	this.sBahn = true;
	this.uBahn = true;
	this.bus = true;
	this.datetime = new Date();
	this.datetime.setSeconds(0);
	this.datetime.setMilliseconds(0);
	
	this.isDeparture = true; // false = arrival	
	this.opnvResponseCache = null;
	
	this.map;
	this.isSelected = false;

	this.listeners = new Array();
	this.listeners.push(GEvent.bind(this.startWaypoint, "dragend", this, function(){
		this.bikeResponseCache = null;
		this.opnvResponseCache = null;
		if(this.currentRequest)this.currentRequest.transport.abort();
		this.currentRequest = null;
		this.load();
	}));
	this.listeners.push(GEvent.bind(this.endWaypoint, "dragend", this, function(){
		this.bikeResponseCache = null;
		this.opnvResponseCache = null;
		if(this.currentRequest)this.currentRequest.transport.abort();
		this.currentRequest = null;
		this.load();
	}));

	// erzwinge Neuberechnung, damit die Anschlussstrecke bei Zwischenknoten passen!
	this.listeners.push(GEvent.bind(this.startWaypoint, "typeChanged", this, function(){
		if(this.useOpnv) GEvent.trigger(this.startWaypoint, "dragend");
	}));
	this.listeners.push(GEvent.bind(this.endWaypoint, "typeChanged", this, function(){
		if(this.useOpnv) GEvent.trigger(this.endWaypoint, "dragend");
	}));
	
	this.currentRequest = null;
	this.responseId = null;
	this.polyline = null; // einzelne Polyline nutzen! (partialRoutes verursachen Fehler)
	this.transportationMarkers = new Array();	
	
	this.loadingMarker = null;	
	
}
MMRoute.prototype = new GOverlay();


MMRoute.nopathIcon = new GIcon(
	    {image: "dateien/marker/nopath.gif",
	     iconSize:new GSize(13,12), 
	     iconAnchor: new GPoint(6,6), 
	     infoWindowAnchor: new GPoint(6,6), 
	     shadow: null});
	     
MMRoute.loadingBlueIcon = new GIcon(
	    {image: "dateien/marker/loading_blue.gif",
	     iconSize:new GSize(24,24), 
	     iconAnchor: new GPoint(12,12), 
	     shadow: null});
	    
MMRoute.loadingRedIcon = new GIcon(
	    {image: "dateien/marker/loading_red.gif",
	     iconSize:new GSize(24,24), 
	     iconAnchor: new GPoint(12,12), 
	     shadow: null});
	     

MMRoute.prototype.OpnvAvailable = function()
{
	var vvs = new GLatLngBounds(new GLatLng(48.511345, 8.760019), new GLatLng(49.076105, 9.766591));
	return (vvs.containsLatLng(this.startWaypoint.GetPoint()) && vvs.containsLatLng(this.endWaypoint.GetPoint()));
}

MMRoute.prototype.GetOpnv = function(){ return this.useOpnv; }
MMRoute.prototype.SetOpnv = function(bool){		
	if(this.useOpnv != bool && this.currentRequest){
		this.currentRequest.transport.abort();
		this.currentRequest = null;
	}
	
	this.useOpnv = bool;
}

MMRoute.prototype.GetHeightdifferenceUp = function(){return this.heightUp;}
MMRoute.prototype.GetHeightdifferenceDown = function(){return this.heightDown;}

/* time of departure / arrival */
MMRoute.prototype.SetTime = function(datetime, isDeparture){
	if(this.datetime.getTime() != datetime.getTime() || this.isDeparture != isDeparture) this.opnvResponseCache = null;
	this.datetime = datetime;
	this.isDeparture = isDeparture;
}
MMRoute.prototype.GetTime = function(){ return this.datetime; }
MMRoute.prototype.TimeIsDeparture = function(){ return this.isDeparture; }

/* Properties transportation */
MMRoute.prototype.SetTransportation = function(regionalbahn, sbahn, ubahn, bus){
	
	if(this.regionalbahn != regionalbahn || this.sBahn != sbahn || this.uBahn != ubahn || this.bus != bus) this.opnvResponseCache = null;
	
	this.regionalbahn = regionalbahn;
	this.sBahn = sbahn;
	this.uBahn = ubahn;
	this.bus = bus;
}
MMRoute.prototype.GetRegionalbahn = function(){ return this.regionalbahn; }
MMRoute.prototype.GetSbahn = function(){ return this.sBahn; }
MMRoute.prototype.GetUbahn = function(){ return this.uBahn; }
MMRoute.prototype.GetBus = function(){ return this.bus; }



/* Properties of a simple bike route */
MMRoute.prototype.GetUseElevation = function(){ return this.useElevation; }
MMRoute.prototype.SetUseElevation = function(bool){
	if(this.useElevation != bool) this.bikeResponseCache = null;
	this.useElevation = bool;
}

MMRoute.prototype.GetSurface = function(){ return this.surface; }
MMRoute.prototype.SetSurface = function(surface){
	if(this.surface != surface) this.bikeResponseCache = null;
	this.surface = surface;
}

MMRoute.prototype.GetDifficulty = function(){ return this.difficulty; }
MMRoute.prototype.SetDifficulty = function(difficulty){
	if(this.difficulty != difficulty) this.bikeResponseCache = null;
	this.difficulty = difficulty;
}

MMRoute.prototype.GetTraffic = function(){ return this.traffic; }
MMRoute.prototype.SetTraffic = function(traffic){
	if(this.traffic != traffic) this.bikeResponseCache = null;
	this.traffic = traffic;
}



MMRoute.prototype.GetStartWaypoint = function(){
	return this.startWaypoint;
}

MMRoute.prototype.GetEndWaypoint = function(){
	return this.endWaypoint;
}


MMRoute.prototype.IsCostfree = function(){ return this.costfree; }


/**
 * Called by the map after the overlay is added to the map using GMap2.addOverlay(). The overlay object 
 * can draw itself into the different panes of the map that can be obtained using GMap2.getPane().
 */
MMRoute.prototype.initialize = function(map){
	this.map = map;
}


/**
 * Called by the map when the map display has changed. The argument force will be true if the zoom level or 
 * the pixel offset of the map view has changed, so that the pixel coordinates need to be recomputed.
 */
MMRoute.prototype.redraw = function(force){
	if(this.polyline)this.polyline.redraw(force);
}


/**
 * Called by the map after the overlay is removed from the map using GMap2.removeOverlay() or GMap2.clearOverlays(). 
 * The overlay must remove itself from the map panes here.
 */
MMRoute.prototype.remove = function(){
		
	GEvent.trigger(this, "remove");
	
	if(this.currentRequest)	this.currentRequest.transport.abort();
	if(this.polyline)this.map.removeOverlay(this.polyline);
	if(this.loadingMarker)this.map.removeOverlay(this.loadingMarker);
		
	for(var i=0; i<this.listeners.length; i++){
		GEvent.removeListener(this.listeners[i]);
	}
	
	for(var i=0; i<this.transportationMarkers.length; i++){
		this.map.removeOverlay(this.transportationMarkers[i]);
	}
	
	this.transportationMarkers = new Array();
	this.listeners = new Array();
	this.map = null;
}


/**
 * Returns an uninitialized copy of itself that can be added to the map.
 */
MMRoute.prototype.copy = function(map){
	return new MMRoute();
}


MMRoute.prototype.loadFromCache = function(){
			
	if(this.useOpnv == false && this.bikeResponseCache != null)
	{
		this.replacePolyline(this.bikeResponseCache);
		return true;
	}
	else if(this.useOpnv == true && this.opnvResponseCache != null)
	{
		this.replacePolyline(this.opnvResponseCache);
		return true;
	}
	return false;
}



MMRoute.prototype.loadFromServer = function(){
	
	// no changes, because load is now initalized
	if(this.useOpnv)this.opnvResponseCache = null;
	else this.bikeResponseCache = null;
	
	var start = this.startWaypoint.GetPoint();
	var end = this.endWaypoint.GetPoint();
	
	var url = MMRegistry.urlPortal +"CalculateRoute.php";
	var para = "?from=" + start.lat() +","+ start.lng() +"&to=" + end.lat() +","+ end.lng();
	
	if(this.useOpnv)
	{
		para += "&time="+ this.datetime.toGMTString();		
		if(this.isDeparture) para += "&type=departure";
		else para += "&type=arrival";
		
		para += "&rbahn="+ this.regionalbahn;
		para += "&sbahn="+ this.sBahn;
		para += "&ubahn="+ this.uBahn;
		para += "&bus="+ this.bus;
		
		if(this.startWaypoint.GetType() == 1) para += "&snapstart=1";
		if(this.endWaypoint.GetType() == 1) para += "&snapend=1";
		
	}else{
		para += "&difficulty="+ this.difficulty;
		para += "&surface="+ this.surface;
		if(this.useElevation == 1) para += "&useElevation=1";	
		if(this.traffic      != 0) para += "&traffic="+this.traffic; // neu
	}
	

	this.currentRequest = new Ajax.Request(
		url,
		{
			method: 'get',	
			parameters: para,
		
			onFailure: function(transport){
			
				// set nopath information
				if(this.map){
					this.SetCenterIcon(3);						
				}
				this.currentRequest = null;
				
				// there is no route to cache
				if(this.useOpnv)this.opnvResponseCache = null;
				else this.bikeResponseCache = null;
			},
			onSuccess: function(transport)
			{	
				try
				{					
					var json = transport.responseText.evalJSON();
					
					if(this.useOpnv)this.opnvResponseCache = json;
					else this.bikeResponseCache = json;
					
					this.replacePolyline(json);								
				}
				catch(e)
				{
					this.SetCenterIcon(3);
					
					// there is no route to cache
					if(this.useOpnv)this.opnvResponseCache = null;
					else this.bikeResponseCache = null;
				}
				
				this.currentRequest = null;
			
			}.bind(this)
		});
			

}

MMRoute.prototype.replacePolyline = function(json){

	if(json.status == 100)
	{						
		this.SetCenterIcon(-1);
		
		// set new polyline								
		this.polyline.setEncodedPolyline(json.polyline);		
		this.polyline.SetOpacity(0.45);
		this.responseId = json.responseId;
		
		// add transportationMarkers
		for(var i=0; i<json.stationList.length; i++)
		{
			var station = json.stationList[i];
			var type = station.transportation.type;
				
			if(i > 0 || type != 10)
			{								
				var mmStation = new MMStation(station);
				this.map.addOverlay(mmStation);
				this.transportationMarkers.push(mmStation);
			}							
		}
		
		this.heightUp = json.up;
		this.heightDown = json.down;		
		
		this.SetSelection(this.isSelected);						
		
		if(json.costfree)this.costfree = true;
		else this.costfree = false;
		
		GEvent.trigger(this, "routechanged");
	}
	else
	{
		this.SetCenterIcon(0);
	}
	
}


/**
 * Issues a new route query and draws itself
 */
MMRoute.prototype.load = function(doServerRequest)
{
	if(arguments.length == 0) var doServerRequest = true;
	
	// route can't be displayed if it is not initialized
	if(this.map == null) return false;
	
	// to avoid multiple loading of the same!
	if(this.useOpnv == true && this.currentRequest != null) return false;
	else if(this.useOpnv == false && this.currentRequest != null) return false;

					
	// cancel any running request
	if(this.currentRequest){
		this.currentRequest.transport.abort();
		this.currentRequest = null;
	}

	
	// set beeline (first call initializes Polyline)
	var start = this.startWaypoint.GetPoint();
	var end = this.endWaypoint.GetPoint();
		
	if(this.polyline)
	{
		this.polyline.setPoints([start, end]);
		GEvent.trigger(this, "routechanged");
	}
	else
	{
		this.polyline = new MMPolyline([start, end]);
		GEvent.trigger(this, "routechanged");
				
		this.map.addOverlay(this.polyline);
		this.listeners.push( GEvent.bind(this.polyline, "click", this, this.PolylineClick) );
		this.listeners.push( GEvent.bind(this.polyline, "rightclick", this, this.PolylineRightClick) );
		this.listeners.push( GEvent.bind(this.polyline, "mouseover", this, this.PolylineMouseOver) );
		this.listeners.push( GEvent.bind(this.polyline, "mousemove", this, this.PolylineMouseMove) );
		this.listeners.push( GEvent.bind(this.polyline, "mouseout", this, this.PolylineMouseOut) );
	}
	
	// set polyline properties
	this.polyline.SetOpacity(0.2);	
	if(doServerRequest)
	{
		if(this.isSelected) this.SetCenterIcon(2);
		else this.SetCenterIcon(1);
	}
	
	
	// remove transportationMarkers
	for(var i=0; i<this.transportationMarkers.length; i++){
		this.map.removeOverlay(this.transportationMarkers[i]);
	}	
	this.transportationMarkers = new Array();
	
	
	// replace the beeline Polyline by the requested route
	if(this.loadFromCache() == false && doServerRequest == true) this.loadFromServer();	
}


MMRoute.prototype.SetSelection = function(bool){	
	this.isSelected = bool;
		
	if(this.isSelected)
	{
		var color = "#ff0000";
		if(this.loadingMarker && this.currentRequest)this.SetCenterIcon(2);
	}
	else
	{
		var color = "#0000ff";
		if(this.loadingMarker && this.currentRequest)this.SetCenterIcon(1);
	}
	
	this.polyline.SetColor(color);	
}


MMRoute.prototype.PolylineClick = function(point){	
	GEvent.trigger(this, "click", this, point);	
}

MMRoute.prototype.PolylineRightClick = function(pxPoint){	
	GEvent.trigger(this, "rightclick", pxPoint, this);
}


MMRoute.prototype.PolylineMouseOver = function(pxPoint){	
	GEvent.trigger(this, "mouseover", this, pxPoint);	
}


MMRoute.prototype.PolylineMouseMove = function(pxPoint){	
	GEvent.trigger(this, "mousemove", this, pxPoint);
}

MMRoute.prototype.PolylineMouseOut = function(){
	GEvent.trigger(this, "mouseout", this);
}

MMRoute.prototype.SetWeight = function(weight){
	if(this.polyline)this.polyline.SetWeight(weight);
}

/**
 * Returns the length (in meters) of the polyline along the surface of a spherical Earth.
 */
MMRoute.prototype.getLength = function()
{
	if(this.polyline) return this.polyline.getLength();
	else return 0.0;
}


/**
 * Returns the number of vertices in the polyline.
 */
MMRoute.prototype.getVertexCount = function()
{
	if(this.polyline) return this.polyline.getVertexCount();
	else return 0;
}


/**
 * Returns the bounds for this Route
 */
MMRoute.prototype.getBounds = function()
{
	if(this.polyline) return this.polyline.getBounds();
	else return new GLatLngBounds();
}


MMRoute.prototype.SetCenterIcon = function(type){

	if(!this.map) return false;
	
	if(this.loadingMarker)this.map.removeOverlay(this.loadingMarker);
	this.loadingMarker = null;
	var start = this.startWaypoint.GetPoint();
	var end = this.endWaypoint.GetPoint();
	var center = new GLatLng((start.lat()*1 + end.lat()*1) / 2.0, (start.lng()*1 + end.lng()*1)/2.0);	
	
	switch(type)
	{
		case 0: // No Path
			this.loadingMarker = new GMarker(center, { icon: MMRoute.nopathIcon, clickable:true});
			this.map.addOverlay(this.loadingMarker);
			this.loadingMarker.bindInfoWindowHtml('<div style="font-size:10pt;font-family:arial, sans-serif;">Kein Pfad gefunden</div>');
			break;
			
		case 3: // Routingservice nicht verfügbar
			this.loadingMarker = new GMarker(center, { icon: MMRoute.nopathIcon, clickable:true});
			this.map.addOverlay(this.loadingMarker);			
			this.loadingMarker.bindInfoWindowHtml('<div style="font-size:10pt;font-family:arial, sans-serif;">Der Routingservice ist f&#252;r diese Region nicht verf&#252;gbar.<br />Sind Sie beim ADFC-Tourenportal angemeldet?</div>');
			break;
		
		case 1: // Loading (blue)		
			this.loadingMarker = new GMarker(center, { icon: MMRoute.loadingBlueIcon });
			this.map.addOverlay(this.loadingMarker);
			break;
		
		
		case 2: // Loading (red)
			this.loadingMarker = new GMarker(center, { icon: MMRoute.loadingRedIcon });
			this.map.addOverlay(this.loadingMarker);
			break;		
	}	
}

/**
 * Returns the ID of the server-site cached PolylineResponse
 */
MMRoute.prototype.getId = function()
{
	return this.responseId;
}
