ENT.Base = "base_entity"
ENT.Type = "anim"
ENT.RenderGroup = RENDERGROUP_VIEWMODEL
ENT.RenderMode = RENDERMODE_ENVIROMENTAL
--ENT.AutomaticFrameAdvance = true

function ENT:Initialize()
    if (!IsValid(self:GetOwner())) then
        error("Invalid weapon for viewmodel!")
    end

    self:AddEFlags(EFL_KEEP_ON_RECREATE_ENTITIES)
    self:AddEFlags(EFL_FORCE_CHECK_TRANSMIT)
    self:AddEFlags(EFL_NO_THINK_FUNCTION)
    self:AddEFlags(EFL_NO_GAME_PHYSICS_SIMULATION)
    self:AddEFlags(EFL_DONTBLOCKLOS)
    self:AddEFlags(EFL_DONTWALKON)
    self:AddEFlags(EFL_NO_DISSOLVE)
    self:AddEFlags(EFL_NO_PHYSCANNON_INTERACTION)
    self:AddEFlags(EFL_NO_DAMAGE_FORCES)
    self:AddEffects(EF_NOINTERP)
    self:AddFlags(FL_NOTARGET)
    self:AddFlags(FL_DONTTOUCH)
    self:AddFlags(FL_STEPMOVEMENT)

    self:SetMoveType(MOVETYPE_NONE)
    self:SetSolid(SOLID_NONE)
    self:SetNotSolid(true)
    self:SetRenderMode(self.RenderMode)
    self:DrawShadow(false)
    --self:SetNoDraw(true)
    self:UseClientSideAnimation()

    local weapon = self:GetOwner()

    if (CLIENT) then
        self:DestroyShadow()
        self:InvalidateBoneCache()
        self:SetupBones()

        self:ResetSequence(0)
        self:SetCycle(0)
        self:SetPlaybackRate(1)

        self:CreateRig()
        self:CreateGloves()
        self:CreateCHands()

        self:AddCallback("BuildBonePositions", function(vm, numbones)
            if (!vm.bRendering) then
                return
            end

            --vm:GetAttachment(vm:LookupAttachment("camera"))
            local matrix = vm:GetBoneMatrix(mw_utils.LookupBoneCached(vm, "tag_camera"))
            
            if (matrix != nil) then
                local worldMatrix = vm:GetBoneMatrix(0)
                self.m_CameraAttachment = matrix:GetInverse() * worldMatrix
            end

            if (VManip != nil) then
                hook.GetTable()["PostDrawViewModel"]["VManip"](vm, vm:GetOwner():GetOwner(), vm:GetOwner()) 
            end
        end)
        
        if (VManip != nil) then
            hook.Add("VManipPostPlayAnim", self, function(self, name) 
                self:VManipPostPlayAnim(name)
            end)

            hook.Add("VManipHoldQuit", self, function(self) 
                self:VManipHoldQuit()
            end)

            hook.Add("VManipRemove", self, function(self) 
                self:VManipRemove()
            end)
        end
    end

    self.m_LastSequenceIndex = "INIT"
    self.m_Tick = 0
    
    --old compatibility
    --weapon.m_ViewModel = self
end

function ENT:GetAnimID(weaponSequenceIndex)
    local id = 0

    for index, _ in SortedPairs(self:GetOwner().Animations) do
        id = id + 1

        if (string.lower(index) == string.lower(weaponSequenceIndex)) then
            return id
        end
    end

    return -1
end

function ENT:GetSequenceIndexByID(animId)
    local id = 0

    for index, _ in SortedPairs(self:GetOwner().Animations) do
        id = id + 1

        if (id == animId) then
            return index
        end
    end

    return nil
end

function ENT:GetPlayerOwner()
    if (IsValid(self:GetOwner())) then
        return self:GetOwner():GetOwner()
    end

    return NULL
end

function ENT:GetWeaponOwner()
    return self:GetOwner()
end

function ENT:OnRemove()
    if (IsValid(self.m_Rig)) then self.m_Rig:Remove() end
    if (IsValid(self.m_Gloves)) then self.m_Gloves:Remove() end
    if (IsValid(self.m_CHands)) then self.m_CHands:Remove() end
end

function ENT:PlayAnimation(weaponSequenceIndex, bNoTick) --"Holster", "Draw", ...
    self.m_LastSequenceIndex = weaponSequenceIndex

    if (!bNoTick) then
        self.m_Tick = self.m_Tick + 1
    end

    local weaponSequence = nil--self:GetOwner().Animations[weaponSequenceIndex]

    for index, seq in pairs(self:GetOwner().Animations) do
        if (string.lower(index) == string.lower(weaponSequenceIndex)) then
            weaponSequence = seq
            break
        end
    end

    if (weaponSequence == nil) then
        return
    end
    
    local animId = self:GetAnimID(weaponSequenceIndex)
    local rate = weaponSequence.Fps / 30

    if (CLIENT) then
        local anims = weaponSequence.Sequences
        self:PlaySequence(anims[math.random(1, #anims)], rate)
    end

    if (SERVER) then
        net.Start("mgbase_viewmodelanim", true)
            net.WriteEntity(self)
            net.WriteFloat(rate)
            net.WriteUInt(animId, 16)
            net.WriteUInt(self.m_Tick, 16)
        net.Broadcast() 
    end
end

function ENT:UpdateAnimation()
    local cycle = self:GetCycle()
    self:PlayAnimation(self.m_LastSequenceIndex, true)
    self:SetCycle(cycle)
end

--sorryyyyy garrysmod-issues/issues/5344
local oldCleanup = game.CleanUpMap
function game.CleanUpMap(dontSendToClients, ExtraFilters)
    dontSendToClients = dontSendToClients || false
    ExtraFilters = ExtraFilters || {}
    table.insert(ExtraFilters, "mg_viewmodel")
    oldCleanup(dontSendToClients, ExtraFilters)
end