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

#ifndef GLM_SIMULATIONDATA_H
#define GLM_SIMULATIONDATA_H

#include <glmCrowdIOAPI.h>
#include "glmSimulationCacheCommon.h"

#include "stdint.h"
#include "stdio.h"

#define GSC_PP_MAX_NAME_LENGTH 256

namespace glm
{
    namespace crowdio
    {
        //-------------------------------------------------------------------------
        // Simulation Data Types
        //-------------------------------------------------------------------------

        // per-particle attributes types
        typedef enum
        {
            GSC_PP_FLOAT = 1,
            GSC_PP_VECTOR = 2
        } GlmPPAttributeType;

        // per-simulation data
        typedef struct GlmSimulationData_v0
        {
            uint8_t _version;
            uint32_t _contentHashKey; // to check if simulation matches frame file
            uint32_t _licenseHashKey; // licensing information

            float _framerate;

            //uint32_t _rngSeed; // legacy
			uint32_t _assetGroupCount;
			uint32_t *_assetResetIndex; // entityCacheIndex where we must reset asset association computation
            uint32_t* _assetRngSeeds;   // rng seed to set for random ppattributes at each above _assetResetIndex

            // entity.
            uint32_t _entityCount;        // number of entities in the simulation cache
            int64_t* _entityIds;          // entity Ids for all entities, array size = _entityCount, -1 means invalid entity
            uint16_t* _entityTypes;       // entity types for all entities, array size = _entityCount, 0xFFFF value means invalid entity
            uint32_t* _indexInEntityType; // entity index in its entityType, array size = _entityCount, entity if _entityId[i] is at index _indexInEntityType[i] of _entityType[i], useful to retrieve a specific position/orientation/etc.
            float* _scales;               // scales for all entities, array size = _entityCount

            // entity assets
            int32_t* _characterIdx;     // character file index, array size = _entityCount, -1 means invalid character
            int32_t* _renderingTypeIdx; // rendering type index in character file, array size = _entityCount, -1 means invalid rendering type

            // entityType
            uint16_t _entityTypeCount;                  // number of different entity types
            uint32_t* _entityCountPerEntityType;        // number of entities for this EntityType, array size = _entityTypeCount
            uint16_t* _boneCount;                       // number of bones for this EntityType, array size = _entityTypeCount
            uint32_t* _iBoneOffsetPerEntityType;        // indexes of the first bone of the first entity of an EntityType, for _bonePositions and _boneOrientations, array size = _entityTypeCount
            float* _maxBonesHierarchyLength;            // max length of a skeleton bones hierarchy, array size = _entityTypeCount
            uint16_t* _blindDataCount;                  // number of blindData for this EntityType, array size = _entityTypeCount
            uint32_t* _iBlindDataOffsetPerEntityType;   // indexes of the first blindData of the first entity of an EntityType, for _blindData, array size = _entityTypeCount
            uint8_t* _hasGeoBehavior;                   // does this entity type have a geometry behavior?, array size = _entityTypeCount
            uint32_t* _iGeoBehaviorOffsetPerEntityType; // indexes of the first geometry behavior of the first entity of an EntityType, for _geoBehaviorGeometryIds, _geoBehaviorBlendModes and _geoBehaviorBlendModes, array size = _entityTypeCount
            uint16_t* _snsCountPerEntityType;           // count of sns information per entityType (defined by gskm/gch)
            uint32_t* _snsOffsetPerEntityType;          // offset per entityType = sum of previous (_snsCountPerEntityType * entityCountPerEntityType)
            float (*_shapeExtents)[3];                  // perception shape size, array size = _entityTypeCount
            float (*_shapeOffset)[3];                   // perception shape offset, array size = _entityTypeCount

            // dynamic ppAttribute
            uint32_t _ppFloatAttributeCount;                          // number of Float attributes
            char (*_ppFloatAttributeNames)[GSC_PP_MAX_NAME_LENGTH];  // name of the float per particle attribute, array size first dimension = _floatAttributeCount, second dimension = _entityCountPerCrowdField
            uint32_t _ppVectorAttributeCount;                         // number of Vector attributes
            char (*_ppVectorAttributeNames)[GSC_PP_MAX_NAME_LENGTH]; // name of the vector per particle attribute, array size first dimension = _vectorAttributeCount, second dimension = _entityCountPerCrowdField
            uint8_t* _backwardCompatPPAttributeTypes;

            // static ppAttribute
            uint32_t _staticPpFloatAttributeCount;                          // number of Float attributes
            char(*_staticPpFloatAttributeNames)[GSC_PP_MAX_NAME_LENGTH];  // name of the float per particle attribute, array size first dimension = _floatAttributeCount, second dimension = _entityCountPerCrowdField
            uint32_t _staticPpVectorAttributeCount;                         // number of Vector attributes
            char(*_staticPpVectorAttributeNames)[GSC_PP_MAX_NAME_LENGTH]; // name of the vector per particle attribute, array size first dimension = _vectorAttributeCount, second dimension = _entityCountPerCrowdField
            // static ppAttribute data
            float** _staticPpFloatAttributeData;       // float data per particle attributes, array size first dimension = _floatAttributeCount, second dimension - access with simulation data _entityToBakeIndex, array size = _entityToBakeCount
            float(**_staticPpVectorAttributeData)[3]; // vector data per particle attributes, array size = _vectorAttributeCount, second dimension - access with simulation data _entityToBakeIndex, array size = _entityToBakeCount

            // helpers not serialized :
            uint8_t* _entityWritten;            // helper to write simulation data incrementally
            uint32_t* _usedEntityPerEntityType; // helper (not serialized) : entities actually already instanced (to get a reliable index per entityType)
            uint32_t _entitiesWrittenInCache;   // used to increment crowdEntity indexInCache
            uint32_t _entityToBakeCount;        // number of entities with _entityToBakeIndex >= 0
            int32_t* _entityToBakeIndex;        // entity index in the frame data, array size = _entityCount, -1 means not exported

        } GlmSimulationData_v0;
        typedef GlmSimulationData_v0 GlmSimulationData;

