/*
 * vim: set ts=4 :
 * ======================================================
 * Metamod:Source
 * Copyright (C) 2004-2008 AlliedModders LLC and authors.
 * All rights reserved.
 * ======================================================
 *
 * This software is provided 'as-is', without any express or implied warranty.
 * In no event will the authors be held liable for any damages arising from 
 * the use of this software.
 * 
 * Permission is granted to anyone to use this software for any purpose, 
 * including commercial applications, and to alter it and redistribute it 
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not 
 * claim that you wrote the original software. If you use this software in a 
 * product, an acknowledgment in the product documentation would be 
 * appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must not be
 * misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 *
 * Version: $Id$
 */

#ifndef _INCLUDE_ISMM_API_H
#define _INCLUDE_ISMM_API_H

/**
 * @brief Core API calls that are provided to plugins.
 * @file ISmmAPI.h
 */

#include <stdarg.h>
#include <sourcehook.h>
#include <IPluginManager.h>
#include <ISmmPlugin.h>
#include <ISmmPluginExt.h>

#if defined __GNUC__
#if ((__GNUC__ == 3) && (__GNUC_MINOR__ < 4)) || (__GNUC__ < 3)
#error "You must compile with at least GCC 3.4! If you know what you are doing, you can remove this message."
#endif //version check
#endif //__GNUC__

#define	MMIFACE_SOURCEHOOK		"ISourceHook"			/**< ISourceHook Pointer */
#define	MMIFACE_PLMANAGER		"IPluginManager"		/**< SourceMM Plugin Functions */
#define MMIFACE_SH_HOOKMANAUTOGEN	"IHookManagerAutoGen"		/**< SourceHook::IHookManagerAutoGen Pointer */
#define IFACE_MAXNUM			999						/**< Maximum interface version */

#if defined META_NO_HL2SDK
class CGlobalVars;
class IServerPluginCallbacks;
struct edict_t;
class ConCommandBase;
#else
#include <eiface.h>
#endif

// Interface return status, binary-compatible with HL2SDK's IFACE_OK and IFACE_FAILED.
enum 
{
	META_IFACE_OK = 0,
	META_IFACE_FAILED
};

typedef void* (*CreateInterfaceFn)(const char *pName, int *pReturnCode);

namespace SourceMM
{
	class ISmmPlugin;
	class IMetamodListener;

	/**
	 * The core API that Metamod:Source provides to plugins.
	 */
	class ISmmAPI
	{
	public:
		/**
		 * @brief Logs a message through the HL2 log system.
		 * Note: Newlines are appended automatically.
		 *
		 * @param pl			Plugin API pointer (used for tagging message)
		 * @param msg			Formatted string.
		 */
		virtual void LogMsg(ISmmPlugin *pl, const char *msg, ...) =0;
	
		/**
		 * @brief Returns an interface factory for the HL2 engine.
		 *
		 * @param syn			If syn is true, the synthetic wrapper is returned.  
		 *						If syn is false, the true function is returned.
		 * @return				CreateInterfaceFn function pointer.
		 */
		virtual CreateInterfaceFn GetEngineFactory(bool syn=true) =0;

		/**
		 * @brief Returns an interface factory for the HL2 physics engine.
		 *
		 * @param syn			If syn is true, the synthetic wrapper is returned.  
		 *						If syn is false, the true function is returned.
		 * @return				CreateInterfaceFn function pointer.
		 */
		virtual CreateInterfaceFn GetPhysicsFactory(bool syn=true) =0;

		/**
		 * @brief Returns an interface factory for the HL2 file system.
		 *
		 * @param syn			If syn is true, the synthetic wrapper is returned.  
		 *						If syn is false, the true function is returned.
		 * @return				CreateInterfaceFn function pointer.
		 */
		virtual CreateInterfaceFn GetFileSystemFactory(bool syn=true) =0;

		/**
		 * @brief Returns an interface factory for the GameDLL.
		 *
		 *						If syn is false, the true function is returned.
		 * @return				CreateInterfaceFn function pointer.
		 */
		virtual CreateInterfaceFn GetServerFactory(bool syn=true) =0;

		/**
		 * @brief Returns a CGlobalVars pointer from the HL2 Engine.
		 *
		 * @return				CGlobalVars pointer.
		 */
		virtual CGlobalVars *GetCGlobals() =0;

		/**
		 * @brief Registers a ConCommandBase.
		 *
		 * @param plugin		Parent plugin API pointer.
		 * @param pCommand		ConCommandBase to register.
		 * @return				True if successful, false otherwise.
		 */
		virtual bool RegisterConCommandBase(ISmmPlugin *plugin, ConCommandBase *pCommand) =0;

		/**
		 * @brief Unregisters a ConCommandBase.
		 *
		 * @param plugin		Parent plugin API pointer.
		 * @param pCommand		ConCommandBase to unlink.
		 */
		virtual void UnregisterConCommandBase(ISmmPlugin *plugin, ConCommandBase *pCommand) =0;
	
