#include "mwindow.h"

#include "geometry/dpi_helper.h"
#include "platform_window/platform_window.h"
#include "render/render_context.h"

#include "mwindow_impl.cpp"

// 静态成员初始化
std::vector<std::weak_ptr<mwindow>> mwindow::windows_;


struct mwindow_make_shared_enabler : public mwindow {
	mwindow_make_shared_enabler(const Eigen::Vector2i& in_size, const std::wstring& in_title) :
		mwindow(in_size.x(), in_size.y(), in_title.c_str()) {}
};

//==============================================================================
// mwindow 类实现
//==============================================================================

std::shared_ptr<mwindow> mwindow::create(const Eigen::Vector2i& in_size, const std::wstring& in_title) {
	auto window = std::make_shared<mwindow_make_shared_enabler>(in_size, in_title);
	windows_.push_back(window);
	return window;
}

mwindow::mwindow(int32_t width, int32_t height, const wchar_t* title)
    : pimpl_(std::make_unique<impl>(this, width, height, title))
{
}

mwindow::~mwindow() = default;

void mwindow::show() {
    pimpl_->show();
}

void mwindow::hide() {
    pimpl_->hide();
}

void mwindow::close() {
    pimpl_->close();
}

void mwindow::update() {
    pimpl_->update();
}

platform_window* mwindow::get_platform_window() const {
    return pimpl_->get_platform_window();
}

void mwindow::set_content(const std::shared_ptr<mwidget>& content) {
    pimpl_->set_content(content);
}

std::shared_ptr<mwidget> mwindow::get_content() const {
    return pimpl_->get_content();
}

float mwindow::get_dpi_scale() const {
    return pimpl_->get_dpi_scale();
}

transform2d mwindow::get_local_to_screen_transform() const {
    return pimpl_->get_local_to_screen_transform();
}

transform2d mwindow::get_local_to_window_transform() const {
    return pimpl_->get_local_to_window_transform();
}

geometry_t mwindow::get_window_geometry_in_screen() const {
    return pimpl_->get_window_geometry_in_screen();
}

geometry_t mwindow::get_window_geometry_in_window() const {
    return pimpl_->get_window_geometry_in_window();
}

void mwindow::invalidate_all() {
    pimpl_->invalidate_all();
}

void mwindow::invalidate_rect(const Eigen::Vector2f& rect) {
    pimpl_->invalidate_rect(rect);
}

const mirage_window_state& mwindow::get_render_state() const {
    return pimpl_->get_render_state();
}

void mwindow::rebuild_swapchain() {
    pimpl_->rebuild_swapchain();
}

const std::vector<std::weak_ptr<mwindow>>& mwindow::get_all() {
    return windows_;
}

Eigen::Vector2f mwindow::compute_desired_size(float scale_multiplier) const {
    return get_platform_window()->get_window_frame_size().cast<float>();
}

void mwindow::arrange_children(const geometry_t& allotted_geometry) {
    auto content = get_content();
    if (content) {
        auto child_geo = allotted_geometry.make_child(
            {0, 0},
            get_platform_window()->get_window_frame_size().cast<float>()
        );
        content->set_geometry(child_geo);
    }
}

void mwindow::on_paint(mirage_paint_context& context) {
    auto content = get_content();
    if (content) {
        content->on_paint(context);
    }
}
