#pragma once

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

#include <vector>

namespace psemek::ui
{

	struct selector
		: element
	{
		selector();
		~selector() override;

		void set_parent(element * parent) override;

		children_range children() const override { return children_range_; }

		struct shape const & shape() const override { return shape_; }

		void reshape(math::box<float, 2> const & box) override;

		math::box<float, 2> size_constraints() const override;

		bool on_event(mouse_move const & e) override;
		bool on_event(mouse_click const & e) override;

		virtual std::size_t size() const;
		virtual void resize(std::size_t size);
		virtual std::size_t add(std::shared_ptr<element> child);
		virtual std::shared_ptr<element> get(std::size_t index) const;
		virtual void set_submenu(std::size_t index, std::shared_ptr<selector> submenu);
		virtual std::shared_ptr<selector> submenu(std::size_t index) const;
		virtual void clear();

		virtual math::interval<float> y_range(std::size_t index) const;

		using callback_type = std::function<void(std::size_t)>;

		virtual std::optional<std::size_t> selected() const;
		virtual void on_selected(callback_type callback);
		virtual void on_mouseover(std::function<void(std::optional<std::size_t>)> callback);

		virtual callback_type on_selected() const;

		virtual math::box<float, 2> const & item_box(std::size_t index) const { return child_boxes_[index]; }

	protected:

		// extra width for each element with a submenu
		virtual int submenu_extra() const { return 0; }

		// extra distance between successive elements
		virtual int y_extra() const { return 0; }

		virtual void on_submenu(std::size_t index);

		virtual void release_submenu();

	private:
		std::vector<std::shared_ptr<element>> children_;
		std::vector<element *> children_range_;

		box_shape shape_;
		std::vector<std::shared_ptr<selector>> submenu_;
		std::optional<std::size_t> active_submenu_;
		float active_submenu_y_ = 0.f;

		std::vector<math::box<float, 2>> child_boxes_;

		std::optional<std::size_t> selected_;

		callback_type callback_;
		std::function<void(std::optional<std::size_t>)> mouseover_callback_;
	};

	bool spawn_selector(element * root, std::shared_ptr<selector> selector, math::point<float, 2> const & position, std::function<void()> on_canceled = nullptr);

}
