//	TwoFloats.h - Simple struct containing two floats.
//  ----------------------------------------------------------------------------
//	This file is part of 'NiallsAVLib', base code for any kind of audiovisual
//	apps.
//	Copyright (C) 2012  Niall Moody
//
//	This program is free software; you can redistribute it and/or modify
//	it under the terms of the GNU General Public License as published by
//	the Free Software Foundation; either version 2 of the License, or
//	(at your option) any later version.
//
//	This program is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//	GNU General Public License for more details.
//
//	You should have received a copy of the GNU General Public License
//	along with this program; if not, write to the Free Software
//	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//	----------------------------------------------------------------------------

#ifndef TWOFLOATS_H_
#define TWOFLOATS_H_

#include <cmath>

///	Simple struct containing two floats.
struct TwoFloats
{
	float x;
	float y;

	///	Default constructor.
	TwoFloats()
	{
		x = y = 0.0f;
	};

	///	Constructor (scalar).
	TwoFloats(float val)
	{
		x = y = val;
	};

	///	Constructor.
	TwoFloats(float xVal, float yVal)
	{
		x = xVal;
		y = yVal;
	};

	///	Int constructor.
	TwoFloats(int xVal, int yVal)
	{
		x = static_cast<float>(xVal);
		y = static_cast<float>(yVal);
	};

	///	Copy Constructor.
	TwoFloats(const TwoFloats& op2)
	{
		x = op2.x;
		y = op2.y;
	};

	///	Assignment operator.
	TwoFloats& operator=(const TwoFloats& op2)
	{
		x = op2.x;
		y = op2.y;
		return *this;
	};

	///	Assignment operator (scalar).
	TwoFloats& operator=(float val)
	{
		x = val;
		y = val;
		return *this;
	};

	///	Addition operator.
	TwoFloats operator+(const TwoFloats& op2) const
	{
		TwoFloats retval;

		retval.x = x + op2.x;
		retval.y = y + op2.y;

		return retval;
	};

	///	Addition operator (scalar).
	TwoFloats operator+(float val) const
	{
		TwoFloats retval;

		retval.x = x + val;
		retval.y = y + val;

		return retval;
	};

	///	Subtraction operator.
	TwoFloats operator-(const TwoFloats& op2) const
	{
		TwoFloats retval;

		retval.x = x - op2.x;
		retval.y = y - op2.y;

		return retval;
	};

	///	Subtraction operator (scalar).
	TwoFloats operator-(float val) const
	{
		TwoFloats retval;

		retval.x = x - val;
		retval.y = y - val;

		return retval;
	};

	///	Multiplication operator.
	TwoFloats operator*(const TwoFloats& op2) const
	{
		TwoFloats retval;

		retval.x = x * op2.x;
		retval.y = y * op2.y;

		return retval;
	};

	///	Multiplication operator (scalar).
	TwoFloats operator*(float val) const
	{
		TwoFloats retval;

		retval.x = x * val;
		retval.y = y * val;

		return retval;
	};

	///	Division operator (x1/x2, y1/y2).
	TwoFloats operator/(const TwoFloats& op2) const
	{
		TwoFloats retval;

		retval.x = x / op2.x;
		retval.y = y / op2.y;

		return retval;
	};

	///	Division operator (scalar: x1/val, y1/val).
	TwoFloats operator/(float val) const
	{
		TwoFloats retval;

		retval.x = x / val;
		retval.y = y / val;

		return retval;
	};

	///	Addition assignment operator.
	TwoFloats& operator+=(const TwoFloats& op2)
	{
		x += op2.x;
		y += op2.y;

		return *this;
	};

	///	Addition assignment operator (scalar).
	TwoFloats& operator+=(float val)
	{
		x += val;
		y += val;

		return *this;
	};

	///	Subtraction assignment operator.
	TwoFloats& operator-=(const TwoFloats& op2)
	{
		x -= op2.x;
		y -= op2.y;

		return *this;
	};

	///	Subtraction assignment operator (scalar).
	TwoFloats& operator-=(float val)
	{
		x -= val;
		y -= val;

		return *this;
	};

	///	Multiplication assignment operator.
	TwoFloats& operator*=(const TwoFloats& op2)
	{
		x *= op2.x;
		y *= op2.y;

		return *this;
	};

	///	Multiplication assignment operator (scalar).
	TwoFloats& operator*=(float val)
	{
		x *= val;
		y *= val;

		return *this;
	};

	///	Division assignment operator.
	TwoFloats& operator/=(const TwoFloats& op2)
	{
		x /= op2.x;
		y /= op2.y;

		return *this;
	};

	///	Division assignment operator (scalar).
	TwoFloats& operator/=(float val)
	{
		x /= val;
		y /= val;

		return *this;
	};

	///	Equality operator.
	bool operator==(const TwoFloats& op2) const
	{
		return (x==op2.x)&&(y==op2.y);
	};

