#pragma once

//! @file Mix/Vector2.h
//! @brief 2次元浮動小数点ベクトルクラスインクルードファイル

namespace Mix
{
	class Point;

	//! @class Vector2
	//! @brief 2次元浮動小数点ベクトルクラス
	class _MIX_DLL_API Vector2
	{
	public:
		union
		{
			struct
			{
				Float32 x;	//!< X座標
				Float32 y;	//!< Y座標
			};

			struct
			{
				Float32 u;	//!< U座標
				Float32 v;	//!< V座標
			};

			Float32 data[2];	//!< データ
		};

	public:
		//! @brief コンストラクタ
		Vector2( void );
		//! @brief コンストラクタ
		//! @param[in] v コピー元ポイント
		Vector2( const Vector2& v );
		//! @brief コンストラクタ
		//! @param[in] p コピー元ポイント
		Vector2( const Point& p );
		//! @brief コンストラクタ
		//! @param[in] vx Ｘ座標
		//! @param[in] vy Ｙ座標
		Vector2( Float32 vx, Float32 vy );

		//! @brief 等価比較
		//! @param[in] v 比較するベクトル
		//! @return 値が等しい場合は True を返します
		Boolean operator == ( const Vector2& v ) const;
		//! @brief 等価比較
		//! @param[in] v 比較するベクトル
		//! @return 値が等しくない場合は True を返します
		Boolean operator != ( const Vector2& v ) const;

		//! @brief 代入
		//! @param[in] v 代入する値
		//! @return 代入したベクトルを返します
		Vector2& operator = ( const Vector2& v );
		//! @brief 代入
		//! @param[in] p 代入する値
		//! @return 代入したベクトルを返します
		Vector2& operator = ( const Point& p );
		//! @brief 代入加算
		//! @param[in] v 加算する値
		//! @return 代入加算したベクトルを返します
		Vector2& operator += ( const Vector2& v );
		//! @brief 代入減算
		//! @param[in] v 減算する値
		//! @return 代入減算したベクトルを返します
		Vector2& operator -= ( const Vector2& v );
		//! @brief 代入乗算
		//! @param[in] v 乗算する値
		//! @return 代入乗算したベクトルを返します
		Vector2& operator *= ( const Vector2& v );
		//! @brief 代入除算
		//! @param[in] v 除算する値
		//! @return 代入除算したベクトルを返します
		Vector2& operator /= ( const Vector2& v );

		//! @brief 加算
		//! @param[in] v 加算する値
		//! @return 加算したベクトルを返します
		Vector2 operator + ( const Vector2& v ) const;
		//! @brief 減算
		//! @param[in] v 減算する値
		//! @return 減算したベクトルを返します
		Vector2 operator - ( const Vector2& v ) const;
		//! @brief 乗算
		//! @param[in] v 乗算する値
		//! @return 乗算したベクトルを返します
		Vector2 operator * ( const Vector2& v ) const;
		//! @brief 除算
		//! @param[in] v 除算する値
		//! @return 除算したベクトルを返します
		Vector2 operator / ( const Vector2& v ) const;

		//! @brief 乗算
		//! @param[in] s 乗算する値
		//! @return 代入乗算したベクトルを返します
		Vector2& operator *= ( Float32 s );
		//! @brief 除算
		//! @param[in] s 除算する値
		//! @return 代入除算したベクトルを返します
		Vector2& operator /= ( Float32 s );

		//! @brief 乗算
		//! @param[in] s 乗算する値
		//! @return 乗算したベクトルを返します
		Vector2 operator * ( Float32 s ) const;
		//! @brief 除算
		//! @param[in] s 除算する値
		//! @return 除算したベクトルを返します
		Vector2 operator / ( Float32 s ) const;

		//! @brief 正の符号として扱います
		//! @return ベクトルを返します
		Vector2 operator +( void ) const;
		//! @brief 符号を反転します
		//! @return 符号を反転したベクトルを返します
		Vector2 operator -( void ) const;

		//! @brief 乗算
		//! @param[in] s 乗算先の値
		//! @param[in] v 乗算元の値
		//! @return 乗算されたベクトルを返します
		friend const Vector2 operator * ( Float32 s, const Vector2& v )
		{
			Vector2 tmp( v );
			tmp *= s;
			return tmp;
		}

		//! @brief 除算
		//! @param[in] s 除算先の値
		//! @param[in] v 除算元の値
		//! @return 除算されたベクトルを返します
		friend const Vector2 operator / ( Float32 s, const Vector2& v )
		{
			Vector2 tmp( v );
			tmp /= s;
			return tmp;
		}

		//! @brief ベクトルを設定します
		//! @param[in] vx Ｘ座標
		//! @param[in] vy Ｙ座標
		void Set( Float32 vx, Float32 vy );

