--[[
 -- @Description:
 -- Hello , DiaoSi ~ ( or not ? ) ,glad you saw my comment
 -- If you think my mod is okay , you can sponsor my breakfast by a tiny amount donation  ($_$)
 -- paypal:td1madao@163.com     alipay:td1madao@163.com
 -- If any question ,Please email me
 -- What's more ,don't modify and republish my mods . 3Q for cooperation
 -- What's more ,don't modify and republish my mods . 3Q for cooperation
 -- What's more ,don't modify and republish my mods . 3Q for cooperation
 -- @version 1.0.0
 -- @author td1madao
 -- @email td1madao@163.com
 -- @qq 360810498
 -- @date 16/8/6
 ]]
local TD = TD.td1madao.rivendst
local Rivendst_common_skill_manager = Class(function(self, inst)
    TD.see()
    self.inst = inst
    TD.common(inst, function()
        self.skill = {}
        self.skillBuffer = {}
        self.skillMap = {}
    end)
end)

function Rivendst_common_skill_manager:player_letter2num(tag)
    if not tag then
        return -1
    end
    return self.skillMap[tag] or -1
end

function Rivendst_common_skill_manager:server_num2letter(num)
    if not num then
        return "nil"
    end
    local skillMap = self.skillMap
    for k, v in pairs(skillMap) do
        if k and skillMap[k] and skillMap[k] == num then
            return k
        end
    end
    return "nil"
end

function Rivendst_common_skill_manager:common_registOrder(tag, num)
    if not tag then
        return
    end
    if not self.skillMap[tag] then
        self.skillMap[tag] = num
    end
end

function Rivendst_common_skill_manager:common_declare(tag, cd, num)
    TD.see()
    if not tag or not cd then
        return
    end
    if not self.skill[tag] then
        self.skill[tag] = {}
        self.skill[tag].cd = 0
    end
    if not self.skillBuffer[tag] then
        self.skillBuffer[tag] = {}
        self.skillBuffer[tag].maxCd = cd
    end
    self:common_registOrder(tag, num)
    self:common_refresh()
end

function Rivendst_common_skill_manager:player_skillTagTimeout()
    --    TD.see()
    TD.getC(self.inst, "rivendst_common_task_manager"):player_task(15, function()
        self:player_removeTag()
    end, "td1madao_rivendst_removeTag_all")
end

function Rivendst_common_skill_manager:player_showAsCd(tag)
    TD.see()
    self:player_removeTag(tag)
    local inst = self.inst.td1madaoRivendstSkillControls
    if inst and tag and inst[tag] then
        inst[tag]:setTint(0.2, 0.2, 0.2, 1)
        inst[tag]:setColour(1, 0, 0, 1)
        inst[tag]:setString(tostring(self.skill[tag].cd))
    end
end

local function getKeyConfigDesc(tag)
    -- TD.see()
    local name = string.format("TD1MADAO_RIVENDST_%s_DESC", string.upper(tag))
    return TUNING[name]
end

function Rivendst_common_skill_manager:player_showAsReady(tag)
    TD.see()
    local inst = self.inst.td1madaoRivendstSkillControls
    if inst and tag and inst[tag] then
        inst[tag]:setTint(1, 1, 1, 1)
        inst[tag]:setColour(0, 1, 0, 1)
        inst[tag]:setString(getKeyConfigDesc(tag))
    end
end

function Rivendst_common_skill_manager:common_refresh(force)
    -- TD.see()
    local player = self.inst
    if not player then
        return
    end
    local skill = self.skill
    for k, v in pairs(skill) do
        local ready = false
        local isPlayer = TD.isPlayer(player)
        if k and skill[k] and skill[k].cd and skill[k].cd > 0 then
            skill[k].cd = skill[k].cd - 1
            if skill[k].cd < 0 then
                skill[k].cd = 0
            end
            if isPlayer and skill[k].cd == 0 then
                ready = true
            end
        end
        if isPlayer then
            if skill[k].cd > 0 then
                self:player_showAsCd(k)
            elseif ready or force then
                self:player_showAsReady(k)
            end
        end
    end
