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

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

namespace Matrices
{
	namespace IO
	{
		CRSMatrixWriter::CRSMatrixWriter(const std::string &dir, const std::string &s)
			: CCSMultiFileWriter(dir, s, "crs")
		{
			pointers_file_suffix = "_row_";
			indices_file_suffix = "_col_";
		}

		void CRSMatrixWriter::WriteMatrix(CRSMatrix &matrix)
		{
			boost::filesystem::path dir = boost::filesystem::path(dirpath);
			dir.normalize();


			name = matrix.GetName();

			// if not exists -> create
			if( !boost::filesystem::exists(dir) )
			{
				boost::filesystem::create_directory(dir);
			}

			// if is file -> throw
			if( !boost::filesystem::is_directory(dir) )
				throw filesystem_error("CCSMatrixWriter::Write", dir.string() + " is not a direcotry!");

			dir /= name;
			boost::filesystem::create_directory(dir);


			// konwersja macierz -> listy
			ConvertToLists(matrix);

			rows = matrix.NumberOfRows();
			cols = matrix.NumberOfColumns();
			nonzeros = vals->size();

			SaveToFile(dir.string());

			this->rowind->clear();
			this->colptrs->clear();
			this->vals->clear();
		}

		void CRSMatrixWriter::ConvertToLists(CRSMatrix &matrix)
		{
			size_t rows_number =  matrix.NumberOfRows();
			size_t insertIndex = 0;

			for(size_t row = 0; row < rows_number; row++)
			{
				CompressedVectorPtr v = matrix.GetCompressedRow(row);

				for(std::map<size_t, double>::const_iterator iter = v->GetValues()->begin(); iter != v->GetValues()->end(); iter++)
				{
					rowind->push_back(iter->first);
					vals->push_back(iter->second);
				}

				colptrs->push_back(insertIndex);

				insertIndex = vals->size();
			}
			colptrs->push_back(vals->size());
		}

		void WriteToSingleFile(CRSMatrixPtr pMatrix, const std::string &filename)
		{
			// first count NZ
			size_t nz = 0;
			for(size_t row_no = 0; row_no < pMatrix->NumberOfRows(); row_no++)
				nz += pMatrix->GetCompressedRow(row_no)->GetValues()->size();

			std::ofstream file(filename.c_str());
			if(!file)
				throw filesystem_error( "Cannot open file for writing: " + filename);

			file << pMatrix->NumberOfRows() << " "  << pMatrix->NumberOfColumns() << " " << nz << std::endl;

			for(size_t row_no = 0; row_no < pMatrix->NumberOfRows(); row_no++)
			{
				std::map<size_t, double>* vals = pMatrix->GetCompressedRow(row_no)->GetValues();
				for(std::map<size_t, double>::iterator iter = vals->begin(); iter != vals->end(); iter++)
				{
					file << iter->first << " " << iter->second << " ";
					if(iter->second==0)
						LOG4CXX_WARN(logger,"Warning: inserted value 0 into output file!");
				}
				file << std::endl;
			}

			file.close();
		}
	}
}

