//
// 2x3 matrix class
//

#ifndef __MATRIX2C_H__
#define __MATRIX2C_H__

#include "Vector2C.h"
#include "PajaTypes.h"


namespace PajaTypes {

	//! 2x3 matrix class.
	/*!	Matrix2C class defines a 2 by 3 matrix class which is used by
		the Demopaja system. The matrix class implements standard set
		of methods and overdriven operators for easy use. 

		This class is implemented by the system. 
	*/
	class Matrix2C {
	public:
		//! Default constructor.
		Matrix2C();

		//! Copy constructor.
		Matrix2C( const Matrix2C& rMat );

		//! Contructor from array of floats.
		/*!	Creates a new vector with the values as the array pointed by the argument.
			The array should contain 6 values, 2 for each row in the matrix.
			The rows in the array are arranged linearly. 
		*/
		Matrix2C( const float32* pMat );

		//! Default destructor.
		virtual ~Matrix2C();
  
		//! Multiplies two matrices and returns the result.
		Matrix2C	operator*( const Matrix2C& rMat ) const;

		//! Multiplies two matrices and stores the result.
		Matrix2C&	operator*=( const Matrix2C& rMat );

		//! Returns reference to the vector at a row pointed by the index. 
		/*!	The index values from 0 to 2 corresponds to the rows in the matrix.
			There are two versions of this method, this version enables to assign
			values. 
		*/
		Vector2C&			operator[]( int32 i );

		//! Returns reference to the vector at a row pointed by the index. 
		/*!	The index values from 0 to 2 corresponds to the rows in the matrix.
			There are two versions of this method, this version is for retrieving the values. 
		*/
		const Vector2C&		operator[]( int32 i ) const;

		//! Negates the matrix and returns the result.
		Matrix2C			operator-() const;

		//! Subtracts two matrices and stores the result in the matrix.
		Matrix2C&			operator-=( const Matrix2C& rMat );
		
		//! Adds two matrices and stores the result in the matrix.
		Matrix2C&			operator+=( const Matrix2C& rMat );
		
		//! Substracts two matrices and returns the result.
		Matrix2C			operator-( const Matrix2C& rMat ) const;

		//! Adds two matrices and returns the result.
		Matrix2C			operator+( const Matrix2C& rMat ) const;

		//! Multiplies the specified vector by the specified matrix and returns the result. 
		friend Vector2C		operator*( const Matrix2C& rMat, const Vector2C& rVec );
		
		//! Multiplies the specified vector by the specified matrix and returns the result. 
		friend Vector2C		operator*( const Vector2C& rVec, const Matrix2C& rMat );
		
		//! Multiplies the specified vector by the specified matrix and stores the result to the vector. 
		friend Vector2C&	operator*=( Vector2C& rVec, const Matrix2C& rMat );
		
		//! Sets the matrix as identity matrix.
		Matrix2C&	set_identity();

		//! Sets the matrix to identity and then translates the matrix to the value of the argument.
		Matrix2C&	set_trans( const Vector2C& rVec );

		//! Sets the matrix to identity and then scales the matrix to the value of the argument.
		Matrix2C&	set_scale( const Vector2C& rVec );

		//! Sets the matrix to identity and then rotates the matrix to the value of the argument.
		Matrix2C&	set_rot( float32 f32Angle );

		//! Pretranslates the matrix and returns the result.
		Matrix2C	pre_trans( const Vector2C& rVec ) const;

		//! Inverts the matrix and returns the result.
		Matrix2C	invert() const;

		//! Transposes the matrix and returns the result.
		Matrix2C	transpose() const;

		//! Ortho normalizes the matrix and returns the result.
		Matrix2C	ortho_norm() const;

	private:
		Vector2C	m_rMat[3];

	};



	inline
	Vector2C&
	Matrix2C::operator[]( int32 i )
	{
		assert( i >= 0 || i < 3 );
		return m_rMat[i];
	}

	inline
	const Vector2C&
	Matrix2C::operator[]( int32 i ) const
	{
		assert( i >= 0 || i < 3 );
		return m_rMat[i];
	}


	inline
	Vector2C
	operator*( const Matrix2C& m, const Vector2C& v )
	{
		return Vector2C( v[0] * m[0][0] + v[1] * m[1][0] + m[2][0],
						 v[0] * m[0][1] + v[1] * m[1][1] + m[2][1] );
	}

	inline
	Vector2C
	operator*( const Vector2C& v, const Matrix2C& m )
	{
		return Vector2C( v[0] * m[0][0] + v[1] * m[1][0] + m[2][0],
						 v[0] * m[0][1] + v[1] * m[1][1] + m[2][1] );
	}

	inline
	Vector2C&
	operator*=( Vector2C& v, const Matrix2C& m )
	{
		Vector2C	temp( v[0] * m[0][0] + v[1] * m[1][0] + m[2][0],
						  v[0] * m[0][1] + v[1] * m[1][1] + m[2][1] );
		v = temp;
		return v;
	}

};	// namespace

#endif