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

#include <set>
#include <vector>
#include <fstream>

#include <boost/program_options.hpp>
#include <boost/algorithm/string.hpp>

#include <boost/foreach.hpp>
#include <libcorpus2/io/xcesreader.h>
#include <libcorpus2/tagsetmanager.h>
#include <libwccl/values/strset.h>


namespace builder{
	MatrixBuilder::MatrixBuilder(const config &cfg)
		: config_(cfg),
	      tagset(Corpus2::get_named_tagset(cfg.tagset))
	{
		// no op?
	}

	void MatrixBuilder::run()
	{
		using namespace std;
		using namespace boost;
		typedef map<string,size_t> str2st;

		ofstream out(config_.outfile.c_str(), ios::trunc);
		if(!out)
			throw runtime_error("Cannot open file for writing: " + config_.outfile);


		BOOST_FOREACH (std::string corpus, config_.corpora)
		{
			Corpus2::TokenReader::TokenReaderPtr pReader =
					Corpus2::TokenReader::create_path_reader(config_.reader_class,
															 tagset,
															 corpus);
			std::cout << "Processing " << corpus << std::endl;

			Corpus2::Sentence::Ptr pSentence;

			while( (pSentence = pReader->get_next_sentence()))
				process_sentence(pSentence);

		}
		
		BOOST_FOREACH (str2st::value_type &entry2count, data)
			out << entry2count.first << ";" << entry2count.second
				<< std::endl;
		cout << " Done." << std::endl;

	} // run
	
	void MatrixBuilder::process_sentence(Corpus2::Sentence::Ptr sentence)
	{
		using namespace std;
		using namespace boost;
		typedef pair<string,string> strpair;
		typedef map<strpair,size_t> index_type;
		typedef map<string,size_t> str2st;
		
		BOOST_FOREACH (const Operator & oper, config_.operators)
		{
			index_type cols;
			index_type rows;
	
			// index sentence
			for(size_t i = 0; i < sentence->size(); ++i)
			{
				Corpus2::Token* pToken = sentence->at(i);
				// TODO: all lexemes?
				Corpus2::Lexeme lex = pToken->get_preferred_lexeme(tagset);
	
				std::string pos_str = tagset.get_pos_name(lex.tag().get_pos());
				std::string lemma = lex.lemma_utf8();
	
				if(oper.row_poses.find(pos_str) != oper.row_poses.end())
					rows.insert(make_pair(make_pair(pos_str, lemma), i));
				if(oper.operator_poses.find(pos_str) != oper.operator_poses.end())
					cols.insert(make_pair(make_pair(pos_str, lemma), i));
			} // index sentence
			//check operators
			Wccl::SentenceContext sc(sentence);
			BOOST_FOREACH (index_type::value_type &r2i, rows)
			{
				sc.set_position(r2i.second);
				BOOST_FOREACH (index_type::value_type & c2i, cols)
				{
					if(r2i.second == c2i.second)
						continue;
					Wccl::StrSet ss;
					ss.insert_utf8(c2i.first.second);
					oper.proper_operator->set("Var", ss);
					if(oper(sc))
					{
						std::string entry = r2i.first.first + ":" + r2i.first.second + ";"
								+ oper.relation_name + ";" + c2i.first.first + ":" + c2i.first.second;
						str2st::iterator find = data.find(entry);
						if(find == data.end())
							data.insert( make_pair(entry, 1) );
						else
							find->second  += 1;
					}
				}
			} // check operators
		}  // for each operator
	}

} // namespace builder
