/*
    Copyright (C) 2012 Bartosz Broda, Jacek Bochenek, Łukasz Biłeńkij, 
    Damian Jaworski, Wojciech Mazur, Dominik Piasecki, Maciej Piasecki, 
    Radosław Ramocki
    
    This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your option)
any later version.

    This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. 

    See the LICENSE and COPYING files for more details.
*/

#include "matrices_headers.h"

#include "MemoryMatrix.h"

static log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger("SuperMatrix.matrices.MemoryMatrix"));

namespace Matrices
{
	MemoryMatrix::MemoryMatrix(const std::string &name, size_t rows, size_t columns)
		: Matrix(name, rows, columns)
	{
		AllocateMemory();
	}
	MemoryMatrix::~MemoryMatrix(void)
	{
		FreeMemory();
	}
	void MemoryMatrix::AllocateMemory()
	{
		size_t rows = m_stRows;
		size_t columns = m_stColumns;
		if(rows > 0 && columns > 0)
		{
			m_pdMatrix = new double*[rows];

			for(size_t rowNo = 0; rowNo < rows; rowNo++)
			{
				m_pdMatrix[rowNo] = new double[columns];
				memset(m_pdMatrix[rowNo],0, sizeof(double)*columns);
			}

		}
		else
			throw std::runtime_error("MemoryMatrix::MemoryMatrix: Wrong matrix dimenstions!");
	}

	void MemoryMatrix::FreeMemory()
	{
		size_t rows = m_stRows;
		for(size_t rowNo = 0; rowNo < rows; rowNo++)
			delete m_pdMatrix[rowNo];
		delete[] m_pdMatrix;
		m_pdMatrix = NULL;
	}

	double* MemoryMatrix::GetColumn(size_t colNo)
	{
		size_t rows = m_stRows;

		double * col = new double[rows];

		for(size_t rowNo = 0; rowNo < rows; rowNo++)
			col[rowNo] = m_pdMatrix[rowNo][colNo];

		return col;
	}

	double* MemoryMatrix::GetRow(size_t rowNo)
	{
		double* row = new double[m_stColumns];
		memcpy(row,m_pdMatrix[rowNo],sizeof(double)*m_stColumns);
		return row;
	}

	double* MemoryMatrix::operator[](size_t rowNo)
	{
		return m_pdMatrix[rowNo];
	}
	void MemoryMatrix::SetRow(std::vector<double> &row, size_t rowIndex)
	{
		size_t columns = m_stColumns;

		for(size_t colNo = 0; colNo < columns; colNo++)
			m_pdMatrix[rowIndex][colNo] = row[colNo];
	}
	void MemoryMatrix::SetRow(double* row, size_t rowIndex)
	{
		memcpy(m_pdMatrix[rowIndex], row, sizeof(double)*m_stColumns);
	}
	void MemoryMatrix::SetColumn(double* col, size_t colIndex)
	{
		size_t rows = m_stRows;

		for(size_t rowNo = 0; rowNo < rows; rowNo++)
			m_pdMatrix[rowNo][colIndex] = col[rowNo];
	}
	void MemoryMatrix::SumRows(double *row, size_t rowIndex)
	{
		size_t columns = m_stColumns;

		for(size_t colNo = 0; colNo < columns; colNo++)
			m_pdMatrix[rowIndex][colNo] += row[colNo];
	}

	void MemoryMatrix::SetCell(double val, size_t rowInd, size_t colInd)
	{
		m_pdMatrix[rowInd][colInd] = val;
	}

	double MemoryMatrix::GetCell(size_t rowInd, size_t colInd)
	{
		return m_pdMatrix[rowInd][colInd] ;
	}
	void MemoryMatrix::Clear()
	{
		FreeMemory();
		AllocateMemory();
	}

	void MemoryMatrix::AddToCell(double value, size_t rowIndex, size_t columnIndex)
	{
		m_pdMatrix[rowIndex][columnIndex] += value;
	}

	void MemoryMatrix::Clone(Matrix* matrix)
	{
		if(matrix != NULL)
			matrix->Clear();
		else
			matrix = new MemoryMatrix(m_sName, m_stRows, m_stColumns);

		for(size_t rowIndex = 0; rowIndex < NumberOfRows(); rowIndex++)
			matrix->SetRow(GetRow(rowIndex),rowIndex);
	}

	Matrix*& MemoryMatrix::Transpose(Matrix*&  returnMatrix)
	{
		if(returnMatrix != NULL)
			throw std::runtime_error("MemoryMatrix::Transpose : returnMatrix != NULL");

		MemoryMatrix* mat = new MemoryMatrix(m_sName, m_stRows, m_stColumns);
		returnMatrix = (Matrix*) mat;

		size_t columns = m_stColumns;
		for(size_t oldMCol = 0; oldMCol < columns ; oldMCol++)//dla kazdej kolumny w starej macierzy
		{
			double* col = GetColumn(oldMCol);
			mat->SetRow(col, oldMCol);
			delete[] col;
			if(oldMCol%20 == 0)
				LOG4CXX_INFO(logger, "Odwracam macierz... Krok " << oldMCol<< " z " << columns);
		}

		return returnMatrix;
	}
}

