﻿#include <core/ui_window.h>
#include <debugger/ui_debug.h>
#include <util/ui_time_meter.h>
#include <control/ui_viewport.h>
#include <container/pod_vector.h> 
#include <core/ui_window_manager.h>


#include <cassert>
#include <algorithm>

//namespace LongUI { namespace impl {
//    // find viewport
//    UIViewport* find_viewport(
//        const POD::Vector<UIViewport*>&, 
//        const char*
//    ) noexcept;
//}}

namespace LongUI {
    // 视口?
    bool IsViewport(const UIControl&) noexcept;
    // all
    struct AllWindows : Node<AllWindows> {};
}

/// <summary>
/// private data/func for WndMgr
/// </summary>
struct LongUI::CUIWndMgr::Private {
    // windows cast
    static inline auto cast(CUIWindow* windows) noexcept {
        assert(windows);
        return reinterpret_cast<AllWindows*>(&windows->m_oListNode);
    }
    // windows cast
    static inline auto cast(AllWindows* windows) noexcept {
        assert(windows);
        constexpr size_t of = offsetof(CUIWindow, m_oListNode);
        const auto addr = reinterpret_cast<char*>(windows);
        return reinterpret_cast<CUIWindow*>(addr - of);
    }
    // end iterator
    auto end()noexcept ->Node<AllWindows>::Iterator {;
        return { static_cast<AllWindows*>(&tail) };
    }
    // begin iterator
    auto begin()noexcept->Node<AllWindows>::Iterator {
        return { static_cast<AllWindows*>(head.next) };
    }
    // windows
    using WindowVector = POD::Vector<CUIWindow*>;
    // viewports
    using ViewportVector = POD::Vector<UIViewport*>;
    // ctor
    Private() noexcept;
    // dtor
    ~Private() noexcept {}
    // high time-meter
    CUITimeMeterH       timemeter;
    // all window list - head
    Node<AllWindows>    head;
    // all window list - tail
    Node<AllWindows>    tail;
    // subviews
    Node<UIControl>     subviews;
#if 0
    // windows list for updating
    WindowVector        windowsu;
    // windows list for rendering
    WindowVector        windowsr;
    // subviewports
    ViewportVector      subviewports;
#endif
};


/// <summary>
/// Initializes a new instance of the <see cref="PrivateWndMgr"/> struct.
/// </summary>
LongUI::CUIWndMgr::Private::Private() noexcept {
    head = { nullptr, static_cast<AllWindows*>(&tail) };
    tail = { static_cast<AllWindows*>(&head), nullptr };
    const auto ptr = static_cast<UIControl*>(&subviews);
    subviews = { ptr, ptr };
}


/// <summary>
/// Moves the sub view to global.
/// </summary>
/// <param name="vp">The vp.</param>
/// <returns></returns>
void LongUI::CUIWndMgr::MoveToGlobalSubView(UIViewport& sub) noexcept {
    // 之前的数据
    if (sub.prev) static_cast<UIViewport*>(sub.prev)->next = sub.next;
    if (sub.next) static_cast<UIViewport*>(sub.next)->prev = sub.prev;
    // 清除数据
    sub.RefWindow().m_pParent = nullptr;
    // 连接前后节点
    auto& subviews = wm().subviews;
    static_cast<UIViewport*>(subviews.prev)->next = &sub;
    sub.prev = static_cast<UIViewport*>(subviews.prev);
    sub.next = static_cast<UIControl*>(&subviews);
    subviews.prev = &sub;
}

/// <summary>
/// Finds the sub viewport with uid-string.
/// </summary>
/// <param name="name">The name.</param>
/// <returns></returns>
auto LongUI::CUIWndMgr::FindSubViewportWithUID(const char* name)const noexcept->UIViewport*{
    auto& subviews = wm().subviews;
    return UIViewport::FindSubViewport(subviews.next, subviews, name);
}



/// <summary>
/// Ends this instance.
/// </summary>
/// <returns></returns>
auto LongUI::CUIWndMgr::end()noexcept->Iterator {
    return { static_cast<CUIWindow*>(&m_oTail) };
}
/// <summary>
/// Begins this instance.
/// </summary>
/// <returns></returns>
auto LongUI::CUIWndMgr::begin()noexcept->Iterator {
    return { static_cast<CUIWindow*>(m_oHead.next) }; 
}

/// <summary>
/// Initializes a new instance of the <see cref="CUIWndMgr"/> class.
/// </summary>
LongUI::CUIWndMgr::CUIWndMgr(Result& out) noexcept {
    // 节点
    m_oHead = { nullptr, static_cast<CUIWindow*>(&m_oTail) };
    m_oTail = { static_cast<CUIWindow*>(&m_oHead), nullptr };
    // 静态检查
    enum {
        wm_size = sizeof(Private),
        pw_size = impl::private_wndmgr<sizeof(void*)>::size,

        wm_align = alignof(Private),
        pw_align = impl::private_wndmgr<sizeof(void*)>::align,
    };
    static_assert(wm_size == pw_size, "must be same");
    static_assert(wm_align == pw_align, "must be same");
    impl::ctor_dtor<Private>::create(&wm());
    // 开始计时
    wm().timemeter.Start();
    // 更新显示频率
    this->refresh_display_frequency();
    // 已经发生错误
    //if (!out) return;
}


