debug = true

stock = {}
players = {}
turtle_id = 1

update_player_timer = nil
update_inventory_timer = nil

update_player_interval = 0.2
update_inventory_interval = 2.0

serialize = textutils.serialize

centre = vector.new(698, 4, -636)
isn_offsets = {
    vector.new(-1,  2,  8),
    vector.new(-1,  2,  2),
    vector.new(-1,  2, -2),
    vector.new(-1,  2, -8),
}

chest_details = {
    ['Chest'] = 'Chest',
    ['cpw.mods.ironchest.TileEntityCopperChest'] = 'Copper chest',
    ['cpw.mods.ironchest.TileEntityIronChest'] = 'Iron chest',
    ['cpw.mods.ironchest.TileEntitySilverChest'] = 'Silver chest',
    ['cpw.mods.ironchest.TileEntityGoldChest'] = 'Gold chest',
    ['cpw.mods.ironchest.TileEntityDiamondChest'] = 'Diamond chest',
    ['cpw.mods.ironchest.TileEntityCrystalChest'] = 'Crystal chest',
    ['thaumcraft.common.blocks.TileChestHungry'] = 'Hungry chest',
}

stock = {}

function listPeripherals()
    for i,side in ipairs(peripheral.getSides()) do
        p = peripheral.wrap(side)
        if p ~= nil then
            print(side..': '..peripheral.getType(side))
        end
    end
end

function string_to_vector(s)
    local t = {}
    for n in s:gmatch('[-%d]+') do
        table.insert(t,tonumber(n))
    end
    return vector.new(t[1], t[2], t[3])
end

function build_table()
    -- build a mapping from relative inventory positions to global positions
    for i,sensor in ipairs(isn) do
        print('checking sensor '..i..' ('..tostring(sensor)..')')
        ctally = 0
        sensor_pos = centre + isn_offsets[i]
        for offset,attrs in pairs(sensor.getTargets()) do
            if chest_details[attrs.type] == nil then
                print('warning: unknown chest type "'..attrs.type..'"')
            else
                v = string_to_vector(offset)
                inv_pos = sensor_pos + v
                if stock[inv_pos.x] == nil then stock[inv_pos.x] = {} end 
                if stock[inv_pos.x][inv_pos.z] == nil then stock[inv_pos.x][inv_pos.z] = {} end 
                if stock[inv_pos.x][inv_pos.z][inv_pos.y] == nil then
                    stock[inv_pos.x][inv_pos.z][inv_pos.y] = sensor.getTargetDetails(offset) end
                ctally = ctally + 1
            end
        end
        print(ctally..' chests')
    end
end


function init()
    
    mmn = peripheral.wrap('top') -- main monitor
    psn = peripheral.wrap('bottom:black') -- proximity sensor
    xmn = {
        peripheral.wrap('bottom:cyan'), -- left most extra monitor
        peripheral.wrap('bottom:gray'),
        peripheral.wrap('bottom:lime'),
        peripheral.wrap('bottom:lightBlue'),
        peripheral.wrap('bottom:magenta'),
        peripheral.wrap('bottom:orange'), -- right most extra monitor
    }
    isn = {
        peripheral.wrap('bottom:silver'), -- left most inventory sensor, yeah, light gray is apparently silver
        peripheral.wrap('bottom:pink'),
        peripheral.wrap('bottom:yellow'),
        peripheral.wrap('bottom:white'), -- right most inventory sensor
    }

    rednet.open('back')
    
end

function test_peripherals()
    for i=1,6 do
        xmn[i].setTextScale(0.5)
        xmn[i].setCursorPos(1,1)
        xmn[i].write('xmn['..i..']')
        print('Extra monitor '..i..' found')
    end
    mmn.setTextScale(0.5)
    mmn.setCursorPos(1,1)
    mmn.write('Main monitor')
    print('Main monitor found')
    if psn.getSensorName() == 'openccsensors.item.proximitysensor' then
        print('Proximity sensor found')
    end
    for i=1,4 do
        if isn[i].getSensorName() == 'openccsensors.item.inventorysensor' then
            print('Inventory sensor '..i..' found')
        end
    end
end

