
--- Utils for grouping
function group_entities(entity_list)
    return group_entities(nil, entity_list)
end

function group_entities(entity_groupid, entity_list)
    return group("entities", entity_groupid, entity_list)
end

function getGroup_entities(entity_groupid)
    return getGroup("entities", entity_groupid)
end

function getGroup_entities_by_member(entity_id)
    return getGroup_byMember("entities", entity_id)
end

function ungroup_entities(entity_groupid)
    return ungroup("entities", entity_groupid)
end


-------------------------------------------------------------------
-- Grouping
--
function group(index_id, group_id, members)
  _init_group(index_id, group_id)

  if index_id == nil then
    index_id = "default"
  end

  if group_id then
    for ix, vx in ipairs(members) do
      _addto_group(index_id, group_id, vx)
    end
    return group_id
  else
    -- no GID, then assign one
    return group(index_id, _new_group(index_id), members)
  end
end

function getGroup(index_id, group_id)
  _init_group(index_id, group_id)

  if group_id then
    return _get_group(index_id, group_id)
  else
    return nil
  end
end

function getGroup_byMember(index_id, group_id, member_id)
  _init_group(index_id, group_id)

  if member_id then
    return _of_group(index_id, group_id, entity_id)
  else
    return nil
  end
end

function ungroup(index_id, group_id)
  _init_group(index_id, group_id)

  if group_id then
    return _clear_group(index_id, group_id)
  else
    return false
  end
end
-------------------------------------------------------------------
function _init_group(index_id)
  if not storage.group then
    storage.group = {}
  end
  if not storage.group.default then
    storage.group.default = {}
  end
  if index_id and not storage.group[index_id] then
    -- don't care if they name their group "default"
    storage.group[index_id] = {}
  end
end

function _new_group(index_id)
  local group_id_n = 0
  local group_id_r = nil

  while group_id_r == nil do
   local group_id_x = "gid-" .. (group_id_n + #storage.group[index_id])
    if storage.group[index_id][group_id_x] then
      -- collision
      group_id_n = group_id_n + 1
    else
      group_id_r = group_id_x
    end
  end

  return group_id_r
end

function _addto_group(index_id, group_id, member_id)
  if storage.group[index_id] then
    if not storage.group[index_id][group_id] then
      storage.group[index_id][group_id] = {}
    end
  end

  table.insert(storage.group[index_id][group_id], member_id)
end

function _get_group(index_id, group_id)
  return storage.group[index_id][group_id]
end

function _of_group(index_id, member_id)
  --full scan
  for kx, vx in pairs(storage.group[index_id]) do
    for ky, vy in pairs(vx) do
      if member_id == vy then
        return vx
      end
    end
  end
  return nil
end

function _clear_group(index_id, group_id)
  storage.group[index_id][group_id] = nil
end
-------------------------------------------------------------------

-------------------------------------------------------------------
-- Cantor Hash
-------------------------------------------------------------------
function cantor(k1, k2)
  return (0.5 * (k1+k2) * (k1+k2+1) + k2)
end
-------------------------------------------------------------------
