/***************************************************************************
*                                                                          *
*  Copyright (C) Golaem S.A.  All Rights Reserved.                         *
*                                                                          *
***************************************************************************/

#pragma once

#include "glmSDKAPI.h"
#include "glmNavigationPathVertex.h"
#include "glmPathEntityComponentLocation.h"
#include "glmQuaternion.h"

namespace glm
{
class NavigationData;
class PathEntityComponentLocation;

/** 
* \brief Description of a path.
*
* \ingroup PathLib
*
* \author Golaem <dev@golaem.com>
*/
class GLM_SDK_API NavigationPath
{
  public:
    GLM_CLASS_STAT_ID( glm::MemoryStatIds::Simulation)

    /** 
	* \brief Constructor.
	*/
    NavigationPath();

    /** 
	* \brief Copy Constructor.
	*/
    NavigationPath(const NavigationPath& polyline);

    virtual ~NavigationPath()
    {
    }

    /**
	* \brief assignment operator
	*/
    NavigationPath& operator=(const NavigationPath& otherPath);

    /**
	* \brief compute a polyline of 3D positions.
	*/
    bool computeGeometryWorld(NavigationMesh3& navMesh, glm::Array<Vector3>& geometry) const;

    /**
	* \brief compute a polyline of 3D positions.
	*/
    bool computeFlattenGeometryWorld(NavigationMesh3& navMesh, const NavigationData& navData, glm::Array<Vector3>& geometry) const;
    Quaternion computeFlattenPathRotation(const PathEntityComponentLocation& navMeshLocation, float entityCurvilinearAbscissa) const;

    /**
	* \brief set SpatialEnvironment without recomputing position and cellID, FOR SERIALIZATION USE ONLY
	*/
    //void setSpatialEnvironment( const SpatialEnvironment & spatialEnvironment );

    /**
	* \brief Clear the polyline.
	*/
    void clear();

    void reserve(size_t size);

    /**
	* \brief Returns the number of vertexs in the polyline.
	*/
    unsigned int getVertexCount() const;

    /**
	* \brief Returns the length of the polyline from its beginning to a given vertex.
	* \param index The index of the vertex.
	*/
    float getCurvilinearAbscissa(unsigned int index) const;

    /**
	* \brief Append a given vertex at the end of the current polyline.
	*/
    bool pushBack(const NavigationPathVertex& vertex, const Vector3& unfoldedPosition, const NavigationMeshCellId& previousSegmentCellId);

    /**
	* \brief Returns the vertex at a given index.
	*/
    const NavigationPathVertex& getVertex(unsigned int index) const;
    NavigationPathVertex& touchVertex(unsigned int index);

    const NavigationMeshCellId& getPreviousSegmentCellId(unsigned int index) const;

    const Vector3& getVertexFlattenInStartRef(unsigned int index) const;

    /**
	* \brief Returns the vertex at a given index.
	*/
    const NavigationPathVertex& operator[](unsigned int index) const;

    /**
	* \brief Returns the last vertex on the polyline.
	*/
    const NavigationPathVertex& getLastVertex() const;
    NavigationPathVertex& touchLastVertex();

    /**
	* \brief Given a curvilinearAbscissa computes the index of the surrounding vertexs.
	*
	* If the given abscissa is equal to one of the vertex's abscissa this methods returns its index twice.
	*/
    void getSurroundingVertexIndices(float curvilinearAbscissa, unsigned int& firstIndex, unsigned int& secoundIndex) const;

    /**
	* \brief Computes and returns the vertex at a given abscissa.
	* \param curvilinearAbscissa The given abscissa.
	*/
    NavigationPathVertex computeVertex(const NavigationMesh3& navMesh, float curvilinearAbscissa) const;
    Vector3 computeFlattenVertex(float curvilinearAbscissa) const;

    /**
	* \brief Returns the length of the polyline.
	*/
    float getLength() const;

  protected:
    //SpatialEnvironment* _spatialEnvironment;
    glm::Array<NavigationPathVertex> _vertices;
    glm::Array<Vector3> _verticesUnfoldedFromStart; // this is a flatten version of the path, with unfold at each edge, in first cell referential. can be used to get a localup version of the path to compute local targets in Nav3D
    glm::Array<int> _previousSegmentCellId;         // the cellId of the segment whose destionation is [index], for first one it is the start cell location normal.

    //glm::Array<Quaternion> _rotationStartToPreviousSegment; // this gives the rotation toward from start orientation to the segment (index 0 -> rotation from vertex"-1" to vertex 0 is identity, index 1 : rotation from vertex 0 to 1 is identity because inside the same cellId, then valuable information)

    glm::PODArray<float> _curvilinearAbscissas;
};
} // namespace glm
