#pragma once

#include "volumeshop.h"
#include "Vector.h"
#include <algorithm>

class DeformationVoxel
{
public:

	DeformationVoxel()
	{
		Set(Vector(0.0f,0.0f,0.0f));
	};

	DeformationVoxel(const Vector & vecVector)
	{
		Set(vecVector);
	};

	DeformationVoxel(const DeformationVoxel & traOther)
	{
		m_vecVector = traOther.m_vecVector;
	};

	~DeformationVoxel()
	{
	};

	void Set(const Vector & vecVector)
	{
		m_vecVector = vecVector;
	};

	const Vector & Get() const
	{
		return m_vecVector;
	};

	const bool operator==(const DeformationVoxel &traOther) const
	{
		return (Get() == traOther.Get());
	};

	const bool operator!=(const DeformationVoxel &traOther) const
	{
		return !(*this == traOther);
	};

	const bool operator>(const DeformationVoxel &traOther) const
	{
		const Vector & vecA = Get();
		const Vector & vecB = traOther.Get();
		return (vecA.GetX() > vecB.GetX() || vecA.GetY() > vecB.GetY() || vecA.GetZ() > vecB.GetZ());
	};

	const bool operator>=(const DeformationVoxel &traOther) const
	{
		const Vector & vecA = Get();
		const Vector & vecB = traOther.Get();
		return (vecA.GetX() >= vecB.GetX() || vecA.GetY() >= vecB.GetY() || vecA.GetZ() >= vecB.GetZ());
	};

	const bool operator<(const DeformationVoxel &traOther) const
	{
		const Vector & vecA = Get();
		const Vector & vecB = traOther.Get();
		return (vecA.GetX() < vecB.GetX() || vecA.GetY() < vecB.GetY() || vecA.GetZ() < vecB.GetZ());
	};

	const bool operator<=(const DeformationVoxel &traOther) const
	{
		const Vector & vecA = Get();
		const Vector & vecB = traOther.Get();
		return (vecA.GetX() <= vecB.GetX() || vecA.GetY() <= vecB.GetY() || vecA.GetZ() <= vecB.GetZ());
	};

	const DeformationVoxel & operator+=(const DeformationVoxel & traOther)
	{
		m_vecVector += traOther.m_vecVector;
		return *this;
	};

	const DeformationVoxel & operator-=(const DeformationVoxel & traOther)
	{
		m_vecVector -= traOther.m_vecVector;
		return *this;
	};

	const DeformationVoxel & operator*=(const float & fOther)
	{
		m_vecVector *= fOther;
		return *this;
	};

	const DeformationVoxel & operator/=(const float & fOther)
	{
		m_vecVector /= fOther;
		return *this;
	};

	const DeformationVoxel operator+(const DeformationVoxel & traOther) const
	{
		DeformationVoxel rotNew = *this;
		rotNew += traOther;
		return rotNew;
	};

	const DeformationVoxel operator-(const DeformationVoxel & traOther) const
	{
		DeformationVoxel rotNew = *this;
		rotNew -= traOther;
		return rotNew;
	};

	const DeformationVoxel operator*(const float & fOther) const
	{
		DeformationVoxel rotNew = *this;
		rotNew *= fOther;
		return rotNew;
	};

	const DeformationVoxel operator/(const float & fOther) const
	{
		DeformationVoxel rotNew = *this;
		rotNew /= fOther;
		return rotNew;
	};

private:
	Vector m_vecVector;
//	float m_fMagnitue;
};

template <>
inline GLenum glInternalFormat<DeformationVoxel>()
{/*
	if (GLEW_ARB_texture_float)
		return GL_RGB16F_ARB;
	else
*/
		return GL_RGB;
};

template <>
inline GLenum glFormat<DeformationVoxel>()
{
	return GL_RGB;
};

template <>
inline GLenum glType<DeformationVoxel>()
{
	return GL_FLOAT;
};


template<>
inline const DeformationVoxel & std::min<DeformationVoxel>(const DeformationVoxel &traA, const DeformationVoxel &traB)
{
	// Evil hack: incredibly ugly and unsafe
	static DeformationVoxel traVoxelA;
	traVoxelA = DeformationVoxel(Vector(std::min(traA.Get().GetX(),traB.Get().GetX()),std::min(traA.Get().GetY(),traB.Get().GetY()),std::min(traA.Get().GetZ(),traB.Get().GetZ())));
	return traVoxelA;
};

template<>
inline const DeformationVoxel & std::max<DeformationVoxel>(const DeformationVoxel &traA, const DeformationVoxel &traB)
{
	// Evil hack: incredibly ugly and unsafe
	static DeformationVoxel traVoxelB;
	traVoxelB = DeformationVoxel(Vector(std::max(traA.Get().GetX(),traB.Get().GetX()),std::max(traA.Get().GetY(),traB.Get().GetY()),std::max(traA.Get().GetZ(),traB.Get().GetZ())));
	return traVoxelB;
};