#include <psemek/test/test.hpp>

#include <psemek/sir/container.hpp>
#include <psemek/io/memory_stream.hpp>

#include "test_type.hpp"

#include <array>
#include <vector>
#include <list>
#include <deque>
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <string>

using namespace psemek;

namespace
{

	template <typename Container>
	void test_container(Container const & c, bool ordered = true)
	{
		using std::begin;
		using std::end;
		using std::cbegin;
		using std::cend;
		using std::size;

		char buffer[1024];
		
		{
			io::memory_ostream s{buffer, buffer + size(buffer)};
			sir::ostream os{s};
			write(os, c);
		}

		Container c2;

		{
			io::memory_istream s{buffer, buffer + size(buffer)};
			sir::istream is{s};
			read(is, c2);
		}

		expect_equal(std::size(c), std::size(c2));

		if (ordered)
		{
			for (auto i1 = cbegin(c), i2 = cbegin(c2); i1 != cend(c); ++i1, ++i2)
				expect_equal(*i1, *i2);

		}
		else
		{
			for (auto i1 = begin(c); i1 != end(c); ++i1)
				expect(std::find(begin(c2), end(c2), *i1) != end(c2));

			for (auto i2 = begin(c2); i2 != end(c2); ++i2)
				expect(std::find(begin(c), end(c), *i2) != end(c));
		}
	}

}

test_case(sir_container_c__array_trivial)
{
	std::uint32_t c[13] { 15, 16, 18, 2, 65535, 14, 5, 8, 42, 555, 18, 729, 76 };
	test_container(c);
}

test_case(sir_container_c__array_custom)
{
	test_type c[3] { {15u}, {65535u}, {1234567u} };
	test_container(c);
}

test_case(sir_container_std__array_trivial)
{
	std::array<std::uint32_t, 13> c { 15, 16, 18, 2, 65535, 14, 5, 8, 42, 555, 18, 729, 76 };
	test_container(c);
}

test_case(sir_container_std__array_custom)
{
	std::array<test_type, 3> c {{ {15u}, {65535u}, {1234567u} }};
	test_container(c);
}

test_case(sir_container_vector_trivial)
{
	std::vector<std::uint32_t> c { 15, 16, 18, 2, 65535, 14, 5, 8, 42, 555, 18, 729, 76 };
	test_container(c);
}

test_case(sir_container_vector_custom)
{
	std::vector<test_type> c { {15u}, {65535u}, {1234567u} };
	test_container(c);
}

test_case(sir_container_list_trivial)
{
	std::list<std::uint32_t> c { 15, 16, 18, 2, 65535, 14, 5, 8, 42, 555, 18, 729, 76 };
	test_container(c);
}

test_case(sir_container_list_custom)
{
	std::list<test_type> c { {15u}, {65535u}, {1234567u} };
	test_container(c);
}

test_case(sir_container_deque_trivial)
{
	std::deque<std::uint32_t> c { 15, 16, 18, 2, 65535, 14, 5, 8, 42, 555, 18, 729, 76 };
	test_container(c);
}

test_case(sir_container_deque_custom)
{
	std::deque<test_type> c { {15u}, {65535u}, {1234567u} };
	test_container(c);
}

test_case(sir_container_set_trivial)
{
	std::set<std::uint32_t> c { 15, 16, 18, 2, 65535, 14, 5, 8, 42, 555, 18, 729, 76 };
	test_container(c);
}

test_case(sir_container_set_custom)
{
	std::set<test_type> c { {15u}, {65535u}, {1234567u} };
	test_container(c);
}

test_case(sir_container_unordered__set_trivial)
{
	std::unordered_set<std::uint32_t> c { 15, 16, 18, 2, 65535, 14, 5, 8, 42, 555, 18, 729, 76 };
	test_container(c, false);
}

test_case(sir_container_unordered__set_custom)
{
	std::unordered_set<test_type> c { {15u}, {65535u}, {1234567u} };
	test_container(c, false);
}

test_case(sir_container_map_trivial)
{
	std::map<std::uint32_t, float> c { {10, 3.1415f}, {15, 6.7123f}, {1, -24.444f} };
	test_container(c);
}

test_case(sir_container_map_custom__key)
{
	std::map<test_type, float> c { {{15u}, 3.1415f}, {{65535u}, 23.451f}, {{1234567u}, -29.231f} };
	test_container(c);
}

test_case(sir_container_unordered__map_trivial)
{
	std::unordered_map<std::uint32_t, float> c { {10, 3.1415f}, {15, 6.7123f}, {1, -24.444f} };
	test_container(c, false);
}

test_case(sir_container_unordered__map_custom__key)
{
	std::unordered_map<test_type, float> c { {{15u}, 3.1415f}, {{65535u}, 23.451f}, {{1234567u}, -29.231f} };
	test_container(c, false);
}

test_case(sir_container_string)
{
	std::string c = "Hello, world!";
	test_container(c);
}
