#include <psemek/ui/style.hpp>
#include <psemek/ui/element.hpp>

namespace psemek::ui
{

	namespace
	{

		template <typename T>
		void merge(std::optional<T> & dst, std::optional<T> const & src)
		{
			if (!dst) dst = src;
		}

		template <typename T>
		void merge(std::shared_ptr<T> & dst, std::shared_ptr<T> const & src)
		{
			if (!dst) dst = src;
		}

		template <typename T>
		void scale(T & dst, float factor)
		{
			if (dst) dst = static_cast<T>(std::ceil((*dst) * factor));
		}

		template <typename T, std::size_t N>
		void scale(std::optional<math::vector<T, N>> & dst, float factor)
		{
			if (dst)
				for (std::size_t i = 0; i < N; ++i)
					(*dst)[i] = static_cast<T>(std::ceil((*dst)[i] * factor));
		}

	}

	style::style(style const & other)
	{
		merge(*this, other);
	}

	void style::on_changed()
	{
		for (auto e : use_as_style)
			e->style_updated();

		for (auto e : use_as_own_style)
			e->own_style_updated();
	}

	void merge(style & dst, style const & src)
	{
		merge(dst.scale, src.scale);
		merge(dst.bg_color, src.bg_color);
		merge(dst.fg_color, src.fg_color);
		merge(dst.highlight_color, src.highlight_color);
		merge(dst.action_color, src.action_color);
		merge(dst.action_offset, src.action_offset);
		merge(dst.border_color, src.border_color);
		merge(dst.border_width, src.border_width);
		merge(dst.bevel_light_color, src.bevel_light_color);
		merge(dst.bevel_dark_color, src.bevel_dark_color);
		merge(dst.bevel_type, src.bevel_type);
		merge(dst.bevel_width, src.bevel_width);
		merge(dst.axis_color, src.axis_color);
		merge(dst.ref_height, src.ref_height);
		merge(dst.shadow_offset, src.shadow_offset);
		merge(dst.shadow_color, src.shadow_color);
		merge(dst.inner_margin, src.inner_margin);
		merge(dst.outer_margin, src.outer_margin);
		merge(dst.text_color, src.text_color);
		merge(dst.text_scale, src.text_scale);
		merge(dst.text_style, src.text_style);
		merge(dst.text_shadow_offset, src.text_shadow_offset);
		merge(dst.link_color, src.link_color);
		merge(dst.link_style, src.link_style);
		merge(dst.link_hover_color, src.link_hover_color);
		merge(dst.link_hover_style, src.link_hover_style);
		merge(dst.link_click_color, src.link_click_color);
		merge(dst.link_click_style, src.link_click_style);
		merge(dst.font, src.font);
		merge(dst.bold_font, src.bold_font);
	}

	style scale(style const & s, float factor)
	{
		style result = s;
		scale(result.scale, factor);
		scale(result.action_offset, factor);
		scale(result.border_width, factor);
		scale(result.ref_height, factor);
		scale(result.shadow_offset, factor);
		scale(result.inner_margin, factor);
		scale(result.outer_margin, factor);
		scale(result.text_scale, factor);
		scale(result.text_shadow_offset, factor);
		return result;
	}

	style default_style()
	{
		style s;

		s.scale = 1;

		s.bg_color = {95, 95, 95, 255};
		s.fg_color = {127, 127, 127, 255};
		s.highlight_color = {159, 159, 159, 255};
		s.action_color = {63, 63, 63, 255};

		s.action_offset = {1, 1};

		s.border_color = {255, 255, 255, 255};
		s.border_width = 3;

		s.bevel_light_color = {159, 159, 159, 255};
		s.bevel_dark_color = {63, 63, 63, 63};
		s.bevel_type = bevel_type::up;
		s.bevel_width = 1;

		s.axis_color = {255, 255, 255, 255};

		s.ref_height = 22;

		s.shadow_offset = {1, 1};
		s.shadow_color = {0, 0, 0, 255};

		s.inner_margin = {5, 5};
		s.outer_margin = 10;

		s.text_color = {255, 255, 255, 255};
		s.text_scale = 1;
		s.text_style = text_style{};
		s.text_shadow_offset = {1, 1};

		s.link_color = {0, 0, 255, 255};
		s.link_style = text_style{};

		s.link_hover_color = {127, 127, 255, 255};
		s.link_hover_style = text_style{};

		s.link_click_color = {0, 0, 127, 255};
		s.link_click_style = text_style{};

		return s;
	}

}
