-- All tree Growing stuff
local Event = require('__kry_stdlib__/stdlib/event/event').set_protected_mode(true)

local terrains = require("libs/trees-and-terrains")

Bi_Industries = {}

Bi_Industries.fertility = {
    ["vegetation-green-grass-1"] = 100,
    ["grass-1"] = 100,
    ["grass-3"] = 85,
    ["grass-2"] = 70,
    ["grass-4"] = 60,
    ["red-desert-0"] = 50,
    ["dirt-3"] = 40,
    ["dirt-5"] = 37,
    ["dirt-6"] = 34,
    ["dirt-7"] = 31,
    ["dirt-4"] = 28,
    ["dry-dirt"] = 25,
    ["dirt-2"] = 22,
    ["dirt-1"] = 19,
    ["red-desert-2"] = 16,
    ["red-desert-3"] = 13,
    ["sand-3"] = 10,
    ["sand-2"] = 7,
    ["sand-1"] = 4,
    ["red-desert-1"] = 1,
    ["frozen-snow-0"] = 1,
    ["frozen-snow-1"] = 1,
    ["frozen-snow-2"] = 1,
    ["frozen-snow-3"] = 1,
    ["frozen-snow-4"] = 1,
    ["frozen-snow-5"] = 1,
    ["frozen-snow-6"] = 1,
    ["frozen-snow-7"] = 1,
    ["frozen-snow-8"] = 1,
    ["frozen-snow-9"] = 1,
    ["mineral-aubergine-dirt-1"] = 45,
    ["mineral-aubergine-dirt-2"] = 45,
    ["mineral-aubergine-dirt-3"] = 25,
    ["mineral-aubergine-dirt-4"] = 25,
    ["mineral-aubergine-dirt-5"] = 25,
    ["mineral-aubergine-dirt-6"] = 25,
    ["mineral-aubergine-dirt-7"] = 25,
    ["mineral-aubergine-dirt-8"] = 25,
    ["mineral-aubergine-dirt-9"] = 25,
    ["mineral-aubergine-sand-1"] = 15,
    ["mineral-aubergine-sand-2"] = 15,
    ["mineral-aubergine-sand-3"] = 10,
    ["mineral-beige-dirt-1"] = 45,
    ["mineral-beige-dirt-2"] = 45,
    ["mineral-beige-dirt-3"] = 25,
    ["mineral-beige-dirt-4"] = 25,
    ["mineral-beige-dirt-5"] = 25,
    ["mineral-beige-dirt-6"] = 25,
    ["mineral-beige-dirt-7"] = 25,
    ["mineral-beige-dirt-8"] = 25,
    ["mineral-beige-dirt-9"] = 25,
    ["mineral-beige-sand-1"] = 10,
    ["mineral-beige-sand-2"] = 10,
    ["mineral-beige-sand-3"] = 10,
    ["mineral-black-dirt-1"] = 45,
    ["mineral-black-dirt-2"] = 45,
    ["mineral-black-dirt-3"] = 25,
    ["mineral-black-dirt-4"] = 25,
    ["mineral-black-dirt-5"] = 25,
    ["mineral-black-dirt-6"] = 25,
    ["mineral-black-dirt-7"] = 25,
    ["mineral-black-dirt-8"] = 25,
    ["mineral-black-dirt-9"] = 25,
    ["mineral-black-sand-1"] = 10,
    ["mineral-black-sand-2"] = 10,
    ["mineral-black-sand-3"] = 10,
    ["mineral-brown-dirt-1"] = 25,
    ["mineral-brown-dirt-2"] = 25,
    ["mineral-brown-dirt-3"] = 25,
    ["mineral-brown-dirt-4"] = 25,
    ["mineral-brown-dirt-5"] = 25,
    ["mineral-brown-dirt-6"] = 25,
    ["mineral-brown-dirt-7"] = 25,
    ["mineral-brown-dirt-8"] = 25,
    ["mineral-brown-dirt-9"] = 25,
    ["mineral-brown-sand-1"] = 10,
    ["mineral-brown-sand-2"] = 10,
    ["mineral-brown-sand-3"] = 10,
    ["mineral-cream-dirt-1"] = 25,
    ["mineral-cream-dirt-2"] = 25,
    ["mineral-cream-dirt-3"] = 25,
    ["mineral-cream-dirt-4"] = 25,
    ["mineral-cream-dirt-5"] = 25,
    ["mineral-cream-dirt-6"] = 25,
    ["mineral-cream-dirt-7"] = 25,
    ["mineral-cream-dirt-8"] = 25,
    ["mineral-cream-dirt-9"] = 25,
    ["mineral-cream-sand-1"] = 10,
    ["mineral-cream-sand-2"] = 10,
    ["mineral-cream-sand-3"] = 10,
    ["mineral-dustyrose-dirt-1"] = 25,
    ["mineral-dustyrose-dirt-2"] = 25,
    ["mineral-dustyrose-dirt-3"] = 25,
    ["mineral-dustyrose-dirt-4"] = 25,
    ["mineral-dustyrose-dirt-5"] = 25,
    ["mineral-dustyrose-dirt-6"] = 25,
    ["mineral-dustyrose-dirt-7"] = 25,
    ["mineral-dustyrose-dirt-8"] = 25,
    ["mineral-dustyrose-dirt-9"] = 25,
    ["mineral-dustyrose-sand-1"] = 10,
    ["mineral-dustyrose-sand-2"] = 10,
    ["mineral-dustyrose-sand-3"] = 10,
    ["mineral-grey-dirt-1"] = 25,
    ["mineral-grey-dirt-2"] = 25,
    ["mineral-grey-dirt-3"] = 25,
    ["mineral-grey-dirt-4"] = 25,
    ["mineral-grey-dirt-5"] = 25,
    ["mineral-grey-dirt-6"] = 25,
    ["mineral-grey-dirt-7"] = 25,
    ["mineral-grey-dirt-8"] = 25,
    ["mineral-grey-dirt-9"] = 25,
    ["mineral-grey-sand-1"] = 10,
    ["mineral-grey-sand-2"] = 10,
    ["mineral-grey-sand-3"] = 10,
    ["mineral-purple-dirt-1"] = 25,
    ["mineral-purple-dirt-2"] = 25,
    ["mineral-purple-dirt-3"] = 25,
    ["mineral-purple-dirt-4"] = 25,
    ["mineral-purple-dirt-5"] = 25,
    ["mineral-purple-dirt-6"] = 25,
    ["mineral-purple-dirt-7"] = 25,
    ["mineral-purple-dirt-8"] = 25,
    ["mineral-purple-dirt-9"] = 25,
    ["mineral-purple-sand-1"] = 10,
    ["mineral-purple-sand-2"] = 10,
    ["mineral-purple-sand-3"] = 10,
    ["mineral-red-dirt-1"] = 25,
    ["mineral-red-dirt-2"] = 25,
    ["mineral-red-dirt-3"] = 25,
    ["mineral-red-dirt-4"] = 25,
    ["mineral-red-dirt-5"] = 25,
    ["mineral-red-dirt-6"] = 25,
    ["mineral-red-dirt-7"] = 25,
    ["mineral-red-dirt-8"] = 25,
    ["mineral-red-dirt-9"] = 25,
    ["mineral-red-sand-1"] = 10,
    ["mineral-red-sand-2"] = 10,
    ["mineral-red-sand-3"] = 10,
    ["mineral-tan-dirt-1"] = 25,
    ["mineral-tan-dirt-2"] = 25,
    ["mineral-tan-dirt-3"] = 25,
    ["mineral-tan-dirt-4"] = 25,
    ["mineral-tan-dirt-5"] = 25,
    ["mineral-tan-dirt-6"] = 25,
    ["mineral-tan-dirt-7"] = 25,
    ["mineral-tan-dirt-8"] = 25,
    ["mineral-tan-dirt-9"] = 25,
    ["mineral-tan-sand-1"] = 10,
    ["mineral-tan-sand-2"] = 10,
    ["mineral-tan-sand-3"] = 10,
    ["mineral-violet-dirt-1"] = 25,
    ["mineral-violet-dirt-2"] = 25,
    ["mineral-violet-dirt-3"] = 25,
    ["mineral-violet-dirt-4"] = 25,
    ["mineral-violet-dirt-5"] = 25,
    ["mineral-violet-dirt-6"] = 25,
    ["mineral-violet-dirt-7"] = 25,
    ["mineral-violet-dirt-8"] = 25,
    ["mineral-violet-dirt-9"] = 25,
    ["mineral-violet-sand-1"] = 10,
    ["mineral-violet-sand-2"] = 10,
    ["mineral-violet-sand-3"] = 10,
    ["mineral-white-dirt-1"] = 25,
    ["mineral-white-dirt-2"] = 25,
    ["mineral-white-dirt-3"] = 25,
    ["mineral-white-dirt-4"] = 25,
    ["mineral-white-dirt-5"] = 25,
    ["mineral-white-dirt-6"] = 25,
    ["mineral-white-dirt-7"] = 25,
    ["mineral-white-dirt-8"] = 25,
    ["mineral-white-dirt-9"] = 25,
    ["mineral-white-sand-1"] = 10,
    ["mineral-white-sand-2"] = 10,
    ["mineral-white-sand-3"] = 10,
    ["vegetation-blue-grass-1"] = 70,
    ["vegetation-blue-grass-2"] = 70,
    ["vegetation-green-grass-2"] = 75,
    ["vegetation-green-grass-3"] = 85,
    ["vegetation-green-grass-4"] = 70,
    ["vegetation-mauve-grass-1"] = 70,
    ["vegetation-mauve-grass-2"] = 70,
    ["vegetation-olive-grass-1"] = 70,
    ["vegetation-olive-grass-2"] = 70,
    ["vegetation-orange-grass-1"] = 70,
    ["vegetation-orange-grass-2"] = 70,
    ["vegetation-purple-grass-1"] = 70,
    ["vegetation-purple-grass-2"] = 70,
    ["vegetation-red-grass-1"] = 70,
    ["vegetation-red-grass-2"] = 70,
    ["vegetation-turquoise-grass-1"] = 70,
    ["vegetation-turquoise-grass-2"] = 70,
    ["vegetation-violet-grass-1"] = 70,
    ["vegetation-violet-grass-2"] = 70,
    ["vegetation-yellow-grass-1"] = 70,
    ["vegetation-yellow-grass-2"] = 70,
    ["volcanic-blue-heat-1"] = 1,
    ["volcanic-blue-heat-2"] = 1,
    ["volcanic-blue-heat-3"] = 1,
    ["volcanic-blue-heat-4"] = 1,
    ["volcanic-green-heat-1"] = 1,
    ["volcanic-green-heat-2"] = 1,
    ["volcanic-green-heat-3"] = 1,
    ["volcanic-green-heat-4"] = 1,
    ["volcanic-orange-heat-1"] = 1,
    ["volcanic-orange-heat-2"] = 1,
    ["volcanic-orange-heat-3"] = 1,
    ["volcanic-orange-heat-4"] = 1,
    ["volcanic-purple-heat-1"] = 1,
    ["volcanic-purple-heat-2"] = 1,
    ["volcanic-purple-heat-3"] = 1,
    ["volcanic-purple-heat-4"] = 1,
    ["landfill"] = 1,
}




