--[[---------------------------------------------------------
   Name: string.ToTable( string )
-----------------------------------------------------------]]
function string.ToTable ( str )
	local tbl = {}
	
	for i = 1, string.len( str ) do
		tbl[i] = string.sub( str, i, i )
	end
	
	return tbl
end


function string.JavascriptSafe( str )

	str = str:Replace( "\\", "\\\\" )
	str = str:Replace( "\"", "\\\"" )
	str = str:Replace( "\n", "\\n" )
	str = str:Replace( "\r", "\\r" )
	
	return str

end
--[[---------------------------------------------------------
   Name: explode(seperator ,string)
   Desc: Takes a string and turns it into a table
   Usage: string.explode( " ", "Seperate this string")
-----------------------------------------------------------]]
local totable = string.ToTable
local string_sub = string.sub
local string_gsub = string.gsub
local string_gmatch = string.gmatch
function string.Explode(separator, str, withpattern)
	if (separator == "") then return totable( str ) end
	 
	local ret = {}
	local index,lastPosition = 1,1
	 
	-- Escape all magic characters in separator
	if not withpattern then separator = string_gsub( separator, "[%-%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%1" ) end
	 
	-- Find the parts
	for startPosition,endPosition in string_gmatch( str, "()" .. separator.."()" ) do
		ret[index] = string_sub( str, lastPosition, startPosition-1)
		index = index + 1
		 
		-- Keep track of the position
		lastPosition = endPosition
	end
	 
	-- Add last part by using the position we stored
	ret[index] = string_sub( str, lastPosition)
	return ret
end

function string.Split( str, delimiter )
	return string.Explode( delimiter, str )
end

--[[---------------------------------------------------------
   Name: Implode(seperator ,Table)
   Desc: Takes a table and turns it into a string
   Usage: string.Implode( " ", {"This", "Is", "A", "Table"})
-----------------------------------------------------------]]
function string.Implode(seperator,Table) return 
	table.concat(Table,seperator) 
end

--[[---------------------------------------------------------
   Name: GetExtensionFromFilename(path)
   Desc: Returns extension from path
   Usage: string.GetExtensionFromFilename("garrysmod/lua/modules/string.lua")
-----------------------------------------------------------]]
function string.GetExtensionFromFilename( path )
	return path:match( "%.([^%.]+)$" )
end

--[[---------------------------------------------------------
   Name: StripExtension( path )
-----------------------------------------------------------]]
function string.StripExtension( path )

	local i = path:match( ".+()%.%w+$" )
	if ( i ) then return path:sub(1, i-1) end
	return path

end

--[[---------------------------------------------------------
   Name: GetPathFromFilename(path)
   Desc: Returns path from filepath
   Usage: string.GetPathFromFilename("garrysmod/lua/modules/string.lua")
-----------------------------------------------------------]]
function string.GetPathFromFilename(path)
	return path:match( "^(.*[/\\])[^/\\]-$" ) or ""
end
--[[---------------------------------------------------------
   Name: GetFileFromFilename(path)
   Desc: Returns file with extension from path
   Usage: string.GetFileFromFilename("garrysmod/lua/modules/string.lua")
-----------------------------------------------------------]]
function string.GetFileFromFilename(path)
	return path:match( "[\\/]([^/\\]+)$" ) or ""
end

--[[-----------------------------------------------------------------
   Name: FormattedTime( TimeInSeconds, Format )
   Desc: Given a time in seconds, returns formatted time
		 If 'Format' is not specified the function returns a table 
		 conatining values for hours, mins, secs, ms

   Examples: string.FormattedTime( 123.456, "%02i:%02i:%02i")  ==> "02:03:45"
			 string.FormattedTime( 123.456, "%02i:%02i")       ==> "02:03"
			 string.FormattedTime( 123.456, "%2i:%02i")        ==> " 2:03"
			 string.FormattedTime( 123.456 )        		==> {h = 0, m = 2, s = 3, ms = 45}
-------------------------------------------------------------------]]

function string.FormattedTime( seconds, Format )
	if not seconds then seconds = 0 end
	local hours = math.floor(seconds / 3600)
	local minutes = math.floor((seconds / 60) % 60)
	local millisecs = ( seconds - math.floor( seconds ) ) * 100
	seconds = math.floor(seconds % 60)
	
	if Format then
		return string.format( Format, minutes, seconds, millisecs )
	else
		return { h=hours, m=minutes, s=seconds, ms=millisecs }
	end
end

--[[---------------------------------------------------------
   Name: Old time functions
-----------------------------------------------------------]]

function string.ToMinutesSecondsMilliseconds( TimeInSeconds )	return string.FormattedTime( TimeInSeconds, "%02i:%02i:%02i")	end
function string.ToMinutesSeconds( TimeInSeconds )		return string.FormattedTime( TimeInSeconds, "%02i:%02i")	end

