---
--- Date         : 2020-08-10 15:36:36
--- Author       : LICHAO7
--- LastEditors  : LICHAO7
--- LastEditTime : 2020-08-20 12:41:48
--- Description  : Simple flight assemble
---

local LBaseAssemble = ImportScript("ugc_common/script/core/assemble/base_assemble.lua").LBaseAssemble;
---
--- @class LSimpleFlightAssemble extends LBaseAssemble
---
LSimpleFlightAssemble = LSimpleFlightAssemble or class("LSimpleFlightAssemble", LBaseAssemble);

function LSimpleFlightAssemble:ctor()
    self.m_lTrailEmitter1     = nil;
    self.m_lTrailEmitter2     = nil;
    self.m_NitroEmitter       = nil;
    self.m_szTrail1EmitterRes = "data/source/other/新特效/技能/Pss/发招/Q_七秀轻功花b.pss";
    self.m_szTrail2EmitterRes = "data/source/other/新特效/技能/Pss/发招/S_少林双人轻功拖尾01.pss";
    self.m_szNitroEmitterRes  = "UGCSource/particle/御剑.pss";
    self.m_tbSocketName = {
        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_tbProperty = {
        PlayerOffset = {
            Label = util.a2u8("驾驶者位置"),
            Value = {0, 0, 0}
        },
        PlayerOrientation = {
            Label = util.a2u8("驾驶者朝向"),
            Value = {0, 0, 0}
        },
        FlightOrientation = {
            Label = util.a2u8("飞行朝向"),
            Value = {0, 0, 0},
            LabelValue = 0,
            CheckboxLable = util.a2u8("负方向"),
            CheckboxValue = false,
        },
        PartOrientation = {
            Label = util.a2u8("飞行器朝向"),
            Value = {0, 0, 0},
        },
    };
    self.m_strControlTip = util.a2u8([[
      操作按键提示
挡位:1 | 2 | 3 | 4 | 0
W(向下推降) | S(向上拉升)
Q(向左翻转) | E(向右翻转)
A(左侧偏航) | D(右侧偏航)
      Space(加速)
    ]]);
end

function LSimpleFlightAssemble:dtor() end

---
--- Construct edit property
---
function LSimpleFlightAssemble:ConstructPropertyFromLogicSockets()
    self.m_tbProperty.PlayerOffset.Value      = self.m_tbLogicSockets.Root.PlayerOffset or {0, 0, 0};
    self.m_tbProperty.PlayerOrientation.Value = self.m_tbLogicSockets.Root.PlayerOrientation or {0, 0, 0};
    self.m_tbProperty.FlightOrientation.Value = self.m_tbLogicSockets.Root.FlightOrientation or {0, 0, 0};
    self.m_tbProperty.PartOrientation.Value   = self.m_tbLogicSockets.Root.PartOrientation or {0, 0, 0};
    if (self.m_tbProperty.FlightOrientation.Value[1] < 0 or
        self.m_tbProperty.FlightOrientation.Value[2] < 0 or
        self.m_tbProperty.FlightOrientation.Value[3] < 0)
    then
        self.m_tbProperty.FlightOrientation.CheckboxValue = true;
    end
    for key, value in ipairs(self.m_tbProperty.FlightOrientation.Value) do
        if value == 1 then
            self.m_tbProperty.FlightOrientation.LabelValue = key - 1;
            break;
        end
    end
end

---
--- Dump edit property to logic socket
---
function LSimpleFlightAssemble:DumpPropertyToLogicSockets()
    self.m_tbLogicSockets.Root.PlayerOffset      = self.m_tbProperty.PlayerOffset.Value;
    self.m_tbLogicSockets.Root.PlayerOrientation = self.m_tbProperty.PlayerOrientation.Value;
    self.m_tbLogicSockets.Root.FlightOrientation = self.m_tbProperty.FlightOrientation.Value;
    self.m_tbLogicSockets.Root.PartOrientation   = self.m_tbProperty.PartOrientation.Value;
end

---
--- 从FlightAssemble初始化飞机
---
--- @return boolean
---
function LSimpleFlightAssemble:SetupFlightFromAssemble()
    local meshActor = nil;
    for index, item in ipairs(self.m_tbChildren) do
        if item.m_bIsRoot then
            meshActor = g_ActorManager:CreateSimpleFlightActor(item.m_strAsset);
            -- TODO: 现在只设置Root节点，后面看情况加上其他部位的设置
        end
    end
    return meshActor;
end

function LSimpleFlightAssemble:DrawPropertyWidget(strSocketName)
    ImGui.Text(self.m_tbProperty.PlayerOffset.Label);
    _, self.m_tbProperty.PlayerOffset.Value[1] = ImGui.DragFloat("##PlayerOffset X", self.m_tbProperty.PlayerOffset.Value[1], 0.5, 0, 360, "X: %.3f");
    _, self.m_tbProperty.PlayerOffset.Value[2] = ImGui.DragFloat("##PlayerOffset Y", self.m_tbProperty.PlayerOffset.Value[2], 0.5, 0, 360, "Y: %.3f");
    _, self.m_tbProperty.PlayerOffset.Value[3] = ImGui.DragFloat("##PlayerOffset Z", self.m_tbProperty.PlayerOffset.Value[3], 0.5, 0, 360, "Z: %.3f");

    ImGui.Text(self.m_tbProperty.FlightOrientation.Label);
    _, self.m_tbProperty.FlightOrientation.LabelValue = ImGui.RadioButton("X", self.m_tbProperty.FlightOrientation.LabelValue, 0); ImGui.SameLine();
    _, self.m_tbProperty.FlightOrientation.LabelValue = ImGui.RadioButton("Y", self.m_tbProperty.FlightOrientation.LabelValue, 1); ImGui.SameLine();
    _, self.m_tbProperty.FlightOrientation.LabelValue = ImGui.RadioButton("Z", self.m_tbProperty.FlightOrientation.LabelValue, 2); ImGui.SameLine();
    _, self.m_tbProperty.FlightOrientation.CheckboxValue = ImGui.Checkbox(
        self.m_tbProperty.FlightOrientation.CheckboxLable,
        self.m_tbProperty.FlightOrientation.CheckboxValue
    );
    if self.m_tbProperty.FlightOrientation.LabelValue == 0 then
        self.m_tbProperty.FlightOrientation.Value = {1, 0, 0};
    elseif self.m_tbProperty.FlightOrientation.LabelValue == 1 then
        self.m_tbProperty.FlightOrientation.Value = {0, 1, 0};
    elseif self.m_tbProperty.FlightOrientation.LabelValue == 2 then
        self.m_tbProperty.FlightOrientation.Value = {0, 0, 1};
    end
    -- 负方向
    if self.m_tbProperty.FlightOrientation.CheckboxValue then
        self.m_tbProperty.FlightOrientation.Value[1] = self.m_tbProperty.FlightOrientation.Value[1] * -1;
        self.m_tbProperty.FlightOrientation.Value[2] = self.m_tbProperty.FlightOrientation.Value[2] * -1;
        self.m_tbProperty.FlightOrientation.Value[3] = self.m_tbProperty.FlightOrientation.Value[3] * -1;
    end

    -- ImGui.Text(self.m_tbProperty.PartOrientation.Label);
    -- _, self.m_tbProperty.PartOrientation.Value[1] = ImGui.DragFloat("##Part X", self.m_tbProperty.PartOrientation.Value[1], 0.5, 0, 360, "X: %.3f");
    -- _, self.m_tbProperty.PartOrientation.Value[2] = ImGui.DragFloat("##Part Y", self.m_tbProperty.PartOrientation.Value[2], 0.5, 0, 360, "Y: %.3f");
    -- _, self.m_tbProperty.PartOrientation.Value[3] = ImGui.DragFloat("##Part Z", self.m_tbProperty.PartOrientation.Value[3], 0.5, 0, 360, "Z: %.3f");

    ImGui.Text(self.m_tbProperty.PlayerOrientation.Label);
    _, self.m_tbProperty.PlayerOrientation.Value[1] = ImGui.DragFloat("##Player X", self.m_tbProperty.PlayerOrientation.Value[1], 0.5, 0, 360, "X: %.3f");
    _, self.m_tbProperty.PlayerOrientation.Value[2] = ImGui.DragFloat("##Player Y", self.m_tbProperty.PlayerOrientation.Value[2], 0.5, 0, 360, "Y: %.3f");
    _, self.m_tbProperty.PlayerOrientation.Value[3] = ImGui.DragFloat("##Player Z", self.m_tbProperty.PlayerOrientation.Value[3], 0.5, 0, 360, "Z: %.3f");

    self:UpdateProperty(strSocketName);
end

function LSimpleFlightAssemble:DrawControlTipWidget()
    ImGui.TextWrapped(self.m_strControlTip);
end

---
--- Create MeshActor.
---
--- TODO: 这些代码发完周二版本再整理
--- @return boolean
---
function LSimpleFlightAssemble:CreateActor()
    if self.m_actor or self.m_player then
        return true;
    end

    self.m_actor     = self:SetupFlightFromAssemble();
    self.m_player    = g_ActorManager:GetLocalPlayer();
    local _, x, y, z = self.m_player:GetWorldPosition();
    -- local _, pitch, yaw, roll  = self.m_player:GetWorldRotation();

    self.m_actor:SetWorldPosition(x, y + 300, z);
    self.m_actor:SetWorldRotation(
        self.m_tbProperty.PartOrientation.Value[1],
        self.m_tbProperty.PartOrientation.Value[2],
        self.m_tbProperty.PartOrientation.Value[3]
    );
    self.m_actor:SetCollisionType(Core.QueryAndPhysics);
    self.m_actor:BeginControl();
    self.m_player:AttachToParent(self.m_actor, Core.eAR_SnapToTarget);
    self.m_player:SetLocalPosition(
        self.m_tbProperty.PlayerOffset.Value[1],
        self.m_tbProperty.PlayerOffset.Value[2],
        self.m_tbProperty.PlayerOffset.Value[3]
    );
    self.m_player:SetLocalRotation(
        self.m_tbProperty.PlayerOrientation.Value[1],
        self.m_tbProperty.PlayerOrientation.Value[2],
        self.m_tbProperty.PlayerOrientation.Value[3]
    );

    local faceDir = KVec3:new_local(
        self.m_tbProperty.FlightOrientation.Value[1],
        self.m_tbProperty.FlightOrientation.Value[2],
        self.m_tbProperty.FlightOrientation.Value[3]
    );
    self.m_actor:SetFaceDirection(faceDir);

    self.m_lTrailEmitter1 = g_ActorManager:CreateEmitter(self.m_szTrail1EmitterRes);
    self.m_lTrailEmitter1:AttachToParent(self.m_actor);

    self.m_lTrailEmitter2 = g_ActorManager:CreateEmitter(self.m_szTrail2EmitterRes);
    self.m_lTrailEmitter2:AttachToParent(self.m_actor);
    self.m_lTrailEmitter2:Stop();

    self.m_NitroEmitter = g_ActorManager:CreateEmitter(self.m_szNitroEmitterRes);
    self.m_NitroEmitter:AttachToParent(self.m_actor);
    self.m_NitroEmitter:Stop();
    self.m_NitroEmitter:SetLocalRotation(0, -90, 0);

    g_EventDispatcherManager:AddEventListener("Flight", "NitroStart", self.OnNitroStart, self);
    g_EventDispatcherManager:AddEventListener("Flight", "NitroEnd", self.NitroEnd, self);

    g_NetWorking:EntityCreated(g_NetWorking.ENTITY_TYPE_FLIGHT, self.m_actor:GetId(), self.m_strAsset);
end

---
--- Destroy MeshActor.
---
--- TODO: 这些代码发完周二版本再整理
--- @return boolean
---
function LSimpleFlightAssemble:DestroyActor()
    if self.m_actor then
        g_EventDispatcherManager:RemoveEventListener("Flight", "NitroStart", self.OnNitroStart, self);
        g_EventDispatcherManager:RemoveEventListener("Flight", "NitroEnd", self.NitroEnd, self);
        self.m_actor:EndControl();
        self.m_player:DetachFromParent();

        local pitch, yaw, roll = self.m_player:GetLocalRotation();
        self.m_player:SetLocalRotation(0, yaw, 0);

        g_NetWorking:EntityDeleted(self.m_actor:GetId());
        g_ActorManager:DestroyActor(self.m_actor);
        self.m_actor = nil;

        if self.m_lTrailEmitter1 ~= nil then
            g_ActorManager:DestroyActor(self.m_lTrailEmitter1);
            self.m_lTrailEmitter1 = nil;
        end
        if self.m_lTrailEmitter2 ~= nil then
            g_ActorManager:DestroyActor(self.m_lTrailEmitter2);
            self.m_lTrailEmitter2 = nil;
        end
        if self.m_NitroEmitter ~= nil then
            g_ActorManager:DestroyActor(self.m_NitroEmitter);
            self.m_NitroEmitter = nil;
        end

        KLGameWorld.CameraSwitch("role");
    end
    self.m_player = nil;
    return true;
end

-- TODO: 这些代码发完周二版本再整理
function LSimpleFlightAssemble:OnNitroStart()
    if not self.m_actor then
        return;
    end
    if self.m_NitroEmitter ~= nil then
        self.m_NitroEmitter:Play(false);
    end

    if self.m_lTrailEmitter1 ~= nil then
        self.m_lTrailEmitter1:Stop();
    end
    if self.m_lTrailEmitter2 ~= nil then
        self.m_lTrailEmitter2:Play(true);
    end
end

-- TODO: 这些代码发完周二版本再整理
function LSimpleFlightAssemble:NitroEnd()
    if not self.m_actor then
        return;
    end
    if self.m_NitroEmitter ~= nil then
        self.m_NitroEmitter:Stop();
    end
    if self.m_lTrailEmitter1 ~= nil then
        self.m_lTrailEmitter1:Play(true);
    end
    if self.m_lTrailEmitter2 ~= nil then
        self.m_lTrailEmitter2:Stop();
    end
end

function LSimpleFlightAssemble:UpdateProperty(strSocketName)
    local faceDir = KVec3:new_local(
        self.m_tbProperty.FlightOrientation.Value[1],
        self.m_tbProperty.FlightOrientation.Value[2],
        self.m_tbProperty.FlightOrientation.Value[3]
    );
    self.m_actor:SetFaceDirection(faceDir);
    -- self.m_actor:SetWorldRotation(
    --     self.m_tbProperty.PartOrientation.Value[1],
    --     self.m_tbProperty.PartOrientation.Value[2],
    --     self.m_tbProperty.PartOrientation.Value[3]
    -- );
    self.m_player:SetLocalPosition(
        self.m_tbProperty.PlayerOffset.Value[1],
        self.m_tbProperty.PlayerOffset.Value[2],
        self.m_tbProperty.PlayerOffset.Value[3]
    );
    self.m_player:SetLocalRotation(
        self.m_tbProperty.PlayerOrientation.Value[1],
        self.m_tbProperty.PlayerOrientation.Value[2],
        self.m_tbProperty.PlayerOrientation.Value[3]
    );
end
