#include <utility>
#include <vector>
#//#include "Dense"
#include "Eigen/Dense"
#include <unsupported/Eigen/Splines>
#pragma once

namespace ZZ_MATH
{
	template<typename T>
	void MinHeapify(T*arry, int size, int element)
	{
		int lchild = element * 2 + 1, rchild = lchild + 1;
		while (rchild < size)
		{
			if (arry[element] <= arry[lchild] && arry[element] <= arry[rchild])
			{
				return;
			}
			if (arry[lchild] <= arry[rchild])
			{
				std::swap(arry[element], arry[lchild]);
				element = lchild;
			}
			else
			{
				std::swap(arry[element], arry[rchild]);
				element = rchild;
			}
			lchild = element * 2 + 1;
			rchild = lchild + 1;
		}
		if (lchild < size&&arry[lchild] < arry[element])
		{
			std::swap(arry[lchild], arry[element]);
		}
		return;
	}

	template<typename T>
	void MaxHeapify(T*arry, int size, int element)
	{
		int lchild = element * 2 + 1, rchild = lchild + 1;
		while (rchild < size)
		{
			if (arry[element] >= arry[lchild] && arry[element] >= arry[rchild])
			{
				return;
			}
			if (arry[lchild] >= arry[rchild])
			{
				std::swap(arry[element], arry[lchild]);
				element = lchild;
			}
			else
			{
				std::swap(arry[element], arry[rchild]);
				element = rchild;
			}
			lchild = element * 2 + 1;
			rchild = lchild + 1;
		}
		if (lchild<size&&arry[lchild]>arry[element])
		{
			std::swap(arry[lchild], arry[element]);
		}
		return;
	}


	template<typename T>
	void HeapSort(T*arry, int size)
	{
		int i;
		for (i = size - 1; i >= 0; i--)
		{
			MinHeapify(arry, size, i);
		}
		while (size > 0)
		{
			std::swap(arry[size - 1], arry[0]);

			size--;
			MinHeapify(arry, size, 0);
		}
		return;
	}

	namespace PolyFit
	{
		void   Eigen_Polyfit(const std::vector<double> &xv, const std::vector<double> &yv, std::vector<double> &coeff, int order);
		double Eigen_Polyeval(std::vector<double> coeffs, double x);
	};

	namespace SplineFit
	{
		using namespace Eigen;
		VectorXd Eigen_Normalize(const VectorXd &x);
		void   Test(std::vector<double> const &x_vec, std::vector<double> const &y_vec);// do not call


		class SplineInterpolation 
		{
		public:
			SplineInterpolation(Eigen::VectorXd const &x_vec,Eigen::VectorXd const &y_vec);
			double operator()(double x) const;
		
		private:
			double x_min;
			double x_max;

			double scaled_value(double x) const;
			Eigen::RowVectorXd scaled_values(Eigen::VectorXd const &x_vec) const;
	
			Eigen::Spline<double, 1> spline_;
		};
	};
};