		//! @brief 正規化します
		//! @return 正規化する前のベクトルの長さ
		Float32 Normalize( void );
		//! @brief 正規化したベクトルを取得します
		//! @param[out] pLength 正規化する前のベクトルの長さ 
		//! @return 正規化したベクトルを表す Mix::Vector2 クラスを返します
		Vector2 ToNormalize( Float32* pLength = NULL ) const;

		//! @brief 0.0f〜1.0f に飽和します
		void Saturate( void );
		//! @brief 0.0f〜1.0f に飽和したベクトルを取得します
		//! @return 飽和したベクトルを表す Mix::Vector2 クラスを返します
		Vector2 ToSaturate( void ) const;

		//! @brief 長さの2乗を取得します
		//! @return 長さの2乗を返します
		Float32 GetLengthSqr( void ) const;
		//! @brief 長さを取得します
		//! @return 長さを返します
		Float32 GetLength( void ) const;
		//! @brief 長さを取得します
		//! @return 長さを返します
		//! @note 平方根を求める際に Mix::SqrtF を使用しています
		Float32 GetLengthF( void ) const;

		//! @brief 二つのポイントの内積を返します
		//! @param[in] l ポイント1
		//! @param[in] r ポイント2
		//! @return 内積
		static Float32 Dot( const Vector2& l, const Vector2& r );

		//! @brief 乱数( 0.0f〜1.0f )を取得します
		//! @return 乱数を表す Mix::Vector2 クラスを返します
		static Vector2 Rand( void );
		//! @brief 乱数( 0.0f〜v )を取得します
		//! @param[in] v 乱数の範囲を表す x::Vector2 クラス
		//! @return 乱数を表す Mix::Vector2 クラスを返します
		static Vector2 Rand( const Vector2& v );
		//! @brief 乱数( v0〜v1 )を取得します
		//! @param[in] v0 乱数の開始値を表す Mix::Vector2 クラス
		//! @param[in] v1 乱数の終了値を表す Mix::Vector2 クラス
		//! @return 乱数を表す Mix::Vector2 クラスを返します
		static Vector2 Rand( const Vector2& v0, const Vector2& v1 );

		//! @brief 二つのベクトルの最小値を取得します
		//! @param[in] v0 比較するポイントを表す Mix::Vector2 クラス
		//! @param[in] v1 比較するポイントを表す Mix::Vector2 クラス
		//! @return ベクトルの最小値を表す Mix::Vector2 クラスを返します
		static Vector2 Min( const Vector2& v0, const Vector2& v1 );
		//! @brief 二つのベクトルの最大値を取得します
		//! @param[in] v0 比較するポイントを表す Mix::Vector2 クラス
		//! @param[in] v1 比較するポイントを表す Mix::Vector2 クラス
		//! @return ベクトルの最大値を表す Mix::Vector2 クラスを返します
		static Vector2 Max( const Vector2& v0, const Vector2& v1 );

		//! @brief 線形補間をします
		//! @param[in] vs 線形補間を開始するベクトルを表す Mix::Vector2 クラス
		//! @param[in] ve 線形補間を終了するベクトルを表す Mix::Vector2 クラス
		//! @param[in] t 補間係数( 0.0f〜1.0f )
		//! @return 線形補間されたベクトルを表す Mix::Vector2 クラスを返します
		static Vector2 Lerp( const Vector2& vs, const Vector2& ve, Float32 t );
		//! @brief 球面線形補間をします
		//! @param[in] vs 補間を開始するベクトルを表す Mix::Vector2 クラス
		//! @param[in] ve 補間を終了するベクトルを表す Mix::Vector2 クラス
		//! @param[in] t 補間係数( 0.0f〜1.0f )
		//! @return 補間されたベクトルを表す Mix::Vector2 を返します
		static Vector2 Slerp( const Vector2& vs, const Vector2& ve, Float32 t );

	public:
		//! @brief 初期値( 0.0f, 0.0f )を取得します
		//! @return 初期値を表す Mix::Vector2 クラスを返します
		static const Vector2& Zero( void )
		{
			static const Vector2 zero( 0.0f, 0.0f );
			return zero;
		}

		//! @brief X軸( 1.0f, 0.0f )を取得します
		//! @return X軸を表す Mix::Vector2 クラスを返します
		static const Vector2& XAxis( void )
		{
			static const Vector2 xAxis( 1.0f, 0.0f );
			return xAxis;
		}

		//! @brief Y軸( 0.0f, 1.0f )を取得します
		//! @return Y軸を表す Mix::Vector2 クラスを返します
		static const Vector2& YAxis( void )
		{
			static const Vector2 yAxis( 0.0f, 1.0f );
			return yAxis;
		}
	};
};
