/*************************************************************************
Crytek Source File.
Copyright (C), Crytek Studios, 2001-2004.
-------------------------------------------------------------------------
$Id$
$DateTime$
Description: C++ Weapon Implementation

-------------------------------------------------------------------------
History:
- 22:8:2005   12:50 : Created by Márcio Martins

*************************************************************************/
#ifndef __WEAPON_H__
#define __WEAPON_H__

#if _MSC_VER > 1000
# pragma once
#endif


#include <IItemSystem.h>
#include <IWeapon.h>
#include <IAgent.h>
#include "Item.h"
#include "Projectile.h"


#define WEAPON_FADECROSSHAIR_SELECT	(0.250f)
#define WEAPON_FADECROSSHAIR_ZOOM		(0.200f)
#define WEAPON_SHOOT_TIMER					(5000)


class CWeapon :
	public CItem,
	public IWeapon
{
	typedef std::map<string, int>								TFireModeIdMap;
	typedef std::vector<IFireMode *>						TFireModeVector;
	typedef std::map<string, int>								TZoomModeIdMap;
	typedef std::vector<IZoomMode *>						TZoomModeVector;
	typedef std::map<string, int>								TAmmoMap;
	typedef std::multimap<string, string>				TAccessoryActivation;	// accessory->fire/zoommode

	typedef std::vector<IWeaponEventListener*>	TEventListenerVector;

	typedef struct SWeaponCrosshairStats
	{
		SWeaponCrosshairStats():
			fading(false),
			visible(true),
			fadefrom(1.0f),
			fadeto(1.0f),
			fadetime(0.0f),
			fadetimer(0.0f),
			opacity(1.0f)
		{
		}

		bool fading;
		bool visible;
		float fadefrom;
		float fadeto;
		float fadetime;
		float fadetimer;
		float opacity;
	};

	enum ETimer
	{
		eWT_Shoot = eIT_Last+0,
		eWT_Last,
	};

public:
	CWeapon();
	virtual ~CWeapon();

	// IItem, IGameObjectExtension
	virtual bool Init(IGameObject * pGameObject);
	virtual void InitClient(int channelId) { CItem::InitClient(channelId); };
	virtual void PostInit(IGameObject * pGameObject );
	virtual void PostInitClient(int channelId) { CItem::PostInitClient(channelId); };
	virtual void Release();
	virtual void Serialize(TSerialize ser, unsigned aspects);
	virtual void Update(SEntityUpdateContext& ctx, int);
	virtual void PostUpdate( float frameTime ) {};
	virtual void HandleEvent(const SGameObjectEvent&);
	virtual void ProcessEvent(SEntityEvent& );
	virtual void SetChannelId(uint16 id) {};
	virtual void SetAuthority(bool auth);

	virtual void OnAction(EntityId actorId, const char *actionName, int activationMode, float value);
	virtual void UpdateFPView(float frameTime);

	virtual IWeapon *GetIWeapon() { return this; };

	virtual void MeleeAttack();
	virtual bool CanMeleeAttack() const;
	
	virtual void Select(bool select);
	// ~IItem

	// Events
	void OnShoot(EntityId shooterId, EntityId ammoId, const char *ammoType, 
		const Vec3 &pos, const Vec3 &dir, const Vec3 &vel);
	void OnStartFire(EntityId shooterId);
	void OnStopFire(EntityId shooterId);
	void OnStartReload(EntityId shooterId, const char *ammoType);
	void OnEndReload(EntityId shooterId, const char *ammoType);
	void OnOutOfAmmo(const char *ammoType);
	void OnReadyToFire();

	// IWeapon
	virtual void SetFiringLocator(IWeaponFiringLocator *pLocator);
	virtual IWeaponFiringLocator *GetFiringLocator() const;

	virtual void AddEventListener(IWeaponEventListener *pListener);
	virtual void RemoveEventListener(IWeaponEventListener *pListener);

  virtual void SetDestination(const Vec3& pos){ m_destination = pos; }
  virtual const Vec3& GetDestination(){ return m_destination; }
	
	virtual void StartFire(EntityId shooterId);
	virtual void StopFire(EntityId shooterId);
	virtual bool CanFire() const;

	virtual void StartZoom(EntityId shooterId);
	virtual void StopZoom(EntityId shooterId);
	virtual bool CanZoom() const;
	virtual void ExitZoom();

	virtual void MountAt(const Vec3 &pos);

	virtual void Reload(bool force=false);
	virtual bool CanReload() const;

	virtual bool OutOfAmmo(bool allFireModes) const;

	virtual int GetAmmoCount(const char *ammoType) const;
	virtual void SetAmmoCount(const char *ammoType, int count);

	virtual int GetClipCount(const char *ammoType) const;
	virtual void SetClipCount(const char *ammoType, int count);

	virtual IFireMode *GetFireMode(int idx) const;
	virtual IFireMode *GetFireMode(const char *name) const;
	virtual int GetFireModeIdx(const char *name) const;
	virtual int GetCurrentFireMode() const;
	virtual void SetCurrentFireMode(int idx);
	virtual void SetCurrentFireMode(const char *name);
	virtual void ChangeFireMode();
	virtual void EnableFireMode(int idx, bool enable);
	virtual void FixAccessories(SAccessoryParams *newParams, bool attach);

	virtual IZoomMode *GetZoomMode(int idx) const;
	virtual IZoomMode *GetZoomMode(const char *name) const;
	virtual int GetZoomModeIdx(const char *name) const;
	virtual int GetCurrentZoomMode() const;
	virtual void SetCurrentZoomMode(int idx);
	virtual void SetCurrentZoomMode(const char *name);
	virtual void ChangeZoomMode();
	virtual void EnableZoomMode(int idx, bool enable);

	virtual void SetCrosshairVisibility(bool visible);
	virtual bool GetCrosshairVisibility() const;
	virtual void SetCrosshairOpacity(float opacity);
	virtual float GetCrosshairOpacity() const;
	virtual void FadeCrosshair(float from, float to, float time);
	virtual void UpdateCrosshair(float frameTime);
  
	virtual void AccessoriesChanged();
	virtual void PatchFireModeWithAccessory(IFireMode *pFireMode, const char *firemodeName);
	virtual void PatchZoomModeWithAccessory(IZoomMode *pZoomMode, const char *zoommodeName);

	virtual float GetSpinUpTime() const;
	virtual float GetSpinDownTime() const;
	virtual void SwitchAccessory(const char *acc);
	virtual void ScheduleAttachAccessory(const char *accessoryName, bool attach);
	virtual string CurrentAttachment(const char *attachmentPoint);

	virtual const AIWeaponDescriptor& GetAIWeaponDescriptor( ) const;
// ~IWeapon

	// network
	struct RequestShootParams
	{
		RequestShootParams(): shooterId(0) {};
		RequestShootParams(EntityId _shooterId, const Vec3 &at): shooterId(_shooterId), hit(at) {};

		EntityId shooterId;
		Vec3 hit;
		void SerializeWith(TSerialize ser)
		{
			ser.Value("shooterId", shooterId, NSerPolicy::AC_EntityId());
			ser.Value("hit", hit, NSerPolicy::Q_FloatVec(0, 4095, 24));
		};
	};

	struct RequestFireModeParams
	{
		RequestFireModeParams(): id(0) {};
		RequestFireModeParams(int fmId): id(fmId) {};

		int id;
		void SerializeWith(TSerialize ser)
		{
			ser.Value("id", id, NSerPolicy::AS_RangedInt32(0, 7));
		};
	};
	
	DECLARE_SERVER_RMI_PREATTACH(SvRequestShoot, RequestShootParams, eNRT_ReliableOrdered);
	DECLARE_CLIENT_RMI_PREATTACH(ClShoot, RequestShootParams, eNRT_UnreliableOrdered);

	DECLARE_SERVER_RMI_PREATTACH(SvRequestFireMode, RequestFireModeParams, eNRT_ReliableOrdered);


	int NetGetCurrentFireMode() const;
	void NetSetCurrentFireMode(int id);

	void NetShoot(const Vec3 &hit);
	
	CProjectile *SpawnAmmo(const char *ammoName);
protected:
	virtual bool ReadItemParams(const IItemParamsNode *params);
	const IItemParamsNode *GetFireModeParams(const char *name);
	const IItemParamsNode *GetZoomModeParams(const char *name);
	void InitFireModes(const IItemParamsNode *firemodes);
	void InitZoomModes(const IItemParamsNode *zoommodes);
	void InitAmmos(const IItemParamsNode *ammo);
	void InitAIData(const IItemParamsNode *aiDescriptor);

	IFireMode					*m_fm;
	int								m_fmId;

	IFireMode					*m_melee;

	IZoomMode					*m_zm;
	int								m_zmId;

	TFireModeIdMap		m_fmIds;
	TFireModeVector		m_firemodes;

	TZoomModeIdMap		m_zmIds;
	TZoomModeVector		m_zoommodes;

	TAmmoMap					m_ammo;
	TAmmoMap					m_clips;

	bool							m_fire_alternation;

	const IItemParamsNode	*m_fmDefaults;
	const IItemParamsNode *m_zmDefaults;
	const IItemParamsNode	*m_params;

	TEventListenerVector	m_listeners;
	IWeaponFiringLocator	*m_pFiringLocator;

	SWeaponCrosshairStats	m_crosshairstats;


	float	m_dofValue;
	float	m_dofSpeed;

  Vec3 m_destination;

	AIWeaponDescriptor	m_aiWeaponDescriptor;
};


#endif //__WEAPON_H__
