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

#pragma once

#include "glmSDKAPI.h"
#include "glmTypes.h"
#include "glmPinMesh.h"
#include "glmMap.h"
#include "glmVector3.h"
#include "glmQuaternion.h"
#include "glmMatrix4.h"
#include "glmEntity.h"
#include "glmAABB.h"

namespace glm
{
    //-------------------------------------------------------------------------
    class EntityPinMeshData
    {
    public:
        Vector3 _triangleBarycentricCoordinates;
        Vector3 _orthoNormal;
        Vector3 _stoppingStartPosDelta;
        Vector3 _lastPositionSet;
        Vector3 _target;
        Quaternion _remainingDelta;
        Entity* _entity;
        int _lastTriangle;
        int _pinMeshIndex;
        float _lastFloorEntityDelta;
        float _maxRadPerSec;
        float _startStopRampCoef; // should be 1 when playing full, 0 when starting or stopped.
        float _deltaHeightUnscaled;
        //bool			_smoothOrientation;
        bool _forceAdaptation;
        bool _firstCorrection;
        bool _isStopping;
        bool _stickToFloor;
        bool _useTarget;
        bool _active;

        EntityPinMeshData()
            : _triangleBarycentricCoordinates(0, 0, 0)
            , _orthoNormal(0, 0, 1)
            , _stoppingStartPosDelta(0.f)
            , _lastPositionSet(0.f)
            , _target(0.f)
            , _remainingDelta(0, 0, 0, 1)
            , _entity(NULL)
            , _lastTriangle(-1)
            , _pinMeshIndex(-1)
            , _lastFloorEntityDelta(0.f)
            , _maxRadPerSec(GLM_PI)
            , _startStopRampCoef(0.f)
            , _deltaHeightUnscaled(0.f)
            //, _smoothOrientation(true)
            , _forceAdaptation(false)
            , _firstCorrection(true)
            , _isStopping(false)
            , _stickToFloor(false)
            , _useTarget(false)
            , _active(false)
        {
        }
    };

    //-------------------------------------------------------------------------
    class GLM_SDK_API EntityPinMesh : public PinMesh
    {
    public: //methods
		GLM_CLASS_STAT_ID(glm::MemoryStatIds::Simulation)
        typedef SmartPointer<EntityPinMesh> SP;

        EntityPinMesh();
        virtual ~EntityPinMesh();

        bool pinEntity(Entity& entity, EntityPinMeshData& entityData, Vector3& pinnedPositionDelta, Quaternion& pinnedOrientationDelta, bool deformable, const Matrix4* additionalGroundTransform = &Matrix4::identity, const Matrix4* additionalGroundTransformInverse = &Matrix4::identity) const;
        bool verticalRaycastFromEntity(const Entity& entity, float& returnDistance2) const;

    protected: //methods
        // to get position at any time, raycast the -up vector of entity _lastPosition on mesh and find nearest point, then apply triangle/edge traversal
        void setOrientationDeltaFromUp(const Vector3& lastUp, const Vector3& newUp, Entity& entity, EntityPinMeshData& entityData, Quaternion& pinnedOrientationDelta) const;

    private:
        GLM_DISALLOW_COPY_AND_ASSIGN(EntityPinMesh);
    };
} // namespace glm
