/*************************************************************************
Crytek Source File.
Copyright (C), Crytek Studios, 2001-2005.
-------------------------------------------------------------------------
$Id$
$DateTime$
Description: Directs the 'Film' asking the CFilmCamera for shots, and CFilmAction for choreography.
-------------------------------------------------------------------------
History:
- 30:6:2005: Created by Nick Hesketh

*************************************************************************/

/*
  The Film system consists of
    CFilmDirector - The director of the 'film'
    CFilmCamera   - The cinematographer
    CFilmAction   - The action choreographer

  CFilmDirector (The director)
      Monitors game events, world state, player state, and designer hints/commands.
      Decides the moods to portray/invoke.
      Decides the intensity of the moods.
      Decides the pacing of the cuts/shots.
      Tells CFilmCamera the style of shot desired.
      Tells CFilmAction how intense the action should be.
      Occasionally explicitly tells CFilmAction to implement certain choreographed moves.

  CFilmCamera (The cinematographer)
      (Cut on the thought - blinks)
      PostFX

  CFilmAction (The choreographer)
      Directs gun combat via the hit/miss system.
      Directs melee combat.
      Implements choreographed moves (signals actors to apply behaviours)
      Suppresses certain behaviours at key moments (e.g. during cuts) possibly signalling fumble behaviours etc

  CFilmWorld
      Monitors the world and extracts useful information for CFilmDirector

  HitMiss system
  AutoCombat targetting system
  
*/


#pragma once

#include <list>

class CFilmCamera;
class CFilmAction;
class CFilmWorld;
class CGame;
struct IActor;
class CPlayer;
class CPlayerG4;
struct SViewParams;
struct SFilmShotSeq;

#include "FilmCamera.h"

// What we're trying to invoke/portray in/to the player (observers). Indices to the mood array.
enum eFilmMood
{
  // Faster cuts or motion, higher contrast, more saturated colors, punchy shots. (Action)
  eAdrenaline=0,
  // Claustrophobic/Obscured vision, jerky movement, uncomfortable colors, foreshadowing via colors and sound 
  eTension,
  // (Fraternal Love or attachment) Softer lenses and lighting, lingering shots, closeups, focal area eyes and up.
  eAttraction,
  // As per attraction, but focal area of closeups emphasises lips, and occasionally cleavage etc.
  eSexualAttraction,
  // Harsh lenses and lighting, straight at eyes (angry staring), possible color wash
  eHatred,
  // distance and angle of camera shots - low emotional attachment => distant shots
  eEmotionalAttachment,
  // if >0 then weird camera angles and disturbing camera moves
  eDisorientation,
  eLastMood // This must be the last entry. determines the size of the mood array.
};

struct SFilmMood
{
  float aMood[eLastMood];  // The moods that the director is trying to express or invoke in the player
};

// What the director's trying to achieve
struct SFilmDirection
{
  SFilmMood mood;
  float visualIntensity;  // The visual strength with which these are portrayed.
};

// Interesting cues for the director.
enum eFilmEvents
{
  eNull,
	// Game hints
  eApproachingAction,   // Near an action bubble - Probably leads to director invoking tension via foreshadowing
  eCombat,              // We're in combat
  eMelee,				        // We're in hand-to-hand
  eCarRace,
  eCarFight,
  eCarCollision,
  eEnemyDeath,			    // Enemy about to die
  eFriendDeath,			    // Friend about to die
  eExplosion,			      // Explosion - if it's nearby with interest objects nearby, may be worth a slow-mo
  eNewTarget,           // Auto Combat has picked a new target
  // Game requests
  eCutAway,             // Request for a cut-away
  eEndCutAway,
  eEstablish,           // Request for an establishing shot
  eEndEstablish,
  eDeathCut,            // Request for a specific death cut
  eEndDeathCut,
};

class CFilmEvent
{
public:
  eFilmEvents type;
  float priority;
  //IActor *apActors[4];
  EntityId aIdActors[4];
  Vec3 vPos;

