#include "Salamander.h"
#include "Mat2.h"

namespace Salamander
{

Mat2::Mat2()
{
	a_ = 1.0f; b_ = 0.0f;
	c_ = 0.0f; d_ = 1.0f;
	x_ = 0.0f; y_ = 0.0f;
	s_ = 1.0f; t_ = 1.0f;
}

Mat2::Mat2(double rotation)
{
	double c = cos(rotation);
	double s = sin(rotation);

	// a basic rotation matrix
	a_ = c; b_ = -s;
	c_ = s; d_ =  c;

	// translation
	x_ = 0.0f;
	y_ = 0.0f;

	// scale
	s_ = 1.0f;
	t_ = 1.0f;
}

Mat2::Mat2(const Vec2& translation, const Vec2& scale, double rotation)
{
	setTranslation(translation);
	setScale(scale);
	setRotation(rotation);
}

Mat2::Mat2(double a, double b, double c, double d, double x, double y, double s, double t)
{
	a_ = a;
	b_ = b;
	c_ = c;
	d_ = d;

	x_ = x;
	y_ = y;

	s_ = s;
	t_ = t;
}

Mat2::~Mat2()
{

}

void Mat2::setTranslation(const Vec2& translation)
{
	// homogeneous co-ordinates
	x_ = translation.x_;
	y_ = translation.y_;
}

Vec2 Mat2::getTranslation() const
{
	return Vec2(x_, y_);
}

void Mat2::setScale(const Vec2& scale)
{
	s_ = scale.x_;
	t_ = scale.y_;
}

Vec2 Mat2::getScale() const
{
	return Vec2(s_, t_);
}

void Mat2::setRotation(double rotation)
{
	double c = cos(rotation);
	double s = sin(rotation);

	// a basic rotation matrix
	a_ = c; b_ = -s;
	c_ = s; d_ =  c;
}

double Mat2::getRotation() const
{
	return atan2(c_, a_);
}

Mat2 Mat2::transpose() const
{
	return Mat2(a_, c_, 
			    b_, d_,	
			    -y_, -x_,
				t_, s_);
}

Mat2 Mat2::inverse() const
{
	double d = determinant();
	if(d == 0.0f || s_ == 0.0f || t_ == 0.0f) return Mat2();

	d = 1.0f / d;
	return Mat2(
		 d * d_, -d * b_,
		-d * c_,  d * a_,		
		-x_, -y_,
		1.0f / s_, 1.0f / t_);
}

double Mat2::determinant() const
{
	return a_ * d_ - b_ * c_;
}

Mat2 Mat2::operator + (const Mat2& rhs)
{
	return Mat2(a_ + rhs.a_, b_ + rhs.b_, 
			    c_ + rhs.c_, d_ + rhs.d_,		
			    x_ + rhs.x_, y_ + rhs.y_,
				s_ + rhs.s_, t_ + rhs.t_);
}

Mat2 Mat2::operator * (const Mat2& rhs)
{
	return Mat2(
		a_ * rhs.a_ + b_ * rhs.c_, a_ * rhs.b_ + b_ * rhs.d_,
		c_ * rhs.a_ + d_ * rhs.c_, c_ * rhs.b_ + d_ * rhs.d_,
		x_ + rhs.x_, y_ + rhs.y_,
		s_ * rhs.s_, t_ * rhs.t_);
}

Vec2 Mat2::operator * (const Vec2& rhs)
{
	return Vec2((a_ * rhs.x_ + b_ * rhs.y_) * s_ + x_,
			    (c_ * rhs.x_ + d_ * rhs.y_) * t_ + y_);
}

}
