//--------------------------------------------------------------------------------------------------------------
// Map Proxy - use a single interface to access map api's from multiple vendors.
// Requires: imMap.js, imPlayer.js, imUtils.js, imAjax.js, imXml.js
// Author: Ben Siroshton
// Date: 01/22/2010
//--------------------------------------------------------------------------------------------------------------

/**
* @class
* @constructor
*/
function imMapTrack(){
	this.videoUrl = null;
	this.gpsTrack = null;
	this.mapIcon = null;
};


/**
* @class
* @constructor
*/
function imPlayerMapTrack(player, map){
	
	this.player = player;
	this.map = map;
	this.trackArea = null;
	this.tracks = new Array();
	this.timeIcon = null;

	this.currentTrack = null;
	this.timerRunning = false;

	this.addTrack = function(videoUrl, xmlUrl, mapIcon){
	
		if( this.tracks[xmlUrl]!=null ){
			// track already loaded
			return;
		}

		var Track = new imMapTrack();
		
		Track.videoUrl = videoUrl;
		Track.mapIcon = mapIcon;
		Track.gpsTrack = new imGpsTrack();
		Track.gpsTrack.load(xmlUrl, this);

		this.tracks[xmlUrl] = Track;
	
		return Track;
	
	};
	
	this.gpsTrackLoaded = function(sender){

		imLogger.instance().log("loaded gps track: " + sender.xmlUrl);

		var Track = this.tracks[sender.xmlUrl];

		// Add Map Route
		var Points = new imPointArray();

		var Cycle = 0;
		
		for (var Key in Track.gpsTrack.list){
			var P = Track.gpsTrack.list[Key];
			var LngLat = new imLatLong(P.latitude, P.longitude);
			Points.add(LngLat);
			
			if( this.trackArea==null ){
				this.trackArea = new imLatLongRect(LngLat, LngLat);
			}else{
				this.trackArea.expand(LngLat);	
			}
			Cycle++;
		}

		if( Points.list.length>0 ){

			// Add Route To Map
			if( Points.list.length>1 ){
				imLogger.instance().log("adding route to map. " + Points.list.length + " points.");
				this.map.addLine(Points);
			}else{
				imLogger.instance().log("not enough points loaded to draw a route.");
			}

			// Add Icon To Map
			var player = this.player;
			var me = this;

			if( Track.mapIcon==null ){
				Track.mapIcon = new imMapIcon(Points.list[0], null, 0, 0);
			}else{
				Track.mapIcon.latLng = Points.list[0];
			}

			Track.mapIcon.onClick = function(){
				imLogger.instance().log("loading video: " + Track.videoUrl);

				if( me.timeIcon.map==null ){
					me.timeIcon.latLng = Track.mapIcon.latLng;
					me.map.addIcon(me.timeIcon);					
				}else{
					me.timeIcon.moveToTop();
				}

				me.currentTrack = Track;
				player.loadVideo(Track.videoUrl);

				if( !me.timerRunning ){
					me.timerRunning = true;
					imTimer.instance().setTimeout(me, 1000);
				}
			}

			this.map.addIcon(Track.mapIcon);

			this.onTrackAdded(Track);

		}else{
			imLogger.instance().log("gps stream has zero points, not adding to map.");
			this.onTrackLoadFailed(sender.xmlUrl);
		}	
	
	}

	this.panToTrack = function(track){
		if( track==null || track.gpsTrack==null || track.gpsTrack.list==null || track.gpsTrack.list.length==0 ){
			return;
		}
		
		var P = track.gpsTrack.list[0];
		imLogger.instance().log("panning to " + P.toString());
		
		this.map.panToLatLng(P.latitude, P.longitude);
	}

	this.gpsTrackFailed = function(sender){
		imLogger.instance().log("track load failed");
		this.onTrackLoadFailed(sender.xmlUrl);
	}	
	
	this.onTrackAdded = function(track){		
	}
	
	this.onTrackLoadFailed = function(xmlUrl){
	}

	this.onTimer = function(){

		if( this.timeIcon==null || this.currentTrack==null )
		{
			this.timerRunning = false;
			return;	
		}

		var time = this.player.getMediaTime();
		
		var P = this.getLocationAtTime(time);
		if( P==null ){
			this.timerRunning = false;
			return;
		}

		var LatLng = new imLatLong(P.latitude, P.longitude);
		this.timeIcon.setLocation(LatLng);			
		
		this.timerRunning = true;
		imTimer.instance().setTimeout(this,1000);
	}
		
	this.getLocationAtTime = function(time)
	{
		if( this.currentTrack==null || this.currentTrack.gpsTrack==null || this.currentTrack.gpsTrack.list==null ){
			return null;
		}
		
		var List = this.currentTrack.gpsTrack.list;
		
		for(var Index=0;Index<List.length-1;Index++){
			var P1 = List[Index];
			var P2 = List[Index+1];
			
			if( time>=P1.time && time<P2.time ){

				var IntTime = (time-P1.time) / Math.max(0.00001,P2.time-P1.time);				
				
				var RP = new imGpsPoint();
				RP.time = imUtils.lerp(P1.time, P2.time, IntTime);
				RP.longitude = imUtils.lerp(P1.longitude, P2.longitude, IntTime);
				RP.latitude = imUtils.lerp(P1.latitude, P2.latitude, IntTime);

				return RP;	

			}else if(Index==List.length-2){
				return P2;	
			}
			
		}
		
		return null;
		
	}
		
	this.load = function(videoUrl, xmlUrl){
		
		this.drawTrack(xmlUrl);
		
		player.loadVideo(videoUrl);
		
	};
	

};


