#include <iostream>
#include <string>
using namespace std;
#include "matrix.h"

matrix::matrix(int rows, int cols, string name) {
	numRows=rows;
	numCols=cols;
	myName=name;

	//col=new double[cols];
	mx=new double*[rows];
	for ( int i=0; i < rows; i++ ) {
		mx[i] = new double[cols];
		// initalize each element of the new row.
		for ( int c=0; c < cols; c++ ) {
			mx[i][c] = 0;
		}
	}
}
matrix::matrix(const matrix &theMatrix) {
	int rows=theMatrix.numRows;
	int cols=theMatrix.numCols;

	mx=new double*[rows];
	for ( int r=0; r < rows; r++ ) {
		mx[r] = new double[cols];
		// copy each element of the new row.
		for ( int c=0; c < cols; c++ ) {
			mx[r][c] = theMatrix.mx[r][c];
		}
	}
}
matrix::~matrix() {
	deleteMatrix();
}
void matrix::deleteMatrix() {
	for ( int r=0; r < numRows; r++ ) 
		delete [] mx[r];
	delete [] mx;
}
void matrix::setValues ()  {
	cout << "\nSet Values for (" << numRows << " x " << numCols << ") Matrix: " << myName << endl;
	for ( int r=0; r < numRows; r++ ) {
		for ( int c=0; c < numCols; c++ ) {
			cin >> mx[r][c];
		}
	}
}
void matrix::display() {
	cout << "\nDisplaying (" << numRows << " x " << numCols << ") Matrix: " << myName << endl;
	cout << &*this << endl;

	for ( int r=0; r < numRows; r++ ) {
		for ( int c=0; c < numCols; c++ ) {
			cout << mx[r][c] << " "; 
		}
		cout << endl;
	}
}

void matrix::negative() {
	for ( int r=0; r < numRows; r++ ) {
		for ( int c=0; c < numCols; c++ ) {
			mx[r][c]= (-1) * mx[r][c];
		}
	}
}

matrix matrix::operator =(const matrix right) {
	if ( right.numRows != numRows || right.numCols != numCols ) {
		cout << "\nError while trying to copy matrix, the right side matrix has different dimentions.\n";
		cout << "\nThis: (" << numRows << " x " << numCols << ")";
		cout << "\nRght: (" << right.numRows << " x " << right.numCols << ")\n";
	} else {
		//deleteMatrix();

		//mx=new double*[numRows];
		//for ( int i=0; i < numRows; i++ )
		//	mx[i] = new double[numCols];

		for ( int r=0; r < numRows; r++ ) {
			for ( int c=0; c < numCols; c++ ) {
				mx[r][c] = right.mx[r][c];
			}
		}
	}
	return *this;
}
matrix matrix::operator +(const matrix &right) const {
	matrix result(numRows,numCols);
	if ( right.numRows != numRows || right.numCols != numCols ) {
		cout << "\nError while adding matricies, the two must have the same dimentions.\n";
	} else {
		for ( int r=0; r < numRows; r++ ) {
			for ( int c=0; c < numCols; c++ ) {
				result.mx[r][c] = (this->mx[r][c]) + (right.mx[r][c]);
			}
		}
	}

	return result;
}
matrix matrix::operator -(const matrix &right) const {
	matrix tmp(right);
	tmp.negative();
	return *this+tmp;
}
matrix matrix::operator *(const matrix &right) const {
	matrix result(right.numRows,numCols);
	
	if ( right.numRows != numCols || right.numCols != numRows ) {
		cout << "\nError in matrix multiplication, left rows must = right cols and left cols must = right rows\n";
	} else {
		int leftRow=0, leftCol=0, rightRow=0, rightCol=0;
		int resultRow=0, resultCol=0;

		for ( resultRow=0; resultRow < right.numRows; resultRow++ ) {
			for ( resultCol=0; resultCol < numCols; resultCol++ ) {
				leftRow=resultRow;
				leftCol=0;
				rightRow=0;
				rightCol=resultCol;


				while ( leftCol < numCols) {
					result.mx[resultRow][resultCol] += mx[leftRow][leftCol] * right.mx[rightRow][rightCol];
					leftCol++;
					rightRow++;
				}

			}
		}
	}
	return result;
}
matrix matrix::operator ^(int power) const {
	matrix result(numRows,numCols);
	result=*this;

	for ( int i=0; i < power; i++ ) {
		matrix tmp(numRows,numCols);
		tmp=result;
		result=( tmp * (*this) );
	}

	return result;
}