-- If we get passed on a tile_name, we can skip getting the tile at position!
local function get_tile_fertility(surface, position, tile_name)
    surface = BioInd.is_surface(surface) or BioInd.arg_err(surface or "nil", "surface")
    position = BioInd.normalize_position(position) or BioInd.arg_err(position or "nil", "position")

    tile_name = tile_name or surface.get_tile(position.x, position.y).name

    local fertility = Bi_Industries.fertility[tile_name]

    return fertility and { fertility = fertility, key = "fertilizer" } or
        { fertility = 1, key = "default" }
end


local function plant_tree(tabl, tree, create_entity)
    BioInd.check_args(tabl, "table")
    BioInd.check_args(tree, "table")
    BioInd.check_args(tree.time, "number", "time")
    -- tree.tree_name is only required if we really want to create a tree,
    -- not if we just want to add a table entry!
    if create_entity then
        BioInd.check_args(tree.tree_name, "string", "tree_name")
    end

    if not (tree.position and BioInd.normalize_position(tree.position)) then
        BioInd.arg_err(tree.position or "nil", "position")
    elseif not (tree.surface and BioInd.is_surface(tree.surface)) then
        BioInd.arg_err(tree.surface or "nil", "surface")
    end

    local grow_until_tick = tree.time
    BioInd.show("grow_until_tick", grow_until_tick)
    tabl[grow_until_tick] = tabl[grow_until_tick] or {}

    -- Update table
    table.insert(tabl[grow_until_tick], tree)
    BioInd.writeDebug("Added tree to table!")

    -- Plant the new tree
    if create_entity then
        tree.surface.create_entity({
            name = tree.tree_name,
            position = tree.position,
            force = "neutral"
        })
    end
