--
-- Created by IntelliJ IDEA.
-- User: RJ
-- Date: 30/04/14
-- Time: 09:57
-- To change this template use File | Settings | File Templates.
--

TrapSystem = {}
TrapSystem.traps = {};

TrapSystem.wantNoise = getDebug()
local noise = function(msg)
    if TrapSystem.wantNoise then print('trapping: '..msg) end
end
TrapSystem.noise = noise

-- Change age of bait each day
TrapSystem.EveryDays = function()
    if isClient() then return; end
    for iB,vB in ipairs(TrapSystem.traps) do
        if vB.bait then
            vB.baitDay = vB.baitDay + 1;
            --        print("check trap at " .. vB.x .. "," .. vB.y)
            local square = getWorld():getCell():getGridSquare(vB.x, vB.y, vB.z);
            vB:toModData(square, true)
        end
    end
end

function TrapSystem.isTrapObject(object)
    if not object then return false end
    if object:getName() == "Trap" then
        return true
    end
    return false
end

function TrapSystem.findTrapObject(square)
    if not square then return nil end
    for i=0,square:getObjects():size()-1 do
        local object = square:getObjects():get(i)
        if TrapSystem.isTrapObject(object) then
            return object
        end
    end
    return nil
end

TrapSystem.getPlacedTrap = function(x, y, z)
    if isClient() then
        -- TrapSystem.traps is empty on the client.  Create a fake ISTrap if there is a trap object here.
        local square = getCell():getGridSquare(x, y, z)
        local trapObject = TrapSystem.findTrapObject(square)
        if trapObject then
            local trap = ISTrap:new(x, y, z)
            trap:fromModData(square)
            return trap
        end
        return nil
    end
    for i,v in ipairs(TrapSystem.traps) do
        if v.x == x and v.y == y and v.z == z then
            return v;
        end
    end
    return nil;
end

