-- Salt's ComputerCraft Storage Network Script
--
-- For information on this script, physical in-world setup, and configuration,
-- see: https://git.desu.ltd/salt/mc-scripts/src/branch/master/storage-net

-- Startup diagnostics
print("Salt's CC Storage Net")

-- Global scope locals
local output = peripheral.wrap("top") or error("Put a chest on top of this terminal for output items", 0)

-- Helper functions
function getDepositHoppers()
    -- Get all connected inventories that push items into the system
    return {peripheral.find("inventory", function(name,i)
        return string.find(name, "minecraft:hopper")
    end)}
end
function getConnectedChests()
    -- Get all connected inventories that store items
    return {peripheral.find("inventory", function(name,i)
        return string.find(name, "minecraft:chest")
    end)}
end

-- Common functions
function pushDepositsToChests()
    -- Take all the contents of all connected hoppers and stuff them into any other connected inventory
    -- These things are wrapped into tables because that's how you take multiple return values and stuff them in a table, apparently
    local hoppers = getDepositHoppers()
    local chests = getConnectedChests()
    -- For each hopper connected to the network...
    for k,hopper in ipairs(hoppers) do
        -- For each item in that hopper's inventory...
        for hslot,hitem in pairs(hopper.list()) do
            local remaining = hitem["count"]
            -- For each connected "chest"...
            for k,chest in ipairs(chests) do
                -- First, make an attempt to find slots that we can shove the item into
                for cslot,citem in pairs(chest.list()) do
                    if
                        citem["name"] == hitem["name"] and                  -- We have the same item
                        citem["count"] < chest.getItemLimit(cslot) and      -- There's space in this slot
                        remaining > 0                                       -- We still have things to sort
                    then
                        difference = chest.getItemLimit(cslot) - citem["count"]
                        hopper.pushItems(peripheral.getName(chest),hslot,difference,cslot)
                        remaining = remaining - difference
                    end
                end
            end
            -- We've fallen through trying to fill up existing stacks. Fragmentation is not a concern, put it wherever
            if remaining > 0 then
                for k,chest in ipairs(chests) do
                    hopper.pushItems(peripheral.getName(chest),hslot)
                end
            end
        end
    end
end

-- Application entrypoint
function main()
    while true do
        -- Manage inventory cleanup tasks
        pushDepositsToChests()                  -- Take all deposit terminals and push them into the inventory network
        -- Sleep for a tick
        sleep(0.05)                             -- This is to stop CC from killing us
    end
end

main()