end

-- t_base, t_penalty: numbers; seedbomb: Boolean
local function plant_seed(event, t_base, t_penalty, seedbomb)
    for a, arg in pairs({
        { arg = event,     type = "table" },
        { arg = t_base,    type = "number" },
        { arg = t_penalty, type = "number" }
    }) do
        BioInd.check_args(arg.arg, arg.type, arg.desc)
    end

    BioInd.show("event", event)
    BioInd.show("t_base", t_base)
    BioInd.show("t_penalty", t_penalty)
    BioInd.show("seedbomb", seedbomb)
    -- Seed Planted (Put the seedling in the table)
    local entity = event.entity or event.created_entity or
        BioInd.arg_err("nil", "entity")
    local surface = BioInd.is_surface(entity.surface) or
        BioInd.arg_err(entity.surface or "nil", "surface")
    local pos = BioInd.normalize_position(entity.position) or
        BioInd.arg_err(entity.position or "nil", "position")

    -- Minimum will always be 1
    local fertility = get_tile_fertility(surface, pos).fertility

    -- Things will grow faster on fertile than on barren tiles
    -- (No penalty for tiles with maximum fertility)
    local grow_time = math.max(1, math.random(t_base) + t_penalty - (40 * fertility))
    local tree_data = {
        position = pos,
        time = event.tick + grow_time,
        surface = surface,
        seed_bomb = seedbomb
    }
    plant_tree(storage.bi.tree_growing, tree_data, false)