/// <summary>
/// Deletes all window.
/// </summary>
/// <returns></returns>
void LongUI::CUIWndMgr::delete_all_window() noexcept {
    auto& subviews = wm().subviews;
    // 释放sub列表?
    auto node = subviews.next;
    while (node != &subviews) {
        assert(LongUI::IsViewport(*node));
        const auto view = static_cast<UIViewport*>(node);
        node = view->next;
        delete view;
    }
    // 删除还存在的窗口
    while (m_oHead.next != &m_oTail)
        m_oTail.prev->Delete();
}

/// <summary>
/// Finalizes an instance of the <see cref="CUIWndMgr"/> class.
/// </summary>
/// <returns></returns>
LongUI::CUIWndMgr::~CUIWndMgr() noexcept {
    assert(m_oHead.next == &m_oTail);
    // 析构掉
    wm().~Private();
}

/// <summary>
/// Updates the delta time.
/// </summary>
/// <returns></returns>
auto LongUI::CUIWndMgr::update_delta_time() noexcept -> float {
    // TODO: 固定时间更新频率
    auto& meter = wm().timemeter;
    const auto time = meter.Delta_s<double>();
    meter.MovStartEnd();
    return static_cast<float>(time);
}


/// <summary>
/// Adds the topwindow.
/// </summary>
/// <param name="window">The window.</param>
/// <returns></returns>
void LongUI::CUIWndMgr::add_topwindow(CUIWindow& window) noexcept {
    // 连接前后节点
    m_oTail.prev->next = &window;
    window.prev = m_oTail.prev;
    window.next = static_cast<CUIWindow*>(&m_oTail);
    m_oTail.prev = &window;
}

/// <summary>
/// Adds to allwindow.
/// </summary>
/// <param name="window">The window.</param>
/// <returns></returns>
void LongUI::CUIWndMgr::add_to_allwindow(CUIWindow& window) noexcept {
    const auto allwin = Private::cast(&window);
    auto& tail = wm().tail;
    // 添加到全表中
    tail.prev->next = allwin;
    allwin->prev = tail.prev;
    allwin->next = static_cast<AllWindows*>(&tail);
    tail.prev = allwin;
}

/// <summary>
/// Removes from allwindow.
/// </summary>
/// <param name="window">The window.</param>
/// <returns></returns>
void LongUI::CUIWndMgr::remove_from_allwindow(CUIWindow & window) noexcept {
    const auto allwin = Private::cast(&window);
    // 未初始化就被删除的话节点为空
    if (allwin->prev) {
        // 连接前后节点
        allwin->prev->next = allwin->next;
        allwin->next->prev = allwin->prev;
        allwin->prev = allwin->next = nullptr;
    }
}


/// <summary>
/// Pres the render windows.
/// </summary>
/// <param name="itr">The itr.</param>
/// <param name="endi">The endi.</param>
/// <returns></returns>
void LongUI::CUIWndMgr::before_render_windows(Iterator itr, const Iterator endi) noexcept {
    // XXX: 优化

    // 进行渲染预处理, 途中不该会出现节点变化(下帧执行)
    while (itr != endi) {
        // 执行预处理
        itr->PrepareRender();
        // 预处理子窗口
        before_render_windows(itr->begin(), itr->end());
        // 递进
        ++itr;
    }
}

/// <summary>
/// Renders the windows.
/// </summary>
/// <param name="itr">The itr.</param>
/// <param name="endi">The endi.</param>
/// <returns></returns>
auto LongUI::CUIWndMgr::render_windows(const Iterator begini, const Iterator endi) noexcept -> Result {
    auto itr = begini;
    // 渲染途中不该会出现节点变化(下帧执行)
    while (itr != endi) {
        // 执行渲染
        auto hr = itr->Render();
        // 渲染子窗口
        if (hr) hr = render_windows(itr->begin(), itr->end());
        // 失败
        if (!hr) return hr;
        // 递进
        ++itr;
    }
    // 成功
    return Result{ Result::RS_OK };
}

