#ifndef __DIRECTIONALPREDICTOR_H__
#define __DIRECTIONALPREDICTOR_H__

#include "Predictor.h"

#pragma once

template<class T>
struct DirectionalPredictor : public IPredictor <T>
{
	DirectionalPredictor():m_values(0)
	{

	}

	virtual void Value(const T& x)
	{
		if (m_values == 1)
		{
			SVec3 dir = x - m_x;
			if (fabsf(dir.x) < 1e-6f && fabsf(dir.y) < 1e-6f)
				return;
		}
		m_y = m_x;
		m_x = x;
		m_values++;
	}

	virtual bool Predict(T& y)
	{
		if(m_values<2)
			return false;
		SVec3 dir = m_y - m_x;
		SVec3 pred = m_y + dir;
		if (fabsf(dir.x) < 1e-6f && fabsf(dir.y) < 1e-6f)
			dir = m_dir;
		SVec3 orig = y;
		// error in z is taken directly, error in x,y is calculated after rotation in the direction of dir
		orig = y;
		y.z = orig.z - pred.z;
		orig.z = pred.z = 0;
		SVec3 err = orig - pred;
		float cosAng = dir.x / dir.GetLength2D();
		float sinAng = dir.y / dir.GetLength2D();
		y.x = cosAng * err.x + sinAng * err.y;
		y.y = -sinAng * err.x + cosAng * err.y;
		m_dir = dir;
		return true;
	}

	T		m_x;
	T		m_y;
	SVec3 m_dir;
	size_t	m_values;
};

class CDirectionalPredictorCreator : public IPredictorCreator
{
public:
	IPredictor<SVec3>* Create()
	{
		return new DirectionalPredictor<SVec3>;
	}

private:
	CDirectionalPredictorCreator()
	{
		CPredictionHub::GetPredictorMap()["Directional"] = this;
	}

	static CDirectionalPredictorCreator s_singleton;
};

#endif /*__DIRECTIONALPREDICTOR_H__*/
