#pragma once

#include "valMatrix.h"
#include "valVector3.h"

namespace FDK
{
	[System::Serializable]
	[System::Runtime::InteropServices::StructLayout( System::Runtime::InteropServices::LayoutKind::Sequential )]
	public value class Quaternion : System::IEquatable<Quaternion>
	{
	public:
		float X;
		float Y;
		float Z;
		float W;

		Quaternion( float x, float y, float z, float w );
		Quaternion( Vector3 value, float w );
		
		[System::ComponentModel::Browsable(false)]
		property bool IsIdentity
		{
			bool get();
		}
		property Vector3 Axis
		{
			Vector3 get();
		}
		property float Angle 
		{
			float get();
		}

		float Length();
		float LengthSquared();
		void Normalize();
		void Conjugate();
		void Invert();
		
		static property Quaternion Identity
		{
			Quaternion get();
		}
		
		static Quaternion Add( Quaternion left, Quaternion right );
		static void Add( Quaternion% left, Quaternion% right, [Out] Quaternion% result );
		static Quaternion Barycentric( Quaternion source1, Quaternion source2, Quaternion source3, float weight1, float weight2 );
		static void Barycentric( Quaternion% source1, Quaternion% source2, Quaternion% source3, float weight1, float weight2, [Out] Quaternion% result );
		static Quaternion Conjugate( Quaternion quaternion );
		static void Conjugate( Quaternion% quaternion, [Out] Quaternion% result );
		static Quaternion Divide( Quaternion left, Quaternion right );
		static void Divide( Quaternion% left, Quaternion% right, [Out] Quaternion% result );
		static float Dot( Quaternion left, Quaternion right );
		static Quaternion Exponential( Quaternion quaternion );
		static void Exponential( Quaternion% quaternion, [Out] Quaternion% result );
		static Quaternion Invert( Quaternion quaternion );
		static void Invert( Quaternion% quaternion, [Out] Quaternion% result );
		static Quaternion Lerp( Quaternion start, Quaternion end, float amount );
		static void Lerp( Quaternion% start, Quaternion% end, float amount, [Out] Quaternion% result );
		static Quaternion Logarithm( Quaternion quaternion );
		static void Logarithm( Quaternion% quaternion, [Out] Quaternion% result );
		static Quaternion Multiply( Quaternion left, Quaternion right );
		static void Multiply( Quaternion% left, Quaternion% right, [Out] Quaternion% result );
		static Quaternion Multiply( Quaternion quaternion, float scale );
		static void Multiply( Quaternion% quaternion, float scale, [Out] Quaternion% result );
		static Quaternion Negate( Quaternion quaternion );
		static void Negate( Quaternion% quaternion, [Out] Quaternion% result );
		static Quaternion Normalize( Quaternion quaternion );
		static void Normalize( Quaternion% quaternion, [Out] Quaternion% result );
		static Quaternion RotationAxis( Vector3 axis, float angle );
		static void RotationAxis( Vector3% axis, float angle, [Out] Quaternion% result );
		static Quaternion RotationMatrix( Matrix matrix );
		static void RotationMatrix( Matrix% matrix, [Out] Quaternion% result );
		static Quaternion RotationYawPitchRoll( float yaw, float pitch, float roll );
		static void RotationYawPitchRoll( float yaw, float pitch, float roll, [Out] Quaternion% result );
		static Quaternion Slerp( Quaternion start, Quaternion end, float amount );
		static void Slerp( Quaternion% start, Quaternion% end, float amount, [Out] Quaternion% result );
		static Quaternion Squad( Quaternion source1, Quaternion source2, Quaternion source3, Quaternion source4, float amount );
		static void Squad( Quaternion% source1, Quaternion% source2, Quaternion% source3, Quaternion% source4, float amount, [Out] Quaternion% result );
		static array<Quaternion>^ SquadSetup( Quaternion source1, Quaternion source2, Quaternion source3, Quaternion source4 );
		static Quaternion Subtract( Quaternion left, Quaternion right );
		static void Subtract( Quaternion% left, Quaternion% right, [Out] Quaternion% result );
		static Quaternion operator * ( Quaternion left, Quaternion right );
		static Quaternion operator * ( Quaternion quaternion, float scale );
		static Quaternion operator * ( float scale, Quaternion quaternion );
		static Quaternion operator / ( Quaternion left, float right );
		static Quaternion operator + ( Quaternion left, Quaternion right );
		static Quaternion operator - ( Quaternion left, Quaternion right );
		static Quaternion operator - ( Quaternion quaternion );
		static bool operator == ( Quaternion left, Quaternion right );
		static bool operator != ( Quaternion left, Quaternion right );
		static bool Equals( Quaternion% value1, Quaternion% value2 );

		virtual System::String^ ToString() override;
		virtual int GetHashCode() override;
		virtual bool Equals( System::Object^ value ) override;
		virtual bool Equals( Quaternion value );
	};
}
