local function edge_to_id(x, y, width, height)
    if y == 0 then
        return 1 + x
    elseif x == width - 1 then
        return width + y
    elseif y == height - 1 then
        return width + height + ((width - 1) - x) - 1
    else
        return width * 2 + height + ((height - 1) - y) - 2
    end
end

local function id_to_edge(id, width, height)
    if id <= width then
        return id - 1, 0
    elseif id < width + height - 1 then
        return width - 1, id - width
    elseif id < width * 2 + height - 2 then
        return width - (id - width - height + 2), height - 1
    else
        return 0, height - (id - width * 2 - height + 3)
    end
end

local function should_extend(x, y, dx, dy)
    if level.get_tile(x, y).get_name() == "base:foundation" and
        level.is_room_type_at(x + dx, y + dy, "base:building") and
        not level.get_tile(x + dx * 2, y + dy * 2).has_property("building_edge")
    then
        return true
    else
        return false
    end
end

function update(room, prev)
    local ox, oy, width, height = room:get_bounds()

    local state = {
        joins = {},
    }
    if prev ~= nil then
        -- TODO: Other things?
        state.plants = prev.plants

        for id, v in pairs(prev.joins) do
            local x, y = id_to_edge(id, width, height)
            local flags = state.joins[id] or {}
            if v.down and level.is_room_type_at(ox + x, oy + y - 1, "base:building") then
                flags.down = true
            end
            if v.up and level.is_room_type_at(ox + x, oy + y + 1, "base:building") then
                flags.up = true
            end
            if v.left and level.is_room_type_at(ox + x - 1, oy + y, "base:building") then
                flags.left = true
            end
            if v.right and level.is_room_type_at(ox + x + 1, oy + y, "base:building") then
                flags.right = true
            end
            if flags.up or flags.down or flags.left or flags.right then
                state.joins[id] = flags
            end
        end
    end
    -- Look for changes

    for i = 1, width*2 + height*2 - 4 do
        local x, y = id_to_edge(i, width, height)

        -- TODO: Corners are buggy
        if not ((x == 0 or x == width - 1) and (y == 0 or y == height - 1)) then
            local flags = state.joins[i] or {}
            if x == 0 and should_extend(ox + x, oy + y, -1, 0) then
                flags.left = true
            end
            if x == width - 1 and should_extend(ox + x, oy + y, 1, 0) then
                flags.right = true
            end
            if y == 0 and should_extend(ox + x, oy + y, 0, -1) then
                flags.down = true
            end
            if y == height - 1 and should_extend(ox + x, oy + y, 0, 1) then
                flags.up = true
            end

            if flags.up or flags.down or flags.left or flags.right then
                state.joins[i] = flags
            end
        end
    end

    return state
end

function apply(room, placer, state)
    local ox, oy, width, height = room:get_bounds()
    for id = 1, width*2 + height*2 - 4 do
        local x, y = id_to_edge(id, width, height)
        if state.joins[id] ~= nil then
            if level.get_tile(ox + x, oy + y).get_name() == "base:foundation" then
                placer:set_tile(ox + x, oy + y, "base:building")
            end
            placer:depends_on(ox + x, oy + y)
            local flags = state.joins[id]
            if flags.down then
                placer:depends_on(ox + x, oy + y - 1)
            end
            if flags.up then
                placer:depends_on(ox + x, oy + y + 1)
            end
            if flags.left then
                placer:depends_on(ox + x - 1, oy + y)
            end
            if flags.right then
                placer:depends_on(ox + x + 1, oy + y)
            end
        else
            if level.get_tile(ox + x, oy + y).get_name() == "base:building" then
                placer:set_tile(ox + x, oy + y, "base:foundation")
            end
        end
    end
end