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

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


// Local variables
local Hooks = {}


// Exposed Functions

/*---------------------------------------------------------
   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, ... )

	if ( Hooks[ name ] ~= nil ) then
		for k, v in pairs( Hooks[ name ] ) 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")
				Hooks[ name ][ k ] = nil // remove this hook
				break;
			
			else
				// Call hook function
				local 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")
						Hooks[ name ][ k ] = nil // remove this hook
				
				else
					// Allow gamemodes to override return values
					if (retval != nil) then
						return retval
					end
				end
			end
			
		end
	end
	
	if (gm[ name ] == 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
	
	local b, retval = pcall( gm[ name ], 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")
		
		// Don't Spam
		if ( gm[ name .. "_ERRORCOUNT" ] > 10 ) then
			Msg("**********************************************************\n")
			Msg("GAMEMODE: Removing Function '"..tostring(name).."' (Too many errors)\n")
			Msg("**********************************************************\n\n")
			gm[ name ] = function() end
			gm[ name .. "_ERRORCOUNT" ] = nil
		end
		
		return nil
		
	else
	
		gm[ name .. "_ERRORCOUNT" ] = nil
		
	end
	
	return retval
	
end