end

function seed_planted(event)
    plant_seed(event, 1000, 4000, false)
end

function seed_planted_trigger(event)
    plant_seed(event, 2000, 6000, true)
end

function seed_planted_arboretum(event, entity)
    event.created_entity = entity
    plant_seed(event, 2000, 6000, false)
end

function summ_weight(tabl)
    local summ = 0
    for i, tree_weights in pairs(tabl or {}) do
        if (type(tree_weights) == "table") and tree_weights.weight then
            summ = summ + tree_weights.weight
        end
    end
    return summ
end

function tree_from_max_index_tabl(max_index, tabl)
    BioInd.check_args(max_index, "number")

    local rnd_index = math.random(max_index)
    for tree_name, tree_weights in pairs(tabl or {}) do
        if (type(tree_weights) == "table") and tree_weights.weight then
            rnd_index = rnd_index - tree_weights.weight
            if rnd_index <= 0 then
                return tree_name
            end
        end
    end
    return nil
end

local function random_tree(tile_name)
    BioInd.show("[random_tree] tile_name", tile_name)
    if terrains[tile_name] then
        local trees_table = terrains[tile_name]
        local max_index = summ_weight(trees_table)
        BioInd.writeDebug("Found %s in table terrains.\tmax_index: %s",
            { tile_name, max_index })
        return tree_from_max_index_tabl(max_index, trees_table)
    end
end


-- Settings used for the different grow stages
local stage_settings = {
    [1] = {
        fertilizer = { max = 1500, penalty = 3000, factor = 30 },
        default = { max = 1500, penalty = 6000, factor = 30 },
    },
    [2] = {
        fertilizer = { max = 1000, penalty = 2000, factor = 20 },
        default = { max = 1500, penalty = 6000, factor = 30 },
    },
    [3] = {
        fertilizer = { max = 1000, penalty = 2000, factor = 20 },
        default = { max = 1500, penalty = 6000, factor = 30 },
    },
}