end

function Rivendst_common_skill_manager:player_refresh(force)
    -- TD.see()
    self:common_refresh(force)
end


function Rivendst_common_skill_manager:OnSave()
    return
    {
        skill = self.skill or {}
    }
end

function Rivendst_common_skill_manager:OnLoad(data)
    if data ~= nil and self.inst then
        self.skill = data.skill or {}
    end
    self:common_refresh()
end

function Rivendst_common_skill_manager:player_castCondition(tag)
    --    TD.see()
    local player = self.inst
    local skill = self.skill
    local cd = skill[tag].cd
    if cd > 0 then
        return false
    end
    if not self.inst.replica.inventory:GetEquippedItem(EQUIPSLOTS.HANDS) then
        return false
    end
    if player:HasTag("playerghost") then
        return false
    end
    if not player:HasTag("rivendst") then
        return false
    end
    return true
end

function Rivendst_common_skill_manager:player_cast(tag)
    TD.see()
    if tag == "q" then
        self:player_castq()
    elseif tag == "w" then
        self:player_castw()
    elseif tag == "e" then
        self:player_caste()
    elseif tag == "r" then
        local rivenRtwice = TD.getC(self.inst, "rivendst_common_synchronizer"):player_get("rivenRtwice")
        if rivenRtwice then
            self:player_castr2()
        else
            self:player_castr1()
        end
    end
end

function Rivendst_common_skill_manager:player_sendRPC(tag)
    TD.see()
    local player = self.inst
    if TD.isPlayer(player) then
        local x, y, z = (TheInput:GetWorldPosition() or Vector3(0, 0, 0)):Get()
        local data = {}
        data.x = x
        data.z = z
        TD.server(function()
            self:server_rpcReceiver(tag, data)
        end, function()
            SendModRPCToServer(MOD_RPC[TD.NAMESPACE][TD.ACTION], self:player_letter2num(tag), x, z)
        end)
    end
end

function Rivendst_common_skill_manager:player_castq()
    TD.see()
    local tag = "q"
    if not self:player_castCondition(tag) then
        return
    end
    if TD.smart() then
        self:player_sendRPC(tag)
        return
    end
    local player = self.inst
    self.skillBuffer[tag].tag = true
    self:player_skillTagTimeout()
end

function Rivendst_common_skill_manager:player_castw()
    TD.see()
    local tag = "w"
    if not self:player_castCondition(tag) then
        return
    end
    self:player_sendRPC(tag)
end

function Rivendst_common_skill_manager:player_caste()
    TD.see()
    local tag = "e"
    if not self:player_castCondition(tag) then
        return
    end
    if TD.smart() then
        self:player_sendRPC(tag)
        return
    end
    local player = self.inst
    self.skillBuffer[tag].tag = true
    self:player_skillTagTimeout()
end

function Rivendst_common_skill_manager:player_castr1()
    TD.see()
    local tag = "r"
    if not self:player_castCondition(tag) then
        return
    end
    self:player_sendRPC(tag)
end

function Rivendst_common_skill_manager:player_castr2()
    TD.see()
    local tag = "r"
    if not self:player_castCondition(tag) then
        return
    end
    if TD.smart() then
        self:player_sendRPC(tag)
        return
    end
    local player = self.inst
    self.skillBuffer[tag].tag = true
    self:player_skillTagTimeout()
end

function Rivendst_common_skill_manager:server_rpcReceiver(tag, data)
    TD.see()
    if not data then
        data = {}
    end
    if tag == "q" then
        self:server_rpcq(data.x, data.z)
    elseif tag == "w" then
        self:server_rpcw()
    elseif tag == "e" then
        self:server_rpce(data.x, data.z)
    elseif tag == "r" then
        local rivenRtwice = TD.getC(self.inst, "rivendst_common_synchronizer").server_rivenRBuff
        if rivenRtwice then
            self:server_rpcr2(data.x, data.z)
        else
            self:server_rpcr1()
        end
    end
end


