/**
 * vim: set ts=4 :
 * ================================================================
 * SourcePawn
 * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
 * ================================================================
 *
 * This program is free software; you can redistribute it and/or 
 * modify it under the terms of the GNU General Public License, 
 * version 3.0, as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * As a special exception, AlliedModders LLC gives you permission to 
 * link the code of this program (as well as its derivative works) to 
 * "Half-Life 2," the "Source Engine," the "SourcePawn JIT," and any 
 * Game MODs that run on software by the Valve Corporation.  You must 
 * obey the GNU General Public License in all respects for all other 
 * code used. Additionally, AlliedModders LLC grants this exception 
 * to all derivative works. AlliedModders LLC defines further 
 * exceptions, found in LICENSE.txt (as of this writing, version 
 * JULY-31-2007), or <http://www.sourcemod.net/license.php>.
 *
 * Version: $Id$
 */

#ifndef _INCLUDE_SOURCEPAWN_VM_ENGINE_H_
#define _INCLUDE_SOURCEPAWN_VM_ENGINE_H_

#include "sp_vm_api.h"
#include "sp_vm_function.h"

struct TracedCall
{
	uint32_t cip;
	uint32_t frm;
	sp_context_t *ctx;
	TracedCall *next;
	unsigned int chain;
};

class CContextTrace : public IContextTrace
{
public:
	CContextTrace(TracedCall *pStart, int error, const char *msg, uint32_t native);
public:
	int GetErrorCode();
	const char *GetErrorString();
	bool DebugInfoAvailable();
	const char *GetCustomErrorString();
	bool GetTraceInfo(CallStackInfo *trace);
	void ResetTrace();
	const char *GetLastNative(uint32_t *index);
private:
	int m_Error;
	const char *m_pMsg;
	TracedCall *m_pStart;
	TracedCall *m_pIterator;
	uint32_t m_Native;
};

class SourcePawnEngine : public ISourcePawnEngine
{
public:
	SourcePawnEngine();
	~SourcePawnEngine();
public: //ISourcePawnEngine
	sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err);
	sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err);
	int FreeFromMemory(sp_plugin_t *plugin);
	IPluginContext *CreateBaseContext(sp_context_t *ctx);
	void FreeBaseContext(IPluginContext *ctx);
	void *BaseAlloc(size_t size);
	void BaseFree(void *memory);
	void *ExecAlloc(size_t size);
	void ExecFree(void *address);
	IDebugListener *SetDebugListener(IDebugListener *pListener);
	unsigned int GetContextCallCount();
	unsigned int GetEngineAPIVersion();
public: //Debugger Stuff
	/**
	 * @brief Pushes a context onto the top of the call tracer.
	 * 
	 * @param ctx		Plugin context.
	 */
	void PushTracer(sp_context_t *ctx);

	/**
	 * @brief Pops a plugin off the call tracer.
	 */
	void PopTracer(int error, const char *msg);

	/**
	 * @brief Runs tracer from a debug break.
	 */
	void RunTracer(sp_context_t *ctx, uint32_t frame, uint32_t codeip);
public: //Plugin function stuff
	CFunction *GetFunctionFromPool(funcid_t f, IPluginContext  *plugin);
	void ReleaseFunctionToPool(CFunction *func);
private:
	TracedCall *MakeTracedCall(bool new_chain);
	void FreeTracedCall(TracedCall *pCall);
private:
	IDebugListener *m_pDebugHook;
	TracedCall *m_FreedCalls;
	TracedCall *m_CallStack;
	unsigned int m_CurChain;
	//CFunction *m_pFreeFuncs;
};

#endif //_INCLUDE_SOURCEPAWN_VM_ENGINE_H_