local typecodeMap = {}
typecodeMap[1] = "whole-number"
typecodeMap[2] = "true/false"
typecodeMap[3] = "colour"
typecodeMap[4] = "enum"
local bonkerboxshorthand = "bb"
local bonkerboxseparator = "_"
local shorthandentryname = "shorthand"
local commandstablename = "commands"
local cmdinfostrname = "info"
local cmdadminboolname = "admin"
local duhdescstr = "Self-explanatory."
local replaynotifstr = "This variable will NOT save to replays by design (and by extension can be modified during a replay) because it is an accessibility feature."
local commandinfo = {}

local function GenCommandInfo(desc,argDescPairs)

	if(BonkerBox_G.StringEmptyOrNil(desc, false)==true)
		desc=""
	end
	
	if(BonkerBox_G.IsTable(argDescPairs)~=true)
		argDescPairs = {}
	end

	local str = ""
	str = $..desc

	local accessKeys = {}
	
	for k,v in pairs(argDescPairs)
	
		if(BonkerBox_G.IsTable(v)~=true)
			continue
		end

		accessKeys[k] = v
	end
	
	local counter = 1
	local count = BonkerBox_G.CountTable(accessKeys)
	local leftspace=false
	
	for k,v in pairs(accessKeys)
		if(leftspace~=true)
			local addspace = "\n\n"
			
			if(BonkerBox_G.StringEmptyOrNil(str, false)==true)
				addspace = ""
			end
		
			str = $..addspace.."IN-ORDER ARGUMENTS:\n"
			leftspace=false
		end
		
		local mappedTypecode = typecodeMap[v["typecode"]]
		
		if(BonkerBox_G.StringEmptyOrNil(mappedTypecode, false)==true)
			mappedTypecode = "unknown"
		end

		local append = k.." ("..mappedTypecode..") - "
		
		if(BonkerBox_G.StringEmptyOrNil(v["desc"], false)==true)
			append = $.."An undocumented argument. Who knows what it could do?"
		else
			append = $..v["desc"]
		end
		
		str= $..append
		
		if(counter < count)
			str = $.."\n"
		end
		
		counter = $+1
	end
	
	return str
end

local function DBAddCommandRacer(skin, skinshort)
	if(BonkerBox_G.StringEmptyOrNil(skin, false) == true)
		return false
	end
	
	if(BonkerBox_G.StringEmptyOrNil(skinshort, false) == true)
		return false
	end
	
	if(BonkerBox_G.IsTable(commandinfo[skin]) ~= true)
		commandinfo[skin] = {}
	end
	
	commandinfo[skin][shorthandentryname] = skinshort
	return true
end

local function DBAddCommand(skin, commandname, info, adminonly)
	if(BonkerBox_G.StringEmptyOrNil(skin, false) == true)
		return false
	end

	if(BonkerBox_G.IsTable(commandinfo[skin]) ~= true)
		return false
	end
	
	if(BonkerBox_G.StringEmptyOrNil(commandname, false) == true)
		return false
	end
	
	if(BonkerBox_G.StringEmptyOrNil(info, false) == true)
		return false
	end
	
	if(BonkerBox_G.IsBool(adminonly) ~= true)
		return false
	end
	
	if(BonkerBox_G.IsTable(commandinfo[skin][commandstablename]) ~= true)
		commandinfo[skin][commandstablename] = {}
	end
	
	commandinfo[skin][commandstablename][commandname] = {}
	commandinfo[skin][commandstablename][commandname][cmdinfostrname] = info
	commandinfo[skin][commandstablename][commandname][cmdadminboolname] = adminonly
	return true
end

local function GenCommandName(skinname,cmdname)
	if(BonkerBox_G.IsTable(commandinfo)~=true)
		BonkerBox_G.InternalError(nil,"commandinfo table doesn't exist")
		return
	end
	
	if(BonkerBox_G.StringEmptyOrNil(skinname, false)==true)
		BonkerBox_G.InternalError(nil,"skinname is empty or nil")
		return
	end
	
	if(BonkerBox_G.IsTable(commandinfo[skinname])~=true)
		BonkerBox_G.InternalError(nil,"skinname is not in commandinfo table")
		return
	end
	
	if(BonkerBox_G.StringEmptyOrNil(commandinfo[skinname][shorthandentryname], false)==true)
		BonkerBox_G.InternalError(nil,"skinname has no shorthand equivalent")
		return
	end
	
	if(BonkerBox_G.StringEmptyOrNil(cmdname, false)==true)
		BonkerBox_G.InternalError(nil,"cmdname is empty or nil")
		return
	end
	
	return bonkerboxshorthand..(commandinfo[skinname][shorthandentryname])..bonkerboxseparator..cmdname
