DiseaseGridDeltaEvent = {}
local DiseaseGridDeltaEvent_mt = Class(DiseaseGridDeltaEvent, Event)
InitEventClass(DiseaseGridDeltaEvent, "DiseaseGridDeltaEvent")

function DiseaseGridDeltaEvent.emptyNew()
    return Event.new(DiseaseGridDeltaEvent_mt)
end

function DiseaseGridDeltaEvent.new(cells, resetBefore)
    local self = DiseaseGridDeltaEvent.emptyNew()
    self.cells = cells or {}
    self.resetBefore = resetBefore == true
    return self
end

local function writeCell(streamId, cell)
    streamWriteUInt16(streamId, math.max(0, tonumber(cell.x or 0) or 0))
    streamWriteUInt16(streamId, math.max(0, tonumber(cell.z or 0) or 0))
    streamWriteUIntN(streamId, math.max(0, math.min(3, tonumber(cell.severity or 0) or 0)), 2)
    streamWriteUIntN(streamId, math.max(0, math.min(15, tonumber(cell.threatId or 0) or 0)), 4)
    streamWriteUIntN(streamId, math.max(0, math.min(3, tonumber(cell.protection or 0) or 0)), 2)
end

local function readCell(streamId)
    return {
        x = streamReadUInt16(streamId),
        z = streamReadUInt16(streamId),
        severity = streamReadUIntN(streamId, 2),
        threatId = streamReadUIntN(streamId, 4),
        protection = streamReadUIntN(streamId, 2)
    }
end

function DiseaseGridDeltaEvent:writeStream(streamId, _)
    streamWriteBool(streamId, self.resetBefore == true)
    streamWriteUInt16(streamId, #self.cells)
    for _, cell in ipairs(self.cells) do
        writeCell(streamId, cell)
    end
end

function DiseaseGridDeltaEvent:readStream(streamId, connection)
    self.resetBefore = streamReadBool(streamId)
    self.cells = {}

    local count = streamReadUInt16(streamId)
    for _ = 1, count do
        table.insert(self.cells, readCell(streamId))
    end

    self:run(connection)
end

function DiseaseGridDeltaEvent:run(_)
    if DiseaseGrid ~= nil and DiseaseGrid.applyNetworkCellBatch ~= nil then
        DiseaseGrid:applyNetworkCellBatch(self.cells, self.resetBefore == true)
    end
end

function DiseaseGridDeltaEvent.sendToConnection(connection, cells, resetBefore)
    if connection ~= nil and cells ~= nil then
        connection:sendEvent(DiseaseGridDeltaEvent.new(cells, resetBefore))
    end
end

function DiseaseGridDeltaEvent.broadcast(cells)
    if g_server ~= nil and cells ~= nil and #cells > 0 then
        g_server:broadcastEvent(DiseaseGridDeltaEvent.new(cells, false), false)
    end
end
