//-----------------------------------------------------------------------------------------------
// Vector4.hpp
//
#pragma once
#ifndef include_Vector4
#define include_Vector4

//-----------------------------------------------------------------------------------------------
#include "Engine/Core/MathBase.hpp"


/////////////////////////////////////////////////////////////////////////////////////////////////
class Vector4
{
public:
	float x;
	float y;
	float z;
	float w;

public:
	static const Vector4 ZERO;
	static const Vector4 ONE;

public:
	// Constructors
	~Vector4() {}
	Vector4() {}
	Vector4( const Vector4& copy );
	explicit Vector4( float initialX, float initialY, float initialZ, float initialW );
	explicit Vector4( const char* asText );

	// Mutators
	void SetFromText( const char* asText );
	void SetXY( float newX, float newY, float newZ, float newW );

	// Accessors
	void GetXY( float& out_x, float& out_y ) const;
	void GetXYZ( float& out_x, float& out_y, float& out_z ) const;
	void GetXYZW( float& out_x, float& out_y, float& out_z, float& out_w ) const;
	const float* GetAsFloatArray() const { return &x; }
	float* GetAsFloatArray() { return &x; }

	// Operators
	const bool operator == ( const Vector4& vectorToEqual ) const;
	const bool operator != ( const Vector4& vectorToNotEqual ) const;
	const Vector4 operator + ( const Vector4& vectorToAdd ) const;
	const Vector4 operator - ( const Vector4& vectorToSubtract ) const;
	const Vector4 operator * ( const float scale ) const;
	void operator *= ( const float scale );
	void operator += ( const Vector4& vectorToAdd );

	// External/friend functions and utilities
	friend const float CalcDistanceSquared( const Vector4& a, const Vector4& b );
	friend const Vector4 Interpolate( const Vector4& start, const Vector4& end, float fractionTowardEnd );
	friend const Vector4 operator * ( const float scale, const Vector4& vectorToScale );
};


/////////////////////////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------------------------
inline Vector4::Vector4( const Vector4& copy )
	: x( copy.x )
	, y( copy.y )
	, z( copy.z )
	, w( copy.w )
{
}


//-----------------------------------------------------------------------------------------------
inline Vector4::Vector4( float initialX, float initialY, float initialZ, float initialW )
	: x( initialX )
	, y( initialY )
	, z( initialZ )
	, w( initialW )
{
}


//-----------------------------------------------------------------------------------------------
inline void Vector4::SetXY( float newX, float newY, float newZ, float newW )
{
	x = newX;
	y = newY;
	z = newZ;
	w = newW;
}



//-----------------------------------------------------------------------------------------------
inline const bool Vector4::operator == ( const Vector4& vectorToEqual ) const
{
	return (x == vectorToEqual.x) && (y == vectorToEqual.y) && (z == vectorToEqual.z) && (w == vectorToEqual.w);
}


//-----------------------------------------------------------------------------------------------
inline const bool Vector4::operator != ( const Vector4& vectorToNotEqual ) const
{
	return (x != vectorToNotEqual.x) || (y != vectorToNotEqual.y) || (z != vectorToNotEqual.z) || (w != vectorToNotEqual.w);
}


//-----------------------------------------------------------------------------------------------
inline const Vector4 Vector4::operator + ( const Vector4& vectorToAdd ) const
{
	return Vector4( x + vectorToAdd.x, y + vectorToAdd.y, z + vectorToAdd.z, w + vectorToAdd.w );
}


//-----------------------------------------------------------------------------------------------
inline const Vector4 Vector4::operator - ( const Vector4& vectorToSubtract ) const
{
	return Vector4( x - vectorToSubtract.x, y - vectorToSubtract.y, z - vectorToSubtract.z, w - vectorToSubtract.w );
}


//-----------------------------------------------------------------------------------------------
inline const Vector4 Vector4::operator * ( const float scale ) const
{
	return Vector4( x * scale, y * scale, z * scale, w * scale );
}


//-----------------------------------------------------------------------------------------------
inline void Vector4::operator *= ( const float scale )
{
	x *= scale;
	y *= scale;
	z *= scale;
	w *= scale;
}


//-----------------------------------------------------------------------------------------------
inline void Vector4::operator += ( const Vector4& vectorToAdd )
{
	x += vectorToAdd.x;
	y += vectorToAdd.y;
	z += vectorToAdd.z;
	w += vectorToAdd.w;
}


//-----------------------------------------------------------------------------------------------
inline const float CalcDistanceSquared( const Vector4& a, const Vector4& b )
{
	const float xDisp = a.x - b.x;
	const float yDisp = a.y - b.y;
	const float zDisp = a.z - b.z;
	const float wDisp = a.w - b.w;
	return( (xDisp * xDisp) + (yDisp * yDisp) + (zDisp * zDisp) + (wDisp * wDisp) );
}


//-----------------------------------------------------------------------------------------------
inline const Vector4 Interpolate( const Vector4& start, const Vector4& end, float fractionTowardEnd )
{
	return Vector4( start.x + fractionTowardEnd * (end.x - start.x),
		start.y + fractionTowardEnd * (end.y - start.y),
		start.z + fractionTowardEnd * (end.z - start.z),
		start.w + fractionTowardEnd * (end.w - start.w) );
}


//-----------------------------------------------------------------------------------------------
inline const Vector4 operator * ( const float scale, const Vector4& vectorToScale )
{
	return Vector4( scale * vectorToScale.x, scale * vectorToScale.y, scale * vectorToScale.z, scale * vectorToScale.w );
}


#endif // include_Vector4