	///	Equality operator (scalar).
	bool operator==(float val) const
	{
		return (x==val)&&(y==val);
	};

	///	Inequality operator.
	bool operator!=(const TwoFloats& op2) const
	{
		return (x!=op2.x)||(y!=op2.y);
	};

	///	Inequality operator (scalar).
	bool operator!=(float val) const
	{
		return (x!=val)||(y!=val);
	};

	///	Less than operator.
	bool operator<(const TwoFloats& op2) const
	{
		return (x < op2.x)&&(y < op2.y);
	};

	///	Less than operator (scalar).
	bool operator<(float val) const
	{
		return (x < val)&&(y < val);
	};

	///	Greater than operator.
	bool operator>(const TwoFloats& op2) const
	{
		return (x > op2.x)&&(y > op2.y);
	};

	///	Greater than operator (scalar).
	bool operator>(float val) const
	{
		return (x > val)&&(y > val);
	};

	///	Less than or equal operator.
	bool operator<=(const TwoFloats& op2) const
	{
		return (x <= op2.x)&&(y <= op2.y);
	};

	///	Less than or equal operator (scalar).
	bool operator<=(float val) const
	{
		return (x <= val)&&(y <= val);
	};

	///	Greater than or equal operator.
	bool operator>=(const TwoFloats& op2) const
	{
		return (x >= op2.x)&&(y >= op2.y);
	};

	///	Greater than or equal operator (scalar).
	bool operator>=(float val) const
	{
		return (x >= val)&&(y >= val);
	};

	///	Returns an absolute version of the TwoFloats.
	TwoFloats abs() const
	{
		TwoFloats retval(fabsf(x), fabsf(y));

		return retval;
	};

	///	Returns the distance between two TwoFloats.
	float getDistance(const TwoFloats& op2) const
	{
		float tempX = op2.x - x;
		float tempY = op2.y - y;

		return sqrtf((tempX*tempX) + (tempY*tempY));
	};
	///	Faster than getDistance().
	float getDistanceSquared(const TwoFloats& op2) const
	{
		float tempX = op2.x - x;
		float tempY = op2.y - y;

		return (tempX*tempX) + (tempY*tempY);
	};
	///	Returns the magnitude of the TwoFloats.
	float getMagnitude() const
	{
		return sqrtf((x*x) + (y*y));
	};

	///	Returns the angle between two TwoFloats.
	float getAngle(const TwoFloats& op2) const
	{
		return atan2f((op2.x-x), (op2.y-y));
	};
	///	Returns the angle of this TwoFloats and the origin.
	float getAngle() const
	{
		return atan2f(x, y);
	};

	///	Returns a TwoFloats vector perpendicular to this one.
	TwoFloats perpendicular() const
	{
		TwoFloats retval(y, -x);

		return retval;
	};

	///	Returns a normalised version of the TwoFloats.
	TwoFloats normal() const
	{
		float tempf;
		TwoFloats retval;

		tempf = sqrtf((x*x) + (y*y));
		if(tempf > 0.0f)
		{
			retval.x = x/tempf;
			retval.y = y/tempf;
		}

		return retval;
	};

	///	Returns the dot product of this TwoFloats and another.
	float dotProduct(const TwoFloats& other) const
	{
		return -x*other.x - y*other.y;
	};

	///	Returns the cross product of this TwoFloats and another.
	float crossProduct(const TwoFloats& other) const
	{
		return (x*other.y) - (y*other.x);
	};

	///	Mirrors this TwoFloats around another TwoFloats & returns the result.
	TwoFloats mirror(const TwoFloats& mirrorVector) const
	{
		float dot;
		TwoFloats retval;

		dot = dotProduct(mirrorVector);
		retval.x = x + 2.0f*mirrorVector.x*dot;
		retval.y = y + 2.0f*mirrorVector.y*dot;

		return retval;
	};

	///	Projects this TwoFloats onto another.
	TwoFloats project(const TwoFloats& other) const
	{
		TwoFloats retval;
		TwoFloats dir(other.normal());

		retval = other + (dir * (this->dotProduct(dir)));

		return retval;
	};
	///	Projects this TwoFloats onto a direction (unit) vector, returns the scalar result.
	float projectDir(const TwoFloats& dir) const
	{
		return this->dotProduct(dir);
	};

	///	Returns true if the point is within the bounds of the passed-in rectangle.
	bool isWithin(const TwoFloats& topLeft, const TwoFloats& size) const
	{
		bool retval = false;

		if((*this > topLeft) && (*this < (topLeft+size)))
			retval = true;

		return retval;
	};

	friend TwoFloats operator+(float op1, const TwoFloats& op2);
	friend TwoFloats operator-(float op1, const TwoFloats& op2);
	friend TwoFloats operator*(float op1, const TwoFloats& op2);
	friend TwoFloats operator/(float op1, const TwoFloats& op2);
};

#endif
