---
--- Date         : 2020-08-13 14:34:11
--- Author       : LICHAO7
--- LastEditors  : LICHAO7
--- LastEditTime : 2020-08-19 18:15:26
--- Description  : Assemble page
---

local LBaseVehiclePage = ImportScript("ugc_common/script/cases/vehicle/base.page.lua").LBaseVehiclePage;
local Dataset          = ReLoadScript("ugc_common/script/cases/vehicle/dataset.lua");

---
--- 模型选择tab页
---
--- @class AssemblePage
---
AssemblePage = AssemblePage or class("AssemblePage", LBaseVehiclePage);

function AssemblePage:ctor()
    ---
    --- @type LBaseAssemble
    ---
    self.m_model           = nil;
    self.m_oModelBak       = nil;
    self.m_oSocket         = nil;
    self.m_oSocketBak      = nil;
    self.m_oSocketKey      = 1;
    self.m_strSaveName     = KLString:new_local("");
    self.m_io              = ImGui.GetIO();
    self.m_parts           = Dataset.GetParts();
    self.m_bDrawSaveModal  = false;
    self.m_bDrawBackModal  = false;
    self.m_bDrawResetModal = false;
    self.m_nDrawProperty   = 1;
    self.m_bSaved          = true;
    self.m_uiText = {
        LeftSocketText      = util.a2u8("可编辑部位"),
        RightSocketText     = util.a2u8("零件箱"),
        SaveButtonText      = util.a2u8("保存"),
        ResetButtonText     = util.a2u8("重置"),
        PropertyHeaderText  = util.a2u8("可调整的部件属性"),
        SaveNamePanel       = util.a2u8("保存名称"),
        SaveNamePanelTip    = util.a2u8("为新创建的改装配置起个名字吧"),
        SaveNameCanel       = util.a2u8("取消"),
        SaveNameConfirm     = util.a2u8("确认"),
        ResetPanelTip       = util.a2u8("重置后将不可恢复，是否继续"),
        BackPanel           = util.a2u8("返回"),
        BackPanelTip        = util.a2u8("不保存直接返回，将丢失您的编辑数据，是否继续"),
        RefreshPartsBtnText = util.a2u8("刷新"),
        SocketCurAssetPath  = util.a2u8("资源:"),
    };
    self.m_uiSocketName = {
        S_Bone_Wheel_LF = util.a2u8("左前轮"),
        S_Bone_Wheel_RF = util.a2u8("右前轮"),
        S_Bone_Wheel_LR = util.a2u8("左后轮"),
        S_Bone_Wheel_RR = util.a2u8("右后轮"),
        Root            = util.a2u8("车身"),
    };
    self.m_styles = {
        LeftSocketsPanelSize  = ImVec2:new_local(285, 720),
        RightSocketsPanelSize = ImVec2:new_local(285, 720),
        SocketItemSize        = ImVec2:new_local(275, 65),
        PropertyItemSize      = ImVec2:new_local(275, 300),
        RefreshPartsBtnSize   = ImVec2:new_local(35, 18),
        SaveBtnSize           = ImVec2:new_local(75, 35),
        BackBtnSize           = ImVec2:new_local(75, 35),
    };
    self.m_socketParams = {
        x = 0,
        y = 0,
        z = 0,
    };
end
function AssemblePage:dtor() end

---
--- 设置参数
---
--- @param params table
--- @param params.model LBaseAssemble
--- @return void
---
function AssemblePage:SetParams(params)
    if params and params.model then
        self.m_model    = params.model;
        self.m_modelBak = Dataset.LAssembleFactory(params.model.m_strPath);
    end
end

function AssemblePage:Clean()
    if self.m_model.m_actor and self.m_model.m_player then
        self.m_model:DestroyActor();
    end
    self.m_model           = nil;
    self.m_oSocket         = nil;
    self.m_oSocketBak      = nil;
    self.m_oSocketKey      = -1;
    self.m_bDrawSaveModal  = false;
    self.m_bDrawBackModal  = false;
    self.m_bDrawResetModal = false;
    self.m_nDrawProperty   = 1;
    self.m_bSaved          = true;
    self.m_strSaveName     = KLString:new_local("");
    self.m_socketParams = {
        x = 0,
        y = 0,
        z = 0,
    };
end

