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


namespace Matrices
{
	namespace IO
	{
		CCSConverter::CCSConverter(bool showMsg, std::ostream &log) : 
			 m_bShowMsg(showMsg),
			 logout(log)
		{
		}

		CCSConverter::~CCSConverter()
		{		
		}

		void CCSConverter::MatrixToCCS(Matrices::Matrix &matrix, std::vector<size_t> &rowind, std::vector<size_t> &colptrs, 
			std::vector<double> &vals, size_t &nz) 
		{
			m_Matrix = &matrix;
			this->colptrs  = &colptrs;
			this->rowind = &rowind;
			this->vals = &vals;

			rowind.clear();
			colptrs.clear();
			vals.clear();

			CreateFromMatrix();
			nz = (size_t) vals.size();
		}

		void CCSConverter::CCSToMatrix(Matrices::Matrix &matrix,std::vector<size_t> &rowind, 
			std::vector<size_t> &colptrs, std::vector<double> &vals)
		{
			m_Matrix = &matrix;
			this->colptrs  = &colptrs;
			this->rowind = &rowind;
			this->vals = &vals;
			size_t cols = matrix.NumberOfColumns();

			for(size_t colNo = 0; colNo < cols; colNo++)
			{

					double *col = DecompressCol(colNo);
					matrix.SetColumn(col,colNo);
					delete[] col;
				if(m_bShowMsg && colNo%100 == 0)
				{
					logout  << "Kolumna nr: " << colNo << " z "<< cols << "\r";
					logout.flush();
				}
			}
			logout << std::endl;
		}

		double* CCSConverter::DecompressCol(size_t columnNo)
		{
			size_t rows = m_Matrix->NumberOfRows();
			double* col = new double[rows];
			memset(col,0,sizeof(double)*rows);
			size_t startIndex = (*colptrs)[columnNo];
			//colptrs.size()-1 to ilosc nz
			size_t endIndex = (size_t) ( (columnNo != (*colptrs).size()-1) ? (*colptrs)[columnNo+1]: (*colptrs).size() );
			for(size_t i = startIndex; i < endIndex; i++)
			{
				col[(*rowind)[i]] = (*vals)[i];			
			}

			return col;
		}

		void CCSConverter::CreateFromMatrix()
		{

			for(size_t columnNo = 0; columnNo < m_Matrix->NumberOfColumns(); columnNo++)
			{//dla kazdej kolumny
				bool colAdded = false;

				double *column = m_Matrix->GetColumn(columnNo);

				for(size_t rowNo = 0; rowNo < m_Matrix->NumberOfRows(); rowNo++)
				{//dla kazdego wiersza
					if( column[rowNo] != 0 )
					{
						if(!colAdded)
						{
							colAdded = true;
							(*colptrs).push_back((size_t)(*rowind).size());
						}
						(*rowind).push_back(rowNo);
						(*vals).push_back(column[rowNo]);
					}
					if(!colAdded)
					{
						colAdded = true;
						(*colptrs).push_back((size_t)(*rowind).size());
					}

				}
				if(m_bShowMsg &&columnNo % 100 == 0)
					logout << "Przetwarzam kolumne: " << columnNo << " z " << m_Matrix->NumberOfColumns() << "\r";

				delete[]column;


			}
			logout << std::endl;
			(*colptrs).push_back((size_t)(*vals).size());

		}

		
	}
}