local function Grow_tree_first_stage(first_stage_table, event)
    BioInd.check_args(first_stage_table, "table")
    BioInd.check_args(event, "table")
    local surface = BioInd.is_surface(first_stage_table.surface) or
        BioInd.arg_err(first_stage_table.surface or "nil", "surface")
    local position = BioInd.normalize_position(first_stage_table.position) or
        BioInd.arg_err(first_stage_table.position or "nil", "position")
    local seed_bomb = first_stage_table.seed_bomb

    local tree = surface.find_entity("seedling", position)
    local tree2 = surface.find_entity("seedling-2", position)
    local tree3 = surface.find_entity("seedling-3", position)
    BioInd.writeDebug("tree: %s\ttree2: %s\ttree3: %s",
        { tree and tree.valid and tree.name or "nil",
            tree2 and tree2.valid and tree2.name or "nil",
            tree3 and tree3.valid and tree3.name or "nil" })

    local tile_name = surface.get_tile(position).name

    -- fertility will be 1 if terrain type is not listed above, so very small chance to grow.
    local f = get_tile_fertility(surface, position, tile_name)
    local fertility, key = f.fertility, f.key
    BioInd.show("fertility", fertility)
    BioInd.show("key", key)
    -- Random value. Tree will grow if this value is smaller than the 'Fertility' value
    local growth_chance = math.random(100)

    local tree_name, can_be_placed
    if tree or tree2 or tree3 then
        BioInd.writeDebug("Found a seedling!")
        tree_name = random_tree(tile_name)
    end
    BioInd.show("tree_name", tree_name)


    if tree then
        BioInd.writeDebug("Have tree")
        if tree.valid then
            tree.destroy()
            BioInd.writeDebug("Destroyed tree!")
        end

        if tree_name and key == "fertilizer" and not seed_bomb then
            -- Depending on Terrain, choose tree type & Convert seedling into a tree
            BioInd.writeDebug("Fertilizer and no seed bomb: New tree can grow!")
            -- Grow the new tree
            can_be_placed = surface.can_place_entity({
                name = tree_name, position = position, force = "neutral"
            })
            BioInd.show("can_be_placed", can_be_placed)
            BioInd.show("growth_chance", growth_chance)
            BioInd.show("fertility", fertility)
            BioInd.show(growth_chance .. " <= (" .. fertility .. " + 5)", growth_chance <= (fertility + 5))

            if can_be_placed and growth_chance <= (fertility + 5) then
                BioInd.writeDebug("Can be placed etc!")
                -- Trees will grow faster on Fertile than on barren tiles
                local grow_time = math.max(1, math.random(2000) + 4000 - (40 * fertility))
                BioInd.show("grow_time", grow_time)

                local stage_1_tree_name = "bio-tree-" .. tree_name .. "-1"
                if not (prototypes.item[stage_1_tree_name] or
                        prototypes.entity[stage_1_tree_name]) then
                    stage_1_tree_name = tree_name
                end
                BioInd.writeDebug("stage_1_tree_name: %s", { stage_1_tree_name })

                local tree_data = {
                    tree_name = stage_1_tree_name,
                    final_tree = tree_name,
                    position = position,
                    time = event.tick + grow_time,
                    surface = surface
                }
                plant_tree(storage.bi.tree_growing_stage_1, tree_data, true)
            end
        end
    end

    --- Seed Bomb Code
    BioInd.show("tree_name", tree_name)
    BioInd.show("tree2", tree2)
    BioInd.show("tree3", tree3)

    if seed_bomb then
        BioInd.writeDebug("Seed bomb was used!")
        if tree2 and tree2.valid then
            tree2.destroy()
            BioInd.writeDebug("Removed tree2!")
        end
        if tree3 and tree3.valid then
            tree3.destroy()
            BioInd.writeDebug("Removed tree3!")
        end

        --- Depending on Terrain, choose tree type & Convert seedling into a tree
        BioInd.show("key", key)
        if key == "fertilizer" then
            BioInd.writeDebug("Got Tile")
            if tree_name then
                BioInd.writeDebug("Found Tree: %s", { tree_name })
                local new_tree = { name = tree_name, position = position, force = "neutral" }
                can_be_placed = surface.can_place_entity(new_tree)
                BioInd.show("can_be_placed", can_be_placed)
                BioInd.show("growth_chance", growth_chance)
                BioInd.show("fertility", fertility)
                BioInd.show("growth_chance <= fertility", growth_chance <= fertility)
                if can_be_placed and growth_chance <= fertility then
                    surface.create_entity(new_tree)
                    BioInd.writeDebug("Created new tree!")
                end
            else
                BioInd.writeDebug("Tree not Found")
            end
        else
            BioInd.writeDebug("Tile not Found")
        end
    end
end

local function Grow_tree_last_stage(last_stage_table)
    BioInd.check_args(last_stage_table, "table")
    BioInd.check_args(last_stage_table.tree_name, "string", "tree_name")
    BioInd.check_args(last_stage_table.final_tree, "string", "final_tree")

    local surface = BioInd.is_surface(last_stage_table.surface) or
        BioInd.arg_err(last_stage_table.surface or "nil", "surface")
    local position = BioInd.normalize_position(last_stage_table.position) or
        BioInd.arg_err(last_stage_table.position or "nil", "position")

    local tree_name = last_stage_table.tree_name
    local final_tree = last_stage_table.final_tree

    local tree = tree_name and surface.find_entity(tree_name, position)


    if tree then
        tree.destroy()

        -- fertility will be 1 if terrain type not listed above, so very small change to grow.
        local f = get_tile_fertility(surface, position)
        local fertility, key = f.fertility, f.key

        -- Random value. Tree will grow if this value is smaller than the 'Fertility' value
        local growth_chance = math.random(100)

        --- Convert growing tree to fully grown tree
        if (key == "fertilizer" or growth_chance <= fertility) then
            -- Grow the new tree
            BioInd.writeDebug("Final Tree Name: %s", { final_tree })
            surface.create_entity({
                name = final_tree,
                position = position,
                force = "neutral"
            })
        end
    end
