#include "TestFramework.h"
#include "TestUtils.h"
#include "TestRenderUtils.h"

#include "RectangleNode.h"
#include "CircleNode.h"
#include "LineNode.h"
#include "PathNode.h"
#include "PolygonNode.h"

void addRect(const Point& loc, std::vector<std::unique_ptr<MaterialNode> >& nodes, double radius = 0.0)
{
	auto node = std::make_unique<RectangleNode>(loc, 150.0, 100.0);
	node->setRadius(radius);
	nodes.push_back(std::move(node));
}

void addCircle(const Point& loc, std::vector<std::unique_ptr<MaterialNode> >& nodes, double minorRadius = 0.0)
{
	const auto radius = 50.0;
	auto centre_loc = loc;
	centre_loc.move(0.0, radius);

	auto node = std::make_unique<CircleNode>(centre_loc, radius);

	if (minorRadius != 0.0)
	{
		node->setMinorRadius(minorRadius);
	}

	nodes.push_back(std::move(node));
}

void addLine(const Point& loc, std::vector<std::unique_ptr<MaterialNode> >& nodes)
{
	std::vector<Point> points = { Point(150.0, 100.0) };
	auto node = std::make_unique<LineNode>(loc, points);
	nodes.push_back(std::move(node));
}

void addPath(const Point& loc, const std::string& path, std::vector<std::unique_ptr<MaterialNode> >& nodes)
{
	auto node = std::make_unique<PathNode>(loc, path);
	nodes.push_back(std::move(node));
}

void addPolygon(const Point& loc, std::vector<std::unique_ptr<MaterialNode> >& nodes)
{
	auto p0 = Point{ 0.0, 0.0 };
	auto p1 = Point{ 150.0, 0.0 };
	auto p2 = Point{ 75.0, 75.0 };

	auto node = std::make_unique<PolygonNode>(loc);
	node->setPoints({ p0, p1, p2 });
	nodes.push_back(std::move(node));
}

void addShapes(const Point& start_loc, std::vector<std::unique_ptr<MaterialNode> >& nodes, bool use_fill = false)
{
	auto loc = start_loc;

	auto fill_color = Color(200, 0, 200);

	addRect(loc, nodes);

	loc.move(250, 0);
	addCircle(loc, nodes);

	loc.move(100, 0);
	addLine(loc, nodes);

	loc.move(200, 0);
	addPolygon(loc, nodes);

	loc = Point(10, 150);
	addRect(loc, nodes, 10.0);

	loc.move(250, 0);
	addCircle(loc, nodes, 75.0);

	loc.move(100, 0);
	addPath(loc, "M0 0 h150 v100 h-150Z", nodes);

	loc = Point(10, 300);
	addPath(loc, "M0 0 h150 q50 50 0 100 h-150Z", nodes);

	loc.move(250, 0);
	addPath(loc, "M0 0 h150 c25 25 25 75 0 100 h-150Z", nodes);

	loc.move(250, 0);
	addPath(loc, "M0 0 h150 a50 50 0 0 1 0 100 h-150Z", nodes);

	if (use_fill)
	{
		for (auto& node : nodes)
		{
			node->setFillColor(fill_color);
		}
	}
}

TEST_CASE(TestD2dOffScreenRendering_Outlines, "graphics")
{
	TestRenderer renderer(800, 800);

	std::vector<std::unique_ptr<MaterialNode> > nodes;
	
	auto loc = Point(10, 10);

	addShapes(loc, nodes, false);

	auto scene = renderer.getScene();
	for (const auto& node : nodes)
	{
		scene->addNode(node.get());
	}

	renderer.writeSvg(TestUtils::getTestOutputDir(__FILE__) / "outlines.svg");
	renderer.write(TestUtils::getTestOutputDir(__FILE__) / "outlines.png");
};

TEST_CASE(TestD2dOffScreenRendering_Fill, "graphics")
{
	TestRenderer renderer(800, 800);

	std::vector<std::unique_ptr<MaterialNode> > nodes;

	auto loc = Point(10, 10);

	addShapes(loc, nodes, true);

	auto scene = renderer.getScene();
	for (const auto& node : nodes)
	{
		scene->addNode(node.get());
	}

	renderer.writeSvg(TestUtils::getTestOutputDir(__FILE__) / "fill.svg");
	renderer.write(TestUtils::getTestOutputDir(__FILE__) / "fill.png");
};