function copy_table(object)
    local lookup_table = {}

    local function _copy(object)
        if type(object) ~= "table" then
            return object
        elseif lookup_table[object] then
            return lookup_table[object]
        end
        local new_table = {}
        lookup_table[object] = new_table
        for index, value in pairs(object) do
            new_table[_copy(index)] = _copy(value)
        end
        return setmetatable(new_table, getmetatable(object))
    end
    
    return _copy(object)
end


function shallow_copy_table(t)
    local result = {}
    for k, v in pairs (t) do
        result [k] = v
    end
    return setmetatable (result, getmetatable (t))
end


function join_tables(first, second)
    local out = copy_table(first)
    local second_copy = copy_table(second)
    for k, v in pairs(second_copy) do
        if type(k) == "number" then
            table.insert(out, v)
        else
            out[k] = v
        end
    end
    return out
end


function printt(table)
    print(table_to_string(table))
end


function table_to_string(tt, indent, done)
    -- this function is used for saving/loading tables from disk
    -- so be very careful changing it
    done = done or {}
    indent = indent or 0
    local key_str
    if type(tt) == "table" then
        local sb = {}
        for key, value in pairs (tt) do
            if type(key) == "number" then
                key_str = "["..tostring(key).."]"
            else
                key_str = "[\""..tostring(key).."\"]"
            end
            table.insert(sb, string.rep (" ", indent)) -- indent it
            if type (value) == "table" and not done [value] then
                done [value] = true
                table.insert(sb, key_str.." = {\n");
                table.insert(sb, table_to_string (value, indent + 2, done))
                table.insert(sb, string.rep (" ", indent)) -- indent it
                table.insert(sb, "},\n");
            else
                if type(value) == "number" then
                    table.insert(sb, string.format("%s = %g,\n", key_str, value))
                elseif type(value) == "boolean" then
                    table.insert(sb, string.format("%s = %s,\n", key_str, tostring(value)))
                else
                    table.insert(sb, string.format("%s = \"%s\",\n", key_str, tostring(value)))
                end
            end
        end
        return table.concat(sb)
    else
        return tt .. "\n"
    end
end


function angle_dist(a1, a2)
	local d1 = math.abs(a2 - a1) % 360
	local d2 = 360 - d1

	if d1 < d2 then
		if a2 >= a1 then return d1
		else return -d1 end
	else
		if a2 >= a1 then return -d2
		else return d2 end
    end
end


function normalize_angle(angle)
    if a < 0 then
        return 360 + a % 360
    else
        return a % 360
    end
end


function file_load_lua_table(file_name)
    local table, err
    local s = file_load(file_name)
    s = "return { "..s.." }"
    table, err = loadstring(s)
    if err then
        print("ERROR LOADING "..file_name)
        error(err)
        return nil
    end
    return table()
end


function save_table_to_string(table)
end


function generate_guid()
    return string.format("%04x-%04x-%04x-%04x", math.random(0, 65535), math.random(0, 65535), math.random(0, 65535), math.random(0, 65535))
end


function standardize_file_name(name)
    -- spaces to underscores, filter non-alphanumeric, go lowercase
    return string.lower(string.gsub(string.gsub(name, " ", "_"), "[^0-9a-zA-Z\-\_]", ""))
end


------------ string utils from http://lua-users.org/wiki/CommonFunctions

-- remove trailing and leading whitespace from string.
function trim(s)
  return (s:gsub("^%s*(.-)%s*$", "%1"))
end

-- remove leading whitespace from string.
function ltrim(s)
  return (s:gsub("^%s*", ""))
end

-- remove trailing whitespace from string.
function rtrim(s)
  local n = #s
  while n > 0 and s:find("^%s", n) do n = n - 1 end
  return s:sub(1, n)
end

-- substitute variables into string.
-- Example: subst("a=$(a),b=$(b)", {a=1, b=2}) --> "a=1,b=2".
function subst(s, t)
  -- note: handle {a=false} substitution
  s = s:gsub("%$%(([%w_]+)%)", function(name)
    local val = t[name]
    return val ~= nil and tostring(val)
  end)
  return s
end

-- [mjc 6/12/2008] here is my basic split implementation.
-- takes a string and a pattern to split with. returns a table
-- of words that have been seperated at the pattern (does not
-- include the pattern in any words in the returned table).
function split(str, patt)
	vals = {}; valindex = 0; word = ""
	-- need to add a trailing separator to catch the last value.
	str = str .. patt
	for i = 1, string.len(str) do

		cha = string.sub(str, i, i)
		if cha ~= patt then
			word = word .. cha
		else
			if word ~= nil then
				vals[valindex] = word
				valindex = valindex + 1
				word = ""
			else
				-- in case we get a line with no data.
				break
			end
		end

	end
	return vals
end
