/*
    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 "pseudoreader.h"
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <fstream>
#include <libcorpus2/tagsetmanager.h>
#include <libcorpus2/tagging.h>
#include <boost/lexical_cast.hpp>

namespace Corpus2{

bool PseudoReader::registered = TokenReader::register_path_reader<PseudoReader>(
	"pseudoreader","pseudoinner,words"); // TODO more help?

	PseudoReader::PseudoReader(const Tagset &tagset, const std::string &filename)
		: TokenReader(tagset), inner_filename_(filename)
	{
		myTagset=tagset;
	}

	PseudoReader::~PseudoReader()
	{
		// TODO implementataion
	}

	void PseudoReader::change_input_file(const std::string &filename)
	{
		inner_reader_ = create_path_reader(inner_name, this->tagset(),filename);
	}

	Token* PseudoReader::get_next_token()
	{
		if(currentSentence->empty())
			currentSentence=get_next_sentence();

		std::vector<Token*> tokens = currentSentence->tokens();
		if(token_index<tokens.size())
		{
			return tokens.at(token_index++);
		}
		else
		{
			currentSentence=get_next_sentence();
			if(currentSentence==NULL)
			{
				return NULL;
			}
			tokens = currentSentence->tokens();
			token_index=0;
			return tokens.at(token_index++);
		}
	}

	Sentence::Ptr PseudoReader::get_next_sentence()
	{
		currentSentence = inner_reader_->get_next_sentence();
		if(currentSentence==0)
			return currentSentence;
		return process_sentence(currentSentence);
	}

	Sentence::Ptr PseudoReader::process_sentence(Corpus2::Sentence::Ptr sentence)
	{
		std::vector<Token*> &tokens = sentence->tokens();
		Tag all_masks = Corpus2::get_attribute_mask(myTagset,"");
		Sentence::Ptr new_sentence = boost::make_shared<Sentence>();
		BOOST_FOREACH (Token* tok, tokens)
		{
			Lexeme lex = tok->get_preferred_lexeme(myTagset);
			Tag tag = lex.tag();
			Tag pos_tag = tag.get_masked(all_masks);
			std::string pos = myTagset.tag_to_symbol_string(pos_tag);
			std::string base = lex.lemma_utf8();
			if(word_dict.find(pos+":"+base)!=word_dict.end())
			{
				std::string new_base;
				std::vector<std::string>::iterator it;
				for(it = word_dict[pos+":"+base].begin(); it != word_dict[pos+":"+base].end();it++)
				{
					if((it+1) != word_dict[pos+":"+base].end())
					{
						new_base += *it+"_";
					}
					else
					{
						new_base += *it;
					}
				}
				/*BOOST_FOREACH (std::string str, word_dict[pos+":"+base])
				{
					new_base += str+"_";
				}
				*/
				lex.set_lemma_utf8(new_base);
				Corpus2::Token * t = tok->clone();
				BOOST_FOREACH (Lexeme& lex1, t->lexemes())
					if(lex1.is_disamb())
						lex1.set_lemma_utf8(new_base);
				new_sentence->append(t);
			}
			else
			{
				new_sentence->append(tok->clone());
			}
		}	
		return new_sentence;
	}


	boost::shared_ptr<Chunk> PseudoReader::get_next_chunk()
	{
		currentChunk=inner_reader_->get_next_chunk();
		if(currentChunk == NULL)
			return currentChunk;

		 boost::shared_ptr<Chunk> new_chunk = boost::make_shared<Chunk>();

		 BOOST_FOREACH (Corpus2::Sentence::Ptr sentence, currentChunk->sentences())
			 new_chunk->append( process_sentence(sentence) );

		return new_chunk;
	}

	void PseudoReader::set_option(const std::string& option)
	{
		if(boost::algorithm::starts_with(option, "pseudoinner:"))
		{
			inner_name = option.substr(12);
			inner_reader_ = create_path_reader(inner_name, this->tagset(),
											inner_filename_);
			token_index=0;
			currentSentence= boost::make_shared<Sentence>();
		}
		if(boost::algorithm::starts_with(option, "words:"))
		{
			words_path = option.substr(6);
			if(!boost::filesystem::exists(words_path))
				throw Corpus2Error("File "+ words_path + " does not exists");
			boost::algorithm::trim(words_path);
			load_pseudowords(words_path);
		}
	}

	void PseudoReader::validate()
	{
		if(inner_reader_ == NULL)
			throw Corpus2Error("Pseudoinner reader not initialised.");

	}

	std::string PseudoReader::get_option(const std::string& option) const
	{
		if(boost::algorithm::starts_with(option, "pseudoinner:")
			&& inner_reader_ != NULL)
			return option;
		return inner_reader_->get_option(option);
	}

	void PseudoReader::load_pseudowords(std::string& words_path)
	{
		std::string line;
		std::ifstream file(words_path.c_str());
		if (file.is_open())
		{
			while (file.good())
			{
				getline(file,line);
				std::vector<std::string> split_line = string_split(line, ";");
				if (split_line.size()>1)
				{
					BOOST_FOREACH (std::string word, split_line)
					{
						word_dict.insert(std::pair<std::string, std::vector<std::string> >(word, split_line));
					}
				}
			}
			file.close();
		}
	}

	std::vector<std::string> PseudoReader::string_split(std::string str, std::string delim)
	{
		std::vector<std::string> results;
		size_t cutAt;
		while( (cutAt = str.find_first_of(delim)) != str.npos )
		{
			if(cutAt > 0)
			{
				results.push_back(str.substr(0,cutAt));
			}
			str = str.substr(cutAt+1);
		}
		if(str.length() > 0)
		{
			results.push_back(str);
		}
		return results;
	}

}// ns Corpus2