local function pluralizeString(str, quantity)
	return str .. ((quantity ~= 1) and "s" or "")
end

function string.NiceTime( seconds )

	if ( seconds == nil ) then return "a few seconds" end

	if ( seconds < 60 ) then
		local t = math.floor( seconds )
		return t .. pluralizeString(" second", t);
	end

	if ( seconds < 60 * 60 ) then
		local t = math.floor( seconds / 60 )
		return t .. pluralizeString(" minute", t);
	end

	if ( seconds < 60 * 60 * 24 ) then
		local t = math.floor( seconds / (60 * 60) )
		return t .. pluralizeString(" hour", t);
	end

	if ( seconds < 60 * 60 * 24 * 7 ) then
		local t = math.floor( seconds / (60 * 60 * 24) )
		return t .. pluralizeString(" day", t);
	end
	
	if ( seconds < 60 * 60 * 24 * 7 * 52 ) then
		local t = math.floor( seconds / (60 * 60 * 24 * 7) )
		return t .. pluralizeString(" week", t);
	end

	local t = math.floor( seconds / (60 * 60 * 24 * 7 * 52) )
	return t .. pluralizeString(" year", t);

end

function string.Left(str, num)
	return string.sub(str, 1, num)
end

function string.Right(str, num)
	return string.sub(str, -num)
end


function string.Replace( str, tofind, toreplace )
	tofind = tofind:gsub( "[%-%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%1" )
	toreplace = toreplace:gsub( "%%", "%%%1" )
	return ( str:gsub( tofind, toreplace ) )
end

--[[---------------------------------------------------------
   Name: Trim(s)
   Desc: Removes leading and trailing spaces from a string.
		 Optionally pass char to trim that character from the ends instead of space
-----------------------------------------------------------]]
function string.Trim( s, char )
	if ( not char ) then char = "%s" end
	return ( s:gsub( "^" .. char .. "*(.-)" .. char .. "*$", "%1" ) )
end

--[[---------------------------------------------------------
   Name: TrimRight(s)
   Desc: Removes trailing spaces from a string.
		 Optionally pass char to trim that character from the ends instead of space
-----------------------------------------------------------]]
function string.TrimRight( s, char )
	if ( not char ) then char = " " end
	
	if ( string.sub( s, -1 ) == char ) then
		s = string.sub( s, 0, -2 )
		s = string.TrimRight( s, char )
	end
	
	return s
end

--[[---------------------------------------------------------
   Name: TrimLeft(s)
   Desc: Removes leading spaces from a string.
		 Optionally pass char to trim that character from the ends instead of space
-----------------------------------------------------------]]
function string.TrimLeft( s, char )
	if ( not char ) then char = " " end
	
	if ( string.sub( s, 1 ) == char ) then
		s = string.sub( s, 1 )
		s = string.TrimLeft( s, char )
	end
	
	return s
end

function string.NiceSize( size )
	
	size = tonumber( size )

	if ( size <= 0 ) then return "0" end
	if ( size < 1024 ) then return size .. " Bytes" end
	if ( size < 1024 * 1024 ) then return math.Round( size / 1024, 2 ) .. " KB" end
	if ( size < 1024 * 1024 * 1024 ) then return math.Round( size / (1024*1024), 2 ) .. " MB" end
	
	return math.Round( size / (1024*1024*1024), 2 ) .. " GB"

end

-- Note: These use Lua index numbering, not what you'd expect
-- ie they start from 1, not 0.

function string.SetChar( s, k, v )

	local start = s:sub( 0, k-1 )
	local send = s:sub( k+1 )
	
	return start .. v .. send

end

function string.GetChar( s, k )

	return s:sub( k, k )

end

local meta = getmetatable( "" )

function meta:__index( key )
	if ( string[key] ) then
		return string[key]
	elseif ( tonumber( key ) ) then
		return self:sub( key, key )
	else
		error( "bad key to string index (number expected, got " .. type( key ) .. ")", 2 )
	end
end

function string.StartWith( String, Start )

   return string.sub( String, 1, string.len (Start ) ) == Start

end

function string.EndsWith( String, End )

   return End == '' or string.sub( String, -string.len( End ) ) == End

end

function string.FromColor( color )

   return Format( "%i %i %i %i", color.r, color.g, color.b, color.a );

end

function string.ToColor( str )

	local col = Color( 255, 255, 255, 255 )

	col.r, col.g, col.b, col.a = str:match("(%d+) (%d+) (%d+) (%d+)")

	col.r = tonumber( col.r )
	col.g = tonumber( col.g )
	col.b = tonumber( col.b )
	col.a = tonumber( col.a )

	return col

end

function string.Comma( number )

	local number, k = tostring( number ), nil

	while true do  
		number, k = string.gsub( number, "^(-?%d+)(%d%d%d)", '%1,%2')
		if ( k == 0 ) then break end
	end

	return number

end