end


local function Grow_tree_stage(stage_table, stage)
    BioInd.writeDebug("Entered function Grow_tree_stage(%s, %s)", { stage_table, stage })
    BioInd.check_args(stage_table, "table")
    BioInd.check_args(stage, "number")

    if stage == 4 then
        Grow_tree_last_stage(stage_table)
    else
        for a, arg in pairs({
            { arg = stage_table.tree_name,  type = "string", desc = "tree_name" },
            { arg = stage_table.final_tree, type = "string", desc = "final_tree" },
            { arg = stage_table.time,       type = "number", desc = "time" },
        }) do
            BioInd.check_args(arg.arg, arg.type, arg.desc)
        end

        local tree_name = stage_table.tree_name
        local final_tree = stage_table.final_tree
        local time_planted = stage_table.time

        local surface = BioInd.is_surface(stage_table.surface) or
            BioInd.arg_err(stage_table.surface or "nil", "surface")
        local position = BioInd.normalize_position(stage_table.position) or
            BioInd.arg_err(stage_table.position or "nil", "position")



        local tree = tree_name and surface.find_entity(tree_name, position)

        if tree then
            tree.destroy()

            local next_stage = stage + 1
            --- Depending on Terrain, choose tree type & Convert seedling into a tree
            local f = get_tile_fertility(surface, position)
            local fertility, key = f.fertility, f.key

            local next_stage_tree_name = "bio-tree-" .. final_tree .. "-" .. next_stage
            if not (prototypes.item[next_stage_tree_name] or
                    prototypes.entity[next_stage_tree_name]) then
                next_stage_tree_name = final_tree
                BioInd.writeDebug("Next stage %g: Prototype did not exist", { next_stage })
            else
                BioInd.writeDebug("Next stage %g: %s", { next_stage, next_stage_tree_name })
            end

            local can_be_placed = surface.can_place_entity {
                name = next_stage_tree_name,
                position = position,
                force = "neutral"
            }

            if can_be_placed then
                if next_stage_tree_name == final_tree then
                    BioInd.writeDebug("Tree reached final stage, don't insert")
                    surface.create_entity({
                        name = final_tree,
                        position = position,
                        force = "neutral"
                    })
                else
                    -- Trees will grow faster on fertile than on barren tiles!
                    local s = stage_settings[stage][key]
                    local grow_time = math.max(1, math.random(s.max) + s.penalty - (s.factor * fertility))

                    local tree_data = {
                        tree_name = next_stage_tree_name,
                        final_tree = final_tree,
                        position = position,
                        time = time_planted + grow_time,
                        surface = surface
                    }
                    plant_tree(storage.bi["tree_growing_stage_" .. next_stage], tree_data, true)
                end
            end
        else
            BioInd.writeDebug("Did not find that tree I was looking for...")
        end
    end
end


---- Growing Tree
--Event.register(-12, function(event)
Event.register(defines.events.on_tick, function(event)
    if storage.bi.tree_growing_stage_1 == nil then
        for i = 1, 4 do
            storage.bi["tree_growing_stage_" .. i] = storage.bi["tree_growing_stage_" .. i] or {}
        end
    end

    local tick = event.tick

    if storage.bi.tree_growing[tick] then
        for t, tree_data in pairs(storage.bi.tree_growing[tick]) do
            BioInd.writeDebug("Trying to move tree %s to first grow stage!", { t })
            Grow_tree_first_stage(tree_data, event)
        end
        BioInd.writeDebug("Removing storage.bi.tree_growing[%s]!", { tick })
        storage.bi.tree_growing[tick] = nil
    end

    local stage_table
    for stage = 1, 4 do
        stage_table = storage.bi["tree_growing_stage_" .. stage]
        if stage_table[tick] then
            for t, tree_data in pairs(stage_table[tick]) do
                BioInd.writeDebug("Moving tree %s to next grow stage!", { t })
                Grow_tree_stage(tree_data, stage)
            end
            BioInd.writeDebug("Removing storage.bi.tree_growing_stage_%s[%s]!",
                { stage, tick })
            stage_table[tick] = nil
        end
    end
end)
