-- some set testing for usage with semi known items types
-- following http://www.lua.org/pil/13.1.html
-- could probably make a InvSet "type" which has builtin functionality about handling "unknown_n_m" values.

--[[

increased

nil -> assumed (should be impossible)
unknown -> assumed
set -> set * assumed
set -> error if set * assumed == {}

created

Instead of using 'Unknown-1' use a separate integer to indicate the identification of the unknown item.
Use a central server to track stock and request items from

inv = {
    -- [index] = {possible_items, count, space, computer_id, identification}
    [1] = {Set({'Oak wood'}), 60, 4, 1, nil},
    [2] = {Set({'Oak sapling', 'Apple'}, 2, 62, 1, 1},
}

]]--


Set = {}
Set.mt = {}

function Set.new (t)
    local set = {}
    setmetatable(set, Set.mt)
    for _, l in ipairs(t) do set[l] = true end
    return set
end

Set.mt.__tostring = function (set)
    local s = '{'
    local sep = ''
    for e in pairs(set) do
        s = s .. sep .. e
        sep = ', '
    end
    return s .. '}'
end

Set.mt.__add = function (a,b)
    if getmetatable(a) ~= Set.mt or getmetatable(b) ~= Set.mt then
        error('attempt to "unite" a set with a non-set value', 2)
    end
    local res = Set.new{}
    for k in pairs(a) do res[k] = true end
    for k in pairs(b) do res[k] = true end
    return res
end

Set.mt.__mul = function (a,b)
    if getmetatable(a) ~= Set.mt or getmetatable(b) ~= Set.mt then
        error('attempt to "intersect" a set with a non-set value', 2)
    end
    local res = Set.new{}
    for k in pairs(a) do
        res[k] = b[k]
    end
    return res
end

Set.mt.__le = function (a,b)
    for k in pairs(a) do
        if not b[k] then return false end
    end
    return true
end

Set.mt.__lt = function (a,b)
    return a <= b and not (b <= a)
end

Set.mt.__eq = function (a,b)
    return a <= b and b <= a
end

Set.mt.__len = function (a)
    print('wibble')
    return  12
end

function Set.print (s)
  print(Set.tostring(s))
end

uid = 1

function get_uid()
    r = uid
    uid = uid + 1
    return r
end

function check_inventory(assume)
    
    assume = assume or nil
    print('assume = '..textutils.serialize(assume))
    os.sleep(0.5)
    
    for i=1,16 do
        count = turtle.getItemCount(i)
        space = turtle.getItemSpace(i)
        if count == 0 then
            print('Nothing in slot '..i)
            inv[i] = {}
            os.sleep(0.5)
        elseif inv[i] == nil or #inv[i] == 0 then
            print('New item in slot '..i)
            inv[i] = {
                item=assume,
                count=count,
                space=space,
                id1=os.getComputerID(),
                id2=get_uid()
            }
            os.sleep(0.5)
        elseif inv[i].count == count then
            print('Stable situation in slot '..i)
            os.sleep(0.5)
        elseif inv[i].count < count then
            print('Count increased in slot '..i)
            os.sleep(0.5)
        elseif inv[i].count > count then
            print('Count decreased in slot '..i)
            os.sleep(0.5)
        else
            print('Unknown situation for slot '..i)   
            os.sleep(0.5)    
        end
    end
end

--===========================--

t = {}   -- original table (created somewhere)
    
-- keep a private access to original table
local _t = t

-- create proxy
t = {}

-- create metatable
local mt = {
  __index = function (t,k)
    print("*access to element " .. tostring(k))
    return _t[k]   -- access the original table
  end,

  __newindex = function (t,k,v)
    print("*update of element " .. tostring(k) ..
                         " to " .. tostring(v))
    _t[k] = v   -- update original table
  end,
}
setmetatable(t, mt)


t.save = function(t)
    print('saving ... (not really)')
    print(textutils.serialize(t))
  end
--===========================--


cur = {'Unknown 1.1', 4, 60}
assume = Set.new({'Oak wood planks'})

inv = {}
inv[1] = {}
inv[16] = {
    item=Set.new({'Oak sapling', 'Apple'}),
    count=2,
    space=62,
    id1=os.getComputerID(),
    id2=0
}

-- check_inventory(assume)
-- print(textutils.serialize(inv))

t[1] = {}
t[1][1] = {}
t:save()
