#pragma once
/**
 * @file mpanel_widget.h
 * @brief 定义可容纳多个子组件的面板组件基类
 *
 * 本文件定义了mpanel_widget模板类，这是一种可以容纳多个子组件的面板组件。
 * 通过模板参数SlotType可以自定义子组件插槽的具体行为。
 */

#include "mwidget.h"
#include "slot_util.h"

/**
 * @struct mpanel_widget_slot
 * @brief 面板组件的插槽结构，管理子组件
 *
 * @tparam T 插槽的具体类型，通常是派生自此模板的类
 *
 * 提供了对子组件的内容管理功能。
 * 使用SLOT宏来定义插槽的标准功能。
 */
template<typename T>
struct mpanel_widget_slot {
	/**
	 * @brief 获取当前实例的引用，转换为具体类型T
	 * @return 当前实例的引用，类型为T&
	 */
	auto& me() {
		return static_cast<T&>(*this);
	}
	std::weak_ptr<mwidget> slot_owner;

	operator auto() const { return slot_owner.lock(); }

	// 插槽功能宏 - 定义内容管理
	SLOT_CONTENT()
};

/**
 * @class mpanel_widget
 * @brief 可布局多个子组件的面板组件基类
 *
 * @tparam SlotType 插槽类型，控制如何管理子组件
 *
 * 这个类是所有需要容纳多个子组件的面板组件的基类。
 * 它提供了子组件的管理和查询功能。
 */
template<typename SlotType>
class mpanel_widget : public mwidget {
public:
	using slot_type = SlotType;

	//-------------- 绘制 --------------

	/**
	 * @brief 绘制组件
	 * @param in_context 绘制上下文
	 *
	 * 基类实现为空，因为面板组件通常不需要自己绘制，而是依赖子组件的绘制。
	 */
	void on_paint(mirage_paint_context& in_context) override {}

	void cache_all_children_desired_size(float in_layout_scale_multiplier, bool in_force = false) const;

	//-------------- 子项管理 --------------

	/**
	 * @brief 添加新的子组件插槽
	 * @return 新添加的插槽引用，允许链式调用设置插槽属性
	 *
	 * 创建并添加一个新的子组件插槽到面板中。
	 */
	auto& add_slot() {
		auto& slot        = slots_.emplace_back();
		auto  shared_this = shared_from_this();

		slot.slot_owner = shared_this;

		const auto& child_widget = slot.get();
		child_widget->init();
		child_widget->set_parent(shared_this);
		invalidate(invalidate_reason::all);
		return slot;
	}

	template<typename... Args>
	auto& add_slot(Args&&... in_args) {
		auto& slot        = slots_.emplace_back(std::forward<Args>(in_args)...);
		auto  shared_this = shared_from_this();

		slot.slot_owner = shared_this;

		const auto& child_widget = slot.get();
		child_widget->init();
		child_widget->set_parent(shared_this);
		invalidate(invalidate_reason::all);
		return slot;
	}
	auto& push_slot(const SlotType& in_slot) {
		auto& slot        = slots_.emplace_back(in_slot);
		auto  shared_this = shared_from_this();

		slot.slot_owner = shared_this;

		const auto& child_widget = slot.get();
		child_widget->init();
		child_widget->set_parent(shared_this);
		invalidate(invalidate_reason::all);
		return slot;
	}

	const auto& get_slots() const {
		return slots_;
	}
private:
	std::vector<SlotType> slots_;
};

template<typename SlotType>
void mpanel_widget<SlotType>::cache_all_children_desired_size(float in_layout_scale_multiplier, bool in_force) const {
	for (const auto& slot: slots_) {
		const auto& ptr = slot.get();
		ptr->cache_desired_size(in_layout_scale_multiplier, in_force);
	}
}
