-- This config example file is released into the Public Domain.

-- This Lua config demonstrates how to use (some of) the generalization
-- functionality. In this case we are generating a forest layer and create
-- several levels of generalized data from it.
--
-- NOTE THAT THE GENERALIZATION SUPPORT IS EXPERIMENTAL AND MIGHT CHANGE
-- WITHOUT NOTICE!

-- We want to do three levels of generalized data for different zoom levels
-- or scales: small, medium, and large.
local gen_levels = { 's', 'm', 'l' }

-- And these are the zoom levels we do the generalization in. This doesn't
-- mean that these are the zoom levels for which the generalization is shown!
local zoom_levels = { s = 7, m = 8, l = 10 }

local expire_outputs = {}

-- These defines the expire outputs for three levels of generalized data.
-- See flex-config/expire.lua for details on how this works.
for _, level in ipairs(gen_levels) do
    expire_outputs['exp_' .. level] = osm2pgsql.define_expire_output({
        maxzoom = zoom_levels[level],
        table = 'exp_' .. level,
    })
end

local tables = {}

-- This is the table for the original data.
tables.forests = osm2pgsql.define_area_table('forests', {
    -- We'll keep the name tag
    { column = 'name', type = 'text' },
    -- We'll also keep all other tags, just because we can
    { column = 'tags', type = 'jsonb' },
    -- Geometries can be polygons or multipolygons
    { column = 'geom', type = 'geometry', not_null = true,
        expire = {
            { output = expire_outputs.exp_s },
            { output = expire_outputs.exp_m },
            { output = expire_outputs.exp_l },
        }
    },
    -- If the forest has a name and isn't too small, this will be a point
    -- where we can put a label.
    { column = 'labelpoint', type = 'point' },
    -- The area (in Web Mercator units) for lager forests, otherwise NULL.
    { column = 'area', type = 'real' },
})

-- These defines the tables for three levels of generalized data. In this
-- case, the geometries generated by the generalization are always polygons.
for _, level in ipairs(gen_levels) do
    tables['forests_' .. level] = osm2pgsql.define_table({
        name = 'forests_' .. level,
        -- Define the x and y integer columns and add an index for them.
        ids = { type = 'tile' },
        columns = {
            { column = 'geom', type = 'polygon', not_null = true }
        }
    })
end

-- This is where the data is actually inserted into the forests table. If
-- the forest has a name tag and the area is larger than a defined minimum
-- we'll also add the name and a point for the label.
local minimum_area_for_label = 0.001
local function insert_forest(tags, geom)
    local attrs = {
        tags = tags,
        geom = geom,
    }
    if tags.name then
        local area = geom:area()
        if area >= minimum_area_for_label then
            attrs.name = tags.name
            attrs.area = area
            attrs.labelpoint = geom:pole_of_inaccessibility()
        end
    end
    tables.forests:insert(attrs)
end

function osm2pgsql.process_way(object)
    if not object.is_closed then
        return
    end
    local tags = object.tags
    if tags.natural == 'wood' or tags.landuse == 'forest' then
        insert_forest(tags, object:as_polygon())
    end
end

function osm2pgsql.process_relation(object)
    if object.tags.type ~= 'multipolygon' then
        return
    end
    local tags = object.tags
    if tags.natural == 'wood' or tags.landuse == 'forest' then
        insert_forest(tags, object:as_multipolygon())
    end
end

-- This function is called in the generalization step. We define three levels
-- of generalization that should go into the already created tables.
function osm2pgsql.process_gen()
    for _, level in ipairs(gen_levels) do
        osm2pgsql.run_gen('raster-union', {
            name = 'forests_' .. level, -- name (for logging)
            debug = false, -- set to true to get more details debug output
            src_table = 'forests',
            dest_table = 'forests_' .. level,
            zoom = zoom_levels[level],
            geom_column = 'geom',
            margin = 0.1, -- 10% overlap at tile boundaries
            expire_list = 'exp_' .. level, -- where to get expired tiles in append mode
            make_valid = true -- make sure geometries are valid
        })
    end
end

