local ffi = require("ffi")
local C = ffi.C
local core = require("pxl8.core")

local tilemap = {}

tilemap.TILE_FLIP_X = 1
tilemap.TILE_FLIP_Y = 2
tilemap.TILE_SOLID = 4
tilemap.TILE_TRIGGER = 8

local Tilesheet = {}
Tilesheet.__index = Tilesheet

function Tilesheet.new(tile_size)
    local ts = C.pxl8_tilesheet_create(tile_size or 16)
    if ts == nil then
        return nil
    end
    return setmetatable({ _ptr = ts }, Tilesheet)
end

function Tilesheet:destroy()
    if self._ptr then
        C.pxl8_tilesheet_destroy(self._ptr)
        self._ptr = nil
    end
end

function Tilesheet:load(filepath)
    return C.pxl8_tilesheet_load(self._ptr, filepath, core.gfx)
end

tilemap.Tilesheet = Tilesheet

local Tilemap = {}
Tilemap.__index = Tilemap

local tile_data = setmetatable({}, {__mode = "k"})

function Tilemap.new(width, height, tile_size)
    local tm = C.pxl8_tilemap_create(width, height, tile_size or 16)
    if tm == nil then
        return nil
    end
    return setmetatable({ _ptr = tm }, Tilemap)
end

function Tilemap:check_collision(x, y, w, h)
    return C.pxl8_tilemap_check_collision(self._ptr, x, y, w, h)
end

function Tilemap:destroy()
    if self._ptr then
        C.pxl8_tilemap_destroy(self._ptr)
        self._ptr = nil
    end
end

function Tilemap:get_tile_data(tile_id)
    if tile_id == 0 then return nil end
    if not tile_data[self] then return nil end
    return tile_data[self][tile_id]
end

function Tilemap:get_tile_id(layer, x, y)
    return C.pxl8_tilemap_get_tile_id(self._ptr, layer or 0, x, y)
end

function Tilemap:is_solid(x, y)
    return C.pxl8_tilemap_is_solid(self._ptr, x, y)
end

function Tilemap:load_ase(filepath, layer)
    return C.pxl8_tilemap_load_ase(self._ptr, filepath, layer or 0)
end

function Tilemap:render()
    C.pxl8_tilemap_render(self._ptr, core.gfx)
end

function Tilemap:render_layer(layer)
    C.pxl8_tilemap_render_layer(self._ptr, core.gfx, layer)
end

function Tilemap:set_camera(x, y)
    C.pxl8_tilemap_set_camera(self._ptr, x, y)
end

function Tilemap:set_tile(layer, x, y, tile_id, flags)
    C.pxl8_tilemap_set_tile(self._ptr, layer or 0, x, y, tile_id or 0, flags or 0)
end

function Tilemap:set_tile_data(tile_id, data)
    if tile_id == 0 then return end
    if not tile_data[self] then tile_data[self] = {} end
    tile_data[self][tile_id] = data
end

function Tilemap:set_tilesheet(tilesheet)
    return C.pxl8_tilemap_set_tilesheet(self._ptr, tilesheet._ptr)
end

tilemap.Tilemap = Tilemap

return tilemap
