//-----------------------------------------------------------------------------------------------
// LineSegment2D.hpp
//
#pragma once
#ifndef include_LineSegment2D
#define include_LineSegment2D

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


/////////////////////////////////////////////////////////////////////////////////////////////////
class LineSegment2D
{
public:
	Vector2 m_startPosition;
	Vector2 m_displacement;

public:
	// Constructors
	~LineSegment2D() {}
	LineSegment2D() {}
	LineSegment2D( const LineSegment2D& copy );
	explicit LineSegment2D( const Vector2& startPosition, const Vector2& endPosition );
	explicit LineSegment2D( const char* asText );

	// Mutators
	void SetFromText( const char* asText );
	void SetStartPosition( const Vector2& startPosition );
	void SetEndPosition( const Vector2& endPosition );
	void SetDisplacement( const Vector2& displacement );
	void SetStartAndEndPositions( const Vector2& startPosition, const Vector2& endPosition );
	void SetStartAndDisplacement( const Vector2& startPosition, const Vector2& displacement );
	float SetUnitLengthAndYawDegrees( float yawDegrees );
	float SetUnitLengthAndYawRadians( float yawRadians );
	float SetLengthAndYawDegrees( float newLength, float yawDegrees );
	float SetLengthAndYawRadians( float newLength, float yawRadians );
	float SetLength( float newLength );
	void ScaleLength( float lengthScale );
	void Rotate90Degrees();
	void RotateMinus90Degrees();
	void AdvanceStartAlongDisplacement( float numDisplacementsToAdvance );
	float Normalize();

	// Accessors
	const Vector2 GetEndPosition() const;
	void GetStartAndEnd( Vector2& out_startPosition, Vector2& out_endPosition );
	float CalcLengthSquared() const;
	float CalcLength() const;
	float CalcHeadingDegrees() const;
	float CalcHeadingRadians() const;
	bool IsPointBehind( const Vector2& point ) const;
	bool IsPointOnOrBehind( const Vector2& point ) const;
// 	const float* GetAsFloatArray() const { return &x; }
// 	float* GetAsFloatArray() { return &x; }

	// Operators
	const bool operator == ( const LineSegment2D& vectorToEqual ) const;
	const bool operator != ( const LineSegment2D& vectorToNotEqual ) const;
	const LineSegment2D operator + ( const Vector2& translation ) const;
	const LineSegment2D operator - ( const Vector2& antiTranslation ) const;
	const LineSegment2D operator * ( const float lengthScale ) const;
	const LineSegment2D operator / ( const float inverseLengthScale ) const;
	void operator *= ( const float lengthScale );
	void operator += ( const Vector2& translation );
	void operator -= ( const Vector2& antiTranslation );

	// External/friend functions and utilities
	friend const LineSegment2D Interpolate( const LineSegment2D& start, const LineSegment2D& end, float fractionTowardEnd );
	friend const LineSegment2D operator * ( const float lengthScale, const LineSegment2D& lineToScaleDisplacement );
//	friend const float DotProduct( const Vector2& a, const Vector2& b );
};


/////////////////////////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------------------------
inline LineSegment2D::LineSegment2D( const LineSegment2D& copy )
	: m_startPosition( copy.m_startPosition )
	, m_displacement( copy.m_displacement )
{
}


//-----------------------------------------------------------------------------------------------
inline LineSegment2D::LineSegment2D( const Vector2& startPosition, const Vector2& endPosition )
	: m_startPosition( startPosition )
	, m_displacement( endPosition - startPosition )
{
}


//-----------------------------------------------------------------------------------------------
inline void LineSegment2D::ScaleLength( float lengthScale )
{
	m_displacement *= lengthScale;
}


//-----------------------------------------------------------------------------------------------
inline void LineSegment2D::Rotate90Degrees()
{
	float oldX = m_displacement.x;
	m_displacement.x = -m_displacement.y;
	m_displacement.y = oldX;
}


//-----------------------------------------------------------------------------------------------
inline void LineSegment2D::RotateMinus90Degrees()
{
	float oldX = m_displacement.x;
	m_displacement.x = m_displacement.y;
	m_displacement.y = -oldX;
}


//-----------------------------------------------------------------------------------------------
inline void LineSegment2D::AdvanceStartAlongDisplacement( float numDisplacementsToAdvance )
{
	m_startPosition.x += numDisplacementsToAdvance * m_displacement.x;
	m_startPosition.y += numDisplacementsToAdvance * m_displacement.y;
}


//-----------------------------------------------------------------------------------------------
inline const Vector2 LineSegment2D::GetEndPosition() const
{
	return m_startPosition + m_displacement;
}


//-----------------------------------------------------------------------------------------------
inline bool LineSegment2D::IsPointBehind( const Vector2& point ) const
{
	Vector2 backSideDirection( -m_displacement.y, m_displacement.x ); // Not normalized
	Vector2 startToPoint = point - m_startPosition;
	float isBehind = DotProduct( backSideDirection, startToPoint );
	return isBehind > 0.f;
}


//-----------------------------------------------------------------------------------------------
inline bool LineSegment2D::IsPointOnOrBehind( const Vector2& point ) const
{
	Vector2 backSideDirection( -m_displacement.y, m_displacement.x ); // Not normalized
	Vector2 startToPoint = point - m_startPosition;
	float isBehind = DotProduct( backSideDirection, startToPoint );
	return isBehind >= 0.f;
}



#endif // include_Vector2