  CFilmEvent();

  static eFilmEvents NameToType(const char *psName);
  static const char * TypeToName(eFilmEvents eType);
private:
};


typedef std::list<CFilmEvent> TFilmEvents;
typedef std::list<CFilmEvent>::iterator TFilmEventsIter;

// Needs to become a base class with a tick func and visibility evaluation.
struct SFilmCamCut
{
  Vec3 vPos;
  Vec3 vAng;
  int rand1;
  int rand2;
  int rand3;
  float progress;
};

//! Directs the 'Film' asking the CFilmCamera for shots, and CFilmAction for choreography.
class CFilmDirector
{
public:
  friend class CFilmCamera;   // temp hack

  CFilmDirector(CGame *pGame);
  ~CFilmDirector();

  void Update(float frameTime);

  void Event(CFilmEvent ev);

  const SFilmDirection & GetDirection() { return m_direction; }

  const SFilmMood & GetMood() { return m_direction.mood; }
  void SetMood(const SFilmMood &rMood) { m_direction.mood=rMood; }

  bool InCinematic() { return IsActiveCameraCut() || m_pChosenSeq; }
  bool IsActiveCameraCut() { return m_bActiveCamCut; }
  SFilmCamCut & GetActiveCameraCut() { return m_activeCamCut; }

  bool TickCamera(CPlayerG4 *pPlayer,SViewParams &viewParams);

  void EditKey(const char *psName,float val=1.0f);

  CFilmWorld *GetWorld() { return m_pFilmWorld; }

  float GetIntensity();

  void SetShot(const char *psShot);
  void DumpShots();

  void OnEditorSetGameMode(bool bGameMode);

  // set bCritical = true if the fault is reality breaking. (e.g. geometry intersecting the camera)
  void ShotFailed(SFilmCamShotNode *pNode,bool bCritical=false);

  void PlayerDeleted(CPlayerG4 *pPlayer);

private:
  CGame *m_pGame;
  CFilmCamera *m_pFilmCamera;
  CFilmAction *m_pFilmAction;
  CFilmWorld *m_pFilmWorld;
  SFilmDirection m_direction;
  bool m_bActiveCamCut;
  SFilmCamCut m_activeCamCut;
  CFilmEvent m_evEndActive;
  float m_activeDuration;
  TFilmEvents m_events;
  int m_nEvents;
  CFilmEvent m_evChosenShot;
  CFilmEvent m_evEndChosen;
  float m_chosenDuration;
  bool m_bChosenShot;
  float m_progress;
  float m_dProgress;
  const SFilmShotSeq *m_pChosenSeq;
  int m_iChosenSeqShot;
  bool m_bUpdatedSequence;
  bool m_bSlowMo;
  float m_desiredSFXVolume;
  float m_desiredMusicVolume;
  float m_shotCurrentRealDuration;


  void SlowMo(eSlowMoRate mode=eSlowMo_High,eSlowMoEase ease=eSlowMoEase_Hold);
  void SlowMoEnd();
  float GetSlowMoScale();
  void InitEvents();
  void DeInitEvents();
  void FlushEvents();
  int GetNumEvents() { return m_nEvents; }
  bool PopEvent(CFilmEvent & rEvent);
  bool PeekEvent(CFilmEvent & rEvent);
  void PushEvent(CFilmEvent & rEvent);
  void PushEventFront(CFilmEvent & rEvent);

  // Handle shot coverage requested by game, e.g. requests for establishing shots etc.
  void HandleRequestEvents(CFilmEvent & rEv,float frameTime);
  // Handle notification of game events, e.g. Notification of explosions.
  void HandleNotifyEvents(CFilmEvent & rEv,float frameTime);

  void StartChosenShot();

  void SetSequence(const SFilmShotSeq *pSeq);
  void TickSequence();
  void StartChosenSequence();

  void TickSound(float dt);

};

