
// 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: Empty( tab )
    Desc: Empty a table
---------------------------------------------------------*/
function table.Empty( tab )

	for k, v in pairs( tab ) do
		tab[k] = nil
	end

end

/*---------------------------------------------------------
    Name: CopyFromTo( FROM, TO )
    Desc: Make TO exactly the same as FROM - but still the same table.
---------------------------------------------------------*/
function table.CopyFromTo( FROM, TO )

	// Erase values from table TO
	table.Empty( TO )
	
	// Copy values over
	table.Merge( TO, FROM )
	
end


/*---------------------------------------------------------
   Name: xx
   Desc: xx
---------------------------------------------------------*/
function table.Merge(dest, source)

	for k,v in pairs(source) do
	
		if ( type(v) == 'table' && 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.sortdesc( table )
   Desc: Like Lua's default sort, but descending
---------------------------------------------------------*/
function table.sortdesc( Table )

	return table.sort( Table, function(a, b) return a > b end )
end

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

function table.SortByKey( Table, Desc )

	local temp = {}

	for key, _ in pairs(Table) do table.insert(temp, key) end
	if ( Desc ) then
		table.sort(temp, function(a, b) return Table[a] < Table[b] end)
	else
		table.sort(temp, function(a, b) return Table[a] > Table[b] end)
	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 )

	local TableMemberSort = function( a, b, MemberName, bReverse ) 
	
		//
		// All this error checking kind of sucks, but really is needed
		//
		if ( type(a) != "table" ) then return !bReverse end
		if ( type(b) != "table" ) then return bReverse end
		if ( !a[MemberName] ) then return !bReverse end
		if ( !b[MemberName] ) then return bReverse end
	
		if ( bReverse ) then
			return a[MemberName] < b[MemberName]
		else
			return a[MemberName] > b[MemberName]
		end
		
	end

	table.sort( Table, function(a, b) return TableMemberSort( a, b, MemberName, bAsc or false ) end )
	
end


/*---------------------------------------------------------
   Name: table.LowerKeyNames( table )
   Desc: Lowercase the keynames of all tables
---------------------------------------------------------*/
function table.LowerKeyNames( Table )

	local OutTable = {}

	for k, v in pairs( Table ) do
	
		// Recurse
		if ( type( v ) == "table" ) then
			v = table.LowerKeyNames( v )
		end
		
		OutTable[ k ] = v
		
		if ( type( k ) == "string" ) then
	
			OutTable[ k ]  = nil
			OutTable[ string.lower( k ) ] = v
		
		end		
	
	end
	
	return OutTable
	
end


/*---------------------------------------------------------
   Name: table.LowerKeyNames( table )
   Desc: Lowercase the keynames of all tables
---------------------------------------------------------*/
function table.CollapseKeyValue( Table )

	local OutTable = {}
	
	for k, v in pairs( Table ) do
	
		local Val = v.Value
	
		if ( type( Val ) == "table" ) then
			Val = table.CollapseKeyValue( Val )
		end
		
		OutTable[ v.Key ] = Val
	
	end
	
	return OutTable

end

/*---------------------------------------------------------
   Name: table.ClearKeys( table, bSaveKey )
   Desc: Clears the keys, converting to a numbered format
---------------------------------------------------------*/
function table.ClearKeys( Table, bSaveKey )

	local OutTable = {}
	
	for k, v in pairs( Table ) do
		if ( bSaveKey ) then
			v.__key = k
		end
		table.insert( OutTable, v )	
	end
	
	return OutTable

end



local function fnPairsSorted( pTable, Index )

	if ( Index == nil ) then
	
		Index = 1
	
	else
	
		for k, v in pairs( pTable.__SortedIndex ) do
			if ( v == Index ) then
				Index = k + 1
				break
			end
		end
		
	end
	
	local Key = pTable.__SortedIndex[ Index ]
	if ( !Key ) then
		pTable.__SortedIndex = nil
		return
	end
	
	Index = Index + 1
	
	return Key, pTable[ Key ]

end

/*---------------------------------------------------------
   A Pairs function

		Sorted by TABLE KEY
		
---------------------------------------------------------*/
function SortedPairs( pTable, Desc )

	pTable = table.Copy( pTable )
	
	local SortedIndex = {}
	for k, v in pairs( pTable ) do
		table.insert( SortedIndex, k )
	end
	
	if ( Desc ) then
		table.sort( SortedIndex, function(a,b) return a>b end )
	else
		table.sort( SortedIndex )
	end
	pTable.__SortedIndex = SortedIndex

	return fnPairsSorted, pTable, nil
	
end

/*---------------------------------------------------------
   A Pairs function

		Sorted by VALUE
		
---------------------------------------------------------*/
function SortedPairsByValue( pTable, Desc )

	pTable = table.ClearKeys( pTable )
	
	if ( Desc ) then
		table.sort( pTable, function(a,b) return a>b end )
	else
		table.sort( pTable )
	end

	return ipairs( pTable )
	
end

/*---------------------------------------------------------
   A Pairs function

		Sorted by Member Value (All table entries must be a table!)
		
---------------------------------------------------------*/
function SortedPairsByMemberValue( pTable, pValueName, Desc )

	Desc = Desc or false
	
	local pSortedTable = table.ClearKeys( pTable, true )
	
	table.SortByMember( pSortedTable, pValueName, !Desc )
	
	local SortedIndex = {}
	for k, v in ipairs( pSortedTable ) do
		table.insert( SortedIndex, v.__key )
	end
	
	pTable.__SortedIndex = SortedIndex

	return fnPairsSorted, pTable, nil
	
end