/** SGX

The   sss    gggg x   x   
     s      g      x x    Engine
      sss   g  gg   x
         s  g   g  x x          Copyright 1995-2009.
     ssss    gggg x   x         Steven Goodwin. All Rights Reserved.
    
This version has been released under the GNU Public License v2.0.

Please see the license files for details.

File: sgx/src/sgx/graphics/curves/pathfollower.cpp

*/

#include "sgx/core/core.hpp"
#include "sgx/graphics/graphics.hpp"
#include "sgx/graphics/curves/path.hpp"
#include "sgx/graphics/curves/pathfollower.hpp"

CSplineFollower::CSplineFollower(const CSpline &spline)
{
	m_pSpline = &spline;
}

// This method should set a pointer to the varying position which the path follower 
// class must track (e.g. you would pass in a pointer to the entity's position member). 
// It should also calculate which path subpoint the position is currently nearest, and 
// store a pointer to that subpoint. It may also want to store a copy of the current 
// value of the position.

void CSplineFollower::trackPosition(sgxVector3* pPos)
{
	// If I understand the question correctly, the position passed in
	// is not controlled by the spline. But rather, we have to report
	// the nearest spline position to the vector pointed at by the 
	// pPos pointer.
	m_pTrackingPos = pPos;

	// No clues presently, so search the entire spline
	m_pSpline->getClosestSegment(m_NearestSubPoint, pPos);
	m_fDistance2Spline = m_pSpline->getDistanceSquared(m_NearestSubPoint, pPos);

	// To enable differences
	m_vPreviousPos = *pPos;
}

void CSplineFollower::update()
{
	if (*m_pTrackingPos == m_vPreviousPos.x) {		
		// No significant movement has occured
		return;
	}
	
	// Check nearest neighbours
	CBezierHandle other;
	float dist;

	// ...previous
	if (m_pSpline->getPrevSegment(other, m_NearestSubPoint)) {
		dist = m_pSpline->getDistanceSquared(other, m_pTrackingPos);
		if (dist < m_fDistance2Spline) {
			m_fDistance2Spline = dist;
			m_NearestSubPoint = other;
		}
	}

	// ...next
	if (m_pSpline->getNextSegment(other, m_NearestSubPoint)) {
		dist = m_pSpline->getDistanceSquared(other, m_pTrackingPos);
		if (dist < m_fDistance2Spline) {
			m_fDistance2Spline = dist;
			m_NearestSubPoint = other;
		}
	}

	// NOTE: If the object is likely to be travelling fast we start
	// spreading out our search by searching one back, one forward,
	// two back, two forward, etc.
	m_vPreviousPos = *m_pTrackingPos;
}
