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

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

namespace Matrices
{
	namespace IO
	{
		SymmetricSimMatrixPtr LoadSimMatrix(const std::string &filename, const std::string &labelfile, double min_sim)
		{
			using namespace boost::posix_time;
			std::string lfilename = labelfile;
			if(lfilename.length() == 0)
				lfilename = filename + ".rlabel";
			std::vector<std::string> labels;
			LOG4CXX_INFO(logger, "Reading labels from file " << lfilename);
			std::ifstream file( lfilename.c_str() );
			if(!file)
				throw std::runtime_error("Cannot open file: "+ lfilename);
			std::string line;
			Matrices::LabelIndex matrixlabels;
			size_t id = 0;
			while( std::getline(file,line) )
			{
				boost::trim(line);
				if(line.length())
					labels.push_back(line);
				else
					LOG4CXX_WARN(logger, "Warning - empty line in file " << lfilename.c_str() << ". Line no = " << id);
				matrixlabels[line] = id++;

			}//while file
			file.close();

			LOG4CXX_INFO(logger, "Reading similarity db from file " << filename);
			file.open( filename.c_str() );
			if(!file)
				throw std::runtime_error("Cannot open file: "+ filename);
			std::getline(file,line) ;
			std::vector<std::string> first_line_tokens;
			boost::split(first_line_tokens, line, boost::is_any_of(" ") );
			size_t items = boost::lexical_cast<size_t>(first_line_tokens[0]);
			Matrices::SymmetricSimMatrixPtr pMatrix( new Matrices::SymmetricSimMatrix(filename, items) );
			size_t row_no = 0;
			ptime start = microsec_clock::local_time();
			time_duration total_time;
			while( std::getline(file,line) )
			{
				if(line.length() == 0)
				{
					row_no++;
					continue;
				}
				std::vector<std::string> tokens;
				boost::split(tokens, line, boost::is_any_of(" \t") );
				for(size_t i = 0; i < tokens.size()-1; i+=2)
				{
					size_t index = boost::lexical_cast<size_t>(tokens[i] );
					double sim = boost::lexical_cast<double>(tokens[i+1] );
					if(sim < min_sim)
						continue;
					pMatrix->SetCell(sim,row_no, index);
				}
				row_no++;

				ptime end = microsec_clock::local_time();
				time_duration len = end-start;
				if( len.total_milliseconds() > 10000)
				{
					total_time += len;
					long total_time_ms = total_time.total_milliseconds();
					double item_per_sec = double( (row_no+1)*1000)  / total_time_ms;
					long eta_ms = (total_time_ms*(items - row_no - 1)) / (row_no+1);

					LOG4CXX_INFO(logger,"Reading similarity db, " << row_no << " / " << items  << " | row/sec = " << item_per_sec << " ETA: " << to_simple_string(milliseconds(eta_ms) ));
					start = microsec_clock::local_time();
				}
			}
			file.close();
			if( matrixlabels.size() != pMatrix->NumberOfRows() )
				LOG4CXX_WARN(logger,"Warning: number of labels != number of rows!");

			pMatrix->SetLabelIndex(matrixlabels);

			LOG4CXX_INFO(logger, "Reading similarity db from file " << filename << ". DONE!");
			return pMatrix;
		}
	}//namespace IO
}//namespace Matrices