/**
* @class
* @constructor
*/
function imGpsPoint(){
	this.time = 0;
	this.longitude = 0;
	this.latitude = 0;
	
	this.toString = function(){
		return "time: " + this.time + " longitude: " + this.longitude + " latitude: " + this.latitude;
	}
};


/**
* @class
* @constructor
*/
function imGpsTrack(){
	
	this.xmlUrl = null;
	
	this.list = null;
	this.errorStr = null;
	this.hasErrors = false;	

	this.beforeRequest = function(data){
	};

	this.ggaToDecimal = function(ggaLat){
		// <ggaLongitude> -72201740 </ggaLongitude>
		// <ggaLatitude> 18326001 </ggaLatitude>
		
		var S = new String(ggaLat);
		if( S.length<6 ){
			return null;
		}

		var Degrees = S.substring(0, S.length-6);
		var Part = S.substring(Degrees.length);
		var Minutes = Part.substring(0, Part.length-4);
		var Seconds = Part.substring(Minutes.length);	

		Degrees	= new Number(Degrees);
		var Inv = Degrees<0;
		
		if( Inv ){
			Degrees = -Degrees;
		}
		
		Minutes = new Number(Minutes);
		Seconds = new Number(Seconds)/10000*60;
		
		var Result = Degrees + (Minutes * 1/60) + (Seconds * 1/60 * 1/60);

		if( Inv ){
			Result = -Result;	
		}

		//alert("S: " + S + ", Degrees: " + Degrees + ", part: " + Part + ", Minutes: " + Minutes + ", Seconds: " + Seconds + ", Result: " + Result);
		
		return Result;		
	};

	this.onSuccess = function(data){

		var Doc = imXml.parseXML(data);
		if( Doc==null ){
			this.errorStr = "unable to parse result.";
			this.hasErrors = true;			
			this.onFinished();
			return;
		}
		
		var Count = 0;		
		var Node = imXml.findNodeRecursive(Doc, "megaframe_sensordata");
		
		var BaseTime = null;
		
		while(Node!=null){

			if( Count==0 ){
				this.list = new Array();
			}
			
			var LastPoint = null;
			var SysTime = imUtils.trim(imXml.findNodeValue(Node, "sysFrameTime"));
			
			if( BaseTime==null && SysTime!=null ){
				BaseTime = SysTime;
			}
			
			var DataRec = imXml.findNodeRecursive(Node, "sensor_record");
			
			if( SysTime!=null && DataRec!=null ){
							
				var Time = SysTime - BaseTime;
				var Lng = this.ggaToDecimal(imUtils.trim(imXml.findNodeValue(DataRec,"ggaLongitude")));
				var Lat = this.ggaToDecimal(imUtils.trim(imXml.findNodeValue(DataRec,"ggaLatitude")));
				
				if( Time!=null && Lng!=null && Lat!=null ){
					
					var Point = new imGpsPoint();					
					Point.time = Time;
					Point.longitude = Lng;
					Point.latitude = Lat;

					if( LastPoint==null || LastPoint.longitude!=Point.longitude || LatPoint.latitude!=Point.latitude ){
						this.list[Count] = Point;
						LastPoint = Point;
						Count++;
					}
					
				}
			}
			
			Node = Node.nextSibling;
		}	

		this.errorStr = null;
		this.hasErrors = false;
		if( this.target!=null ){
			this.target.gpsTrackLoaded(this);
		}else{
			this.gpsTrackLoaded(this);
		}

	};
	
	this.onFailure = function(data){
		this.errorStr = "request failed.";
		this.hasErrors = true;
		if( this.target!=null ){
			this.target.gpsTrackFailed(this);
		}else{
			this.gpsTrackFailed(this);
		}
	};

	this.gpsTrackLoaded = function(sender){
	}

	this.gpsTrackFailed = function(sender){
	}
	
	this.load = function(xmlUrl, target){

		this.xmlUrl = xmlUrl;
		this.target = target;
		
		var Requester = new imAjaxRequester(this,"GET",null);
		Requester.makeRequest(xmlUrl);	
	}	
	
};
