
local type = type
local pairs = pairs
local table = table
local setmetatable = setmetatable
local getmetatable = getmetatable
local tostring = tostring
local tonumber = tonumber
local string = string
local stringx = stringx
local unpack = unpack
module("tablex")


/*---------------------------------------------------------
   Name: Inherit( t, base )
   Desc: Copies any missing data from base to t
---------------------------------------------------------*/
function Inherit( t, base )

	for k, v in pairs( base ) do 
		if ( t[k] == nil ) then	t[k] = v end
	end
	
	t["BaseClass"] = base
	
	return t

end


/*---------------------------------------------------------
    Name: Copy(t, lookup_table)
    Desc: Taken straight from http://lua-users.org/wiki/PitLibTablestuff
          and modified to the new Lua 5.1 code by me.
          Original function by PeterPrade!
---------------------------------------------------------*/
function Copy(t, lookup_table)
	if (t == nil) then return nil end
	
	local copy = {}
	setmetatable(copy, getmetatable(t))
	for i,v in pairs(t) do
		if type(v) ~= "table" then
			copy[i] = v
		else
			lookup_table = lookup_table or {}
			lookup_table[t] = copy
			if lookup_table[v] then
				copy[i] = lookup_table[v] -- we already copied this table. reuse the copy.
			else
				copy[i] = Copy(v,lookup_table) -- not yet copied. copy it.
			end
		end
	end
	return copy
end


/*---------------------------------------------------------
   Name: xx
   Desc: xx
---------------------------------------------------------*/
function Merge(dest, source)
	for k,v in pairs(source) do
		if type(v)=='table' and type(dest[k])=='table' then
			-- don't overwrite one table with another;
			-- instead merge them recurisvely
			Merge(dest[k], v)
		else
			dest[k] = v
		end
	end
	return dest
end


/*---------------------------------------------------------
   Name: xx
   Desc: xx
---------------------------------------------------------*/
function HasValue( t, val )
	for k,v in pairs(t) do
		if (v == val ) then return true end
	end
	return false
end


/*---------------------------------------------------------
   Name: tablex.Add( dest, source )
   Desc: Unlike merge this adds the two tables together and discards keys.
---------------------------------------------------------*/
function Add( dest, source )

	// At least one of them needs to be a table or this whole thing will fall on its ass
	if (type(source)!='table') then return dest end
	
	if (type(dest)!='table') then dest = {} end

	for k,v in pairs(source) do
		table.insert( dest, v )
	end
	
	return dest
end

/*---------------------------------------------------------
   Name: tablex.SortByKey( table )
   Desc: Returns a table sorted numerically by Key value
---------------------------------------------------------*/

function SortByKey(Table)

	local temp = {}

	for key, _ in pairs(Table) do table.insert(temp, key) end
	table.sort(temp, function(a, b) return Table[a] > Table[b] end)

	return temp
end

/*---------------------------------------------------------
   Name: tablex.Count( table )
   Desc: Returns the number of keys in a table
---------------------------------------------------------*/

function Count (t)
  local i = 0
  for k in pairs(t) do i = i + 1 end
  return i
end


/*----------------------------------------------------------------------
   Name: tablex.IsSequential( table )
   Desc: Returns true if the tables 
	 keys are sequential
-----------------------------------------------------------------------*/

function IsSequential(t)
	local i = 1
	for key, value in pairs (t) do
		if not tonumber(i) or key ~= i then return false end
		i = i + 1
	end
	return true
end


/*---------------------------------------------------------
   Name: tablex.ToString( table,name,nice )
   Desc: Convert a simple table to a string
		table = the table you want to convert (table)
		name  = the name of the table (string)
		nice  = whether to add line breaks and indents (bool)
---------------------------------------------------------*/

function ToString(t,n,nice)
	local 		nl,tab  = "",  ""
	if nice then 	nl,tab = "\n", "\t"	end

	local function MakeTable ( t, nice, indent, done)
		local str = ""
		local done = done or {}
		local indent = indent or 0
		local idt = ""
		if nice then idt = string.rep ("\t", indent) end

		local sequential = IsSequential(t)

		for key, value in pairs (t) do

			str = str .. idt .. tab .. tab

			if not sequential then
				if type(key) == "number" or type(key) == "boolean" then 
					key ='['..tostring(key)..']' ..tab..'='
				else
					key = tostring(key) ..tab..'='
				end
			else
				key = ""
			end

			if type (value) == "table" and not done [value] then

				done [value] = true
				str = str .. key .. tab .. '{' .. nl
				.. MakeTable (value, nice, indent + 1, done)
				str = str .. idt .. tab .. tab ..tab .. tab .."},".. nl

			else
				
				if 	type(value) == "string" then 
					value = '"'..tostring(value)..'"'
				elseif  type(value) == "Vector" then
					value = 'Vector('..value.x..','..value.y..','..value.z..')'
				elseif  type(value) == "Angle" then
					value = 'Angle('..value.pitch..','..value.yaw..','..value.roll..')'
				else
					value = tostring(value)
				end
				
				str = str .. key .. tab .. value .. ",".. nl

			end

		end
		return str
	end
	local str = ""
	if n then str = n.. tab .."=" .. tab end
	str = str .."{" .. nl .. MakeTable ( t, nice) .. "}"
	return str
end

function ForceInsert( t, v )
	if ( t == nil ) then t = {} end
	table.insert( t, v )
end
