/*************************************************************************
Crytek Source File.
Copyright (C), Crytek Studios, 2001-2005.
-------------------------------------------------------------------------
$Id$
$DateTime$
Description: Implements a base class for vehicle movements

-------------------------------------------------------------------------
History:
- 09:28:2005: Created by Mathieu Pinard

*************************************************************************/
#ifndef __VEHICLEMOVEMENTBASE_H__
#define __VEHICLEMOVEMENTBASE_H__

#include <vector>
#include <ParticleParams.h>
#include <IVehicleSystem.h>
#include "Actor.h"

#define ENGINESOUND_MAX_DIST 150.f
#define ENGINESOUND_IDLE_RATIO 0.2f


struct IGroundEffect;

/** exhaust status structure
*/
struct SExhaustStatus
{
  string helper;
  int startStopSlot;
  int runSlot;
    
  SExhaustStatus()
  {    
    startStopSlot = -1;
    runSlot = -1;
  }
};

struct TEnvEmitter
{
  TEnvEmitter()
  { 
    layer = -1;      
    slot = -1;
    matId = -1;
    group = -1;
    bContact = false;
    pGroundEffect = 0;
  }

  int layer; // layer idx the emitter belongs to    
  int slot;  // emitter slot
  int matId; // last surface idx    
  int group; // optional     
  bool bContact; // optional
  IGroundEffect* pGroundEffect;
};

struct SEnvParticleStatus
{
  bool initalized;
  
  typedef std::vector<TEnvEmitter> TEnvEmitters;
  TEnvEmitters emitters;  //maps emitter slots to user-defined index
  
  SEnvParticleStatus() : initalized(false)
  {}
};


/** particle status structure
*/
struct SParticleStatus
{
  ICVar* pExhaustCVar;
  std::vector<SExhaustStatus> exhaustStats; // can hold multiple exhausts
  SEnvParticleStatus envStats;

  SParticleStatus()
  {
    pExhaustCVar = 0;
  }
};

namespace 
{
  bool DebugParticles()
  {
    static ICVar* pVar = GetISystem()->GetIConsole()->GetCVar("v_debugdraw");
    return pVar->GetIVal() == eVDB_Particles;
  }
}

class CVehicleMovementBase
	: public IVehicleMovement, ISoundEventListener
{
public:  
  CVehicleMovementBase();
  virtual ~CVehicleMovementBase(){}

	virtual bool Init(IVehicle* pVehicle, const SmartScriptTable &table);
	virtual void Release();
	virtual void Reset();
  virtual void PostInit(){}
	virtual void Physicalize();

	virtual bool StartEngine(EntityId driverId);
	virtual void StopEngine();
	virtual bool IsPowered() { return m_isEnginePowered; }

	virtual void OnEvent(EVehicleMovementEvent event, float value);
	virtual void OnAction(const char *actionName, int activationMode, float value) {}

	virtual void ProcessMovement(const float deltaTime);
	virtual void ProcessActions(const float deltaTime) {}
	virtual void ProcessAI(const float deltaTime) {}
	virtual void Update(const float deltaTime);
  
	virtual void Serialize(TSerialize ser, unsigned aspects) {}
	virtual void SetChannelId(uint16 id) {};
	virtual void SetAuthority(bool auth){};

	virtual void OnEngineCompletelyStopped() {}

	virtual void RequestActions(const SVehicleMovementAction& movementAction);
	virtual bool RequestMovement(CMovementRequest& movementRequest) { return false; }
	virtual void GetMovementState(SMovementState& movementState);

	virtual void RegisterActionFilter(IVehicleMovementActionFilter* pActionFilter);
	virtual void UnregisterActionFilter(IVehicleMovementActionFilter* pActionFilter);

  virtual void OnSoundEvent(ESoundCallbackEvent event,ISound *pSound);
  
protected:

  bool IsProfilingMovement();
	void DebugDrawSounds();

  void StopSound(int eSID);
  void StopSounds();
  ISound* GetSound(int eSID);
  string GetSoundName(int eSID);
  void SetSoundParam(int eSID, const char* param, float value);
    
  virtual void UpdateGameTokens(const float deltaTime);
  virtual float GetEnginePedal(){ return m_movementAction.power; }
  
  // particle methods
  virtual void InitExhaust();
  virtual void InitEnvParticles();
  virtual void ResetParticles();
  virtual void UpdateEnvParticles(const float deltaTime);
  virtual void UpdateExhaust(const float deltaTime);
  void FreeEmitterSlot(int& slot);
  void FreeEmitterSlot(const int& slot);
  void StartExhaust();
  void StopExhaust();  
  float GetWaterMod(SExhaustStatus& exStatus);
  
  XmlNodeRef GetEffectNode(int matId);
  const char* GetEffectByIndex(const XmlNodeRef& effectNode, int idx);
  // ~particle methods

  
protected:

  // sounds
  enum EVehicleMovementSounds
  {
    eSID_Start = 0,
    eSID_Run,
    eSID_Stop,
    eSID_Ambience,
    eSID_Max,
  };

  tSoundID GetSoundId(int sId) { if (sId<0 || sId>eSID_Ambience) return INVALID_SOUNDID; return m_soundIds[sId]; }

	IVehicle* m_pVehicle;
	IEntity* m_pEntity;
	IEntitySoundProxy* m_pEntitySoundsProxy;
	IPhysicalEntity* m_pPhysics;
  I3DEngine* m_p3DEngine;
  IGameTokenSystem* m_pGameTokenSystem;
  IVehicleSystem* m_pVehicleSystem;

  SVehicleMovementAction m_movementAction;
  
	bool m_isEngineStarting;
	bool m_isEngineGoingOff;
	float m_engineStartup;
	float m_engineIgnitionTime;

	bool m_isEnginePowered;
	float m_damage;

  tSoundID m_soundIds[eSID_Max];  
  string m_soundNames[eSID_Max];
  Vec3 m_enginePos;
  float m_runSoundDelay;
  float m_crossFade;
  float m_rpmScale;
  float m_rpmPitchSpeed;
  
  SParticleParams* m_pPaParams;
  SParticleStatus m_paStats;

  IActor* m_actor;
  pe_status_dynamics m_statusDyn; // gets updated once per update
  float m_maxSpeed;  

	typedef std::list<IVehicleMovementActionFilter*> TVehicleMovementActionFilterList;
	TVehicleMovementActionFilterList m_actionFilters;

  ICVar* m_pSilentStart;
  ICVar* m_pRunFadeInTime;
  ICVar* m_pRunFadeOutTime;

  static XmlNodeRef m_sfxNode;
};

#endif