function get_players()
    -- return a list of players near the proximity sensor
    if psn == nil then return {} end
    local targets = psn.getTargets()
    local l = {}
    for k,v in pairs(targets) do
        if v.type == 'Player' then
            table.insert(l,k)
        end
    end
    return l
end

function update_players()
    local new_players = get_players()
    if #players == 0 and #new_players >= 1 then
        -- greet_player()
        print('Welcome to ya')
    elseif #players >= 1 and #new_players == 0 then
        -- trigger_refresh()
        print('I am so alone')
    end
    players = new_players
    
    update_player_timer = os.startTimer(update_player_interval)
end

function update_display()
    -- update stuff displayed 
end

function refresh_inventory()
    for i,v in ipairs(isn) do
        print('update from '..i)
        
    end
    
    update_inventory_timer = os.startTimer(update_inventory_interval)
end

function list_stock()
    tally = {}
    empty_slots = 0
    total_items = 0
    for ix,vx in pairs(stock) do
        for iz,vz in pairs(vx) do
            for iy,container in pairs(vz) do
                for islot,slot in ipairs(container) do
                    if slot.Name ~= 'empty' then
                        if tally[slot.Name] == nil then
                            tally[slot.Name] = slot.Size
                        else
                            tally[slot.Name] = tally[slot.Name] + slot.Size
                        end
                        total_items = total_items + slot.Size
                    else
                        empty_slots = empty_slots + 1
                    end
                end
            end
        end
    end
    
    for k,v in pairs(tally) do
        print(k..': '..v)
    end
    print('Total items: '..total_items)
    print('Empty slots: '..empty_slots)
end

function update_extra_monitors()
    for i,monitor in ipairs(xmn) do
        monitor.setCursorPos(1,1)
        monitor.clear()
        for i=1,52 do
            cy = math.floor((i + 15) / 14)
            sub_y = (i + 15) % 14
            monitor.setCursorPos(1,i)
            monitor.write(cy..','..sub_y)
        end
    end
    
    m = xmn[1]
    m.clear()
    m.setCursorPos(1,1)
    m.write("<<- Misc. junk")
    m.setCursorPos(1,3)
    m.write("<- Tools")
    m.setCursorPos(1,5)
    m.write("<<- Misc. junk")
    m.setCursorPos(1,7)
    m.write("<- Tools")
    
    function write_left(msg, monitor, y)
        y = y or 1
        local w,h = monitor.getSize()
        x = 1
        monitor.setCursorPos(x,y)
        monitor.clearLine()
        monitor.write(msg)
    end
    
    function write_center(msg, monitor, y)
        y = y or 1
        local w,h = monitor.getSize()
        x = (w - #msg) / 2 + 1
        monitor.setCursorPos(x,y)
        monitor.clearLine()
        monitor.write(msg)
    end
    
    function write_right(msg, monitor, y)
        y = y or 1
        local w,h = monitor.getSize()
        x = w - #msg + 1
        monitor.setCursorPos(x,y)
        monitor.clearLine()
        monitor.write(msg)
    end
    
    xmn[2].clear()
    write_center('xmn[2]', xmn[2],1)
    write_left('<- tools', xmn[2],4)
    write_left('.... ticker .....', xmn[2],5)
    write_right('ingots ->', xmn[2],8)
    write_left('.... ticker .....', xmn[2],9)
    
    
end

init()
build_table()
list_stock()
test_peripherals()
update_extra_monitors()

--print(serialize(stock))


error('exit')

update_players()
refresh_inventory()

while true do
    -- some main loop, question is how to best do it... probably not like this... 
    -- probably should pull events instead with an additional timer to pull sensor data insteald of handling those as events.
    -- parallel.waitForAll(update_players, handle_rednet, update_display)
    
    event, p1, p2, p3 = os.pullEvent()
    if event == 'timer' then
        if p1 == update_player_timer then
            update_players()
        elseif p1 == update_inventory_timer then
        
        else
            print('warning: unknown timer id '..p1)
        end
    elseif event == 'rednet_message' then
        print('Rednet event')
    elseif event == 'char' then
        if p1 == 'q' then
            print('shutting down')
            term.restore()
            break
        end
    else
        print('info: some other event triggered')
        print('  '..event..'('..tostring(p1)..','..tostring(p2)..','..tostring(p3)..')')
    end
    
end