/*
    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.
*/

#ifndef MATRICES_CCSMATRIX_H
#define MATRICES_CCSMATRIX_H

#include "matrices_headers.h"
#include "Matrix.h"
#include "CompressedVector.h"
#include "CRSMatrix.h"

namespace Matrices
{

	/**
	  * Matrix that holds data as compressed columns. The storage engine is std::map, so it is not the best choice for
	  * performance.
	  */
	class MATRICES_API CCSMatrix : public Matrix
	{
	public:
		/**
		  * Standard constructor
		  * \see Matrix
		  **/
		CCSMatrix(const std::string &name, size_t rows, size_t columns);
		virtual ~CCSMatrix(void);
		/**
		  * Retrieves a copy column. Column is dynamically allocated every time, so for large matrices calls to this method
		  * can seriously affect performance. Memory should be freed by calling Matrix::FreeMem.
		  */
		virtual double* GetColumn(size_t colNo);
		/**
		  * Retrieves a copy of a row. Row is dynamically allocated every time, so for large matrices calls to this method
		  * can seriously affect performance. Memory should be freed by calling Matrix::FreeMem.
		  */
		virtual double* GetRow(size_t rowNo);
		/**
		  * Retrieves a copy of a row. Row is dynamically allocated every time, so for large matrices calls to this method
		  * can seriously affect performance. Memory should be freed by calling Matrix::FreeMem.
		  */
		virtual double* operator[](size_t rowNo);
		/// Acts as described in base class
		virtual void SetRow(std::vector<double> &row, size_t rowIndex);
		/// Acts as described in base class
		virtual void SetRow(double* row, size_t rowIndex);
		/// Acts as described in base class
		virtual void SetColumn(double* col, size_t colIndex);
		/// Acts as described in base class
		virtual void SumRows(double *row, size_t rowIndex);
		/**
		 * Matrix transposition. Slow operation on large matrices.
		 * Assumes that returnMatrix is NULL pointer (it will be initialized inside the function)
		 * \throws If returnMatrix != NULL throws std::runtime_errror
		 **/
		virtual Matrix*& Transpose(Matrix*&  returnMatrix);
		/// Acts as described in base class
		virtual void SetCell(double val, size_t rowInd, size_t colInd);
		/// Acts as described in base class
		virtual double GetCell(size_t rowInd, size_t colInd);
		/// Acts as described in base class
		virtual void Clear();
		/// Acts as described in base class
		virtual void AddToCell(double value, size_t rowIndex, size_t columnIndex);
		/**
		 * Clears given matrix, sets new description and copies matrix data.
		 * Prints progress and estimated time on standard output stream.
		 **/
		virtual void Clone(Matrix* matrix) ;

		void Clone(CRSMatrixPtr matrix, std::ostream &out = std::cout);
		/**
		 * Acts exactly in the same manner as Clone(Matrix*, std::ostream&), but uses CCSMatrix instead of arbitrary matrix.
		 * Prints progress and estimated time on given output stream.
		 **/
		virtual void Clone(CCSMatrix* matrix, std::ostream &out = std::cout) ;
		/**
		 * Retrieves pointer on column in compressed format (not a copy, actual data)
		 **/
		CompressedVectorPtr GetCompressedColumn(size_t columnNo);
		/**
		 * Sets compressed column.
		 **/
		void SetCompressedColumn(size_t columnno, const CompressedVector & v);
		void SetCompressedColumn(size_t columnno, const CompressedVectorPtr pV);

                void SetCompressedRow(size_t rowno, const CompressedVectorPtr pV);
                void SetCompressedRow(size_t rowNo, const CompressedVector v);
		/**
		 *  Clears the matrix and sets new descriptor.
		 **/
		virtual void SetDescriptor(const std::string &name, size_t rows, size_t columns);
		
	private:
		/**
		 * Actual matrix data.
		 **/
		std::vector<CompressedVectorPtr>  *m_vColumns;
		/**
		 * Clears memory
		 **/
		void ClearMemory();
		/**
		 * Allocates memory (if memory was allocated, calls ClearMemory)
		 **/
		void AllocateMemory();
	};

	/// Shared pointer to CCSMatrix
	typedef boost::shared_ptr<CCSMatrix> CCSMatrixPtr;
	CCSMatrixPtr MATRICES_API GetNewCCSMatrix(const std::string &name, size_t rows, size_t columns);
}

#endif //MATRICES_CCSMATRIX_H
