/****************************************************************************************

		Matrix22.h

		Copyright: (c) 2001 Eovia Corp. All rights reserved.

		Vector Math Library, Release 2.0,  1/1/96 
		Copyright 1996 Alec Miller, All Rights Reserved 

		Revision History

		when		who			what & why
		==========	==========	======================================================
		12/8/97		Ian			Removed iostream stuff altogether it's not compatible with
								Windows or MSL.
		5/15/96		Alec		new today - added vector math library to InfiniD project

*****************************************************************************************/

#ifndef H_MATRIX22
#define H_MATRIX22

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "Vector2.h"
#include "Matrix22Fwd.h"


/// \addtogroup Math
/// \{

/// Stores a 2 by 2 matrix and implements basic matrix operations.
/// The matrix coeficients are stored in the #value field

template<class T>
class TMatrix22Template : public TMCObject
{
	// this class cannot have virtual functions for C size compatability
	
	public:
		// constant definitions
		static const TMatrix22Template<T> kIdentity;
		static const TMatrix22Template<T> kZero;
	
	public :
		// initialization
		inline		  TMatrix22Template		(void);

		template<class U>
		inline		  TMatrix22Template		(const TMatrix22Template<U>& original)
		{ *this = original; }

		inline		  TMatrix22Template		(const T& m00, const T& m01, const T& m10, const T& m11);
		
		inline uint32 GetRowDimension		(void) const;
		inline uint32 GetColumnDimension	(void) const;
		
		// element access - since there is no [][] operator
		inline T	  operator()			(const uint32 row, const uint32 col) const;
		inline T&	  operator()			(const uint32 row, const uint32 col);
		
		// for [][] access only - second index unchecked
		inline const T*		operator[]		(const uint32 row) const;
		inline T*			operator[]		(const uint32 row);
		
		// row and column access
			   void		   GetRow			(const uint32 row, TVector2Template<T>& v) const;
			   void		   SetRow			(const uint32 row, const TVector2Template<T>& v);
		
			   void		   GetColumn		(const uint32 col, TVector2Template<T>& v) const;
			   void		   SetColumn		(const uint32 col, const TVector2Template<T>& v);

		// matrix conversion
			   void		   SetToTranspose	(void);
			   void		   SetToTransposeOf	(const TMatrix22Template<T>& source);
		
		// standard matrix properties		
		TMatrix22Template<T>	GetTranspose(void) const;
		TMatrix22Template<T>	GetAdjoint	() const;

			   T		   GetTrace			(void) const;
			   T		   GetDeterminant	(void) const;

			   void		   Multiply			(const TMatrix22Template<T>& m, const TMatrix22Template<T>& n);

		TMatrix22Template<T>	Inverse		(boolean* success) const;
		
		// fast matrix operations
		TMatrix22Template<T>&	operator*=	(const T& scalar);

		template<class U>
		TMatrix22Template<T>&	operator=	(const TMatrix22Template<U>& original)
		{
			if (this != (const TMatrix22Template<T>*)&original)
			{
				value[0][0] = (T)original(0,0); value[0][1] = (T)original(0,1); 
				value[1][0] = (T)original(1,0); value[1][1] = (T)original(1,1);
			}
			return *this;
		}

		// TMatrix22 operations
		TMatrix22Template<T>	operator+   (const TMatrix22Template<T>& r) const;
		TMatrix22Template<T>	operator-   (const TMatrix22Template<T>& r) const;
		TMatrix22Template<T>	operator*   (const TMatrix22Template<T>& r) const;
							
	protected:
		T value[2][2];		///< Stores the coeficients of the matrix in the form value[row][col]
};
/// \}

// [operator definitions] --------------------------------------------------------------//

// TMatrix22 operations
template<class T>
TMatrix22Template<T> operator* (const real32 s, const TMatrix22Template<T>& r)
{ return TMatrix22Template<T>(r) *= (T)s; }

template<class T>
TMatrix22Template<T> operator* (const real64& s, const TMatrix22Template<T>& r)
{ return TMatrix22Template<T>(r) *= (T)s; }

// TVector2 operations
template<class T, class U>
inline TVector2Template<U> operator* (const TVector2Template<U>& v, const TMatrix22Template<T>& m)
{
	return TVector2Template<U>
		(
			v(0)*m(0,0) + v(1)*m(1,0),
			v(0)*m(0,1) + v(1)*m(1,1)
		);
}

template<class T, class U>
inline TVector2Template<U> operator* (const TMatrix22Template<T>& m, const TVector2Template<U>& v)
{
	return TVector2Template<U>
		(
			v(0)*m(0,0) + v(1)*m(0,1),
			v(0)*m(1,0) + v(1)*m(1,1)
		);
}


// [inline implementation] -------------------------------------------------------------//

template<class T>
inline TMatrix22Template<T>::TMatrix22Template (void)
	{ }
	
template<class T>
inline TMatrix22Template<T>::TMatrix22Template (const T& m00, const T& m01, const T& m10, const T& m11)
	{
		value[0][0] = m00; value[0][1] = m01; 
		value[1][0] = m10; value[1][1] = m11;
	}

template<class T>
inline uint32 TMatrix22Template<T>::GetRowDimension	(void) const
	{ return 2; }
	
template<class T>
inline uint32 TMatrix22Template<T>::GetColumnDimension	(void) const	
	{ return 2; }

template<class T>
inline T	  TMatrix22Template<T>::operator()		(const uint32 row, const uint32 col) const
	{ return value[row][col]; }

template<class T>
inline T&	  TMatrix22Template<T>::operator()		(const uint32 row, const uint32 col)
	{ return value[row][col]; }

template<class T>
inline const T* TMatrix22Template<T>::operator[]	(const uint32 row) const
	{ return value[row]; }
	
template<class T>
inline T*       TMatrix22Template<T>::operator[]	(const uint32 row)	
	{ return value[row]; }


#endif /* H_MATRIX22 */