
// Globals that we are going to use
local pairs = pairs
local unpack = unpack
local Msg = Msg
local pcall = pcall
local tostring = tostring
local concommand = concommand
local PrintTable = PrintTable
local CLIENT = CLIENT

/*---------------------------------------------------------
   Name: hook
   Desc: For scripts to hook onto Gamemode events
---------------------------------------------------------*/
module("hook")


// Local variables
local Hooks = {}


// Exposed Functions

/*---------------------------------------------------------
   Name: Hooks( )
   Desc: Returns the hook table
---------------------------------------------------------*/
function GetTable()

	return Hooks
	
end

/*---------------------------------------------------------
   Name: Add( event_name, name, function )
   Desc: Adds a hook
   Usage: hook.Add( "Think", "MyHookName", MyThinkFunction )
---------------------------------------------------------*/
function Add( event_name, name, func )

	if (Hooks[ event_name ] == nil) then
		Hooks[ event_name ] = {}
	end

	Hooks[ event_name ][ name ] = func
end

/*---------------------------------------------------------
   Name: Remove( name )
   Desc: Removes a hook
   Usage: Remove( "Think", "MyHookName" )
---------------------------------------------------------*/
function Remove( event_name, name )

	Hooks[ event_name ][ name ] = nil

end

/*---------------------------------------------------------
   Name: Call( name, args )
   Desc: Called by the engine to call a gamemode hook
---------------------------------------------------------*/
function Call( name, gm, ... )

	local b, retval
	local HookTable = Hooks[ name ]
	

	if ( HookTable != nil ) then
	
		for k, v in pairs( HookTable ) do 
			
			if ( v == nil ) then
			
				Msg("**********************************************************\n")
				Msg("ERROR: Hook '"..tostring(k).."' tried to call a nil function!\n")
				Msg("Removing Hook '"..tostring(k).."'\n")
				Msg("**********************************************************\n\n")
				HookTable[ k ] = nil // remove this hook
				break;
			
			else
				// Call hook function
				b, retval = pcall( v, unpack(arg) )
				
				if (!b) then
				
						Msg("**********************************************************\n")
						Msg("ERROR: Hook '"..tostring(k).."' Failed: "..tostring(retval).."\n")
						Msg("Removing Hook '"..tostring(k).."'\n")
						Msg("**********************************************************\n\n")
						HookTable[ k ] = nil // remove this hook
				
				else
				
					// Allow hooks to override return values
					if (retval != nil) then
						return retval
					end
					
				end
			end
			
		end
	end
	
	local GamemodeFunction = gm[ name ]
	
	if ( GamemodeFunction == nil ) then
	
		gm[ name ] = function() end
		Msg( "GAMEMODE ERROR: Function '"..name.."' Is Missing!\n" )
		return nil
		
	end
	
	// This calls the actual gamemode function - after all the hooks have had chance to override
	
	b, retval = pcall( GamemodeFunction, gm, unpack(arg) )
	
	if (!b) then
	
		gm[ name .. "_ERRORCOUNT" ] = gm[ name .. "_ERRORCOUNT" ] or 0
		gm[ name .. "_ERRORCOUNT" ] = gm[ name .. "_ERRORCOUNT" ] + 1
		Msg("**********************************************************\n")
		Msg("ERROR: GAMEMODE:'"..tostring(name).."' Failed: "..tostring(retval).."\n")
		Msg("**********************************************************\n\n")
				
		return nil
		
	end
	
	return retval
	
end

/*************************************
  DEBUG CONSOLE COMMAND FOR LUA CODERS
**************************************/

local function DumpHooks()

	PrintTable( Hooks )

end


if ( CLIENT ) then
	concommand.Add( "dump_hooks_cl", DumpHooks )
else
	concommand.Add( "dump_hooks", DumpHooks )
end
