#pragma once

namespace FDK
{
	value class Quaternion;
	value class Matrix;
	value class Vector3;
	value class Vector4;

	[System::Serializable]
	[System::Runtime::InteropServices::StructLayout( System::Runtime::InteropServices::LayoutKind::Sequential, Pack = 4 )]
	public value class Vector2 : System::IEquatable<Vector2>
	{
	public:
		float X;
		float Y;

		property float default[int]
		{
			float get( int index );
			void set( int index, float value );
		}

		static property Vector2 Zero
		{
			Vector2 get() 
			{
				return Vector2( 0, 0 );
			}
		}
		static property Vector2 UnitX
		{
			Vector2 get()
			{
				return Vector2( 1, 0 );
			}
		}
		static property Vector2 UnitY
		{
			Vector2 get()
			{
				return Vector2( 0, 1 );
			}
		}
		static property int SizeInBytes
		{
			int get()
			{
				return Marshal::SizeOf (Vector2::typeid );
			}
		}

		Vector2( float value );
		Vector2( float x, float y );

		static Vector2 Add( Vector2 left, Vector2 right );
		static void Add( Vector2% left, Vector2% right, [Out] Vector2% result );
		static Vector2 Subtract( Vector2 left, Vector2 right );
		static void Subtract( Vector2% left, Vector2% right, [Out] Vector2% result );
		static Vector2 Multiply( Vector2 value, float scale );
		static void Multiply( Vector2% value, float scale, [Out] Vector2% result );
		static Vector2 Modulate( Vector2 left, Vector2 right );
		static void Modulate( Vector2% left, Vector2% right, [Out] Vector2% result );
		static Vector2 Divide( Vector2 value, float scale );
		static void Divide( Vector2% value, float scale, [Out] Vector2% result );
		static Vector2 Negate( Vector2 value );
		static void Negate( Vector2% value, [Out] Vector2% result );
		static Vector2 Barycentric( Vector2 value1, Vector2 value2, Vector2 value3, float amount1, float amount2 );
		static void Barycentric( Vector2% value1, Vector2% value2, Vector2% value3, float amount1, float amount2, [Out] Vector2% result );
		static Vector2 CatmullRom( Vector2 value1, Vector2 value2, Vector2 value3, Vector2 value4, float amount );
		static void CatmullRom( Vector2% value1, Vector2% value2, Vector2% value3, Vector2% value4, float amount, [Out] Vector2% result );
		static Vector2 Clamp( Vector2 value, Vector2 min, Vector2 max );
		static void Clamp( Vector2% value, Vector2% min, Vector2% max, [Out] Vector2% result );
		static Vector2 Hermite( Vector2 value1, Vector2 tangent1, Vector2 value2, Vector2 tangent2, float amount );
		static void Hermite( Vector2% value1, Vector2% tangent1, Vector2% value2, Vector2% tangent2, float amount, [Out] Vector2% result );
		static Vector2 Lerp( Vector2 start, Vector2 end, float factor );
		static void Lerp( Vector2% start, Vector2% end, float factor, [Out] Vector2% result );
		static Vector2 SmoothStep( Vector2 start, Vector2 end, float amount );
		static void SmoothStep( Vector2% start, Vector2% end, float amount, [Out] Vector2% result );
		static float Distance( Vector2 value1, Vector2 value2 );
		static float DistanceSquared( Vector2 value1, Vector2 value2 );
		static float Dot( Vector2 left, Vector2 right );
		static Vector2 Normalize( Vector2 vector );
		static void Normalize( Vector2% vector, [Out] Vector2% result );
		static Vector4 Transform( Vector2 vector, Matrix transform );
		static void Transform( Vector2% vector, Matrix% transform, [Out] Vector4% result );
		static array<Vector4>^ Transform( array<Vector2>^ vectors, Matrix% transform );
		static Vector4 Transform( Vector2 value, Quaternion rotation );
		static void Transform( Vector2% value, Quaternion% rotation, [Out] Vector4% result );
		static array<Vector4>^ Transform( array<Vector2>^ vectors, Quaternion% rotation );
		static Vector2 TransformCoordinate( Vector2 coord, Matrix transform );
		static void TransformCoordinate( Vector2% coord, Matrix% transform, [Out] Vector2% result );
		static array<Vector2>^ TransformCoordinate( array<Vector2>^ coords, Matrix% transform );
		static Vector2 TransformNormal( Vector2 normal, Matrix transform );
		static void TransformNormal( Vector2% normal, Matrix% transform, [Out] Vector2% result );
		static array<Vector2>^ TransformNormal( array<Vector2>^ normals, Matrix% transform );
		static Vector2 Minimize( Vector2 left, Vector2 right );
		static void Minimize( Vector2% left, Vector2% right, [Out] Vector2% result );
		static Vector2 Maximize( Vector2 left, Vector2 right );
		static void Maximize( Vector2% left, Vector2% right, [Out] Vector2% result );
		static Vector2 operator + ( Vector2 left, Vector2 right );
		static Vector2 operator - ( Vector2 left, Vector2 right );
		static Vector2 operator - ( Vector2 value );
		static Vector2 operator * ( Vector2 value, float scale );
		static Vector2 operator * ( float scale, Vector2 vec );
		static Vector2 operator / ( Vector2 value, float scale );
		static bool operator == ( Vector2 left, Vector2 right );
		static bool operator != ( Vector2 left, Vector2 right );
		static bool Equals( Vector2% value1, Vector2% value2 );

		virtual String^ ToString() override;
		virtual int GetHashCode() override;
		virtual bool Equals( Object^ value ) override;
		virtual bool Equals( Vector2 value );

		float Length();
		float LengthSquared();
		void Normalize();
	};
}