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

#pragma once

#include <glmSDKAPI.h>
#include <glmMotionDefinitions.h>
#include <glmQuaternion.h>

#include <glmGolaemCharacterDeclarations.h> // GolaemCharacter declarations
#include <glmGolaemMotionDeclarations.h> // GolaemMotion declarations

namespace glm
{
    class GenericSpecificConverter;
    class SpecificPosture;

    class ikConfiguration
    {
    public:
        GLM_CLASS_STAT_ID( glm::MemoryStatIds::GolaemShared)

        float _lengthRatio;
        Quaternion* _bonesRestRelativeQuats;
    };

    /**
	* \brief Represent a custom IK system specifically thougth for conversion between Golaem Generic postures and Golaem Specific postures
	*
	* \author dev@golaem.com
	*
	*/
    class GLM_SDK_API GenericSpecificConverterIKCache
    {
    public:
        GLM_CLASS_STAT_ID( glm::MemoryStatIds::GolaemShared)

        GenericSpecificConverterIKCache();
        ~GenericSpecificConverterIKCache();

        void init(
            const int ikCacheConfigCount,
            const Quaternion& orientationToZUpXFront,
            const PODArray<HierarchicalBone*>& hierarchicalBones,
            const GenericSkeleton& genericSkeleton,
            const float ikSolverEndOfChainPositionTolerance,
            const int ikSolverIterationCountMax,
            const glm::Array<Quaternion>& converterLocalOffset,
            const glm::PODArray<const GenericSpecificConverterBone*>& nLinksConstLength_FABRIKBones,
            const glm::PODArray<int>& nLinksConstLength_FABRIKBonesAuxExtIdx);

        void finish();

        bool isInitialized() const;

        int getIkConfigurationCount() const;

        void performCachedIKs(
            const GenericPosture& source,
            SpecificPosture& destination,
            float* perBoneScales,
            const glm::PODArray<HierarchicalBone*>& skeletonBones,
            const glm::Array<Quaternion>& converterLocalOffsets,
            const glm::Array<Quaternion>& converterLocalOffsetsInverse,
            const int genericBoneIndex,
            const glm::PODArray<unsigned int>& correspondingIndexInSpecificPosture) const;

        static bool isBoneCacheable(const GenericSpecificConverterBone* converterBone, int auxExt);

#ifndef NDEBUG
        mutable float _DEBUG_forceLengthRatio;
#endif

    private:
        int _ikConfigurationsCount;
        ikConfiguration* _ikConfigurations;
    };
} // namespace glm
