--//=============================================================================
--//  SHORT INFO WHY WE DO THIS:
--// Cause of the reference based system in lua we can't 
--// destroy objects yourself, instead we have to tell
--// the GarbageCollector somehow that an object isn't
--// in use anymore.
--//  Now we have a quite complex class system in Chili 
--// with parent and children links between objects. Those
--// circles make it normally impossible for the GC to
--// detect if an object (and all its children) can be
--// destructed.
--//  This is the point where so called WeakLinks come
--// into play. Instead of saving direct references to the
--// objects in the parent field, we created a weaktable
--// (use google, if you aren't familiar with this name)
--// which directs to the parent-object. So now the link
--// between children and its parent is 'weak' (the GC can
--// catch the parent), and the link between the parent
--// and its children is 'hard', so the GC won't catch the
--// children as long as there is a parent object.
--//=============================================================================

local wmeta =  {__mode = "v"}
local newproxy = newproxy or getfenv(0).newproxy

function MakeWeakLink(obj,wlink)
  --// 2nd argument is optional, if it's given it will reuse the given link (-> less garbage)

  obj = UnlinkSafe(obj) --// unlink hard-/weak-links -> faster (else it would have to go through multiple metatables)

  if (not isindexable(obj)) then
    return obj
  end

  local mtab
  if (type(wlink) == "userdata") then
    mtab = getmetatable(wlink)
  end
  if (not mtab) then
    wlink = newproxy(true)
    mtab = getmetatable(wlink)
    setmetatable(mtab, wmeta)
  end
  local getRealObject = function() return mtab._obj end --// note: we are using mtab._obj here, so it is a weaklink -> it can return nil!
  mtab._islink = true
  mtab._isweak = true
  mtab._obj = obj
  mtab.__index = obj
  mtab.__newindex = obj
  mtab.__call = getRealObject --// values are weak, so we need to make it gc-safe
  mtab[getRealObject] = true  --// and buffer it in a key, too

  if (not obj._wlinks) then
    local t = {}
    setmetatable(t,{__mode="v"})
    obj._wlinks = t
  end
  obj._wlinks[#obj._wlinks+1] = wlink

  return wlink
end


function MakeHardLink(obj,gc)
  obj = UnlinkSafe(obj) --// unlink hard-/weak-links -> faster (else it would have to go through multiple metatables)

  if (not isindexable(obj)) then
    return obj
  end

  local hlink = newproxy(true)
  local mtab = getmetatable(hlink)
  mtab._islink = true
  mtab._ishard = true
  mtab._obj = obj
  mtab.__gc = gc or function() if not obj._hlinks or not next(obj._hlinks) then obj:AutoDispose() end end
  mtab.__index = obj
  mtab.__newindex = obj
  mtab.__call = function() return mtab._obj end

  if (not obj._hlinks) then
    local t = {}
    setmetatable(t,{__mode="v"})
    obj._hlinks = t
  end
  obj._hlinks[#obj._hlinks+1] = hlink

  return hlink
end


function UnlinkSafe(link)
	local link = link
	while (type(link) == "userdata") do
		link = link()
	end
	return link
end


function CompareLinks(link1,link2)
  return UnlinkSafe(link1) == UnlinkSafe(link2)
end


function CheckWeakLink(link)
  return (type(link) == "userdata") and link()
end

--//=============================================================================
