
------------------------------------------------------------------------------------------
-- Global control utilities

-- Local globals table so we don't accidentally declare globals inside functions
local function GLOBAL_set_locked(locked)
  local function lock_new_index(t, k, v)
    error("Globals are locked: " .. k)
  end
  local function safe_get_value(t, k)
    local value = rawget(t, k)
    if value == nil then
      error ("Unknown nil global: " .. k)
    end
    return value
  end
  local mt = getmetatable(_G) or {}
  if locked then
    mt.__newindex = lock_new_index
    mt.__index = safe_get_value
  else
    mt.__newindex = rawset
    mt.__index = nil
  end
  setmetatable(_G, mt)
end

-- Explicit function to make globals
function set_global(key, value)
  GLOBAL_set_locked(false)
  _G[key] = value
  GLOBAL_set_locked(true)
end

-- Check if global exists
function global_exists(key)
  return rawget(_G, key) ~= nil
end

-- Lock the globals for all 
GLOBAL_set_locked(true)

------------------------------------------------------------------------------------------
-- Run external script from given ingame asset

set_global("run_external_script", function(lua_asset_id)

  -- Load and run the level script
  local code = get_external_script(lua_asset_id) -- Note: C++ engine native call
  local res, error = load(code, "Script: " .. lua_asset_id)

  if not error then
    return res()
  else
    print("ERROR! '" .. lua_asset_id .. "': " .. tostring(error))
    return nil
  end
end)

------------------------------------------------------------------------------------------
-- Table utilities

-- Print table (one level)
set_global("print_table", function (tbl)
  for k,v in pairs(tbl) do
    print(tostring(k) .. " -> " .. tostring(v))
  end
end)

-- Table size (slow!)
set_global("table_size", function (tbl)
  local count = 0
  for _ in pairs(tbl) do
    count = count + 1
  end
  return count
end)

-- Add elements from table 'from' to table 'to'
set_global("table_add", function (to, from)
  for _,v in pairs(from) do
    table.insert(to, v)
  end
end)

-- Check if item is comtained in table
set_global("table_contains", function(tbl, item)
  assert(item ~= nil)
  for _,v in pairs(tbl) do
    if v == item then
      return true
    end
  end
  return false
end)

-- If container doesn't contain 'table_name', create one. Then just insert as normal
set_global("table_insert_forced",  function(container, table_name, value)
  if container[table_name] == nil then
      container[table_name] = {}
  end
  table.insert(container[table_name], value)
end)

-- Reverse an indexed table
set_global("table_reverse", function(tbl)
    local size = #tbl
    local res = {}
    for i,v in ipairs(tbl) do
      res[size - i + 1] = v
    end
    return res
end)

-- Clone table (simple version)
set_global("table_clone",  function(orig)
  local orig_type = type(orig)
  local copy
  if orig_type == 'table' then
    copy = {}
    for ok, ov in pairs(orig) do
      copy[ok] = table_clone(ov)
    end
  else
    copy = orig
  end
  return copy
end)

-- Get random element from the table
set_global("table_random_element", function(tbl)
  assert(false) -- TODO use game random, not global ... don't mess with the globals maaan
  return tbl[math.random(#tbl)] -- random in range [1..len]
end)

-- Ordered iteration of tables (adapted from: http://lua-users.org/wiki/SortedIteration)
set_global("table_ordered_keys", function(t)
    local sorted_keys = {}
    for key,_ in pairs(t) do
        table.insert(sorted_keys, key)
    end
    table.sort(sorted_keys)
    return sorted_keys
end)

set_global("table_ordered_pairs_next", function(t, state)
    -- Equivalent of the next function, but returns the keys in the alphabetic
    -- order. We use a temporary ordered key table that is stored in the
    -- table being iterated.

    if state == nil then
        -- The first time, generate the index
        t.__ordered_keys = table_ordered_keys( t )
        local key = t.__ordered_keys[1]
        return key, t[key]
    end

    -- Fetch the next value
    local key = nil
    local table_size = #t.__ordered_keys

    for i = 1,table_size do
        if t.__ordered_keys[i] == state then
            key = t.__ordered_keys[i+1]
        end
    end

    if key then
      return key, t[key]
    end

    -- No more value to return, cleanup
    t.__ordered_keys = nil
    return
end)

-- Equivalent of the pairs() function on tables. Allows to iterate in order
set_global("table_ordered_pairs", function(t)
    return table_ordered_pairs_next, t, nil
end)

------------------------------------------------------------------------------------------
-- String utilities

-- Split string
set_global("string_split", function(str, sep)
  assert(str ~= nil)
  local sep, fields = sep or ":", {}
  local pattern = string.format("([^%s]+)", sep)
  string.gsub(str, pattern, function(c) fields[#fields+1] = c end)
  return fields
end)

------------------------------------------------------------------------------------------
-- Vector functions

set_global("vec", function(in_x, in_y) 
  return { x = in_x, y = in_y }
end)

set_global("vec_add", function(a, b)
  return { x = a.x + b.x, y = a.y + b.y}
end)

set_global("vec_sub", function(a, b)
  return { x = a.x - b.x, y = a.y - b.y}
end)

set_global("vec_mul_scalar", function(a, b)
  return { x = a.x * b, y = a.y * b}
end)

set_global("vec_len", function(a)
  return math.sqrt(a.x*a.x + a.y*a.y)
end)

set_global("vec_direction", function(from, to)
  local delta = vec_sub(to, from)
  return vec_mul_scalar(delta, 1.0 / vec_len(delta))
end)

------------------------------------------------------------------------------------------

print "common.lua: Finished adding utility functions."
