#pragma once

#include <psemek/vecr/sdf.hpp>
#include <psemek/math/point.hpp>
#include <psemek/math/box.hpp>

namespace psemek::vecr
{

	template <typename Shape>
	struct mirror
	{
		Shape shape;
		math::point<float, 2> origin{0.f, 0.f};
		math::vector<float, 2> axis{1.f, 0.f};
	};

	template <typename Shape>
	sdf_sample sdf(mirror<Shape> const & s, math::point<float, 2> const & p)
	{
		sdf_sample result;

		auto r = p - s.origin;
		auto d = math::dot(r, s.axis);
		if (d < 0.f)
		{
			result = sdf(s.shape, p);
		}
		else
		{
			result = sdf(s.shape, p - (2.f * d) * s.axis);
			result.gradient -= (2.f * math::dot(result.gradient, s.axis)) * s.axis;
		}

		return result;
	}

	template <typename Shape>
	math::box<float, 2> bbox(mirror<Shape> const & s)
	{
		auto sbox = bbox(s.shape);

		if (!math::isfinite(sbox))
			return math::box<float, 2>::full();

		math::box<float, 2> result = sbox;

		for (int x = 0; x <= 1; ++x)
		{
			for (int y = 0; y <= 1; ++y)
			{
				auto p = sbox.corner(x, y);
				p = p - (2.f * math::dot(s.axis, p - s.origin)) * s.axis;
				result |= p;
			}
		}

		return result;
	}

}
