#ifndef FLASHLIGHTEFFECT_H
#define FLASHLIGHTEFFECT_H
#ifdef _WIN32
#pragma once
#endif
 
#include "MaterialSystemUtil.h" 


class CountdownTimer
{
public:
#ifdef CLIENT_DLL
	DECLARE_PREDICTABLE();
#endif
	DECLARE_CLASS_NOBASE(CountdownTimer);
	DECLARE_EMBEDDED_NETWORKVAR();

	CountdownTimer(void);

	void Reset(void)
	{
		m_timestamp = Now() + m_duration;
	}

	void Start(float duration)
	{
		m_timestamp = Now() + duration;
		m_duration = duration;
	}

	void StartFromTime(float startTime, float duration)
	{
		m_timestamp = startTime + duration;
		m_duration = duration;
	}

	void Invalidate(void)
	{
		m_timestamp = -1.0f;
	}

	bool HasStarted(void) const
	{
		return (m_timestamp > 0.0f);
	}

	bool IsElapsed(void) const
	{
		return (Now() > m_timestamp);
	}

	float GetElapsedTime(void) const
	{
		return Now() - m_timestamp + m_duration;
	}

	float GetRemainingTime(void) const
	{
		return (m_timestamp - Now());
	}

	float GetCountdownDuration(void) const
	{
		return (m_timestamp > 0.0f) ? m_duration : 0.0f;
	}

	float GetRemainingRatio(void) const
	{
		if (HasStarted())
		{
			float left = GetRemainingTime() / m_duration;
			if (left < 0.0f)
				return 0.0f;
			if (left > 1.0f)
				return 1.0f;
			return left;
		}

		return 0.0f;
	}

private:
	CNetworkVar(float, m_duration);
	CNetworkVar(float, m_timestamp);
	float Now(void) const;		        
};

struct dlight_t;




class CFlashlightEffect
{
public:

	CFlashlightEffect(int nEntIndex = 0, const char* pszTextureName = NULL, float flFov = 0.0f, float flFarZ = 0.0f, float flLinearAtten = 0.0f);
	~CFlashlightEffect();

	void UpdateLight(int nEntIdx, const Vector& vecPos, const Vector& vecDir, const Vector& vecRight, const Vector& vecUp, float flFov,
		float flFarZ, float flLinearAtten, bool castsShadows, const char* pTextureName);
	void UpdateLight(int nEntIdx, const Vector& vecPos, const Vector& vecDir, const Vector& vecRight, const Vector& vecUp, float flFov,
		bool castsShadows, ITexture* pFlashlightTexture, const Vector& vecBrightness, bool bTracePlayers = true);

	void TurnOn();
	void TurnOff();
	void SetMuzzleFlashEnabled(bool bEnabled, float flBrightness);
	bool IsOn(void) { return m_bIsOn; }

	ClientShadowHandle_t GetFlashlightHandle(void) { return m_FlashlightHandle; }
	void SetFlashlightHandle(ClientShadowHandle_t Handle) { m_FlashlightHandle = Handle; }

	const char* GetFlashlightTextureName(void) const
	{
		return m_textureName;
	}

	int GetEntIndex(void) const
	{
		return m_nEntIndex;
	}

	bool UpdateDefaultFlashlightState(FlashlightState_t& state, const Vector& vecPos, const Vector& vecDir, const Vector& vecRight,
		const Vector& vecUp, bool castsShadows, bool bTracePlayers = true);
	bool ComputeLightPosAndOrientation(const Vector& vecPos, const Vector& vecDir, const Vector& vecRight, const Vector& vecUp,
		Vector& vecFinalPos, Quaternion& quatOrientation, bool bTracePlayers);
	void LightOff();

	void UpdateFlashlightTexture(const char* pTextureName);
	void UpdateLightTopDown(const Vector& vecPos, const Vector& vecDir, const Vector& vecRight, const Vector& vecUp);

	bool m_bIsOn;
	int m_nEntIndex;
	ClientShadowHandle_t m_FlashlightHandle;

	bool m_bMuzzleFlashEnabled;
	float m_flMuzzleFlashBrightness;

	float m_flFov;
	float m_flFarZ;
	float m_flLinearAtten;
	bool  m_bCastsShadows;

	float m_flCurrentPullBackDist;

	CTextureReference m_FlashlightTexture;

	CTextureReference m_MuzzleFlashTexture;

	char m_textureName[64];
};

class CHeadlightEffect : public CFlashlightEffect
{
public:

	CHeadlightEffect();
	~CHeadlightEffect();

	virtual void UpdateLight(const Vector& vecPos, const Vector& vecDir, const Vector& vecRight, const Vector& vecUp, int nDistance);
};
 
 

