#include <boost/test/unit_test.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <libcorpus2/sentence.h>

#include <libwccl/ops/functions/constant.h>
#include <libwccl/ops/functions/strset/getlemmas.h>

using namespace Wccl;

BOOST_AUTO_TEST_SUITE(get_lemmas)

struct LemmasPredFix
{
	LemmasPredFix()
		: s(boost::make_shared<Corpus2::Sentence>()),
		  sc(s),
		  tagset(),
		  cx(sc, boost::make_shared<Variables>()),
		  pos_zero(0),
		  pos_one(1),
		  pos_minus_one(-1),
		  nowhere(Position::Nowhere),
		  begin(Position::Begin),
		  end(Position::End),
		  pos_zero_constant(new Constant<Position>(pos_zero)),
		  pos_one_constant(new Constant<Position>(pos_one)),
		  pos_minus_one_constant(new Constant<Position>(pos_minus_one)),
		  nowhere_constant(new Constant<Position>(nowhere)),
		  begin_constant(new Constant<Position>(begin)),
		  end_constant(new Constant<Position>(end)),
		  empty_set(),
		  first_lemmas(),
		  second_lemmas()
	{
		first_lemmas.insert("aaa");
		first_lemmas.insert("bbb");
		second_lemmas.insert("ccc");
		second_lemmas.insert("ddd");
		Corpus2::Token* the_token = new Corpus2::Token(
				"One",
				PwrNlp::Whitespace::ManySpaces);
		Corpus2::Tag t1(Corpus2::mask_t(0));
		Corpus2::Lexeme l1("aaa", t1);
		Corpus2::Lexeme l2("bbb", t1);
		the_token->add_lexeme(l1);
		the_token->add_lexeme(l2);
		s->append(the_token);
		Corpus2::Token* another_token = new Corpus2::Token(
				"Two",
				PwrNlp::Whitespace::ManySpaces);
		Corpus2::Tag t2(Corpus2::mask_t(0));
		Corpus2::Lexeme l3("ccc", t2);
		Corpus2::Lexeme l4("ddd", t2);
		another_token->add_lexeme(l3);
		another_token->add_lexeme(l4);
		s->append(another_token);
	}

	boost::shared_ptr<Corpus2::Sentence> s;
	SentenceContext sc;
	Corpus2::Tagset tagset;

	FunExecContext cx;
	Position pos_zero;
	Position pos_one;
	Position pos_minus_one;
	Position nowhere;
	Position begin;
	Position end;
	boost::shared_ptr<Function<Position> > pos_zero_constant;
	boost::shared_ptr<Function<Position> > pos_one_constant;
	boost::shared_ptr<Function<Position> > pos_minus_one_constant;
	boost::shared_ptr<Function<Position> > nowhere_constant;
	boost::shared_ptr<Function<Position> > begin_constant;
	boost::shared_ptr<Function<Position> > end_constant;
	StrSet empty_set;
	StrSet first_lemmas;
	StrSet second_lemmas;

};

BOOST_FIXTURE_TEST_CASE(lemmas_nowhere, LemmasPredFix)
{
	GetLemmas lemmas(nowhere_constant);
	BOOST_CHECK(lemmas.apply(cx)->equals(empty_set));
	sc.advance();
	BOOST_CHECK(lemmas.apply(cx)->equals(empty_set));
	sc.advance();
	BOOST_CHECK(lemmas.apply(cx)->equals(empty_set));
}

BOOST_FIXTURE_TEST_CASE(lemmas_begin, LemmasPredFix)
{
	GetLemmas lemmas(begin_constant);
	BOOST_CHECK(lemmas.apply(cx)->equals(first_lemmas));
	sc.advance();
	BOOST_CHECK(lemmas.apply(cx)->equals(first_lemmas));
	sc.advance();
	BOOST_CHECK(lemmas.apply(cx)->equals(empty_set));
}

BOOST_FIXTURE_TEST_CASE(lemmas_end, LemmasPredFix)
{
	GetLemmas lemmas(end_constant);
	BOOST_CHECK(lemmas.apply(cx)->equals(second_lemmas));
	sc.advance();
	BOOST_CHECK(lemmas.apply(cx)->equals(second_lemmas));
	sc.advance();
	BOOST_CHECK(lemmas.apply(cx)->equals(empty_set));
}

BOOST_FIXTURE_TEST_CASE(lemmas_zero, LemmasPredFix)
{
	GetLemmas lemmas(pos_zero_constant);
	BOOST_CHECK(lemmas.apply(cx)->equals(first_lemmas));
	sc.advance();
	BOOST_CHECK(lemmas.apply(cx)->equals(second_lemmas));
	sc.advance();
	BOOST_CHECK(lemmas.apply(cx)->equals(empty_set));
}

BOOST_FIXTURE_TEST_CASE(lemmas_one, LemmasPredFix)
{
	GetLemmas lemmas(pos_one_constant);
	BOOST_CHECK(lemmas.apply(cx)->equals(second_lemmas));
	sc.advance();
	BOOST_CHECK(lemmas.apply(cx)->equals(empty_set));
	sc.advance();
	BOOST_CHECK(lemmas.apply(cx)->equals(empty_set));
}

BOOST_FIXTURE_TEST_CASE(lemmas_minus_one, LemmasPredFix)
{
	GetLemmas lemmas(pos_minus_one_constant);
	BOOST_CHECK(lemmas.apply(cx)->equals(empty_set));
	sc.advance();
	BOOST_CHECK(lemmas.apply(cx)->equals(first_lemmas));
	sc.advance();
	BOOST_CHECK(lemmas.apply(cx)->equals(empty_set));
}
//------ to_string test cases -------

BOOST_FIXTURE_TEST_CASE(lemmas_to_string, LemmasPredFix)
{
	GetLemmas lemmas(begin_constant);
	BOOST_CHECK_EQUAL("base[begin]", lemmas.to_string(tagset));
}

BOOST_FIXTURE_TEST_CASE(lemmas_to_raw_string, LemmasPredFix)
{
	GetLemmas lemmas(end_constant);
	BOOST_CHECK_EQUAL("base[end]", lemmas.to_string(tagset));
	GetLemmas lemmas2(pos_minus_one_constant);
	BOOST_CHECK_EQUAL("base[-1]", lemmas2.to_string(tagset));
}
BOOST_AUTO_TEST_SUITE_END()