		/**
		 * @brief Prints an unformatted string to the remote server console.
		 * 
		 * Note: Newlines are not added automatically.
		 *
		 * @param str			Message string.
		 */
		virtual void ConPrint(const char *str) =0;

		/**
		 * @brief Prints a formatted message to the remote server console.  
		 * 
		 * Note: Newlines are not added automatically.
		 *
		 * @param fmt			Formatted message.
		 */
		virtual void ConPrintf(const char *fmt, ...) =0;

		/**
		 * @brief Returns the Metamod Version numbers as major version and 
		 * minor (API) version.  Changes to minor version are guaranteed to be 
		 * backwards compatible.  Changes to major version are not.
		 * 
		 * @param major			Filled with the major API version number.
		 * @param minor			Filled with the minor API version number.
		 * @param plvers		Filled with the current plugin API version number.
		 * @param plmin			Filled with the minimum plugin API version number 
		 * 						supported.
		 */
		virtual void GetApiVersions(int &major, int &minor, int &plvers, int &plmin) =0;
	
		/** 
		 * @brief Returns sourcehook API version and implementation version.
		 *
		 * @param shvers		Filled with the SourceHook API version number.
		 * @param shimpl		Filled with the SourceHook implementation number.
		 */
		virtual void GetShVersions(int &shvers, int &shimpl) =0;
	
		/**
		 * @brief Adds a Metamod listener.
		 *
		 * @param plugin		Plugin interface pointer.
		 * @param pListener		Listener interface pointer to add.
		 */
		virtual void AddListener(ISmmPlugin *plugin, IMetamodListener *pListener) =0;

		/**
		  * @brief Queries the metamod factory
		  *
		  * @param iface		String containing interface name
		  * @param ret			Optional pointer to store return status
		  * @param id			Optional pointer to store id of plugin that 
		  * 					overrode interface, 0 if none
		  * @return				Returned pointer
		  */
		virtual void *MetaFactory(const char *iface, int *ret, PluginId *id) =0;

		/**
		 * @brief Given a base interface name, such as ServerGameDLL or 
		 * ServerGameDLL003, reformats the string to increase the number, then 
		 * returns the new number. This is the base function to InterfaceSearch() 
		 * and VInterfaceMatch().
		 * 
		 * @param iface			Input/output interface name.  Must be writable.
		 * @param maxlength		Maximum length of iface buffer.  Must be at least 
		 * 						strlen(iface)+4 chars.
		 * @return				The newly incremented iface version number.
		 * @deprecated			Use InterfaceSearch() or VInterfaceMatch instead.
		 */
		virtual int FormatIface(char iface[], unsigned int maxlength) =0;

		/**
		 * @brief Searches for an interface, eliminating the need to loop 
		 * through FormatIface().
		 * 
		 * @param fn			InterfaceFactory function.
		 * @param iface			Interface string name.
		 * @param max			Maximum version to look up.
		 * @param ret			Last return code from interface factory function.
		 * @return				Interface pointer, or NULL if not found.
		 */
		virtual void *InterfaceSearch(CreateInterfaceFn fn, 
									  const char *iface, 
									  int max, 
									  int *ret) =0;

		/**
		 * @brief Returns the base directory of the game/server, equivalent to 
		 * IVEngineServer::GetGameDir(), except the path is absolute.
		 *
		 * @return				Static pointer to game's absolute basedir.
		 */
		virtual const char *GetBaseDir() =0;

		/**
		 * @brief Formats a file path to the local OS.  
		 *
		 * Does not include any base directories.  Note that all slashes and 
		 * black slashes are reverted to the local OS's expectancy.
		 *
		 * @param buffer		Destination buffer to store path.
		 * @param len			Maximum length of buffer, including null 
		 * 						terminator.
		 * @param fmt			Formatted string.
		 * @param ...			Arguments in the string.
		 * @return				Number of bytes written, not including the null 
		 *						terminator.
		 */
		virtual size_t PathFormat(char *buffer, size_t len, const char *fmt, ...) =0;

		/**
		 * @brief Prints text in the specified client's console. Same as 
		 * IVEngineServer::ClientPrintf except that it allows for string 
		 * formatting.
		 *
		 * @param client		Client edict pointer.
		 * @param fmt			Formatted string to print to the client.
		 */
		virtual void ClientConPrintf(edict_t *client, const char *fmt, ...) =0;

		/**
		 * @brief Wrapper around InterfaceSearch().  Assumes no maximum.
		 * This is designed to replace the fact that searches only went upwards.
		 * The "V" is intended to convey that this is for Valve formatted 
		 * interface strings.
		 *
		 * @param fn			Interface factory function.
		 * @param iface			Interface string.
		 * @param min			Minimum value to search from.  If zero, searching 
		 *						begins from the first available version regardless 
		 *						of the interface.  Note that this can return 
		 *						interfaces EARLIER than the version specified.  A 
		 *						value of -1 (default) specifies the string version 
		 *						as the minimum.  Any other value specifices the 
		 *						minimum value to search from.
		 * @return				Interface pointer, or NULL if not found.
		 */
		virtual void *VInterfaceMatch(CreateInterfaceFn fn, 
									  const char *iface, 
									  int min=-1) =0;

