#pragma once

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

namespace psemek::ui
{

	struct scroller
		: single_container
	{
		enum class direction
		{
			horizontal,
			vertical,
		};

		virtual direction preferred_direction() const { return preferred_direction_; }
		virtual void set_preferred_direction(direction d);

		virtual bool set_horizontal_scroll(bool enabled);
		virtual bool set_vertical_scroll(bool enabled);

		virtual bool horizontal_scroll() const { return horizontal_; }
		virtual bool vertical_scroll() const { return vertical_; }

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

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

		struct shape const & shape() const override { return shape_; }
		void reshape(math::box<float, 2> const & bbox) override;

		math::box<float, 2> size_constraints() const override;
		math::interval<float> width_constraints(float height) const override;
		math::interval<float> height_constraints(float width) const override;

		virtual float position(direction dir) const;
		virtual void set_position(direction dir, float position, bool animate);

		void update(float dt) override;

		void draw(painter & p) const override;
		void post_draw(painter & p) const override;

	protected:

		virtual void on_scroll(math::vector<float, 2> const & delta);

		virtual float width() const;
		virtual math::box<float, 2> visible_range() const;

		virtual math::box<float, 2> horizontal_box() const;
		virtual math::box<float, 2> vertical_box() const;

		enum state_t
		{
			normal,
			mouseover,
			mousedown,
		};

		state_t vertical_state_ = state_t::normal;
		state_t horizontal_state_ = state_t::normal;

	private:
		box_shape shape_;
		std::optional<math::point<int, 2>> mouse_;

		direction preferred_direction_ = direction::vertical;

		bool horizontal_ = false;
		bool vertical_ = true;

		math::vector<float, 2> shift_{0.f, 0.f};
		math::vector<float, 2> shift_tgt_{0.f, 0.f};

		void clamp_shift();
	};

}
