#ifndef JL_MATRIX_H
#define JL_MATRIX_H

//
// ==============================================================
//
//					  ECS 110 - Assignment #1
//
//					  Justin Legakis
//
//					  April 27, 1993
//
// ==============================================================
//


#include <iostream.h>

#include "jllib_include.h"


//
// ======================================================
//
//	   Interface for Class
//
//		  JLmatrix
//
// ======================================================
//

class JLmatrix {

	friend class Vec4;

	private:
		real	*_data;
		int		_size;

	public:
//	*** Constructors/Destructor: ***
		JLmatrix();
		JLmatrix(const int);
		JLmatrix(const int, const real*);
		JLmatrix(const JLmatrix&);
		JLmatrix(const char);
		JLmatrix(const Matrix m) { _data=NULL; _size=0; CopyFromGLMatrix(m); }
		~JLmatrix();

//	*** Creates identity matrix: ***
		friend JLmatrix IJLmatrix(const int);

		void SetToIdentity() {
				for (int y=0; y<_size; y++)
					for (int x=0; x<_size; x++)
						_data[y*_size+x] = (x==y);
			}

		void Clear() {
				for (int y=0; y<_size; y++)
					for (int x=0; x<_size; x++)
						_data[y*_size+x] = 0;
			}


		void SetSize(int s);

		void CopyFromGLMatrix(const Matrix m);

//	*** Operators: ***
		JLmatrix& operator=(const JLmatrix &M);
		friend int operator==(const JLmatrix&, const JLmatrix&);
		friend int operator!=(const JLmatrix&, const JLmatrix&);
		friend ostream& operator<<(ostream&, const JLmatrix&);
		friend JLmatrix operator+(const JLmatrix&, const JLmatrix&);
		friend JLmatrix operator-(const JLmatrix&);
		friend JLmatrix operator-(const JLmatrix&, const JLmatrix&);
		friend JLmatrix operator*(const JLmatrix&, const real);
		friend JLmatrix operator*(const real, const JLmatrix&);
		friend JLmatrix operator*(const JLmatrix&, const JLmatrix&);
		JLmatrix& operator+=(const JLmatrix&);
		JLmatrix& operator-=(const JLmatrix&);
		JLmatrix& operator*=(const real);
		JLmatrix& operator*=(const JLmatrix&);

//	*** Calculates transpose of matrix: ***
		JLmatrix transpose();

//	*** Displays matrix, formatted with a prefix ***
//	*** text label, and optional suffix:		 ***
		friend void printJLmatrixWithLabel(const char*, const JLmatrix&,
										   const char* = "");

//	*** Calculates determinant of matrix: ***
		real determinant();

//	*** Access functions: ***
		real value(const int col, const int row) const
			{ return _data[row*_size+col]; }

		int size() const { return _size; }

		JLmatrix& set(int col, int row, real d)
				{ _data[row*_size+col] = d; return (*this); }

		void WriteValues(ostream&) const;
		void ReadValues(istream&);

//	*** Preforms a row operation: ***
		JLmatrix& RowOp(real, int, int);

//	*** LU Decomposition: ***
		int LU(JLmatrix&, JLmatrix&);

		void Transpose(JLmatrix &T);
		void Inverse(JLmatrix &I);

		real MultRowByVector(int r, real *vec);

//	*** Transformations: ***
		JLmatrix& Scale(real x, real y, real z);
		JLmatrix& Scale(real s) { return Scale(s, s, s); }
		JLmatrix& XRotate(real theta);
		JLmatrix& YRotate(real theta);
		JLmatrix& ZRotate(real theta);
		JLmatrix& Translate(real x, real y, real z);

		void GetGLMatrix(Matrix &glm);
		float* GetData() { return _data; }
};

#endif
