#include <catch2/catch.hpp>
#include <alib/set>
#include <alib/algorithm>
#include <alib/vector>

namespace {
	class Moveable {
		int& m_moves;
		int& m_copies;

		public:
		Moveable(int& moves, int& copies) : m_moves(moves), m_copies(copies) {
			m_moves = 0;
			m_copies = 0;
		}

		Moveable(const Moveable& src) : m_moves(src.m_moves), m_copies(src.m_copies) {
			m_copies++;
		}

		Moveable(Moveable&& src) : m_moves(src.m_moves), m_copies(src.m_copies) {
			m_moves++;
		}

		bool operator<(const Moveable&) const {
			return false;
		}
	};

	static ext::set<Moveable> makeSet ( int & moves, int & copies ) {
		ext::set<Moveable> set;
		set.insert ( Moveable(moves, copies) );
		return set;
	}
}

TEST_CASE ( "Set", "[unit][std][container]" ) {
	SECTION ( "Set difference" ) {
		{
			int first[] = {5,10,15,20,25};
			int second[] = {50,40,30,20,10};
			ext::vector<int> v(10);                      // 0  0  0  0  0  0  0  0  0  0
			ext::vector<int>::iterator it;

			std::sort (first,first+5);     //  5 10 15 20 25
			std::sort (second,second+5);   // 10 20 30 40 50

			it=std::set_difference (first, first+5, second, second+5, v.begin());
			v.resize(it-v.begin());

			CHECK(5  == v[0]);
			CHECK(15 == v[1]);
			CHECK(25 == v[2]);
		}
		{
			ext::set<int> first = {1};
			ext::set<int> second = {1, 2, 3};

			ext::set<int> firstMinusSecond;
			ext::set<int> secondMinusFirst;

			std::set_difference (first.begin(), first.end(), second.begin(), second.end(), std::inserter(firstMinusSecond, firstMinusSecond.end()));
			std::set_difference (second.begin(), second.end(), first.begin(), first.end(), std::inserter(secondMinusFirst, secondMinusFirst.end()));

			CHECK(firstMinusSecond.size() == (size_t) 0u);
			CHECK(secondMinusFirst.size() == (size_t) 2u);
		}
	}

	SECTION ( "Move" ) {
		{
			int moves;
			int copies;

			ext::set<Moveable> set2;

			for(Moveable moveable : ext::make_mover ( makeSet ( moves, copies ) ) ) {
				set2.insert(std::move(moveable));
			}

			CHECK(copies == 0);
		}
		{
			int moves;
			int copies;

			ext::set<Moveable> set;
			set.insert ( Moveable(moves, copies) );
			ext::set<Moveable> set2;

			set2.insert ( ext::make_mover ( set ).begin ( ), ext::make_mover ( set ).end ( ) );

			CHECK(copies == 0);
		}
	}
}
