#include <boost/test/unit_test.hpp>
#include <boost/bind.hpp>

#include <libwccl/variables.h>

#include <iostream>

using namespace Wccl;

BOOST_AUTO_TEST_SUITE(variables)

BOOST_AUTO_TEST_CASE(v_basic)
{
	Variables v;
	BOOST_CHECK_EQUAL(v.size<Value>(), 0);
	BOOST_CHECK_EQUAL(v.size<Bool>(), 0);
	v.put("a", new Bool(true));
	BOOST_CHECK_EQUAL(v.size<Value>(), 1);
	BOOST_CHECK_EQUAL(v.size<Bool>(), 1);
	boost::shared_ptr<Bool> b = v.get<Bool>("b");
	BOOST_CHECK(!b);
	b = v.get<Bool>("a");
	BOOST_REQUIRE(b);
	BOOST_CHECK_EQUAL(b->get_value(), true);
	v.put("a", new Bool(false));
	BOOST_CHECK_EQUAL(v.size<Value>(), 1);
	BOOST_CHECK_EQUAL(v.size<Bool>(), 1);
	b = v.get<Bool>("a");
	BOOST_REQUIRE(b);
	BOOST_CHECK_EQUAL(b->get_value(), false);
	v.del<Position>("a");
	BOOST_CHECK(v.get<Bool>("a"));
	v.del<Bool>("a");
	BOOST_CHECK(!v.get<Bool>("a"));
}

BOOST_AUTO_TEST_CASE(v_del_any)
{
	Variables v;
	v.put("a", new Bool(true));
	v.put("b", new Bool(true));
	v.del<Bool>("a");
	BOOST_CHECK(!v.get<Value>("a"));
	v.put("a", new Bool(true));
	v.del<Value>("a");
	BOOST_CHECK(!v.get<Value>("a"));
	BOOST_CHECK(v.get<Value>("b"));
}

BOOST_AUTO_TEST_CASE(v_put_any)
{
	Variables v;
	boost::shared_ptr<Value> a;
	a.reset(new Bool(true));
	v.put_any("aaa", a);
	BOOST_CHECK(v.get<Bool>("aaa"));
	BOOST_CHECK(v.get<Bool>("aaa").get() == a.get());
}

struct Vfix
{
	Variables v;
	Vfix() {
		v.put("b1", Bool(false));
		v.put("b2", new Bool(true));
		v.put("p1", boost::shared_ptr<Position>(new Position(1)));
		v.put("p2", boost::make_shared<Position>(2));
		v.put_any("p3", boost::shared_ptr<Value>(new Position(3)));
	}
};

BOOST_FIXTURE_TEST_CASE(get, Vfix)
{
	BOOST_CHECK(v.get<Bool>("b1"));
	BOOST_CHECK(v.get<Value>("b1"));
	BOOST_CHECK(!v.get<Position>("b1"));
	BOOST_CHECK(v.get<Bool>("b2"));
	BOOST_CHECK(v.get<Position>("p1"));
	BOOST_CHECK(v.get<Position>("p2"));
	BOOST_CHECK(v.get<Position>("p3"));
	BOOST_CHECK(v.get<Value>("p3"));
	BOOST_CHECK(!v.get<Bool>("p3"));
}

BOOST_FIXTURE_TEST_CASE(get_put, Vfix)
{
	BOOST_CHECK(!v.get<Bool>("b3"));
	BOOST_CHECK(v.get_put<Bool>("b1"));
	BOOST_CHECK(v.get_put<Bool>("b3"));
	BOOST_CHECK(v.get<Bool>("b3"));
}

BOOST_FIXTURE_TEST_CASE(get_put_bad, Vfix)
{
	BOOST_CHECK_THROW(v.get_put<Bool>("p1"), VariableTypeMismatch);
}

BOOST_FIXTURE_TEST_CASE(put, Vfix)
{
	boost::shared_ptr<Bool> b1 = v.get<Bool>("b1");
	BOOST_CHECK_EQUAL(b1->get_value(), false);
	v.put("b1", Bool(true));
	BOOST_CHECK_EQUAL(b1->get_value(), false);
	boost::shared_ptr<Bool> b2 = v.get<Bool>("b1");
	BOOST_CHECK(b1.get() != b2.get());
	BOOST_CHECK_EQUAL(b2->get_value(), true);
}

BOOST_FIXTURE_TEST_CASE(put_bad, Vfix)
{
	BOOST_CHECK_THROW(v.put("p1", Bool(true)), VariableTypeMismatch);
}

BOOST_FIXTURE_TEST_CASE(set, Vfix)
{
	boost::shared_ptr<Bool> b1 = v.get<Bool>("b1");
	BOOST_CHECK_EQUAL(b1->get_value(), false);
	v.set("b1", Bool(true));
	BOOST_CHECK_EQUAL(b1->get_value(), true);
}

BOOST_FIXTURE_TEST_CASE(set_new, Vfix)
{
	BOOST_CHECK(!v.get<Bool>("b3"));
	v.set("b3", Bool(false));
	BOOST_CHECK(v.get<Bool>("b3"));
}

BOOST_FIXTURE_TEST_CASE(set_bad, Vfix)
{
	BOOST_CHECK_THROW(v.set("p1", Bool(true)), VariableTypeMismatch);
}

BOOST_FIXTURE_TEST_CASE(del, Vfix)
{
	v.del<Bool>("b1");
	BOOST_CHECK(!v.get<Bool>("b1"));
	v.del<Bool>("p2");
	BOOST_CHECK(v.get<Value>("p2"));
	v.del_any("p2");
	BOOST_CHECK(!v.get<Value>("p2"));
}

BOOST_AUTO_TEST_SUITE_END()