#ifndef IPREDICTIONSYSTEM_H
#define IPREDICTIONSYSTEM_H
#ifdef _WIN32
#pragma once
#endif

#include "predictable_entity.h"

class CBaseEntity;

class IPredictionSystem
{
public:
	IPredictionSystem()
	{
		m_pNextSystem = g_pPredictionSystems;
		g_pPredictionSystems = this;

		m_bSuppressEvent = false;
		m_pSuppressHost = NULL;

		m_nStatusPushed = 0;
	};

	virtual ~IPredictionSystem() {};

	IPredictionSystem* GetNext()
	{
		return m_pNextSystem;
	}

	void SetSuppressEvent(bool state)
	{
		m_bSuppressEvent = state;
	}

	void SetSuppressHost(CBaseEntity* host)
	{
		m_pSuppressHost = host;
	}

	CBaseEntity const* GetSuppressHost(void)
	{
		if (DisableFiltering())
		{
			return NULL;
		}

		return m_pSuppressHost;
	}

	bool CanPredict(void) const
	{
		if (DisableFiltering())
		{
			return false;
		}

		return !m_bSuppressEvent;
	}

	static IPredictionSystem* g_pPredictionSystems;

	static void SuppressEvents(bool state)
	{
		IPredictionSystem* sys = g_pPredictionSystems;
		while (sys)
		{
			sys->SetSuppressEvent(state);
			sys = sys->GetNext();
		}
	}

	static void SuppressHostEvents(CBaseEntity* host)
	{
		IPredictionSystem* sys = g_pPredictionSystems;
		while (sys)
		{
			sys->SetSuppressHost(host);
			sys = sys->GetNext();
		}
	}

private:

	static void Push(void)
	{
		IPredictionSystem* sys = g_pPredictionSystems;
		while (sys)
		{
			sys->_Push();
			sys = sys->GetNext();
		}
	}

	static void Pop(void)
	{
		IPredictionSystem* sys = g_pPredictionSystems;
		while (sys)
		{
			sys->_Pop();
			sys = sys->GetNext();
		}
	}

	void _Push(void)
	{
		++m_nStatusPushed;
	}
	void _Pop(void)
	{
		--m_nStatusPushed;
	}

	bool DisableFiltering(void) const
	{
		return (m_nStatusPushed > 0) ? true : false;
	}

	IPredictionSystem* m_pNextSystem;
	bool				m_bSuppressEvent;
	CBaseEntity* m_pSuppressHost;

	int					m_nStatusPushed;

	friend class CDisablePredictionFiltering;
};

class CDisablePredictionFiltering
{
public:
	CDisablePredictionFiltering(bool disable = true)
	{
		m_bDisabled = disable;
		if (m_bDisabled)
		{
			IPredictionSystem::Push();
		}
	}

	~CDisablePredictionFiltering(void)
	{
		if (m_bDisabled)
		{
			IPredictionSystem::Pop();
		}
	}
private:
	bool	m_bDisabled;
};

#endif  