#ifndef WIDGETS_GRAPHPLOTTER_BEZIERINTERPOLATOR_H
#define WIDGETS_GRAPHPLOTTER_BEZIERINTERPOLATOR_H

#include "Interpolator.h"


// -- TDE NAMESPACE ----------------------------------------------------

namespace TDE {

// -- Widgets NAMESPACE ------------------------------------------------

namespace Widgets {

namespace Plot {


class CubicBezier
{
public:
	static const int N_POINTS = 4;

	// http://en.wikipedia.org/wiki/B%C3%A9zier_curve
	// http://www.tinaja.com/glib/cubemath.pdf
	CubicBezier(const Point P[N_POINTS], const InterpolatorParameters& params);

	boost::optional<double> compute(double x) const;

	double operator()(double x) const 	{ boost::optional<double> bo_y = compute(x); return bo_y ? *bo_y : -1.0; }

	Point p[N_POINTS];
	double A, B, C, D, E, F, G, H;
	double dx;

private:
	void _setup();
	InterpolatorParameters m_parameters;
};

class Bezier
{
public:
	// http://en.wikipedia.org/wiki/B%C3%A9zier_curve
	// http://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm
	// http://www.tinaja.com/glib/cubemath.pdf
	Bezier(const std::vector<Point>& P);
	Bezier(const std::vector<Point>& P, const InterpolatorParameters& params);

	Point evaluate(double t) const;
	boost::optional<double> compute(double x) const;

	double operator()(double x) const 	{ boost::optional<double> bo_y = compute(x); return bo_y ? *bo_y : -1.0; }

	double value_x(double t) const			{ Point p = evaluate(t); return p.x(); }
	double value_y(double t) const			{ Point p = evaluate(t); return p.y(); }

	double derivative_x(double t) const;
	double derivative_y(double t) const;


	std::vector<Point> points;

private:
	Point _getDeCasteljau(int j, int i, double t) const;

	InterpolatorParameters m_parameters;
};

class CubicBezierInterpolator : public Interpolator
{
public:
	CubicBezierInterpolator(const std::vector<Point>& points);
	CubicBezierInterpolator(const std::vector<Point>& points, const InterpolatorParameters& params);
	virtual ~CubicBezierInterpolator();

	virtual double compute(double x) const;
	boost::optional<const CubicBezier&> findBezier(double x) const;

	std::vector<CubicBezier> m_beziers;

private:
	void _setup(const std::vector<Point>& points);
};

class BezierInterpolator : public Interpolator
{
public:
	BezierInterpolator(const std::vector<Point>& points);
	BezierInterpolator(const std::vector<Point>& points, const InterpolatorParameters& params);
	virtual ~BezierInterpolator();

	virtual double compute(double x) const;

	Bezier m_bezier;

private:
};


} /* end of namespace Plot */

} /* end of namespace Widgets */

} /* end of namespace TDE */

#endif /* WIDGETS_GRAPHPLOTTER_BEZIERINTERPOLATOR_H */