function AssemblePage:DrawUI(parent)
    local tab_bar_flags = ImGuiTabBarFlags_.ImGuiTabBarFlags_None;
    local styles        = self.m_styles;
    -- Left
    ImGui.BeginChild("LeftSocketsPanel", styles.LeftSocketsPanelSize, true);
        DrawLeftSockets(self);
    ImGui.EndChild();
    ImGui.SameLine();
    -- Right
    ImGui.BeginChild("RightSocketsPanel", styles.RightSocketsPanelSize, true);
        DrawRightSockets(self);
    ImGui.EndChild();
    DrawBottomOperateBar(self, parent);

    if DrawSaveDialog(self) then
        self.m_bSaved = Dataset.Save(self.m_model, self.m_strSaveName:ToString());
        parent.m_pages.ModelList:ReLoadModels();
    end
    if DrawBackDialog(self) then
        self:Clean();
        parent:To(parent.m_pages.Detail);
    end
    if DrawResetDialog(self) then
        self:RestoreEditSocket();
    end
end

function AssemblePage:SetEditSocket(oSocket, nSocket, comKey)
    if oSocket then
        self.m_oSocket    = oSocket;
        self.m_oSocketBak = table.copy(oSocket, true);
        return true;
    end
    if nSocket and comKey and self.m_oSocket then
        self.m_oSocket.m_strAsset   = nSocket.m_strAsset;
        self.m_oSocket.m_strName    = nSocket.m_strName;
        self.m_oSocket.m_tbChildren = nSocket.m_tbChildren;
        self.m_oSocket.m_strParams  = nSocket.m_strParams;
        local actor = self.m_model:GetActor();
        if actor then
            actor:SetupComponent(self.m_oSocket.m_strAsset, comKey);
            self.m_oSocketKey = comKey;
        end
        self.m_bSaved = false;
    end
    return true;
end

function AssemblePage:RestoreEditSocket()
    if self.m_oSocketKey <= 0 or not self.m_oSocket or not self.m_oSocketBak then
        return false;
    end
    self.m_oSocket.m_strAsset   = self.m_oSocketBak.m_strAsset;
    self.m_oSocket.m_strName    = self.m_oSocketBak.m_strName;
    self.m_oSocket.m_tbChildren = self.m_oSocketBak.m_tbChildren;
    self.m_oSocket.m_strParams  = self.m_oSocketBak.m_strParams;
    local actor  = self.m_model:GetActor();
    local comKey = self.m_oSocketKey;
    if actor then
        actor:SetupComponent(self.m_oSocket.m_strAsset, comKey);
        self.m_oSocketKey = -1;
    end
    return true;
end

function AssemblePage:RestoreModel()
    if not self.m_model or not self.m_modelBak then
        return false;
    end
    for key, socket in ipairs(self.m_model.m_tbChildren) do
        socket.m_strAsset   = self.m_modelBak.m_tbChildren[key].m_strAsset;
        socket.m_strName    = self.m_modelBak.m_tbChildren[key].m_strName;
        socket.m_tbChildren = self.m_modelBak.m_tbChildren[key].m_tbChildren;
        socket.m_strParams  = self.m_modelBak.m_tbChildren[key].m_strParams;
        local actor  = self.m_model:GetActor();
        if actor then
            actor:SetupComponent(socket.m_strAsset, key);
            self.m_bSaved = true;
        end
    end
    return true;
end

function AssemblePage:SetSocketParams(x, y, z)
    self.m_socketParams = {
        x = x,
        y = y,
        z = z,
    };
end

---
--- ImGui::CollapsingHeader的重新实现
---
--- @param text string
--- @param size ImVec2
---
function CollapsingUI(text, size)
    return ImGui.Button(text, size);
end

---
--- Icon button
---
--- @param text string
--- @param size ImVec2
---
function IconButton(text, icon, size)
    return ImGui.Button(text, size);
end

function DrawLeftSockets(self)
    ImGui.Text(self.m_uiText.LeftSocketText);
    ImGui.Separator();
    for key, socket in ipairs(self.m_model.m_tbChildren) do
        local name = self.m_model.m_tbSocketName[socket.m_strSocket] or socket.m_strSocket;
        if CollapsingUI(name, self.m_styles.SocketItemSize) then
            self.m_nDrawProperty = key;
            self:SetEditSocket(socket, nil, nil);
        end
        if self.m_nDrawProperty == key then
            DrawProperty(self, key, socket);
        end
    end
end