        //-------------------------------------------------------------------------
        // Simulation data functions
        //-------------------------------------------------------------------------

        // allocate *simulationData
        extern GLM_CROWDIO_API void createSimulationData(
            GlmSimulationData** simulationData, // *simulationData will be allocated by this function
            uint32_t assetGroupCount,           // rng seed
            float framerate,                    // framerate
            uint32_t entityCount,               // number of entities, range = 0..4,294,967,295
            uint16_t entityTypeCount,           // number of different entity types, range = 1..65,535
            uint32_t ppFloatAttributeCount,      // number of float per particle attributes, range = 0..4,294,967,295
            uint32_t ppVectorAttributeCount,    // number of vector per particle attributes, range = 0..4,294,967,295
            uint32_t staticPpFloatAttributeCount,      // number of float per particle static attributes, range = 0..4,294,967,295
            uint32_t staticPpVectorAttributeCount);    // number of vector per particle static attributes, range = 0..4,294,967,295

        extern GLM_CROWDIO_API void createAndCopySimulationData(const GlmSimulationData* simulationDataSource, GlmSimulationData** simulationDataDestination);

        // allocate and initialize *simulationData from a .gscs file
        // return GSC_SUCCESS || GSC_FILE_OPEN_FAILED || GSC_FILE_MAGIC_NUMBER_ERROR || GSC_FILE_VERSION_ERROR
        extern GLM_CROWDIO_API GlmSimulationCacheStatus createAndReadSimulationData(GlmSimulationData** simulationData, const char* file);

        // write simulationData in a .gscs file
        // return GSC_SUCCESS || GSC_FILE_OPEN_FAILED
        extern GLM_CROWDIO_API GlmSimulationCacheStatus writeSimulationData(const char* file, const GlmSimulationData* simulationData, const uint32_t licenseHashKey);

        // deallocate *simulationData and set it to NULL
        extern GLM_CROWDIO_API void destroySimulationData(GlmSimulationData** simulationData);

        // allocate cloth data for frame data (except entityInUse), not in createFrameData because cloth count can change at every frame
        extern GLM_CROWDIO_API uint64_t computeSimulationDataSize(const GlmSimulationData* data);

        // Compute a content hash
        extern GLM_CROWDIO_API uint32_t computeContentHash(const GlmSimulationData* simulationData);
    } // namespace crowdio
} // namespace glm
#endif // GLM_SIMULATIONDATA_H
