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

#pragma once

#include "glmCoreAPI.h"
#include "glmRTTI.h"

#include <glmGolaemCharacterDeclarations.h> // GolaemCharacter declarations

namespace glm
{
    struct GenericSpecificConverterBoneV0;

    //************************************************************
    //! @name Structures and types
    //************************************************************
    //@{

    struct GLM_CORE_API RollAttributesV0
    {
        GLM_RTTI("02770c08-b3be-47ad-8179-bc03bf04cf21", glm::RollAttributesV0, addAttributes);

    public:
        GLM_CLASS_STAT_ID( glm::MemoryStatIds::Simulation)

        int _farEndBoneIdx;
        glm::Array<int> _rollBonesIdx;
        glm::Array<float> _rollWeights;

        RollAttributesV0();
        ~RollAttributesV0();

    private:
        static void addAttributes();
    };

    struct GLM_CORE_API GenericSpecificConverterBoneV1
    {
        GLM_RTTI("f39bd1db-afff-4d76-9d35-4bcaa5f2398b", glm::GenericSpecificConverterBoneV1, addAttributes)

    public:
        GLM_CLASS_STAT_ID( glm::MemoryStatIds::GolaemShared)

        int _type; //interpreted as a SkeletonPartType::Value

        int _coronalLocation;
        int _transverseLocation;
        int _sagittalLocation;

        //for all the following data, the first value in the array is for the auxiliary bone, the second value in the array is for the extension bone
        int _firstBoneOfChain[2];
        int _lastBoneOfChain[2];

        //ik normal plane
        Vector3 _relativeIkNormalPlane[2];
        bool _computeFullExtentLength[2]; //!< If true, the length of the generic bone will be the sum of all specific bone in the chain. If false, the length of the bone will be the length of the vector going from the first bone to the last bone

        //roll configuration
        glm::Array<RollAttributesV0> _rollAttributes[2];

        // cache data filled by buildCacheData method
        int _genericBoneIndex[2];
        glm::PODArray<unsigned int> _correspondingIndexInSpecificPostureForIK[2];
        glm::PODArray<unsigned int> _correspondingIndexInSpecificPostureFullChain[2];

        GenericSpecificConverterBoneV1();
        GenericSpecificConverterBoneV1(SkeletonPartType::Value type, const HierarchicalBoneV1* firstAuxiliary, const HierarchicalBoneV1* lastAuxiliary,
                                       const HierarchicalBoneV1* firstExtension, const HierarchicalBoneV1* lastExtension,
                                       CoronalPlaneLocation::Value coronalLocation, TransversePlaneLocation::Value transverseLocation, SagittalPlaneLocation::Value sagittalLocation,
                                       const Vector3& auxiliaryIkNormalPlane, const Vector3& extensionIkNormalPlane,
                                       bool auxiliaryComputeFullExtentLength, bool extensionComputeFullExtentLength);

        GenericSpecificConverterBoneV1(SkeletonPartType::Value type, const HierarchicalBoneV1* firstAuxiliary, const HierarchicalBoneV1* lastAuxiliary,
                                       const HierarchicalBoneV1* firstExtension, const HierarchicalBoneV1* lastExtension,
                                       const Vector3& auxiliaryIkNormalPlane, const Vector3& extensionIkNormalPlane,
                                       bool auxiliaryComputeFullExtentLength, bool extensionComputeFullExtentLength);

        GenericSpecificConverterBoneV1(const GenericSpecificConverterBoneV0& source);

        glm::Array<float> _boneLengthsUnscaledForIK[2];     // watch out : this has to be scaled in conversion scale
        glm::Array<float> _boneLengthsUnscaledFullChain[2]; // watch out : this has to be scaled in conversion scale

    private:
        static void addAttributes();

        // These methods are here for serialization purpose only
        int getFirstBoneOfChain(unsigned int index) const
        {
            return _firstBoneOfChain[index];
        }
        void setFirstBoneOfChain(unsigned int index, int bone)
        {
            _firstBoneOfChain[index] = bone;
        }
        int getLastBoneOfChain(unsigned int index) const
        {
            return _lastBoneOfChain[index];
        }
        void setLastBoneOfChain(unsigned int index, int bone)
        {
            _lastBoneOfChain[index] = bone;
        }
        Vector3 getIkNomalPlane(unsigned int index) const
        {
            return _relativeIkNormalPlane[index];
        }
        void setIkNomalPlane(unsigned int index, Vector3 ikNormalPlane)
        {
            _relativeIkNormalPlane[index] = ikNormalPlane;
        }

        bool getComputeFullExtentLength(unsigned int index) const
        {
            return _computeFullExtentLength[index];
        }
        void setComputeFullExtentLength(unsigned int index, bool computeFullExtentLength)
        {
            _computeFullExtentLength[index] = computeFullExtentLength;
        }

        const glm::Array<RollAttributesV0>& getRollAttributes(unsigned int index) const
        {
            return _rollAttributes[index];
        }
        void setRollAttributes(unsigned int index, const glm::Array<RollAttributesV0>& rollAttributes)
        {
            _rollAttributes[index] = rollAttributes;
        }
    };
    //@}
} // namespace glm
