local Msg = Msg
local math = math
local pairs = pairs
local pcall = pcall
local unpack = unpack
local CurTime = CurTime
local CLIENT = CLIENT
local util = util
local table = table
local string = string
local type = type
local tostring = tostring
local tonumber = tonumber
local stringx = stringx

require("hook")
local hook = hook

/*---------------------------------------------------------
   utilx module
   Useful and common functions
---------------------------------------------------------*/
module("utilx")

function KeyValuesToTable( kv, internal )
	
	-- Expected:
	-- * "name" "value"
	-- * name value
	-- * //
	-- * { ... }
	-- * whitespace
	
	local ST_NAME = 0
	local ST_VALUE = 1
	local ST_VALUE_OR_CHILD = 2
	local ST_CHILD = 3
	
	local name = nil
	local value = nil
	local current_pos = 1
	local current_contents = kv
	local state = ST_NAME
	local result = {}
	local first_name = nil
	
	while (true) do
	
		local c = string.sub(current_contents, current_pos, current_pos)
		current_pos = current_pos + 1
		
		if (c == "") then
			break
		elseif (string.byte(c,1) <= 32) then
		
			-- continue (do nothing)

		elseif (c == "/" and string.sub(current_contents, current_pos, current_pos) == "/") then
		
			-- scan till EOL
			while (c != "\n") do
			
				c = string.sub(current_contents, current_pos, current_pos)
				current_pos = current_pos + 1
				
				if (c == "") then
					break
				end
			
			end
			
		elseif (c == "}") then
		
			break
			
		elseif (c == "{") then
		
			state = ST_CHILD
			
			local inc_pos = 0
			result[name],inc_pos = KeyValuesToTable( string.sub(current_contents, current_pos), true )
			current_pos = current_pos + inc_pos
			
			state = ST_NAME

		elseif (c != "" or c == "\"") then

			if (state == ST_VALUE_OR_CHILD) then state = ST_VALUE end

			local quoted = (c == "\"")

			local thing = ""
			if (not quoted) then
				thing = c
			end
			
			while (true) do

				c = string.sub(current_contents, current_pos, current_pos)
				current_pos = current_pos + 1

				if (quoted) then
					if (c == "\\") then
						c = string.sub(current_contents, current_pos, current_pos)
						current_pos = current_pos + 1

						if (c == "n") then		c = "\n"
						elseif (c == "r") then	c = "\r"
						elseif (c == "t") then	c = "\t"
						elseif (c == "\"") then c = "\""
						elseif (c == "\\") then c = "\\"
						else					c = ""
						end

					elseif (c == "\"") then
						break
					end
				else
					if (string.byte(c,1) <= 32) then
						break 
					end
				end

				thing = thing .. c
				
			end
			
			current_pos = current_pos + 1

			if tonumber(thing) then thing = tonumber(thing) end

			if (state == ST_NAME) then	

				name = thing

				if (first_name == nil) then
					first_name = name
				end

				state = ST_VALUE_OR_CHILD	

			elseif (state == ST_VALUE) then	

				value = thing

				result[name] = value

				state = ST_NAME

			end

		end			
	
	end
	
	if (not internal) then
		return result[first_name], first_name
	else
		return result, current_pos
	end
	
end

function TableToKeyValues( val, key, level )
	local tabs = level or 0
	
	// Return a string so that it doesn't bug out later
	if ( tabs > 8 ) then return "" end
	if ( type( val ) != "table" ) then return "" end
	
	local name = key or "Out"
	local str
	
	str = string.rep("\t", tabs) .. "\""..name.."\"\n"
	str = str .. string.rep("\t", tabs) .. "{\n"
	
	for k,v in pairs(val) do
	
		k = stringx.Replace(k, "\\", "\\\\")
		k = stringx.Replace(k, "\"", "\\\"")
		k = stringx.Replace(k, "\t", "\\t")
		k = stringx.Replace(k, "\n", "\\n")
		k = stringx.Replace(k, "\r", "\\r")
	
		if ( type( v ) == "table" ) then
			str = str .. TableToKeyValues(v,k,tabs+1)
		else
			v = stringx.Replace(v, "\\", "\\\\")
			v = stringx.Replace(v, "\"", "\\\"")
			v = stringx.Replace(v, "\t", "\\t")
			v = stringx.Replace(v, "\n", "\\r")
			v = stringx.Replace(v, "\r", "\\n")

			str = str .. string.rep("\t", tabs+1) .. "\""..k.."\"\t\""..v.."\"\n"
		end
	end
	
	str = str .. string.rep("\t", tabs) .. "}\n"
	
	return str
end

/*---------------------------------------------------------
   Name: GetPlayerTrace( ply, dir )
   Desc: Returns a generic trace table for the player
		 (dir is optional, defaults to the player's aim)
---------------------------------------------------------*/
function GetPlayerTrace( ply, dir )

	dir = dir or ply:GetAimVector()

	local trace = {}
	
	trace.start = ply:EyePos()
	trace.endpos = trace.start + (dir * 4096 * 4)
	trace.filter = ply
	
	return trace
	
end


/*---------------------------------------------------------
   Name: QuickTrace( origin, offset, filter )
   Desc: Quick trace
---------------------------------------------------------*/
function QuickTrace( origin, dir, filter )

	local trace = {}
	
	trace.start = origin
	trace.endpos = origin + dir
	trace.filter = filter
	
	return util.TraceLine( trace )
	
end

function tobool( val )
	if ( val == 0 || val == "0" || val == "false" || val == nil ) then return false end
	return true
end

function LocalToWorld( ent, lpos, bone )
	_bone = bone or 0
	if (ent:EntIndex() == 0) then
		return lpos
	else
		if (ent:GetPhysicsObjectNum(_bone) ~= nil && ent:GetPhysicsObjectNum(_bone):IsValid()) then
			return ent:GetPhysicsObjectNum(_bone):LocalToWorld(lpos)
		else
			return ent:LocalToWorld(lpos)
		end
	end
	return nil
end
