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

#pragma once

#include "glmCrowdIOAPI.h"
#include "glmCore.h"
#include "glmAtomic.h"
#include "glmArray.h"
#include "glmString.h"
#include "glmPODArray.h"
#include "glmVector3.h"
#include "glmGeometryFile.h"

#include <glmGolaemCharacterDeclarations.h> // GolaemCharacter declarations

namespace glm
{
    namespace crowdio
    {
        class GLM_CROWDIO_API CrowdGcgCharacter
        {
        public:
			GLM_CLASS_STAT_ID(glm::MemoryStatIds::Cache)

            CrowdGcgCharacter();

            ~CrowdGcgCharacter();

            int getInstancesInUse();

            bool load();

            int getAssetFileMeshIndicesFromMeshAssociation(
                const glm::Array<glm::GlmString>& meshNames,
                const glm::PODArray<size_t>& meshNameIndices,
                const glm::PODArray<int>& materialIdx,
                glm::PODArray<uint32_t>& gcgMeshIndices,
                glm::PODArray<size_t>* notFoundMeshIdxMaterialPairIndices = NULL) const;

            const GlmGeometryFile& getGeometry() const
            {
                return _geometry;
            }

            void reserveRuntimeDeformationArrays(
                const glm::PODArray<uint32_t>& meshIndicesInAssetFile,
                glm::Array<glm::Array<Vector3>>& verticesContainer,
                glm::Array<glm::Array<Vector3>>& normalsContainer,
                glm::Array<glm::Array<Vector3>>* tangentsContainer) const; // array per mesh (major order) then meshVertexCount size

            inline const GlmString& getName() const
            {
                return _name;
            }

            inline const GlmString& getFileName() const
            {
                return _fileName;
            }

            void updateSnSValueIndices(const GolaemCharacter& glmCharacter);

            const glm::PODArray<int>& getSnsValuesIndexToBoneIndex() const
            {
                return _snsValuesIndexToBoneIndex;
            }

            // call this only once !
            void increaseRef();

            // call this only once !
            void decreaseRef();

            inline const glm::Array<glm::PODArray< uint16_t > >& getSkeletonHierarchies() const { return _geoSkeletonHierarchies; }
            inline const glm::Array<glm::PODArray< uint16_t > >& getSkeletonHierarchyParenting() const { return _geoSkeletonHierarchyParenting; }
            inline const glm::PODArray< uint16_t >& getTransformHierarchies() const { return _geoTransformHierarchy; }

            inline const glm::PODArray<uint16_t>& getGeometryBoneIndicesToSkeletonDescriptionBoneIndices() const { return _geometryBoneIndicesToSkeletonDescriptionBoneIndices; }

        protected:
            glm::atomic32_t _instancesInUse; // will be set up and down at each render

        private:
            GlmGeometryFile _geometry; // loaded from file
            GlmString _fileName;

            // mapping from SnSValueIndex to boneIndex it applies on :
            glm::PODArray<int> _snsValuesIndexToBoneIndex; // used when reading SnS Values, each value matches bone[_snsValuesIndexToBoneIndex[i]]

            glm::Array<glm::PODArray< uint16_t > > _geoSkeletonHierarchies; // geo bone ids separated per hierarchy
            glm::Array<glm::PODArray< uint16_t > > _geoSkeletonHierarchyParenting; // holds index of parent bone in the current hierarchy (hierarchy index, not geometry index !)
            glm::PODArray< uint16_t > _geoTransformHierarchy; // hierarchy detected for each mesh/transform at loading

            GlmString _name;

            // runtime
            glm::PODArray<uint16_t> _geometryBoneIndicesToSkeletonDescriptionBoneIndices; // only recomputed when _lastMatchingCharacter is different

            friend class CrowdGcgStorage;
        };
    } // namespace crowdio
} // namespace glm