function TrapSystem.removeTrap(trap, removeObject)
    if not trap then return end
    if removeObject then
        trap:removeObject()
    elseif trap:getSquare() then
        trap:reinitModData(trap:getSquare())
    end
    for i=1,#TrapSystem.traps do
        if TrapSystem.traps[i] == trap then
            table.remove(TrapSystem.traps, i)
            break
        end
    end
    for i=1,#TrapSystem.modData.trapping.traps do
        local data = TrapSystem.modData.trapping.traps[i]
        if data.x == trap.x and data.y == trap.y and data.z == trap.z then
            table.remove(TrapSystem.modData.trapping.traps, i)
            break
        end
    end
    TrapSystem.noise('removed trap '..trap.x..','..trap.y..','..trap.z)
    TrapSystem.noise("#TrapSystem.traps="..#TrapSystem.traps)
    TrapSystem.noise("#TrapSystem.modData.trapping.traps="..#TrapSystem.modData.trapping.traps)
end

-- every hour, calcul the chance of getting something
function TrapSystem.checkTrap()
    if isClient() then return; end
    for iB,vB in ipairs(TrapSystem.traps) do
        local square = getWorld():getCell():getGridSquare(vB.x, vB.y, vB.z);
        vB:calculTrap(square);
    end
end

-- load the traps
function TrapSystem.loadTraps(square)
    if isClient() then return; end
    local trap = TrapSystem.getPlacedTrap(square:getX(), square:getY(), square:getZ())
    if trap then
        if trap:getTrapObject() then
            -- Sync the object with the current state of the trap.
            trap:toModData2(square:getModData())
            trap:fromModData(square)
        else
            -- The object has been removed (could happen if the chunk was blammed).
            noise('removing trap-without-object '..trap.x..','..trap.y..','..trap.z)
            TrapSystem.removeTrap(trap, true)
        end
        return
    end

    -- Find trap objects that aren't in the traps[] table for some reason.
    -- Could happen if map_t.bin wasn't saved due to a crash after a trap was placed and the chunk saved.
    -- Also, doing a server soft-reset wipes GameTime modData.
    local trapObject = TrapSystem.findTrapObject(square)
    if trapObject then
        noise('found an unknown trap object '..square:getX()..','..square:getY()..','..square:getZ())
        trap = ISTrap:new(square:getX(), square:getY(), square:getZ())
        -- TODO: check if the modData is valid; if not, remove the object
        trap:fromModData(square)
        table.insert(TrapSystem.traps, trap)
        
        modData = {}
        trap:toModData2(modData)
        modData.x = trap.x
        modData.y = trap.y
        modData.z = trap.z
        table.insert(TrapSystem.modData.trapping.traps, modData)
        TrapSystem.noise('added previously-unknown trap '..trap.x..','..trap.y..','..trap.z)
        TrapSystem.noise("#TrapSystem.traps="..#TrapSystem.traps)
        TrapSystem.noise("#TrapSystem.modData.trapping.traps="..#TrapSystem.modData.trapping.traps)
    end
end

function TrapSystem.loadGridsquareJavaHook(square, trap, trapObject)
    if isClient() then return; end
    if trap then
        if trapObject then
            noise('sync trap '..trap.x..','..trap.y..','..trap.z)
            -- Sync the object with the current state of the trap.
            trap:toModData2(square:getModData())
            trap:fromModData(square)
        else
            -- The object has been removed (could happen if the chunk was blammed).
            noise('removing trap-without-object '..trap.x..','..trap.y..','..trap.z)
            TrapSystem.removeTrap(trap, true)
        end
        return
    end

    -- Find trap objects that aren't in the traps[] table for some reason.
    -- Could happen if map_t.bin wasn't saved due to a crash after a trap was placed and the chunk saved.
    -- Also, doing a server soft-reset wipes GameTime modData.
    if trapObject then
        noise('found an unknown trap object '..square:getX()..','..square:getY()..','..square:getZ())
        trap = ISTrap:new(square:getX(), square:getY(), square:getZ())
        -- TODO: check if the modData is valid; if not, remove the object
        trap:fromModData(square)
        table.insert(TrapSystem.traps, trap)
        
        modData = {}
        trap:toModData2(modData)
        modData.x = trap.x
        modData.y = trap.y
        modData.z = trap.z
        table.insert(TrapSystem.modData.trapping.traps, modData)
        TrapSystem.noise('added previously-unknown trap '..trap.x..','..trap.y..','..trap.z)
        TrapSystem.noise("#TrapSystem.traps="..#TrapSystem.traps)
        TrapSystem.noise("#TrapSystem.modData.trapping.traps="..#TrapSystem.modData.trapping.traps)
    end
end

TrapSystem.sendCustomModData = function()
    if isClient() then return; end
    for iB,vB in ipairs(TrapSystem.traps) do
        local square = getWorld():getCell():getGridSquare(vB.x, vB.y, vB.z);
        vB:toModData(square, true);
    end
end

function TrapSystem.OnDestroyIsoThumpable(thump, player)
    if isClient() then return end
    if not TrapSystem.isTrapObject(thump) then return end
    noise('TrapSystem.OnDestroyIsoThumpable')
    local square = thump:getSquare()
    if square then
        local trap = TrapSystem.getPlacedTrap(square:getX(), square:getY(), square:getZ())
        if trap then
            TrapSystem.removeTrap(trap, false)
        end
    end
end

function TrapSystem.Init()
    noise('loading GameTime modData')
    TrapSystem.modData = getGameTime():getModData()
    if not TrapSystem.modData.trapping then
        TrapSystem.modData.trapping = {}
        TrapSystem.modData.trapping.traps = {}
    end

    -- Remove duplicates because sh*t happens
    local count = #TrapSystem.modData.trapping.traps
    for i=count,1,-1 do
        local trapi = TrapSystem.modData.trapping.traps[i]
        for j=i-1,1,-1 do
            local trapj = TrapSystem.modData.trapping.traps[j]
            if trapi.x == trapj.x and trapi.y == trapj.y and trapi.z == trapj.z then
                table.remove(TrapSystem.modData.trapping.traps, i)
                noise('ignoring duplicate ISTrap '..trapi.x..','..trapi.y..','..trapi.z)
                break
            end
        end
    end

    TrapSystem.traps = {}
    for i=1,#TrapSystem.modData.trapping.traps do
        local data = TrapSystem.modData.trapping.traps[i]
        local trap = ISTrap:new(data.x, data.y, data.z)
        trap:fromModData2(data)
        table.insert(TrapSystem.traps, trap)
        noise('added trap '..trap.x..','..trap.y..','..trap.z)
    end
    noise("#TrapSystem.traps="..#TrapSystem.traps)
    noise("#TrapSystem.modData.trapping.traps="..#TrapSystem.modData.trapping.traps)
end

function TrapSystem.addSound()
    if isClient() then return; end
    for iB,vB in ipairs(TrapSystem.traps) do
        local square = getWorld():getCell():getGridSquare(vB.x, vB.y, vB.z);
        vB:addSound(square);
    end
end

-- OnGameBoot is to handle soft-reset, no effect on client/sp
function TrapSystem.OnGameBoot()
    if not isClient() then TrapSystem.Init() end
end

function TrapSystem.OnGameStart()
    if not isClient() then TrapSystem.Init() end
end

function TrapSystem.OnGameTimeLoaded()
    if not isClient() then TrapSystem.Init() end
end

Events.OnGameBoot.Add(TrapSystem.OnGameBoot)
--Events.OnGameStart.Add(TrapSystem.OnGameStart)
Events.OnGameTimeLoaded.Add(TrapSystem.OnGameTimeLoaded)
Events.OnDestroyIsoThumpable.Add(TrapSystem.OnDestroyIsoThumpable);
Events.SendCustomModData.Add(TrapSystem.sendCustomModData);
Events.EveryDays.Add(TrapSystem.EveryDays);
--Events.LoadGridsquare.Add(TrapSystem.loadTraps);
Events.EveryHours.Add(TrapSystem.checkTrap);
Events.EveryTenMinutes.Add(TrapSystem.addSound);