function DrawRightSockets(self)
    ImGui.Text(self.m_uiText.RightSocketText);
    ImGui.SameLine(245);
    if ImGui.SmallButton(self.m_uiText.RefreshPartsBtnText) then
        self.m_parts = Dataset.GetParts();
    end
    ImGui.Separator();
    for key, socket in ipairs(self.m_parts) do
        local name = socket.m_strName;
        if IconButton(name, "icon label", self.m_styles.SocketItemSize) then
            self:SetEditSocket(nil, socket, self.m_nDrawProperty - 1);
        end
    end
end

function DrawBottomOperateBar(self, parent)
    if ImGui.Button(self.m_uiText.ResetButtonText, self.m_styles.SaveBtnSize) then
        self.m_bDrawResetModal = true;
    end
    ImGui.SameLine();
    if ImGui.Button(self.m_uiText.BackPanel, self.m_styles.BackBtnSize) then
        if not self.m_bSaved then
            self.m_bDrawBackModal = true;
        else
            self:Clean();
            parent:To(parent.m_pages.Detail);
        end
    end
    ImGui.SameLine();
    if ImGui.Button(self.m_uiText.SaveButtonText, self.m_styles.BackBtnSize) then
        self.m_bDrawSaveModal = true;
    end
end

function DrawProperty(self, key, socket)
    ImGui.BeginChild("#PropertyCollpase", self.m_styles.PropertyItemSize, false, ImGuiWindowFlags_.ImGuiWindowFlags_AlwaysAutoResize);
        ImGui.Text(self.m_uiText.PropertyHeaderText);
        ImGui.Separator();
        if type(self.m_model.DrawPropertyWidget) == "function" then
            self.m_model:DrawPropertyWidget(socket.m_strSocket);
        end
        ImGui.Text(self.m_uiText.SocketCurAssetPath);
        ImGui.TextWrapped(string.replace(socket.m_strAsset, FS.GetCwd(), ""));
    ImGui.EndChild();
    ImGui.Separator();
end

function DialogUI(title, is_show, confirm_btn_text, cancel_btn_text, extral_content)
    if not is_show then
        return false, false;
    end
    local bRetCode = false;
    local center = ImVec2:new_local(
        ImGui.GetIO().DisplaySize.x * 0.5,
        ImGui.GetIO().DisplaySize.y * 0.5
    );
    ImGui.OpenPopup(title);
    ImGui.SetNextWindowPos(center, ImGuiCond_.ImGuiCond_Appearing, ImVec2:new_local(0.5, 0.5));
    if ImGui.BeginPopupModal(title, true, ImGuiWindowFlags_.ImGuiWindowFlags_AlwaysAutoResize) then
        if type(extral_content) == "function" then
            extral_content();
        end
        ImGui.Separator();
        if ImGui.Button(cancel_btn_text, ImVec2(120, 0)) then
            ImGui.CloseCurrentPopup();
            is_show  = false;
        end
        ImGui.SetItemDefaultFocus();
        ImGui.SameLine();
        if ImGui.Button(confirm_btn_text, ImVec2(120, 0)) then
            ImGui.CloseCurrentPopup();
            is_show  = false;
            bRetCode = true;
        end
        ImGui.EndPopup();
    end
    return bRetCode, is_show;
end

function DrawSaveDialog(self)
    local bIsConfirm, bIsDrawModal = DialogUI(
        self.m_uiText.SaveNamePanel,
        self.m_bDrawSaveModal,
        self.m_uiText.SaveNameConfirm,
        self.m_uiText.SaveNameCanel,
        function()
            ImGui.Text(self.m_uiText.SaveNamePanelTip);
            ImGui.Separator();
            KLImGui.InputText("保存名称", self.m_strSaveName, 64);
        end
    );
    self.m_bDrawSaveModal = bIsDrawModal;
    return bIsConfirm;
end

function DrawResetDialog(self)
    local bIsConfirm, bIsDrawModal = DialogUI(
        self.m_uiText.ResetButtonText,
        self.m_bDrawResetModal,
        self.m_uiText.SaveNameConfirm,
        self.m_uiText.SaveNameCanel,
        function()
            ImGui.Text(self.m_uiText.ResetPanelTip);
        end
    );
    self.m_bDrawResetModal = bIsDrawModal;
    return bIsConfirm;
end

function DrawBackDialog(self)
    local bIsConfirm, bIsDrawModal = DialogUI(
        self.m_uiText.BackPanel,
        self.m_bDrawBackModal,
        self.m_uiText.SaveNameConfirm,
        self.m_uiText.SaveNameCanel,
        function()
            ImGui.Text(self.m_uiText.BackPanelTip);
        end
    );
    self.m_bDrawBackModal = bIsDrawModal;
    return bIsConfirm;
end