
#include <string>
#include "Matrix3.h"

template <>
Matrix3f Matrix3f::Identity(
	1, 0, 0,
	0, 1, 0,
	0, 0, 1
);

template<typename T>
inline Matrix3<T>::Matrix3()
{
	v[0] = T(0); v[3] = T(0); v[6] = T(0);
	v[1] = T(0); v[4] = T(0); v[7] = T(0);
	v[2] = T(0); v[5] = T(0); v[8] = T(0);
}

template<typename T>
inline Matrix3<T>::Matrix3(T a, T b, T c, T d, T e, T f, T g, T h, T i)
{
	v[0] = a; v[3] = d; v[6] = g;
	v[1] = b; v[4] = e; v[7] = h;
	v[2] = c; v[5] = f; v[8] = i;
}

template<typename T>
inline Matrix3<T>::Matrix3(T *a)
{
	v[0] = a[0]; v[3] = a[3]; v[6] = a[6];
	v[1] = a[1]; v[4] = a[4]; v[7] = a[7];
	v[2] = a[2]; v[5] = a[5]; v[8] = a[8];
}

template<typename T>
inline Matrix3<T>& Matrix3<T>::operator=(const Matrix3<T>& mat)
{
	if (this != &mat) {
		v[0] = mat.v[0]; v[3] = mat.v[3]; v[6] = mat.v[6];
		v[1] = mat.v[1]; v[4] = mat.v[4]; v[7] = mat.v[7];
		v[2] = mat.v[2]; v[5] = mat.v[5]; v[8] = mat.v[8];
	}
	return *this;
}

template<typename T>
inline bool Matrix3<T>::operator==(const Matrix3<T>& mat) const
{
	for(int i = 0; i < 9; i++) {

		if (v[i] != mat.v[i]) {
			return false;
		}
	}
	return true;
}

template<typename T>
inline bool Matrix3<T>::operator!=(const Matrix3<T>& mat) const
{
	return !(*this == mat);
}

template<typename T>
inline Matrix3<T> Matrix3<T>::operator*(const Matrix3<T>& mat) const
{
	Matrix3<T> c;
	for(int i = 0; i < 3; i++) {
		for(int j = 0; j < 3; j++) {
			T s = T(0);
			for(int k = 0; k < 3; k++) {
				s += m[k][i] * mat.m[j][k];
			}
			c.m[j][i] = s;
		}
	}
	return c;
}

template<typename T>
inline Matrix3<T> Matrix3<T>::operator*=(const Matrix3<T>& mat)
{
	*this = *this * mat;
	return *this;
}

template<typename T>
float Matrix3<T>::det() const
{
	float det = 0.0f;

	det += v[0] * v[4] * v[8];
	det += v[3] * v[7] * v[2];
	det += v[6] * v[1] * v[5];

	det -= v[6] * v[4] * v[2];
	det -= v[3] * v[1] * v[8];
	det -= v[0] * v[7] * v[5];

	return det;
}

template<typename T>
Matrix3<T> Matrix3<T>::transpose() const
{
	Matrix3<T> t;

	t.v[0] = v[0]; t.v[3] = v[1]; t.v[6] = v[2]; 
	t.v[1] = v[3]; t.v[4] = v[4]; t.v[7] = v[5]; 
	t.v[2] = v[6]; t.v[5] = v[7]; t.v[8] = v[8]; 

	return t;
}

template <typename T>
inline std::ostream& operator<<(std::ostream &s, const Matrix3<T>& mat)
{
	return s << mat.v[0] << " " << mat.v[3] << " " << mat.v[6] << std::endl
		 << mat.v[1] << " " << mat.v[4] << " " << mat.v[7] << std::endl
		 << mat.v[2] << " " << mat.v[5] << " " << mat.v[8] << std::endl;
}