end

local function SetUpHelp()
	local preventRepeatName = "BonkerBox_Help_Setup"
	
	if(_G[preventRepeatName] ~= nil)
		return
	end

	COM_AddCommand("bonkerbox_help",function(player,skinname,cmdname)
		if(BonkerBox_G.IsPlayer(player)~=true)
			return
		end
		
		if(BonkerBox_G.IsTable(commandinfo)~=true)
			BonkerBox_G.InternalError(player,"No commandinfo table set up for this command!")
			return
		end
		
		local anyhelpschpiel = "This command follows the format 'bonkerbox_help <skinname> <commandname>'. For more information as to proper usage, consult the README."

		local skinname_isstring = BonkerBox_G.StringEmptyOrNil(skinname, false)~=true
		local cmdname_isstring = BonkerBox_G.StringEmptyOrNil(cmdname, false)~=true

		if((skinname_isstring~=true) or (skinname_isstring==true and BonkerBox_G.IsTable(commandinfo[skinname])~=true))
			BonkerBox_G.UserFacingError(player,anyhelpschpiel)
			return
		end
		
		local shorthand = commandinfo[skinname][shorthandentryname]
		
		if(BonkerBox_G.StringEmptyOrNil(shorthand, false)==true)
			BonkerBox_G.InternalError(player,"Skin '"..skinname.."' doesn't have a matching short-hand representation!")
			return
		end
		
		local commandtable  = commandinfo[skinname][commandstablename]
		
		local nocmdsfunc = function() BonkerBox_G.InternalError(player,"Skin '"..skinname.."' doesn't have any commands to print! Why is it in the commandtable?") end
		
		if(BonkerBox_G.IsTable(commandtable)~=true)
			nocmdsfunc()
			return
		end
		
		local cmdprintlist = ""
		
		for k,v in pairs(commandtable)
			if(BonkerBox_G.StringEmptyOrNil(k, false)==true)
				continue
			end
			
			cmdprintlist = cmdprintlist.."\n"..k
		end
		
		if(BonkerBox_G.StringEmptyOrNil(cmdprintlist, false)==true)
			nocmdsfunc()
			return
		end
		
		
		local commanddata = commandinfo[skinname][commandstablename][cmdname]
		
		local cmdtableexists = BonkerBox_G.IsTable(commanddata)==true
		local cmdinfoexists = false
		
		if(cmdtableexists==true)
			cmdinfoexists = BonkerBox_G.StringEmptyOrNil(commanddata[cmdinfostrname], false)~=true
		end
		
		if(cmdname_isstring~=true or (cmdname_isstring==true and (cmdtableexists~=true or cmdinfoexists~=true)))
			BonkerBox_G.UserFacingInfo(player,"\nPick a command for the '"..skinname.."' racer to learn more about it:\n\n"..cmdprintlist)
			return
		end
		
		local adminonlyval = BonkerBox_G.IsBool(commanddata[cmdadminboolname])==true and commanddata[cmdadminboolname]==true
		
		local adminonlystr = ""
		
		if(adminonlyval==true)
			adminonlystr = " (Admin-Only)"
		end
		
		local printout ="\n"..GenCommandName(skinname,cmdname)..adminonlystr.."\n"..commanddata[cmdinfostrname]
		
		BonkerBox_G.UserFacingInfo(player,printout)
	end)
	
	rawset(_G, preventRepeatName, true)
end

local function ReplayDenyWarning(player)
	BonkerBox_G.UserFacingWarning(player,"You cannot change this variable right now, either the player doesn't exist or a replay is active.")
end

local function ReplayDelayWarning(player)
	BonkerBox_G.UserFacingWarning(player,"Your changes were successful, but due to replay shennanigans, they will only take effect at the beginning of the next map.")
end

local bbc = {}
bbc.GenCommandName = GenCommandName
bbc.GenCommandInfo = GenCommandInfo
bbc.ReplayDenyWarning = ReplayDenyWarning
bbc.ReplayDelayWarning = ReplayDelayWarning
bbc.DBAddCommandRacer = DBAddCommandRacer
bbc.DBAddCommand = DBAddCommand
bbc.SetUpHelp = SetUpHelp
bbc.GetReplayNotif = function() return replaynotifstr end
bbc.GetDuhDesc = function() return duhdescstr end
rawset(_G,"BonkerBox_C",bbc)