#ifndef INCLUDED_CINEMATRACK
#define INCLUDED_CINEMATRACK

#include <list>
#include <map>
#include "ps/CStr.h"
#include "maths/NUSpline.h"

/*
    desc: contains various functions used for cinematic camera paths
    See also: CinemaHandler.cpp, Cinematic.h/.cpp
*/

class CVector3D;
class CVector4D;
class CCamera;

//For loading data
class CCinemaData
{
public:
    CCinemaData() : m_GrowthCount(0), m_Growth(0), m_Switch(0), 
                    m_Mode(0), m_Style(0), m_Timescale(1) {}
    virtual ~CCinemaData() {}
    
    const CCinemaData* GetData() const { return this; }
    
    //Distortion variables
    mutable float m_GrowthCount;
    float m_Growth;
    float m_Switch;
    int m_Mode;
    int m_Style;
    float m_Timescale;  //a negative timescale results in backwards play

};


//Once the data is part of the path, it shouldn't be changeable, so use private inheritance.
//This class encompasses the spline and the information which determines how the path will operate
//and also provides the functionality for doing so

class CCinemaPath : private CCinemaData, public TNSpline
{
public:
    CCinemaPath() { m_TimeElapsed = 0.0f; m_PreviousNodeTime = 0.0f; }
    CCinemaPath(const CCinemaData& data, const TNSpline& spline);
    ~CCinemaPath() { DistStylePtr = NULL;  DistModePtr = NULL; }
    
    enum { EM_IN, EM_OUT, EM_INOUT, EM_OUTIN };
    enum { ES_DEFAULT, ES_GROWTH, ES_EXPO, ES_CIRCLE, ES_SINE };
    
    //sets camera position to calculated point on spline
    void MoveToPointAt(float t, float nodet, const CVector3D& );
    
    //Distortion mode functions-change how ratio is passed to distortion style functions
    float EaseIn(float t) const;
    float EaseOut(float t) const;
    float EaseInOut(float t) const;
    float EaseOutIn(float t) const;

    //Distortion style functions
    float EaseDefault(float t) const;
    float EaseGrowth(float t) const;
    float EaseExpo(float t) const;
    float EaseCircle(float t) const;
    float EaseSine(float t) const;
    
    float (CCinemaPath::*DistStylePtr)(float ratio) const;
    float (CCinemaPath::*DistModePtr)(float ratio) const;

    const CCinemaData* GetData() const { return CCinemaData::GetData(); }

public:

    void DrawSpline(const CVector4D& RGBA, int smoothness, bool lines) const;

    inline CVector3D GetNodePosition(const int index) const { return Node[index].Position; }
    inline float GetNodeDuration(const int index) const { return Node[index].Distance; }
    inline float GetDuration() const { return MaxDistance; }
    
    inline float GetNodeFraction() const { return (m_TimeElapsed -m_PreviousNodeTime) / Node[m_CurrentNode].Distance; }
    inline float GetElapsedTime() const { return m_TimeElapsed; }

    inline void SetTimescale(float scale) { m_Timescale = scale; }
    
    float m_TimeElapsed;
    float m_PreviousNodeTime;   //How much time has passed before the current node
    
    size_t m_CurrentNode;
    CVector3D m_PreviousRotation;

public: 

    //Returns false if finished
    bool Play(float DeltaTime);
    bool Validate();

    inline float GetTimescale() const { return m_Timescale; }   
};

//Class for in game playing of cinematics. Should only be instantiated in CGameView. 
class CCinemaManager
{
public:
    CCinemaManager();
    ~CCinemaManager() {}

    void AddPath(CCinemaPath path, const CStrW& name);

    //Adds track to list of being played. 
    void QueuePath(const CStrW& name, bool queue);
    void OverridePath(const CStrW& name);   //clears track queue and replaces with 'name'
    bool Update(float DeltaTime);
    
    //These stop track play, and accept time, not ratio of time
    void MoveToPointAt(float time);

    inline void StopPlaying() { m_PathQueue.clear(); }
    void DrawSpline() const;
    
    inline bool IsPlaying() const { return !m_PathQueue.empty(); }
    bool HasTrack(const CStrW& name) const; 
    inline bool IsActive() const { return m_Active; }
    inline void SetActive(bool active) { m_Active=active; }

    inline const std::map<CStrW, CCinemaPath>& GetAllPaths() { return m_Paths; }
    void SetAllPaths( const std::map<CStrW, CCinemaPath>& tracks);
    void SetCurrentPath(const CStrW& name, bool current, bool lines);

private:
    
    bool m_Active, m_DrawCurrentSpline, m_DrawLines, m_ValidCurrent;
    std::map<CStrW, CCinemaPath>::iterator m_CurrentPath;
    std::map<CStrW, CCinemaPath> m_Paths;
    std::list<CCinemaPath> m_PathQueue;
};

#endif