// Header file for the Matrix class
// Created by:		Michael Edwards
// Date Started:	5/20/04
// Date Finished:
// Complier Used:	Microsoft Visual C++, Version 6.0 Enterprise Edition

#include <cassert>
#include <memory.h>

class Matrix
{
	public:
		Matrix();
		// Default constructor.  Creates a [0, 0] matrix
		// PRECONDITION:  none.
		// POSTCONDITION: a matrix of size [0, 0] is created

		Matrix(unsigned row, unsigned column);
		// Creates a matrix of row and column with all elements = 0
		// PRECONDITION:  none.
		// POSTCONDITION: a matrix is created with size (row, column) and filled
		//				  with 0

		Matrix(unsigned row, unsigned column, float** userData);
		// Converts a float matrix to a matrix object
		// PRECONDITION:  for all (row, column), userData[row][column] is valid
		// POSTCONDITION: a matrix is created with size (row, column) and filled
		//				  with userData

		Matrix(unsigned row, unsigned column, float* userData);
		// Fills a Matrix with an array of data, userData
		// PRECONDITION:  length of userData >= row * column
		// POSTCONDITION: a matrix is created with size (row, column) and filled
		//				  with userData

		Matrix(const Matrix& rhs);
		// Copy constructor

		virtual ~Matrix();
		// Default destructor

		Matrix operator + (const Matrix &rhs) const;
		// returns the matrix addition of this and rhs
		// NOTE: this and rhs must be the same size
		// PRECONDITION:  matrices must be of same dimension.
		// POSTCONDITION: returns this + rhs

		Matrix operator - (const Matrix &rhs) const;
		// returns the matrix substraction of this and rhs
		// NOTE: this and rhs must be the same size
		// PRECONDITION:  matrices must be of same dimension.
		// POSTCONDITION: returns this - rhs

		Matrix operator * (const Matrix &rhs) const;
		// returns the cross product of this and rhs
		// NOTE: this throws an exception if this->column != rhs.row
		// PRECONDITION:  this->column == rhs.row
		// POSTCONDITION: returns the cross product of this and rhs

		Matrix operator * (const float scalar) const;
		// does the scalar multiplication of this and a scalar, scalar
		// PRECONDITION:  none.
		// POSTCONDITION: returns the scalar multiplication of this and rhs

		friend Matrix operator * (const float scalar, const Matrix& rhs);
		// does the scalar multiplication of this and a scalar, scalar
		// PRECONDITION:  none.
		// POSTCONDITION: returns the scalar multiplication of this and rhs

		Matrix operator / (const float scalar) const;
		// does the scalar division of this and a scalar, scalar
		// PRECONDITION:  scalar != 0.
		// POSTCONDITION: returns the scalar division of this and rhs

		Matrix& operator = (const Matrix &rhs);
		// assignment operator for the matrix class
		// PRECONDITION:  none.
		// POSTCONDITION: this = rhs

		Matrix& operator -= (const Matrix &rhs);
		// returns the matrix substraction of this and rhs
		// NOTE: this and rhs must be the same size
		// PRECONDITION:  matrices must be of same dimension.
		// POSTCONDITION: returns this - rhs

		Matrix& operator += (const Matrix &rhs);
		// returns the matrix addition of this and rhs
		// NOTE: this and rhs must be the same size
		// PRECONDITION:  matrices must be of same dimension.
		// POSTCONDITION: returns this + rhs

		Matrix& operator *= (const float scalar);
		// does the scalar multiplication of this and a scalar, scalar
		// PRECONDITION:  none.
		// POSTCONDITION: returns the scalar multiplication of this and rhs

		Matrix& operator /= (const float scalar);
		// does the scalar division of this and a scalar, scalar
		// PRECONDITION:  scalar != 0.
		// POSTCONDITION: returns the scalar division of this and rhs

		// bool operator ==(const Matrix &rhs) const;
		// this == rhs iff this.Reduce() == rhs.Reduce()
		// PRECONDITION:  none.
		// POSTCONDITION:

		// float Determinant() const;
		// Finds the determinant of the matrix
		// PRECONDITION:  none.
		// POSTCONDITION:
		
		unsigned GetColumn() const { return column; }
		// returns the number of columns of the Matrix
		// PRECONDITION:  none.
		// POSTCONDITION: returns the number of columns

		unsigned GetRow() const { return row; }
		// returns the number of rows of the Matrix
		// PRECONDITION:  none.
		// POSTCONDITION: returns the number of rows.

		Matrix Inverse() const;
		// returns an inverted form of the matrix
		// PRECONDITION:  the current matrix is square
		// POSTCONDITION: returns the inverted form of the current matrix; if no 
		//				  inverse exists, a zero matrix is returned.

		Matrix Reduce() const;
		// returns the Matrix in Row-Echelon Form 
		// PRECONDITION:  none.
		// POSTCONDITION: returns the reduced matrix of this

		const float** const ToFloat() const	{ return (const float**)data; }
		// Converts from a Matrix to a float**
		// PRECONDITION:  none.
		// POSTCONDITION: returns the float** representation of the Matrix
		
		Matrix Transpose() const;
		// returns the transposed matrix of this
		// PRECONDITION:  none.
		// POSTCONDITION: returns the transposition of the current matrix

	private:
		float** CreateMatrix(unsigned row, unsigned column) const;
		// creates a matrix that is row by column
		// PRECONDITION:  none.
		// POSTCONDITION: the matrix is returned
		
		void DestroyMatrix(unsigned row, float** myMatrix);
		// destroys a matrix pointed to by myMatrix with row rows
		// PRECONDITION:  myMatrix is valid and row indicates the correct number of rows
		// POSTCONDITION: myMatrix is deallocated properly

		Matrix GenerateIdentity(unsigned userRow, unsigned userColumn) const;		
		// creates an identity matrix of size [userRow, userColumn]
		// PRECONDITION:  userRow and userColumn is valid
		// POSTCONDITION: returns and identity matrix of [userRow, userColumn]

		unsigned row, column;
		float** data;
};