
// Backwards compatibility
tablex = table

/*---------------------------------------------------------
   Name: Inherit( t, base )
   Desc: Copies any missing data from base to t
---------------------------------------------------------*/
function table.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 table.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] = table.Copy(v,lookup_table) -- not yet copied. copy it.
			end
		end
	end
	return copy
end


/*---------------------------------------------------------
   Name: xx
   Desc: xx
---------------------------------------------------------*/
function table.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
			table.Merge(dest[k], v)
		else
			dest[k] = v
		end
	end
	return dest
end


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

table.InTable = HasValue


/*---------------------------------------------------------
   Name: table.Add( dest, source )
   Desc: Unlike merge this adds the two tables together and discards keys.
---------------------------------------------------------*/
function table.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: table.SortByKey( table )
   Desc: Returns a table sorted numerically by Key value
---------------------------------------------------------*/

function table.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: table.Count( table )
   Desc: Returns the number of keys in a table
---------------------------------------------------------*/

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


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

function table.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: table.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 table.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 = table.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

/*---------------------------------------------------------
   Name: table.Sanitise( table )
   Desc: Converts a table containing vectors, angles, bools so it can be converted to and from keyvalues
---------------------------------------------------------*/
function table.Sanitise( t, done )

	local done = done or {}
	local tbl = {}

	for k, v in pairs ( t ) do
	
		if ( type( v ) == "table" and !done[ v ] ) then

			done[ v ] = true
			tbl[ k ] = table.Sanitise ( v, done )

		else

			if ( type(v) == "Vector" ) then

				local x, y, z = v.x, v.y, v.z
				if y == 0 then y = nil end
				if z == 0 then z = nil end
				tbl[k] = { __type = "Vector", x = x, y = y, z = z }

			elseif ( type(v) == "Angle" ) then

				local p,y,r = v.pitch, v.yaw, v.roll
				if p == 0 then p = nil end
				if y == 0 then y = nil end
				if r == 0 then r = nil end
				tbl[k] = { __type = "Angle", p = p, y = y, r = r }

			elseif ( type(v) == "boolean" ) then
			
				tbl[k] = { __type = "Bool", tostring( v ) }

			else
			
				tbl[k] = tostring(v)

			end
			
			
		end
		
		
	end
	
	return tbl
	
end


/*---------------------------------------------------------
   Name: table.DeSanitise( table )
   Desc: Converts a Sanitised table back
---------------------------------------------------------*/
function table.DeSanitise( t, done )

	local done = done or {}
	local tbl = {}

	for k, v in pairs ( t ) do
	
		if ( type( v ) == "table" and !done[ v ] ) then
		
			done[ v ] = true

			if ( v.__type ) then
			
				if ( v.__type == "Vector" ) then
				
					tbl[ k ] = Vector( v.x, v.y, v.z )
				
				elseif ( v.__type == "Angle" ) then
				
					tbl[ k ] = Angle( v.p, v.y, v.r )
					
				elseif ( v.__type == "Bool" ) then
					
					tbl[ k ] = ( v[1] == "true" )
					
				end
			
			else
			
				tbl[ k ] = table.DeSanitise( v, done )
				
			end
			
		else
		
			tbl[ k ] = v
			
		end
		
	end
	
	return tbl
	
end

function table.ForceInsert( t, v )

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


/*---------------------------------------------------------
   Name: table.SortByMember( table )
   Desc: Sorts table by named member
---------------------------------------------------------*/
function table.SortByMember( Table, MemberName, bAsc )

	if ( bAsc ) then
		table.sort( Table, function(a, b) return a[MemberName] < b[MemberName] end )
	else
		table.sort( Table, function(a, b) return a[MemberName] > b[MemberName] end )
	end
end
