//alert("enter waypoint");
var hSpeedTime = 20;	// time span for horizontal speed average [s]
var vSpeedTime = 20;	// time span for vertical speed average [s]
var kSuspiciousSpeed = 200;	// speed is so high that will probably never exeeded [m/s]
var END_OF_TRIP = -9999;
var BEGIN_OF_TRIP = -9998;
var REACHED_THE_END = new Date(END_OF_TRIP);
var REACHED_THE_BEGINNING = new Date(BEGIN_OF_TRIP);

//--------------------------------------------------------------------------
// class waypoint
//..........................................................................
function _waypoint ( data, preceding ) {
	var clone = getObjectClass ( data ) == '_waypoint' ;
	this.time		= new Date((clone ? data.time.getTime() : data.t * 1000));
	this.lat		= (clone ? data.lat : data.lt);		// latitude [deg]
	this.lon		= (clone ? data.lon : data.ln);		// longitude [deg]
	this.altitude	= (clone ? data.altitude : data.a);	// altitude [m]
	this.noise		= (clone ? data.noise : data.n);	// noise level [0-999]
	this.gLatLon;		// google coordinate
	this.preceding;		// preceding waypoint
	this.leading;		// leading waypoint
	this.timeElapsed;	// time from preceding waypoint [s]
	this.course;		// course from preceding waypoint [m]
	this.distance;		// distance from preceding waypoint [m]
	this.hSpeed;		// horizontal speed [m/s]
	this.vSpeed;		// vertical speed [m/s]

	//------------ public ------------------------------------------------------

	//--------------------------------------------------------------------------
	//	altitudeString	
	//	speedString	
	//..........................................................................
	//	data strings in local dimensions
	this.altitudeString = function ( ) {
		var alt = this.altitude * dimension.altitude.factor;
		return alt.toFixed(0);
	}
	this.speedString = function ( ) {
		var spd = this.hSpeed * dimension.hSpeed.factor;
		return spd.toFixed(spd < 9.95 ? 1 : 0);
	}
	this.varioString = function ( ) {
		var spd = this.vSpeed * dimension.vSpeed.factor;
		var sign = ( spd > 0 ? "+" : "" );
		return sign + spd.toFixed(spd < 9.95 ? 1 : 0);
	}
	//--------------------------------------------------------------------------
	// tempWaypoint	
	//..........................................................................
	//	creates a temporary waypoint between here and the leading waypoint
	//	parameters
	//		amount	how much into the next leg. Value returned by this.portion
	this.tempWaypoint = function ( amount, atTime ) {
		temp = new _waypoint ( this, this );
		temp.moveBy ( amount, atTime );
		return temp;
	}
	//--------------------------------------------------------------------------
	// portion	
	//..........................................................................
	//	returns the portion between 2 waypoints 0.0-1.0
	//	-1.0 --> this is the last waypoint
	//	>1.0 --> atTime is beyond the leading waypoint
	this.portion = function ( atTime, show ) {
		var exact = true;
		if ( this.leading == false )
			return END_OF_TRIP;
		if ( this.preceding == false && atTime <= this.time )
			return BEGIN_OF_TRIP;
		var t1 = this.leading.time.difference(this.time, exact);
		var t2 = atTime.difference(this.time, exact);
		return t2 / t1;
	}
	//--------------------------------------------------------------------------
	// moveBy	
	//..........................................................................
	//	moves this along the path by amount (0.0 - 1.0)
	this.moveBy = function ( amount, atTime ) {
		if ( amount > 0 ) {
			this.lat += (this.leading.lat - this.lat) * amount;
			this.lon += (this.leading.lon - this.lon) * amount;
			this.altitude += (this.leading.altitude - this.altitude) * amount;
			this.time = atTime;
		}
		else if (amount == END_OF_TRIP)
			this.time = atTime;
		else
			this.time = this.preceding.time;
		this.setup ( this.preceding, this.leading );
	}
	//--------------------------------------------------------------------------
	// destruct	
	//..........................................................................
	//	deletes a trip
	this.destruct = function ( ) {
		this.remove();
		delete this.gLatLon;
		delete this.time;
	}	
	//--------------------------------------------------------------------------
	// insertIntoPath	
	//..........................................................................
	//	used to insert a waypoint into the path
	this.insertIntoPath = function ( path ) {
		if ( path )
			path.insertVertex ( 0, this.gLatLon );
	}
	//--------------------------------------------------------------------------
	// overTheEnd	
	//..........................................................................
	//	returns the number of second over the end of the trip or false
	this.overTheEnd = function ( debug) {
		if ( this.leading || this.timeElapsed < 300 )
			return false;
		return this.timeElapsed;
	}
	//--------------------------------------------------------------------------
	// remove	
	//..........................................................................
	//	remove this from the linked list
	this.remove = function ( ) {
		if ( this.preceding != false )
			this.preceding.leading = this.leading;
		if ( this.leading != false )
			this.leading.setup ( this.preceding, this.leading.leading );
	}
	//--------------------------------------------------------------------------
	// suspicious	
	//..........................................................................
	//	checks if this location could be inaccurate
	//	returns 0 if unsuspicious
	//			1 if from leg is suspicious
	//			2 if to leg is suspicious
	//			3 if from and to legs are suspicious
	this.suspicious = function ( speedLimit ) {
		speedLimit = ( speedLimit ? speedLimit : kSuspiciousSpeed );
		var result = ( this.hSpeed > speedLimit ? 1 : 0 );
		if ( this.leading != false )
			result += ( this.leading.hSpeed > speedLimit ? 1 : 0 );
		return result;
	}

	//------------ private -----------------------------------------------------

	//--------------------------------------------------------------------------
	// avarageSpeed	
	//..........................................................................
	//	parameters:	timeToGo	time to go [s]
	//				acuDist		accumulated distance [m]
	//				acuTime		accumulated time [s]
	this.avarageSpeed = function ( timeToGo, acuDist, acuTime ) {
		if ( (timeToGo <= 0) || this.preceding == false )
			return (acuTime == 0 ? 0 : acuDist / acuTime);
		acuDist += this.distance;
		acuTime += this.timeElapsed;
		timeToGo -= this.timeElapsed;
		return this.preceding.avarageSpeed(timeToGo,acuDist,acuTime);
	}
	//--------------------------------------------------------------------------
	// vario	
	//..........................................................................
	//	parameters:	timeToGo	time to go [s]
	//				startAlt	starting altitude [m]
	//				acuTime		accumulated time [s]
	this.vario = function ( timeToGo, startAlt, acuTime) {
		if ( (timeToGo <= 0) || this.preceding == false )
			return (acuTime == 0 ? 0 : (startAlt - this.altitude) / acuTime);
		acuTime += this.timeElapsed;
		timeToGo -= this.timeElapsed;
		return this.preceding.vario(timeToGo,startAlt,acuTime);
	}
	//--------------------------------------------------------------------------
	// vectorTo	
	//..........................................................................
	this.vectorTo = function ( latlon ) {
		return latlon.vectorFrom ( this.gLatLon, this.course );
	}
	//--------------------------------------------------------------------------
	// setup	
	//..........................................................................
	//	is called on construct or removal of the preceding
	this.setup = function ( preceding, leading ) {
		this.preceding	= ( preceding ? preceding : false );
		this.leading	= ( leading ? leading : false );
		this.gLatLon	= new GLatLng ( this.lat, this.lon );
		var no = this.preceding == false;
		if (!(no || clone)) this.preceding.leading = this;
		this.timeElapsed = (no ? 0 : this.time.difference(this.preceding.time));
		var vector = (no ? new PolarVector() : this.preceding.vectorTo(this.gLatLon));
		this.course		= vector.direction;
		this.distance	= vector.distance;
		delete vector;
		this.hSpeed = this.avarageSpeed(hSpeedTime,0,0);
		this.vSpeed = this.vario(vSpeedTime,this.altitude,0);
	}
	this.setup( preceding, ( clone ? data.leading : false ) );
}
//alert("exit waypoint");
