/*
    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 "SuperMatrixWriter.h"
#include "CCSMatrixWriter.h"
#include "CRSMatrixWriter.h"

#include "filesystem_error.h"

#include "defines.h"

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

namespace Matrices
{
	namespace IO
	{
		void SuperMatrixWriter::Write(Matrices::SuperMatrixPtr m_pMatrix, std::string &path) throw(filesystem_error)
		{

			LOG4CXX_INFO(logger,"Writing matrix " << m_pMatrix->GetName() << "...");

			// przygotuj katalog do zapisu
			PrepareDir(m_pMatrix, path);

			// zapisz cechy wierszy
			// zapisz cechy kolumn
			namespace fs = boost::filesystem;
			fs::path base(path);
			base /= m_pMatrix->GetName();
			std::string base_str = base.string();
			WriteFeatures(m_pMatrix, base_str);
			WriteBoundaries(m_pMatrix->Boundaries(), base_str,m_pMatrix->NumberOfColumns());


			// zapisz macierz w formacie CCS i CRS
			WriteMatrix(m_pMatrix, base_str);

			LOG4CXX_INFO(logger,"Writing matrix " << m_pMatrix->GetName() << "... done");

		}

		void SuperMatrixWriter::WriteBoundaries(std::map<size_t, std::string> &boundaries, const std::string &path,size_t numberOfColumns)
		{
			namespace fs = boost::filesystem ;
			fs::path boudaries_path = path;
			boudaries_path /= "boundary.txt";
			std::ofstream file(boudaries_path.string().c_str());
			if(!file)
				throw filesystem_error( (std::string("Cannot open file : ") +boudaries_path.string()).c_str());
			for(std::map<size_t, std::string>::iterator iter = boundaries.begin(); iter != boundaries.end(); ++iter)
				file << iter->second << " := " << iter->first << std::endl;
			if(boundaries.size()==0)
				file << "End_of_matrix := "<< numberOfColumns << std::endl;
			file.close();
		}

		void SuperMatrixWriter::WriteMatrix(SuperMatrixPtr pMatrix, std::string &path)
		{
			namespace fs = boost::filesystem ;

			fs::path dir(path);
			fs::path info_filename = path;//
			info_filename /= INFO_FILENAME;

			LOG4CXX_INFO(logger,"Writing infomation about matrices " << pMatrix->GetName());
			// zapisz nazwy macierzy CCS i CRS do pliku z informacjami
			std::ofstream out(info_filename.string().c_str() );
			if(!out)
				throw filesystem_error( (std::string("Cannot open file : ") +info_filename.string()).c_str());

			out << pMatrix->GetCorpusInfo() << std::endl;
			out << pMatrix->GetTokenCount() << std::endl;

			out.close();

			// zapisz macierz w formacie CCS i CRS

			if( pMatrix->GetCCS() != NULL)
			{
				fs::path filename = path;//
				filename /= CCS_PART_NAME;
				LOG4CXX_INFO(logger, "Writing CCS part of SuperMatrix...");
				WriteToSingleFile(pMatrix->GetCCS(), filename.string() );
			}
			if( pMatrix->GetCRS() != NULL)
			{
				fs::path filename = path;//
				filename /= CRS_PART_NAME;
				LOG4CXX_INFO(logger, "Writing CRS part of SuperMatrix...");
				WriteToSingleFile(pMatrix->GetCRS(), filename.string() );
			}
			LOG4CXX_INFO(logger,"Finished writing matrix content of "<< pMatrix->GetName());


		}

		void SuperMatrixWriter::WriteFeatures(SuperMatrixPtr pMatrix, std::string &path)
		{
			namespace fs = boost::filesystem ;

			fs::path dir(path);
			fs::path rowfeatures = path;
			fs::path rowlabels = path;
			rowfeatures /= ROW_FEATURE_FILENAME;
			rowlabels /= pMatrix->GetName() + ROW_LABELS_SUFFIX;
			LOG4CXX_INFO(logger, "Writing row features...");
			WriteFeatures(pMatrix->GetRowFeatures(), rowfeatures.string());
			WriteLabels(pMatrix->GetRowFeatures(), rowlabels.string());


			LOG4CXX_INFO(logger, "Writing column features...");
			fs::path columnfeatures= path;
			fs::path columnlabels= path;
			columnfeatures /= COLUMN_FEATURE_FILENAME;
			columnlabels /= pMatrix->GetName() + COLUMN_LABELS_SUFFIX;
			WriteFeatures(pMatrix->GetColumnFeatures(), columnfeatures.string());
			WriteLabels(pMatrix->GetColumnFeatures(), columnlabels.string());

		}

		void SuperMatrixWriter::PrepareDir(SuperMatrixPtr pMatrix, std::string &path)
		{
			namespace fs = boost::filesystem ;


			fs::path dir(path);

			dir.normalize();

			if( ! fs::exists(dir) )
			{
				fs::create_directory(dir);

				if( ! fs::exists(dir) )
					throw IO::filesystem_error( std::string("Cannot create directory: ") + dir.string() );

			}

			if( ! fs::is_directory(dir) )
				throw IO::filesystem_error( std::string("Given path is not a directory: ") + dir.string() );

			fs::path store_dir = dir / pMatrix->GetName();

			if( ! fs::exists(store_dir) )
			{
				fs::create_directory(store_dir);

				if( ! fs::exists(store_dir) )
					throw IO::filesystem_error( std::string("Cannot create directory: ") + store_dir.string() );
			}

		}
		void SuperMatrixWriter::WriteFeatures(FeatureVectorPtr v, const std::string &filename)
		{
			std::ofstream file( filename.c_str() );
			if(!file)
				throw filesystem_error( "Cannot open file for writing: " + filename );

			file << "label;nz;tf;TF;entropy" << std::endl;
			for(size_t i = 0; i < v->size(); i++)
			{
				Feature & f = (*v)[i];
				file << f.GetLabel() << ";" << f.GetNZ() << ";" << f.GetTermFrequency() << ";" 
					<< f.GetGlobalTermFrequency() << ";" << f.GetEntropy() 	<< std::endl;
			}
			file.close();
		}	
		
		void SuperMatrixWriter::WriteLabels(FeatureVectorPtr v,const std::string &filename)
		{
			std::ofstream file( filename.c_str() );
			if(!file)
				throw filesystem_error( "Cannot open file for writing: " + filename );

			for(size_t i = 0; i < v->size(); i++)
			{
				Feature & f = (*v)[i];
				file << f.GetLabel() <<  std::endl;
			}
			file.close();
		}	

		void WriteSuperMatrix(SuperMatrixPtr m, const std::string &dir)
		{
			SuperMatrixWriter writer;
			std::string p = dir;
			writer.Write(m, p);
		}
	}//namespace IO
}

