#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef _ASURA_CUTSCENE_TRACK_H_
#define _ASURA_CUTSCENE_TRACK_H_

#include "Core/Asura_Handle.h"
#include "Core/Asura_Maths.h"
#include "Core/Asura_String.h"

#define TrackFlag_InterpolateToNextTrack	0x00000001
#define TrackFlag_OrientationFromPoints		0x00000002 
#define TrackFlag_RollFromPoints			0x00000004 
#define TrackFlag_PitchAlongTrack			0x00000008
#define TrackFlag_Loop						0x00000010 //Track loops back to beginning if time is greater than the end time for the track
#define TrackFlag_Circular					0x00000020 //Makes the track a continuous circuit by taking the first and large control points from other points on the track
#define TrackFlag_IncreasedSpeedAccuracy 	0x00000040 //Adjusts SmoothTrackPosition so that the distance along each section is more evenly spaced between 0 and 1
#define TrackFlag_SmoothSpeed				0x00000080 //Speed changed smoothly using the same spline code as the positions

#define TrackPointFlag_SectionStraight	0x00000001 //track section following this point is straight 
#define TrackPointFlag_Stationary		0x00000002 //speed should reach zero at this point(for smooth speed tracks)

class Asura_Chunk_Stream;

class Asura_Cutscene_Track
{
public :

	Asura_Cutscene_Track();
	virtual ~Asura_Cutscene_Track();

	void Copy(const Asura_Cutscene_Track* pxTrack);
	#ifdef ASURA_TOOLS
	//These two are for moving the members of a cutscene as the cutscene object is moved
	virtual void CalculateRelativePosition(const Asura_Matrix_3x3& xCutsceneOrientInverse,const Asura_Vector_3 xCutscenePosition);
	virtual void UpdateRelativeToPosition(const Asura_Matrix_3x3& xCutsceneOrient,const Asura_Vector_3 xCutscenePosition);
	#endif


    // (MH - 05.11.2002) the chunk loading/saving used to be part of Asura_Chunk_CutsceneTrack.
    // That now calls these functions. This is to cope with tracks being used by actors for 
    // things other than the standard position / orientation. They are defined in 
    // Asura_Chunk_Cutscene.cpp. Note that num points and version are stored in 
    // Asura_Chunk_CutsceneTrack so they gets passed as parameters rather than being in the 
    // chunk data itself.
	int GetChunkBufferSize();
	void FillInChunkBuffer(char*& pcChunkBuffer);
	void LoadFromChunkBuffer(Asura_Handle iFileHandle, int iNumberOfPoints, int iVersion, int iChunkFlags);
	void InitialiseFromChunkBuffer( const char*& pcChunkBuffer );
//	void ReadFromChunkStream(Asura_Chunk_Stream& xStream);
	void WriteToChunkStream(Asura_Chunk_Stream& xStream) const;

	//Points passed are just the points on the track , not the extra control points
	virtual void SetPoints(int numberOfPoints, const Asura_Vector_3* points);
	void CalculateEndControlPoints();//generated first and last pivot from the track points
	void CalculateLengths();


	void GetPositionFromTime(float fTime,Asura_Vector_3* pxOutput,const Asura_Cutscene_Track* pxNextTrack = 0) const;
	void GetPositionFromDistance(float distanceAlongTrack,Asura_Vector_3* output) const;

	//gets a direction vector pointing along the track
	void GetDirectionFromTime(float time,Asura_Vector_3* output,const Asura_Cutscene_Track* pxNextTrack = 0) const;
	void GetDirectionFromDistance(float distanceAlongTrack,Asura_Vector_3* output) const;

	//gets an orientation taken from the tracks direction and/or the point orientations depending on the flags
	void GetOrientationFromTime(float fTime,Asura_Matrix_3x3* pxOutput, const Asura_Cutscene_Track* pxNextTrack =0) const;
	void GetOrientationFromDistance(float fDistanceAlongTrack,Asura_Matrix_3x3* pxOutput) const;

	float GetSpeedFromTime(float fTime) const;
	float GetSpeedFromDistance(float fDistanceAlongTrack) const;
	
	float GetDistanceFromTime(float fTime) const;

	float GetLength() const {return TrackLength;}
	float GetStartTime() const;
	float GetEndTime() const;

	void GetOrientationAtPoint(int iIndex,Asura_Matrix_3x3& xMat) const;
	void SetOrientationAtPoint(int iIndex,const Asura_Matrix_3x3& xMat);


	int GetNumberOfPoints() const;
	Asura_Vector_3* GetPoints() const;

	float GetDistanceAtPoint(int index) const {return TotalLengths ? TotalLengths[index] : 0;}


	int NumberOfPivots;
	Asura_Vector_3* Pivots;
	float* PointArrivalTimes;//time at which each point is reached
	float* PointDurations;//length of time spent paused at each point
	int* PointFlags;//array of flags for each track point
	float* m_pfPointSpeeds;//Speed at each point , if using smoothed speeds

	unsigned m_uTrackFlags;

protected :
	void GetPointOrientationFromDistance(float fDistanceAlongTrack,Asura_Matrix_3x3* pxOutput) const;
	void GetPointOrientationFromTime(float fTime,Asura_Matrix_3x3* pxOutput) const;

	float ConvertTimeToBeInRange(float fTime) const;

	void GetOrientationFromTimeMain(float fTime,Asura_Matrix_3x3* pxOutput) const;

	//Gets the section and proportion along it from distance
	void GetLerpAndSectionFromDistance(float fDistance,float& fLerp,int& iSection) const;
	//Gets the section and proportion along it from time
	void GetLerpAndSectionFromTime(float fTime,float& fLerp,int& iSection,u_int uTrackFlagsToIgnore = 0) const;

	void GetPosition(int iSection,float fLerp,Asura_Vector_3* pxOutput) const;


	//derived data
	int NumberOfSections;
	float* TotalLengths;//accumulated distance at the ith point
	float TrackLength;
	Asura_Quat* m_pxPointOrientations;
	float* m_pfSubTotalLengths;

	#ifdef ASURA_TOOLS
	//relative positions are for temporary use while moving the cutscene object
	Asura_Vector_3* m_pxRelativePivots;
	Asura_Quat* m_pxRelativeOrients;
	#endif

public :
	Asura_String TrackName;//optional track name for editing purposes

};


float LengthOfTrackSection(Asura_Vector_3* pivots,int sectionFlags = 0);
void SmoothTrackPosition(const Asura_Vector_3* pivots,float u,Asura_Vector_3* output);

#endif //_ASURA_CUTSCENE_TRACK_H_
