/*
    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 "SimMatrix.h"

namespace Matrices
{

	SymmetricSimMatrix::SymmetricSimMatrix(const std::string &name, size_t rows)
		: Matrix(name, rows, rows)
	{
		for(size_t row_no = 0; row_no < rows; row_no++)
			m_vRows.push_back( RowMap() );
	}

	SymmetricSimMatrix::~SymmetricSimMatrix()
	{
		m_vRows.clear();
	}
	double* SymmetricSimMatrix::GetColumn(size_t colNo)
	{
		double *col = new double(NumberOfColumns() );
		for(size_t row_no = 0; row_no < NumberOfRows(); row_no++)
			col[row_no] = GetCell(row_no, colNo);
		return col;
	}
	double* SymmetricSimMatrix::GetRow(size_t rowNo)
	{
		double *row = new double( NumberOfColumns() );
		for(size_t col = 0; col < NumberOfColumns(); col++)
			row[ col ] = GetCell(rowNo, col);
		return row;
	}
	double* SymmetricSimMatrix::operator[](size_t rowNo)
	{
		return GetRow(rowNo);
	}
	void SymmetricSimMatrix::SetRow(std::vector<double> &row, size_t rowIndex)
	{
		if( row.size() != NumberOfColumns() )
			throw std::runtime_error( "row.size != colsize invoid SymmetricSimMatrix::SetRow(std::vector<double> &row, size_t rowIndex)" );
		for(size_t i = 0; i < row.size(); i++)
			SetCell(row[i], rowIndex, i);
	}
	void SymmetricSimMatrix::SetRow(double* row, size_t rowIndex)
	{
		RowMap &to_change = m_vRows[rowIndex];
		to_change.clear();
		for(size_t i = 0; i < NumberOfColumns(); i++)
			if( row[i] != 0 )
				to_change[i] = row[i];
	}
	void SymmetricSimMatrix::SetColumn(double* col, size_t colIndex)
	{
		for(size_t i = 0; i < NumberOfRows(); i++)
			SetCell(col[i], i, colIndex);
	}

	void SymmetricSimMatrix::SumRows(double *row, size_t rowIndex)
	{
		for(size_t col_id = 0; col_id < NumberOfColumns(); col_id++)
			SetCell( GetCell(rowIndex,col_id) + row[col_id], rowIndex, col_id);
	}

	Matrix*& SymmetricSimMatrix::Transpose(Matrix*&  returnMatrix)
	{
		throw std::runtime_error("Transpose has no meaning for SymmetricSimMatrix");
		return returnMatrix;
	}
	void SymmetricSimMatrix::SetCell(double val, size_t rowInd, size_t colInd)
	{
		if(rowInd > colInd)
		{
			size_t temp = rowInd;
			rowInd = colInd;
			colInd = temp;
		}

		if(val < 0.00000001 && val > -0.00000001)
		{
			m_vRows[rowInd].erase(colInd);
			return;
		}
		m_vRows[rowInd][colInd] = val;
	}
	double SymmetricSimMatrix::GetCell(size_t rowInd, size_t colInd)
	{
		if(rowInd > colInd)
		{
			size_t temp = rowInd;
			rowInd = colInd;
			colInd = temp;
		}
		RowMap::iterator find = m_vRows[rowInd].find(colInd);
		if(find == m_vRows[rowInd].end() )
			return 0;
		return find->second;
	}
	void SymmetricSimMatrix::Clear()
	{
		for(size_t row_no = 0; row_no < NumberOfRows(); row_no++)
			m_vRows[row_no].clear();
	}
	void SymmetricSimMatrix::AddToCell(double value, size_t rowIndex, size_t columnIndex)
	{
		SetCell( GetCell(rowIndex, columnIndex)+ value, rowIndex, columnIndex);
	}
	void SymmetricSimMatrix::Clone(Matrix* matrix)
	{
		SymmetricSimMatrix *clone_dest = dynamic_cast<SymmetricSimMatrix*> (matrix);
		if(clone_dest)
		{
			clone_dest->m_vRows = m_vRows;
			clone_dest->m_stRows = m_stRows;
			clone_dest->m_stColumns = m_stColumns;
			return;
		}

		throw std::runtime_error("Only cloning SymmetricSimMatrix to SymmetricSimMatrix is implemented");
	}

	void SymmetricSimMatrix::SetDescriptor(const std::string &name, size_t rows, size_t columns)
	{
		if(rows != NumberOfRows() || columns != NumberOfColumns() )
			Clear();
		m_sName = name;
	}

	void SymmetricSimMatrix::SetLabelIndex(const LabelIndex &label_index)
	{
		m_LabelIndex = label_index;
	}

	double SymmetricSimMatrix::GetSimilarity(const std::string& w1, const std::string w2)
	{
        LabelIndex::iterator find1 = m_LabelIndex.find(w1);
        LabelIndex::iterator find2 = m_LabelIndex.find(w2);
		if(find1 == m_LabelIndex.end() || find2 == m_LabelIndex.end())
			return 0;
        return GetCell(find1->second, find2->second);
	}
}//Matrices

