// GridTest.cpp
//
//     Created on: 29. 03. 2018
//         Author: Jan Uhlik
//    Modified by:
//
// Copyright (c) 2017 Czech Technical University in Prague | Faculty of Information Technology. All rights reserved.
// Git repository: https://gitlab.fit.cvut.cz/algorithms-library-toolkit/automata-library

#include <catch2/catch.hpp>
#include <grid/GridClasses.hpp>

using namespace grid;


TEST_CASE ( "GridTest", "[unit][graph][grid]" ) {
	SECTION ( "Grid4" ) {
		grid::SquareGrid4<> grid4(10, 10);
		using node_type = decltype(grid4)::node_type;
		using edge_type = decltype(grid4)::edge_type;

		ext::set<node_type> ref1 = {node_type(5, 4), node_type(5, 6), node_type(4, 5), node_type(6, 5)};
		CHECK(ref1 == grid4.successors(node_type(5, 5)));
		ext::vector<edge_type> ref1e = {edge_type(node_type(5, 5), node_type(5, 4)),
			edge_type(node_type(5, 5), node_type(5, 6)),
			edge_type(node_type(5, 5), node_type(4, 5)),
			edge_type(node_type(5, 5), node_type(6, 5))};
		ext::vector<edge_type> res1e = grid4.successorEdges(node_type(5, 5));
		std::sort(ref1e.begin(), ref1e.end());
		std::sort(res1e.begin(), res1e.end());
		CHECK(ref1e == res1e);

		grid4.addObstacle(node_type(5, 5));

		ext::set<node_type> ref2 = {};
		CHECK(ref2 == grid4.successors(node_type(5, 5)));
		ext::vector<edge_type> ref2e = {};
		ext::vector<edge_type> res2e = grid4.successorEdges(node_type(5, 5));
		std::sort(ref2e.begin(), ref2e.end());
		std::sort(res2e.begin(), res2e.end());
		CHECK(ref2e == res2e);

		ext::set<node_type> ref3 = {node_type(4, 6), node_type(4, 4), node_type(3, 5)};
		CHECK(ref3 == grid4.successors(node_type(4, 5)));
		ext::vector<edge_type> ref3e = {edge_type(node_type(4, 5), node_type(4, 6)),
			edge_type(node_type(4, 5), node_type(4, 4)),
			edge_type(node_type(4, 5), node_type(3, 5))};
		ext::vector<edge_type> res3e = grid4.successorEdges(node_type(4, 5));
		std::sort(ref3e.begin(), ref3e.end());
		std::sort(res3e.begin(), res3e.end());
		CHECK(ref3e == res3e);

		ext::set<node_type> ref4 = {node_type(0, 1), node_type(1, 0)};
		CHECK(ref4 == grid4.successors(node_type(0, 0)));
		ext::vector<edge_type> ref4e = {edge_type(node_type(0, 0), node_type(0, 1)),
			edge_type(node_type(0, 0), node_type(1, 0))};
		ext::vector<edge_type> res4e = grid4.successorEdges(node_type(0, 0));
		std::sort(ref4e.begin(), ref4e.end());
		std::sort(res4e.begin(), res4e.end());
		CHECK(ref4e == res4e);
	}

	// ---------------------------------------------------------------------------------------------------------------------

	SECTION ( "Grid8" ) {
		grid::SquareGrid8<> grid8(10, 10);
		using node_type = decltype(grid8)::node_type;
		using edge_type = decltype(grid8)::edge_type;

		ext::set<node_type> ref1 =
		{node_type(5, 4), node_type(5, 6), node_type(4, 5), node_type(6, 5), node_type(4, 6), node_type(6, 6),
			node_type(6, 4), node_type(4, 4)};
		CHECK(ref1 == grid8.successors(node_type(5, 5)));
		ext::vector<edge_type> ref1e = {edge_type(node_type(5, 5), node_type(5, 4)),
			edge_type(node_type(5, 5), node_type(5, 6)),
			edge_type(node_type(5, 5), node_type(4, 5)),
			edge_type(node_type(5, 5), node_type(4, 6)),
			edge_type(node_type(5, 5), node_type(6, 6)),
			edge_type(node_type(5, 5), node_type(6, 4)),
			edge_type(node_type(5, 5), node_type(4, 4)),
			edge_type(node_type(5, 5), node_type(6, 5))};
		ext::vector<edge_type> res1e = grid8.successorEdges(node_type(5, 5));
		std::sort(ref1e.begin(), ref1e.end());
		std::sort(res1e.begin(), res1e.end());
		CHECK(ref1e == res1e);

		grid8.addObstacle(node_type(4, 4));

		ext::set<node_type> ref2 = {};
		CHECK(ref2 == grid8.successors(node_type(4, 4)));
		ext::vector<edge_type> ref2e = {};
		ext::vector<edge_type> res2e = grid8.successorEdges(node_type(4, 4));
		std::sort(ref2e.begin(), ref2e.end());
		std::sort(res2e.begin(), res2e.end());
		CHECK(ref2e == res2e);

		ext::set<node_type>
			ref3 = {node_type(5, 4), node_type(5, 6), node_type(4, 5), node_type(6, 5), node_type(4, 6), node_type(6, 6),
				node_type(6, 4)};
		CHECK(ref3 == grid8.successors(node_type(5, 5)));
		ext::vector<edge_type> ref3e = {edge_type(node_type(5, 5), node_type(5, 4)),
			edge_type(node_type(5, 5), node_type(5, 6)),
			edge_type(node_type(5, 5), node_type(4, 5)),
			edge_type(node_type(5, 5), node_type(4, 6)),
			edge_type(node_type(5, 5), node_type(6, 6)),
			edge_type(node_type(5, 5), node_type(6, 4)),
			edge_type(node_type(5, 5), node_type(6, 5))};
		ext::vector<edge_type> res3e = grid8.successorEdges(node_type(5, 5));
		std::sort(ref3e.begin(), ref3e.end());
		std::sort(res3e.begin(), res3e.end());
		CHECK(ref3e == res3e);

		ext::set<node_type> ref4 = {node_type(0, 1), node_type(1, 0), node_type(1, 1)};
		CHECK(ref4 == grid8.successors(node_type(0, 0)));
		ext::vector<edge_type> ref4e = {edge_type(node_type(0, 0), node_type(0, 1)),
			edge_type(node_type(0, 0), node_type(1, 1)),
			edge_type(node_type(0, 0), node_type(1, 0))};
		ext::vector<edge_type> res4e = grid8.successorEdges(node_type(0, 0));
		std::sort(ref4e.begin(), ref4e.end());
		std::sort(res4e.begin(), res4e.end());
		CHECK(ref4e == res4e);
	}

	// ---------------------------------------------------------------------------------------------------------------------

	SECTION ( "Grid4 Weighted" ) {
		grid::WeightedSquareGrid4<> grid4(10, 10);
		using node_type = decltype(grid4)::node_type;
		using edge_type = decltype(grid4)::edge_type;

		ext::set<node_type> ref1 = {node_type(5, 4), node_type(5, 6), node_type(4, 5), node_type(6, 5)};
		CHECK(ref1 == grid4.successors(node_type(5, 5)));
		ext::vector<edge_type> ref1e = {edge_type(node_type(5, 5), node_type(5, 4), 1),
			edge_type(node_type(5, 5), node_type(5, 6), 1),
			edge_type(node_type(5, 5), node_type(4, 5), 1),
			edge_type(node_type(5, 5), node_type(6, 5), 1)};
		ext::vector<edge_type> res1e = grid4.successorEdges(node_type(5, 5));
		std::sort(ref1e.begin(), ref1e.end());
		std::sort(res1e.begin(), res1e.end());
		CHECK(ref1e == res1e);

		grid4.addObstacle(node_type(5, 5));

		ext::set<node_type> ref2 = {};
		CHECK(ref2 == grid4.successors(node_type(5, 5)));
		ext::vector<edge_type> ref2e = {};
		ext::vector<edge_type> res2e = grid4.successorEdges(node_type(5, 5));
		std::sort(ref2e.begin(), ref2e.end());
		std::sort(res2e.begin(), res2e.end());
		CHECK(ref2e == res2e);

		ext::set<node_type> ref3 = {node_type(4, 6), node_type(4, 4), node_type(3, 5)};
		CHECK(ref3 == grid4.successors(node_type(4, 5)));
		ext::vector<edge_type> ref3e = {edge_type(node_type(4, 5), node_type(4, 6), 1),
			edge_type(node_type(4, 5), node_type(4, 4), 1),
			edge_type(node_type(4, 5), node_type(3, 5), 1)};
		ext::vector<edge_type> res3e = grid4.successorEdges(node_type(4, 5));
		std::sort(ref3e.begin(), ref3e.end());
		std::sort(res3e.begin(), res3e.end());
		CHECK(ref3e == res3e);

		ext::set<node_type> ref4 = {node_type(0, 1), node_type(1, 0)};
		CHECK(ref4 == grid4.successors(node_type(0, 0)));
		ext::vector<edge_type> ref4e = {edge_type(node_type(0, 0), node_type(0, 1), 1),
			edge_type(node_type(0, 0), node_type(1, 0), 1)};
		ext::vector<edge_type> res4e = grid4.successorEdges(node_type(0, 0));
		std::sort(ref4e.begin(), ref4e.end());
		std::sort(res4e.begin(), res4e.end());
		CHECK(ref4e == res4e);
	}

	// ---------------------------------------------------------------------------------------------------------------------

	SECTION ( "Grid8 Weighted" ) {
		grid::WeightedSquareGrid8<> grid8(10, 10);
		using node_type = decltype(grid8)::node_type;
		using edge_type = decltype(grid8)::edge_type;

		ext::set<node_type> ref1 =
		{node_type(5, 4), node_type(5, 6), node_type(4, 5), node_type(6, 5), node_type(4, 6), node_type(6, 6),
			node_type(6, 4), node_type(4, 4)};
		CHECK(ref1 == grid8.successors(node_type(5, 5)));
		ext::vector<edge_type> ref1e = {edge_type(node_type(5, 5), node_type(5, 4), 1),
			edge_type(node_type(5, 5), node_type(5, 6), 1),
			edge_type(node_type(5, 5), node_type(4, 5), 1),
			edge_type(node_type(5, 5), node_type(4, 6), M_SQRT2),
			edge_type(node_type(5, 5), node_type(6, 6), M_SQRT2),
			edge_type(node_type(5, 5), node_type(6, 4), M_SQRT2),
			edge_type(node_type(5, 5), node_type(4, 4), M_SQRT2),
			edge_type(node_type(5, 5), node_type(6, 5), 1)};
		ext::vector<edge_type> res1e = grid8.successorEdges(node_type(5, 5));
		std::sort(ref1e.begin(), ref1e.end());
		std::sort(res1e.begin(), res1e.end());
		CHECK(ref1e == res1e);

		grid8.addObstacle(node_type(4, 4));

		ext::set<node_type> ref2 = {};
		CHECK(ref2 == grid8.successors(node_type(4, 4)));
		ext::vector<edge_type> ref2e = {};
		ext::vector<edge_type> res2e = grid8.successorEdges(node_type(4, 4));
		std::sort(ref2e.begin(), ref2e.end());
		std::sort(res2e.begin(), res2e.end());
		CHECK(ref2e == res2e);

		ext::set<node_type>
			ref3 = {node_type(5, 4), node_type(5, 6), node_type(4, 5), node_type(6, 5), node_type(4, 6), node_type(6, 6),
				node_type(6, 4)};
		CHECK(ref3 == grid8.successors(node_type(5, 5)));
		ext::vector<edge_type> ref3e = {edge_type(node_type(5, 5), node_type(5, 4), 1),
			edge_type(node_type(5, 5), node_type(5, 6), 1),
			edge_type(node_type(5, 5), node_type(4, 5), 1),
			edge_type(node_type(5, 5), node_type(4, 6), M_SQRT2),
			edge_type(node_type(5, 5), node_type(6, 6), M_SQRT2),
			edge_type(node_type(5, 5), node_type(6, 4), M_SQRT2),
			edge_type(node_type(5, 5), node_type(6, 5), 1)};
		ext::vector<edge_type> res3e = grid8.successorEdges(node_type(5, 5));
		std::sort(ref3e.begin(), ref3e.end());
		std::sort(res3e.begin(), res3e.end());
		CHECK(ref3e == res3e);

		ext::set<node_type> ref4 = {node_type(0, 1), node_type(1, 0), node_type(1, 1)};
		CHECK(ref4 == grid8.successors(node_type(0, 0)));
		ext::vector<edge_type> ref4e = {edge_type(node_type(0, 0), node_type(0, 1), 1),
			edge_type(node_type(0, 0), node_type(1, 1), M_SQRT2),
			edge_type(node_type(0, 0), node_type(1, 0), 1)};
		ext::vector<edge_type> res4e = grid8.successorEdges(node_type(0, 0));
		std::sort(ref4e.begin(), ref4e.end());
		std::sort(res4e.begin(), res4e.end());
		CHECK(ref4e == res4e);
	}
}
