#pragma once
#include <mof/base/mofdef.hpp>
#include <mof/math/threshold.hpp>
#include <boost/operators.hpp>
#include <ostream>
#include <cmath>


namespace mof
{
namespace math
{
	/**
	 * @brief 同次座標ベクトルテンプレートクラス
	 * @note  このテンプレートから直接特殊化することは想定していない．
	 * あくまでvectorxを実装するための補助テンプレートである．
	 * このクラスは不変クラスである．
	 * @tparam Dim     ベクトルの次元(要素数)
	 * @tparam Derived 特殊化されたテンプレートの派生クラス(vectorx)の型
	 */
	template <size_t Dim, typename Derived>
	class basic_vector 
		: boost::addable< Derived 
		, boost::addable2< Derived, float
		, boost::subtractable< Derived 
		, boost::subtractable2< Derived, float
		, boost::multipliable2< Derived, float
		, boost::dividable2< Derived, float
		, boost::equality_comparable< Derived
		> > > > > > > 
	{
	protected:
		float components_[Dim];///< 要素の配列
	public:
		// コンストラクタ，デストラクタはデフォルトのものを使う
		// 代入演算子，コピーコンストラクタはデフォルトのものを使う
//{{{ swap
		void swap(Derived& rhs) throw()
		{
			for (size_t i = 0; i < Dim; ++i) std::swap(rhs.components_[i], components_[i]);
		}
//}}}
//{{{ operator +=
		Derived& operator+=(const Derived& rhs)
		{
			for (size_t i = 0; i < Dim; ++i) components_[i] += rhs.components_[i];
			return *reinterpret_cast<Derived*>(this);//thisがDerived型であることは保証されている．
		}
		
		Derived& operator+=(float rhs) 
		{
			for (size_t i = 0; i < Dim; ++i) components_[i] += rhs;
			return *reinterpret_cast<Derived*>(this);//thisがDerived型であることは保証されている．
		}
		
		friend Derived operator+(float rhs1, Derived& rhs2)
		{
			Derived retval;
			for (size_t i = 0; i < Dim; ++i) retval.components_[i] = rhs1 + rhs2.components_[i];
			return retval;
		}
//}}}
//{{{ operator -=
		Derived& operator-=(const Derived& rhs)
		{
			for (size_t i = 0; i < Dim; ++i) components_[i] -= rhs.components_[i];
			return *reinterpret_cast<Derived*>(this);//thisがDerived型であることは保証されている．
		}
		
		Derived& operator-=(float rhs)
		{
			for (size_t i = 0; i < Dim; ++i) components_[i] -= rhs;
			return *reinterpret_cast<Derived*>(this);//thisがDerived型であることは保証されている．
		}

		friend Derived operator-(float rhs1, Derived& rhs2)
		{
			Derived retval;
			for (size_t i = 0; i < Dim; ++i) retval.components_[i] = rhs1 - rhs2.components_[i];
			return retval;
		}
//}}}
//{{{ operator *=
		Derived& operator*=(float rhs)
		{
			for (size_t i = 0; i < Dim; ++i) components_[i] *= rhs;
			return *reinterpret_cast<Derived*>(this);//thisがDerived型であることは保証されている．
		}
//}}}
//{{{ operator /=
		Derived& operator/=(float rhs)
		{
			for (size_t i = 0; i < Dim; ++i) components_[i] /= rhs;
			return *reinterpret_cast<Derived*>(this);//thisがDerived型であることは保証されている．
		}
//}}}
//{{{ operator ==
		bool operator==(const Derived& rhs) const
		{
			for (size_t i = 0; i < Dim; ++i) {
				if (std::abs(components_[i] - rhs.components_[i]) > MOF_ERROR_THRESHOLD) return false;
			}
			return true;
		}
//}}}
//{{{ operator []
		/**
		 * @note Dim+1番目の要素は常に1
		 * @param[in] index 添字
		 */
		float operator[](size_t index) const
		{
			if (index < Dim) return components_[index];
			else if (index == Dim) return 1;
			// TODO exception
			return 0;
		}
//}}}
//{{{ operator <<
		/**
		 * @brief デバッグ出力用ストリーム演算子
		 * @param[in] stream 出力ストリーム
		 * @param[in] rhs    出力対象となるベクトルオブジェクト
		 * @return 引数で与えられた出力ストリーム
		 */
		friend std::ostream& operator<<
		(
			std::ostream& stream,
			const Derived& rhs
		)
		{
			for (size_t i = 0; i < Dim; ++i)
			{
				if (i != 0) stream << ", ";
				stream << rhs.components_[i];
			}
			return stream;
		}
//}}}
	};
//{{{ swap
	template <size_t Dim, typename Derived>
	void swap(basic_vector<Dim, Derived>& a, basic_vector<Dim, Derived>& b) throw()
	{
		a.swap(b);
	}
//}}}

}// namespace math
}// namespace mof

