/**
 * \file Angle.h
 * \date 13.04.2003
 *
 * Interface for the Angle class
 */

#ifndef COMMON_WORLD_ANGLE_H
#define COMMON_WORLD_ANGLE_H

#include <math.h>

// Microsoft math.h does not define M_PI
#ifndef M_PI
#define M_PI		3.14159265358979323846f
#endif


/**
 * \class Angle
 * \author Maros Ivanco
 * \author Matus Horvath
 * \brief Angle in radians or degrees
 */
class Angle
{
public:
// Construction
	Angle() : deg(0) {}
	Angle(const Angle& a) : deg(a.deg) {}

// Member access
	float GetRad() const { return deg * M_PI / 180.f; }
	float GetDeg() const { return deg; }
	float GetAbsDeg() const { return fabsf(GetDeg()); }
	float GetAbsRad() const { return fabsf(GetRad()); }

// Operations
	inline Angle operator+(const Angle& angle) const;
	inline Angle operator-(const Angle& angle) const;
	inline Angle operator*(float f) const;
	inline Angle operator/(float f) const;

	Angle operator-() const { return Angle(-deg); }

	inline const Angle& operator=(const Angle& angle);
	inline const Angle& operator+=(const Angle& angle);
	inline const Angle& operator-=(const Angle& angle);
	inline const Angle& operator*=(float f);
	inline const Angle& operator/=(float f);
	
	bool operator<(const Angle& angle) const { return deg < angle.deg; }
	bool operator>(const Angle& angle) const { return deg > angle.deg; }
	bool operator<=(const Angle& angle) const { return deg <= angle.deg; }
	bool operator>=(const Angle& angle) const { return deg >= angle.deg; }

// Functions
	float Sin() const { return sinf(GetRad()); }
	float Cos() const { return cosf(GetRad()); }
	float Tan() const { return tanf(GetRad()); }
	float Cotg() const { return 1.f / tanf(GetRad()); }

	Angle Abs() const { return Angle(fabsf(deg)); }

protected:
	Angle(float d) : deg(d) { Normalize(); }

// Set value from float - use DegAngle or RadAngle
	void SetRad(float r) { deg = r * 180.f / M_PI; Normalize(); }
	void SetDeg(float d) { deg = d; Normalize(); }
	
// Normalize angle
	inline float Normalize();

private:
	// Angle value in radians
	float deg;

};

class DegAngle : public Angle
{
public:
// Construction
	DegAngle(float d) : Angle() { SetDeg(d); }

};

class RadAngle : public Angle
{
public:
// Construction
	RadAngle(float r) : Angle() { SetRad(r); }

};


Angle Angle::operator+(const Angle& angle) const
{
	return Angle(deg + angle.deg);
}

Angle Angle::operator-(const Angle& angle) const
{
	return Angle(deg - angle.deg);
}

Angle Angle::operator*(float f) const
{
	return Angle(deg * f);
}

Angle Angle::operator/(float f) const
{
	return Angle(deg / f);
}


const Angle& Angle::operator=(const Angle& angle)
{
	deg = angle.deg;
	return *this;
}

const Angle& Angle::operator+=(const Angle& angle)
{
	deg += angle.deg;
	Normalize();
	
	return *this;
}

const Angle& Angle::operator-=(const Angle& angle)
{
	deg -= angle.deg;
	Normalize();
	
	return *this;
}

const Angle& Angle::operator*=(float f)
{
	deg *= f;
	Normalize();
	
	return *this;
}

const Angle& Angle::operator/=(float f)
{
	deg /= f;
	Normalize();
	
	return *this;
}

float Angle::Normalize()
{
	while(deg < 180.f) deg += 360.f;
	while(deg > 180.f) deg -= 360.f;
	
	return deg;
}

#endif // COMMON_WORLD_ANGLE_H
