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

#pragma once

#include "glmCoreAPI.h"
#include "glmRTTI.h"
#include "glmGenericSpecificConverterBone.h"
#include "glmBonePhysicConfiguration.h"
#include "glmEffectorMirrorSource.h"
#include "glmBlindDataV0.h"
#include "glmHierarchicalSkeletonDescription.h"

namespace glm
{
    struct GenericSpecificConverterMappingV6;

    class SkeletonMappingContainer; //for charamaker access

    class FastBoundingBox;

    /**
    * \brief Represent the generalization of a skeleton (the conversion from the hierarchical skeleton to the generic skeleton)
    *
    * \author dev@golaem.com
    *
    */
    struct GLM_CORE_API GenericSpecificConverterMappingV7
    {
        GLM_RTTI("ae7379db-747a-4b56-8cd4-59c73f977aa5", glm::GenericSpecificConverterMappingV7, addAttributes)

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

        GenericSpecificConverterMappingV7();
        ~GenericSpecificConverterMappingV7();

        //************************************************************
        //! @name Accessors
        //************************************************************
        //@{
        /**
	    * \brief Get the upper direction
	    */
        inline const Vector3& getUpAxis() const;

        /**
	    * \brief Set the upper direction
	    */
        void setUpAxis(const Vector3& upAxis);

        /**
	    * \brief Get the front direction
	    */
        inline const Vector3& getFrontAxis() const;

        /**
	    * \brief Set the front direction
	    */
        void setFrontAxis(const Vector3& frontAxis);
        //@}

        /**
	    * \brief V6 backwards compatibility
	    */
        void createFromV6(GenericSpecificConverterMappingV6& masterV6);
        
        void createFromConst(const GenericSpecificConverterMappingV7& source);

        void finish();
        void clearMappingPart();

        void computePerceptionBoundingBox(FastBoundingBox& boundingBox) const;
        static int findFatherIndexInLimbs(const GenericSpecificConverterBoneV1& source, const GenericSpecificConverterMappingV7& mapping);
        inline const glm::Array<GenericSpecificConverterBoneV1>& getLimbBones() const;

        inline const HierarchicalBoneV1* getPelvisBone() const;
        inline const Quaternion& getOrientationToZUpXFront() const;
        inline const Quaternion& getOrientationToZUpXFrontInverse() const;

    protected:
        /**
         * \brief register the inspectable attributes to the class RTTI
         */
        static void addAttributes();

    private:
        GLM_DISALLOW_COPY_AND_ASSIGN(GenericSpecificConverterMappingV7);

    public:
        bool _cacheAllowedGlobal; //value returned by the isCacheAllowedOn(...) method when the bone is not found in the _cacheAllowed array
        HierarchicalSkeletonDescriptionV1* _skeletonDescription;
        Array<BoneDisplayConfigurationV0>* _skeletonDisplay = NULL; // pointer from GolaemCharacter, not serialized here

        //************************************************************
        //! @name Serialized data
        //************************************************************
        //@{

        int _pelvisBoneIndex;
        glm::Array<GenericSpecificConverterBoneV1> _spineBones;
        glm::Array<GenericSpecificConverterBoneV1> _limbBones;
        glm::Array<GenericSpecificConverterBoneV1> _effectorBones;

        glm::Array<glm::GlmString> _spineBoneNames;
        glm::Array<glm::GlmString> _limbBoneNames;
        glm::Array<glm::GlmString> _effectorBoneNames;

        glm::PODArray<int> _ikExcludedBones; // bones excluded from IK solving

        Vector3 _upAxis;
        Vector3 _frontAxis;

        glm::Array<BonePhysicConfigurationV1> _boneConfigurations;

        glm::PODArray<int> _channelMirrorSources;

        glm::Array<EffectorMirrorSourceV0> _effectorMirrorSources;

        glm::PODArray<int> _spineMirrorSources;

        glm::PODArray<float> _groundHeightArray;

        glm::Array<BlindDataV0> _blindDataInfo;

        glm::PODArray<float> _squashStretchWeightsArray;

        glm::PODArray<int> _bonesSnsScaleModes; //int because XML serialization does not support char (only 6bits are needed here)

        glm::PODArray<bool> _cacheAllowed;
        //@}

        //************************************************************
        //! @name configuration
        //************************************************************

        Quaternion _orientationToZUpXFront;
        Quaternion _orientationToZUpXFrontInverse;
    };

    //************************************************************
    // Definition of inline methods
    //************************************************************

    //-------------------------------------------------------------------------
    inline const Vector3& GenericSpecificConverterMappingV7::getUpAxis() const
    {
        return _upAxis;
    }

    //-------------------------------------------------------------------------
    inline const Vector3& GenericSpecificConverterMappingV7::getFrontAxis() const
    {
        return _frontAxis;
    }

    //------------------------------------------------------------
    inline const glm::Array<GenericSpecificConverterBoneV1>& GenericSpecificConverterMappingV7::getLimbBones() const
    {
        return _limbBones;
    }

    //------------------------------------------------------------
    inline const HierarchicalBoneV1* GenericSpecificConverterMappingV7::getPelvisBone() const
    {
        GLM_DEBUG_ASSERT(_skeletonDescription != NULL);
        return _skeletonDescription->getBones()[_pelvisBoneIndex];
    }

    //-------------------------------------------------------------------------
    inline const Quaternion& GenericSpecificConverterMappingV7::getOrientationToZUpXFront() const
    {
        return _orientationToZUpXFront;
    }

    //-------------------------------------------------------------------------
    inline const Quaternion& GenericSpecificConverterMappingV7::getOrientationToZUpXFrontInverse() const
    {
        return _orientationToZUpXFrontInverse;
    }
} // namespace glm