		/**
		 * @brief Tells SourceMM to add VSP hooking capability to plugins.  
		 *
		 * Since this  potentially uses more resources than it would otherwise, 
		 * plugins have to explicitly enable the feature.  Whether requested or 
		 * not, if it is enabled, all plugins will get a pointer to the VSP 
		 * listener through IMetamodListener.  This will not be called more than 
		 * once for a given plugin; if it is requested more than once, each 
		 * successive call will only give the pointer to plugins which have not 
		 * yet received it.
		 */
		virtual void EnableVSPListener() =0;

		/**
		 * @brief Returns the interface version of the GameDLL's IServerGameDLL 
		 * implementation.
		 *
		 * @return				Interface version of the loaded IServerGameDLL.
		 */
		virtual int GetGameDLLVersion() =0;

		/**
		 * @brief Returns the number of user messages in the GameDLL.
		 *
		 * @return				Number of user messages, or -1 if SourceMM has 
		 *						failed to get user message list.
		 */
		virtual int GetUserMessageCount() =0;

		/**
		 * @brief Returns the index of the specified user message.
		 *
		 * @param name			User message name.
		 * @param size			Optional pointer to store size of user message.
		 * @return				Message index, or -1 on failure.
		 */
		virtual int FindUserMessage(const char *name, int *size=NULL) =0;

		/**
		 * @brief Returns the name of the specified user message.
		 *
		 * @param index			User message index.
		 * @param size			Optional pointer to store size of user message.
		 * @return				Message name, or NULL on failure.
		 */
		virtual const char *GetUserMessage(int index, int *size=NULL) =0;

		/**
		 * @brief Returns the highest interface version of IServerPluginCallbacks 
		 * that the engine supports.  This is useful for games that run on older 
		 * versions of the Source engine, such as The Ship.
		 *
		 * @return				Highest interface version of IServerPluginCallbacks.
		 *						Returns 0 if SourceMM's VSP listener isn't 
		 *						currently enabled.
		 * @deprecated			Use GetVSPInfo() instead.
		 */
		virtual int GetVSPVersion() =0;

		/**
		 * @brief Returns the engine interface that MM:S is using as a backend.
		 *
		 * The values will be one of the SOURCE_ENGINE_* constants from the top
		 * of this file.
	 	 *
	 	 * @return				A SOURCE_ENGINE_* constant value.
		 */
		virtual int GetSourceEngineBuild() =0;

		/**
		 * @brief Returns the VSP listener loaded.  
		 *
		 * This is useful for late-loading plugins which need to decide whether 
		 * to add a listener or not (or need to get the pointer at all).
		 *
		 * @param pVersion		Optional pointer to store the VSP version.
		 * @return				IServerPluginCallbacks pointer, or NULL if an
		 * 						IMetamodListener event has yet to occur for 
		 * 						EnableVSPListener().
		 */
		virtual IServerPluginCallbacks *GetVSPInfo(int *pVersion) =0;

		/**
		 * @brief Formats a string.  This is a platform safe wrapper around 
		 * snprintf/_snprintf.
		 *
		 * @param buffer		Buffer to write to.
		 * @param maxlength		Maximum length of the buffer.
		 * @param format		Format specifiers.
		 * @param ...			Format arguments.
		 * @return				Number of bytes actually written, not including 
		 * 						the null terminator.
		 */
		virtual size_t Format(char *buffer, 
						  	  size_t maxlength,
						  	  const char *format,
						  	  ...) =0;

		/**
		 * @brief Formats a string.  This is a platform safe wrapper around 
		 * vsnprintf/_vsnprintf.
		 *
		 * @param buffer		Buffer to write to.
		 * @param maxlength		Maximum length of the buffer.
		 * @param format		Format specifiers.
		 * @param ap			Format argument list.
		 * @return				Number of bytes actually written, not including the 
		 *						null terminator.
		 */
		virtual size_t FormatArgs(char *buffer,
								  size_t maxlength,
								  const char *format,
								  va_list ap) =0;
	};
}

#if !defined METAMOD_NO_AUTO_NAMESPACE
using namespace SourceMM;
#endif

/** 
 * Version History
 *
 * 1.1.0 Bumped API to 1:0. The breaking changes occurred in SourceHook and the plugin API.
 * 1.1.2 Added API call for generating iface names.
 * 1.2   Added API more helper functions and new SourceHook version.
 * 1.2.2 Added API for printing to client console (with string formatting).
 * 1.3   Added new interface search API.
 * 1.4	 Added VSP listener and user message API.
 * 1.5.0 Added API for getting highest supported version of IServerPluginCallbacks.
 * 1.6.0 Added API for Orange Box.  Broke backwards compatibility.
 */

#endif //_INCLUDE_ISMM_API_H