/// <summary>
/// Recreates the windows.
/// </summary>
/// <param name="begini">The begini.</param>
/// <param name="endi">The endi.</param>
/// <returns></returns>
auto LongUI::CUIWndMgr::recreate_windows() noexcept -> Result {
    Result hr = { Result::RS_OK };
    // 第一次遍历
    const auto traverse_1st = [](Private& primpl) noexcept {
        for (auto& aw : primpl) {
            const auto window = Private::cast(&aw);
            assert(window);
            // 释放所有窗口的设备相关数据
            window->ReleaseDeviceData();
            // 标记全刷新
            window->MarkFullRendering();
        }
    };
    // 第一次遍历
    const auto traverse_2nd = [&](Private& primpl) noexcept {
        for (auto& aw : primpl) {
            const auto window = Private::cast(&aw);
            assert(window);
            // 记录最新的错误数据
            const auto code = window->RecreateDeviceData();
            if (!code) hr = code;
        }
    };
    // 正式处理
    traverse_1st(wm());
    traverse_2nd(wm());
    return hr;
}


#if 0
/// <summary>
/// Refreshes the window minsize.
/// </summary>
/// <param name="itr">The itr.</param>
/// <param name="endi">The endi.</param>
/// <returns></returns>
void LongUI::CUIWndMgr::refresh_window_minsize() noexcept {
    auto& primpl = wm();
    // 处理途中不该会出现节点变化(下帧执行)
    for (auto& aw : primpl) {
        const auto window = Private::cast(&aw);
        assert(window);
        // 需要刷新最小大小
        if (window->m_bMinsizeList) {
            window->m_bMinsizeList = false;
            UIViewport& root = window->RefViewport();
            alignas(uint64_t) const auto minsize1 = root.GetMinSize();
            UIControlPrivate::RefreshMinSize(root);
            alignas(uint64_t) const auto minsize2 = root.GetMinSize();
            // 修改了
            const auto a = reinterpret_cast<const uint64_t&>(minsize1);
            const auto b = reinterpret_cast<const uint64_t&>(minsize2);
            static_assert(sizeof(minsize1) == sizeof(a), "must be same");
            // XXX: 最小大小?
            if (a != b) root.NeedUpdate(Reason_ChildLayoutChanged);
            //if (a != b) root.NeedUpdate(Reason_MinSizeChanged);
        }
    }
}
#endif


// private control
#include "../private/ui_private_control.h"

/// <summary>
/// Refreshes the window world.
/// </summary>
/// <returns></returns>
void LongUI::CUIWndMgr::refresh_window_world() noexcept {
    auto& primpl = wm();
    // 处理途中不该会出现节点变化(下帧执行)
    for (auto& aw : primpl) {
        const auto window = Private::cast(&aw);
        assert(window);
        // 检测每个窗口的最小世界修改
        if (const auto ctrl = window->m_pMiniWorldChange) {
            window->m_pMiniWorldChange = nullptr;
            if (ctrl->IsTopLevel())
                UIControlPrivate::UpdateWorldTop(*ctrl, window->GetAbsoluteSize());
            else
                UIControlPrivate::UpdateWorld(*ctrl);
        }
    }
}


/// <summary>
/// Closes the helper.
/// </summary>
/// <param name="wnd">The WND.</param>
/// <returns></returns>
void LongUI::CUIWndMgr::close_helper(CUIWindow& wnd) noexcept {
    // 隐藏该窗口
    wnd.HideWindow();
    // 直接退出?
    if (wnd.config & CUIWindow::Config_QuitOnClose) 
        return this->exit();
    // 删除窗口
    if (wnd.config & CUIWindow::Config_DeleteOnClose)
        wnd.RefViewport().DeleteLater();
    // 最后一个窗口关闭即退出?
    if (this->is_quit_on_last_window_closed()) {
        // 遍历窗口
        for (auto& x : (*this)) {
            // 不考虑工具窗口
            if (x.config & CUIWindow::Config_ToolWindow) continue;
            // 有一个在就算了
            if (x.IsVisible()) return;
        }
        // 退出程序
        this->exit();
    }
}

// ----------------------------------------------------------------------------

#include <Windows.h>

/// <summary>
/// Refresh_display_frequencies this instance.
/// 刷新屏幕刷新率
/// </summary>
/// <returns></returns>
void LongUI::CUIWndMgr::refresh_display_frequency() noexcept {
    // 获取屏幕刷新率
    DEVMODEW mode; std::memset(&mode, 0, sizeof(mode));
    ::EnumDisplaySettingsW(nullptr, ENUM_CURRENT_SETTINGS, &mode);
    m_dwDisplayFrequency = static_cast<uint32_t>(mode.dmDisplayFrequency);
    // 稍微检查
    if (!m_dwDisplayFrequency) {
        LUIDebug(Error)
            << "EnumDisplaySettingsW failed: "
            << "got zero for DEVMODEW::dmDisplayFrequency"
            << ", now assume as 60Hz"
            << LongUI::endl;
        m_dwDisplayFrequency = 60;
    }
}

/// <summary>
/// Sleeps for vblank.
/// </summary>
/// <returns></returns>
void LongUI::CUIWndMgr::sleep_for_vblank() noexcept {
    // XXX: vblank
    ::Sleep(16);
}