class CFlashlightEffectManager
{
private:
	CFlashlightEffect* m_pFlashlightEffect;
	const char* m_pFlashlightTextureName;
	int m_nFlashlightEntIndex;
	float m_flFov;
	float m_flFarZ;
	float m_flLinearAtten;
	int m_nMuzzleFlashFrameCountdown;
	CountdownTimer m_muzzleFlashTimer;
	float m_flMuzzleFlashBrightness;
	bool m_bFlashlightOn;
	int m_nFXComputeFrame;
	bool m_bFlashlightOverride;

public:
	CFlashlightEffectManager() : m_pFlashlightEffect(NULL), m_pFlashlightTextureName(NULL), m_nFlashlightEntIndex(-1), m_flFov(0.0f),
		m_flFarZ(0.0f), m_flLinearAtten(0.0f), m_nMuzzleFlashFrameCountdown(0), m_flMuzzleFlashBrightness(1.0f),
		m_bFlashlightOn(false), m_nFXComputeFrame(-1), m_bFlashlightOverride(false) {}

	void TurnOnFlashlight(int nEntIndex = 0, const char* pszTextureName = NULL, float flFov = 0.0f, float flFarZ = 0.0f, float flLinearAtten = 0.0f)
	{
		m_pFlashlightTextureName = pszTextureName;
		m_nFlashlightEntIndex = nEntIndex;
		m_flFov = flFov;
		m_flFarZ = flFarZ;
		m_flLinearAtten = flLinearAtten;
		m_bFlashlightOn = true;

		if (m_bFlashlightOverride)
		{
			return;
		}

		if (!m_pFlashlightEffect)
		{
			if (pszTextureName)
			{
				m_pFlashlightEffect = new CFlashlightEffect(m_nFlashlightEntIndex, pszTextureName, flFov, flFarZ, flLinearAtten);
			}
			else
			{
				m_pFlashlightEffect = new CFlashlightEffect(m_nFlashlightEntIndex);
			}

			if (!m_pFlashlightEffect)
			{
				return;
			}
		}

		m_pFlashlightEffect->TurnOn();
	}

	void TurnOffFlashlight(bool bForce = false)
	{
		m_pFlashlightTextureName = NULL;
		m_bFlashlightOn = false;

		if (bForce)
		{
			m_bFlashlightOverride = false;
			m_nMuzzleFlashFrameCountdown = 0;
			m_muzzleFlashTimer.Invalidate();
			delete m_pFlashlightEffect;
			m_pFlashlightEffect = NULL;
			return;
		}

		if (m_bFlashlightOverride)
		{
			return;
		}

		if (m_nMuzzleFlashFrameCountdown == 0 && m_muzzleFlashTimer.IsElapsed())
		{
			delete m_pFlashlightEffect;
			m_pFlashlightEffect = NULL;
		}
	}

	bool IsFlashlightOn() const { return m_bFlashlightOn; }

	void UpdateFlashlight(const Vector& vecPos, const Vector& vecDir, const Vector& vecRight, const Vector& vecUp, float flFov, bool castsShadows,
		float flFarZ, float flLinearAtten, const char* pTextureName = NULL);
	void SetEntityIndex(int index)
	{
		m_nFlashlightEntIndex = index;
	}

	void TriggerMuzzleFlash()
	{
	}

	const char* GetFlashlightTextureName(void) const
	{
		return m_pFlashlightTextureName;
	}

	int GetFlashlightEntIndex(void) const
	{
		return m_nFlashlightEntIndex;
	}

	void EnableFlashlightOverride(bool bEnable)
	{
		m_bFlashlightOverride = bEnable;

		if (!m_bFlashlightOverride)
		{
			if (m_bFlashlightOn && m_pFlashlightEffect == NULL)
			{
				TurnOnFlashlight(m_nFlashlightEntIndex, m_pFlashlightTextureName, m_flFov, m_flFarZ, m_flLinearAtten);
			}
			else if (!m_bFlashlightOn && m_pFlashlightEffect)
			{
				delete m_pFlashlightEffect;
				m_pFlashlightEffect = NULL;
			}
		}
	}

	void UpdateFlashlightOverride(bool bFlashlightOn, const Vector& vecPos, const Vector& vecDir, const Vector& vecRight, const Vector& vecUp,
		float flFov, bool castsShadows, ITexture* pFlashlightTexture, const Vector& vecBrightness)
	{
		Assert(m_bFlashlightOverride);
		if (!m_bFlashlightOverride)
		{
			return;
		}

		if (bFlashlightOn && !m_pFlashlightEffect)
		{
			m_pFlashlightEffect = new CFlashlightEffect(m_nFlashlightEntIndex);
		}
		else if (!bFlashlightOn && m_pFlashlightEffect)
		{
			delete m_pFlashlightEffect;
			m_pFlashlightEffect = NULL;
		}

		if (m_pFlashlightEffect)
		{
			m_pFlashlightEffect->UpdateLight(m_nFlashlightEntIndex, vecPos, vecDir, vecRight, vecUp, flFov, castsShadows, pFlashlightTexture, vecBrightness, false);
		}
	}
};





#endif  
