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

namespace doc_term_architect
{
	Config* Config::m_pInstance = NULL;

	void Config::InitalizeProgramOptions(int ac, char* av[])
	{
		namespace po = boost::program_options;
		std::string configfile;

		po::options_description cmdline("Command line only options", 100);
		po::options_description basic("Basic options", 100);

		cmdline.add_options()
			("help", "Prints this message")
			("cfg-file", po::value<std::string>(&configfile)->default_value(std::string("hal_architect.cfg")), "Config file")
			;

		basic.add_options()
			("file-list", po::value<std::string>(& m_sFileList), "File with paths to corporas(binary) or documents (XML)")
			("info", po::value<std::string>(& m_sCorpusInfo), "Corpus description")
			("workdir", po::value<std::string>(& m_sWorkDir), "Workdir (output dir for matrix)")
			("matrix-name", po::value<std::string>(& m_sMatrixName), "Matrix name" )
			("terms-file", po::value<std::string>(& m_sTermsFilename ), "File with terms to be found in documents")
			("binary", po::value<bool> (& binaryDocuments)->default_value(false), "Set true, if using binary corpus")
			("query-size",po::value<size_t> (&query_size)->default_value(1000), "Size of poliqarp query for binary corpus")
			;

		po::variables_map vm;
		po::options_description all("",100);

		all.add(cmdline).add(basic);

		po::store(po::parse_command_line(ac, av, all), vm);
		po::notify(vm);

		if( vm.count("help") )
		{
			std::cout << "HAL_ARCHITECT, by Bartosz Broda, bartosz.broda@pwr.wroc.pl\n";
			std::cout << all << std::endl;
			exit(0);
		}
		std::ifstream cfgfile( configfile.c_str() );

		if(cfgfile)
		{
			po::store(po::parse_config_file(cfgfile, basic), vm);
			po::notify(vm);
		}
		else if( vm.count("cfg-file") )
			std::cerr << "Cannot open config file " << configfile << ". Proceeding with defaults...\n";


	}
	Config::Config(int argc, char* argv[])
	{
		InitalizeProgramOptions(argc, argv);
	}

	Config* Config::Initalize(int argc, char* argv[])
	{
		if(m_pInstance)
			Delete();
		m_pInstance = new Config(argc, argv);

		m_pInstance->LoadTerms();
		m_pInstance->LoadDocuments();

		return m_pInstance;
	}

	Config* Config::GetInstance()
	{
		return m_pInstance;
	}

	void Config::Delete()
	{
		if(m_pInstance)
		{
			delete m_pInstance;
			m_pInstance = NULL;
		}
	}

	void Config::LoadTerms()
	{
		m_vColumnTerms.clear();
		LoadList(m_sTermsFilename, m_vColumnTerms);
		BuildTermsIndex();
	}

	void Config::LoadDocuments()
	{
		m_vDocumentList.clear();
		LoadList( m_sFileList, m_vDocumentList);
	}

	void Config::BuildTermsIndex()
	{
		Corpus::CWordDictionary *dict = Corpus::CWordDictionary::GetInstance();
		for(size_t term_no = 0; term_no < m_vColumnTerms.size(); term_no++)
		{
			std::vector<std::string> tokens;
			boost::split( tokens, m_vColumnTerms[term_no], boost::is_any_of(":") );
			if( tokens.size() != 3 )
				throw std::runtime_error( "Wrong format of terms file... Term: " + m_vColumnTerms[term_no] );
			//flex [0], term[1]
			std::string flex_str = tokens[0];
			boost::trim(flex_str);
			Corpus::TFlexClass flex = Corpus::CTag::GetFlexClass( flex_str);
			std::map<int, size_t> &inner_index = m_mTermIndex[flex];
			std::string word = tokens[1];
			boost::trim(word);
			int word_index = dict->Add( word );
			if( inner_index.find(word_index) != inner_index.end() )//ups!
				throw std::runtime_error( "Multiple words with the same base in one flex class: " + m_vColumnTerms[term_no] );

			inner_index[ word_index ] = term_no;
		}
	}

	void Config::LoadList(const std::string &filename, std::vector<std::string> &lines)
	{
		std::ifstream file( filename.c_str() );
		if( !file )
			throw std::runtime_error( "Cannot open file: " + filename );
		std::cout<<"Opened file "<<filename<<std::endl;
		std::string line;
		while( std::getline(file, line) )
		{
			boost::trim(line);
			if( line.length() > 0 )
				lines.push_back(line);
		}

	}
}//namespace doc_term_architect