function Rivendst_common_skill_manager:server_castCondition(tag)
    TD.see()
    local player = self.inst
    local skill = self.skill
    if not skill[tag] then
        skill[tag] = {}
        skill[tag].cd = 0
    end
    local cd = skill[tag].cd
    if cd > 0 then
        return false
    end
    if player:HasTag("playerghost") or TD.die(player) then
        return false
    end
    if not player:HasTag("rivendst") then
        return false
    end
    if not player.sg:HasStateTag("attack") and
            (player.sg:HasStateTag("busy") or
                    player.sg:HasStateTag("pausepredict") or
                    player.sg:HasStateTag("td1madao_skill") or
                    player.sg:HasStateTag("tent")) then
        return false
    end
    local weapon = TD.getC(player, "inventory"):GetEquippedItem(EQUIPSLOTS.HANDS)
    if not weapon then
        return false
    end
    return true
end

function Rivendst_common_skill_manager:server_rpcq(x, z)
    TD.see()
    local player = self.inst
    local tag = "q"
    if not self:server_castCondition(tag) then
        return
    end
    local y = 0
    if not x or not z then
        x, y, z = player:GetPosition():Get()
    end
    local syn = TD.getC(self.inst, "rivendst_common_synchronizer")
    if syn.server_qtime == 0 then
        player.sg:GoToState("td1madao_rivendst_q1", Vector3(x, y, z))
        syn.server_qtime = 1
    elseif syn.server_qtime == 1 then
        player.sg:GoToState("td1madao_rivendst_q2", Vector3(x, y, z))
        syn.server_qtime = 2
    elseif syn.server_qtime == 2 then
        player.sg:GoToState("td1madao_rivendst_q3", Vector3(x, y, z))
        syn.server_qtime = 0
    else
        syn.server_qtime = 0
        player.sg:GoToState("td1madao_rivendst_q1", Vector3(x, y, z))
    end
end

function Rivendst_common_skill_manager:server_rpcw()
    TD.see()
    local player = self.inst
    local tag = "w"
    if not self:server_castCondition(tag) then
        return
    end
    player.sg:GoToState("td1madao_rivendst_w")
end

function Rivendst_common_skill_manager:server_rpce(x, z)
    TD.see()
    local player = self.inst
    local tag = "e"
    if not self:server_castCondition(tag) then
        return
    end
    local y = 0
    if not x or not z then
        x, y, z = player:GetPosition():Get()
    end
    player.sg:GoToState("td1madao_rivendst_e", Vector3(x, y, z))
end

function Rivendst_common_skill_manager:server_rpcr1()
    TD.see()
    local player = self.inst
    local tag = "r"
    if not self:server_castCondition(tag) then
        return
    end
    player.sg:GoToState("td1madao_rivendst_r1")
end


function Rivendst_common_skill_manager:server_rpcr2(x, z)
    TD.see()
    local player = self.inst
    local tag = "r"
    if not self:server_castCondition(tag) then
        return
    end
    local syn = TD.getC(player, "rivendst_common_synchronizer")
    if not syn.server_rivenRBuff then
        return
    end
    local y = 0
    if not x or not z then
        x, y, z = player:GetPosition():Get()
    end
    player.sg:GoToState("td1madao_rivendst_r2", Vector3(x, y, z))
end

function Rivendst_common_skill_manager:common_iterator(fun)
    -- TD.see()
    if not fun then
        return
    end
    local skill = self.skill
    for k, v in pairs(skill) do
        if k and skill[k] then
            fun(k)
        end
    end
end

function Rivendst_common_skill_manager:player_iterator(fun)
    self:common_iterator(fun)
end

function Rivendst_common_skill_manager:server_iterator(fun)
    self:common_iterator(fun)
end

function Rivendst_common_skill_manager:player_removeTag(tag)
    --    TD.see()
    local skill = self.skill
    if tag then
        self.skillBuffer[tag].tag = false
        return
    end
    for k, v in pairs(skill) do
        if k and skill[k] then
            self.skillBuffer[k].tag = false
        end
    end
end

return Rivendst_common_skill_manager