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

namespace Matrices
{
	namespace IO
	{
		CCSMultiFileWriter::CCSMultiFileWriter(const std::string &path, const std::string &transformation_suffix,
			const std::string &ct)
			:  compression_type(ct), pointers_file_suffix("_col_"), indices_file_suffix("_row_")
		{
			this->transformation_suffix = transformation_suffix;
			dirpath = path;


			rowind = new std::vector<size_t> ();
			colptrs = new std::vector<size_t>();
			vals = new std::vector<double> ();

		}

		CCSMultiFileWriter::~CCSMultiFileWriter()
		{
			if(rowind)
			{
				delete rowind;
				rowind = NULL;
			}

			if(colptrs)
			{
				delete colptrs;
				colptrs = NULL;
			}

			if(vals)
			{
				delete vals;
				vals = NULL;
			}
		}
		void CCSMultiFileWriter::Write(Matrices::Matrix &matrix) throw (filesystem_error)
		{
			try
			{
				boost::filesystem::path dir = boost::filesystem::path(dirpath);
				dir.normalize();
				CCSConverter converer;

				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("CCSMultiFileWriter::Write", dir.string() + " is not a direcotry!");

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


				converer.MatrixToCCS(matrix, *rowind, *colptrs, *vals, nonzeros);
				rows = matrix.NumberOfRows();
				cols = matrix.NumberOfColumns();

				SaveToFile(dir.string());

				this->rowind->clear();
				this->colptrs->clear();
				this->vals->clear();
			}
			catch(boost::filesystem::filesystem_error e)
			{
				throw filesystem_error("CCSMultiFileWriter::Write", e.what());
			}
		}


		void CCSMultiFileWriter::SaveDim(std::string file) throw (filesystem_error)
		{

			std::ofstream out(file.c_str(),std::ios::trunc);

			if(!out)
				throw filesystem_error("CCSMultiFileWriter", std::string("Can't write to file:"+file));

			out << rows << " " << cols << " " << nonzeros;

			out.close();
		}

		void CCSMultiFileWriter::SaveRows(std::string file) throw (filesystem_error)
		{
			std::ofstream out(file.c_str(), std::ios::trunc);

			if(!out)
				throw filesystem_error("CCSMultiFileWriter", std::string("Can't write to file:"+file));

			for(unsigned long row = 0; row < rowind->size(); row++)
				out << (*rowind)[row] << "\n";
			out.close();
		}
		void CCSMultiFileWriter::SaveCols(std::string file) throw (filesystem_error)
		{
			std::ofstream out(file.c_str(),std::ios::trunc);
			if(!out)
				throw filesystem_error("CCSMultiFileWriter", std::string("Can't write to file:"+file));
			for(unsigned long col = 0; col < colptrs->size(); col++)
				out << (*colptrs)[col] << "\n";
			out.close();

		}
		void CCSMultiFileWriter::SaveVals(std::string file) throw (filesystem_error)
		{
			std::ofstream out(file.c_str(), std::ios::trunc);
			if(!out)
				throw filesystem_error("CCSMultiFileWriter", std::string("Can't write to file:"+file));
			out.precision(std::numeric_limits<double>::digits10);
			for(unsigned long val = 0; val < vals->size(); val++)
				out << (*vals)[val] << "\n";
			out.close();

		}

		void CCSMultiFileWriter::SaveToFile(std::string dir) throw (filesystem_error)
		{
			try
			{
				std::string file;

				file = dir;
				file += "/" + name;
				file += "_dim";
				SaveDim(file);

				file = dir;
				file += "/" + name;
				file +=indices_file_suffix;
				file += compression_type;
				SaveRows(file);

				file = dir;
				file += "/" + name;
				file += pointers_file_suffix;
				file += compression_type;
				SaveCols(file);

				file = dir;
				file += "/" + name;
				file +="_" + transformation_suffix+ "_nz_";
				file += compression_type;
				SaveVals(file);
			}
			catch(boost::filesystem::filesystem_error e)
			{
				throw filesystem_error("CCSMultiFileWriter::SaveToFile", e.what());
			}

		}
	}

}
