/***************************************************************************
*                                                                          *
*  Copyright (C) Golaem S.A. - All Rights Reserved.                        *
*                                                                          *
***************************************************************************/
#ifndef GLM_CROWD_LEGACY_INCLUDE_H
#define GLM_CROWD_LEGACY_INCLUDE_H

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

#include "stdint.h"

namespace glm
{
    namespace crowdio
    {
        //-------------------------------------------------------------------------
        // HistoryV0 Transformation Types
        //-------------------------------------------------------------------------
        struct SimulationCacheV0TransformType
        {
        public:
            enum Value
            {
                Noop, //called merge in the UI
                Rotate,
                Scale,
                Translate,
                Duplicate,
                Kill,
                Unkill,
                Posture,
                PostureBoneEdit,
                SetMeshAssets,
                EnableClothMeshAssets,
                Expand,
                FrameOffset,
                FrameWarp,
                ScaleRange,
                TrajectoryEdit,
                SnapTo,
                SetShaderAttribute,
                Trajectory_Smooth,
                Trajectory_VectorField,
                Trajectory_Avoidance,
                Trajectory_CurveEdit,
                Trajectory_Mode,
                ReplaceShader,
                GroundAdaptation,
                OpsCount //allows to count the number of transforms types
            };
        };

        // history options
        typedef enum
        {
            OptionsGroundAdaptOrient = 1 << 0,
            OptionsGroundAdaptUseTerrain = 1 << 1,
        } GlmHistoryOptions;

        typedef struct GlmHistory_v0
        {
            uint32_t _transformCount;
            uint8_t* _transformTypes;    // values of SimulationCacheTransformType, size = _transformCount
            uint8_t* _active;            // on/off, size = _transformCount
            uint32_t* _boneIndex;        // bone to apply transformation on, size = _transformCount
            uint32_t* _renderingTypeIdx; // renderingTypeIdx if needed, size = _transformCount

            uint32_t _options; // options. see GlmHistoryOptions

            uint32_t _licenseHashKey;

            uint32_t _transformGroupCount;
            uint8_t* _transformGroupActive;                      //size = _transformGroupCount
            char (*_transformGroupName)[GSC_PP_MAX_NAME_LENGTH]; // name of the transform Group, array size first dimension = _transformGroupCount, second dimension = GSC_PP_MAX_NAME_LENGTH
            uint32_t (*_transformGroupBoundaries)[2];            // group boundaries, size = _transformGroupCount

            float (*_transformRotate)[4];    // transform Quaternion parameter, size = _transformCount
            float (*_transformTranslate)[3]; // transform translation parameter, size = _transformCount
            float (*_transformPivot)[3];     // transform pivot world position, size = _transformCount
            float* _scale;                   // uniform scale

            uint32_t* _clothIndice; // Cloth indice if needed, size = _transformCount
            uint32_t* _enableCloth; // Enable/Disable cloth if needed, size = _transformCount

            uint32_t _entityCount;            // array size of all entities operations
            int64_t* _entityIds;              // entities list. size = _entityCount
            uint32_t* _entityArrayStartIndex; // index of first entity used for operation in _entityIds array. size = _transformCount
            uint32_t* _entityArrayCount;      // count of entities transformed per operation. size = _transformCount

            // entity ids for duplicated entities
            // work the same way entityIds work
            uint32_t _duplicatedEntityCount;
            int64_t* _duplicatedEntityIds;
            uint32_t* _duplicatedEntityArrayStartIndex; // size = _transformCount
            uint32_t* _duplicatedEntityArrayCount;      // size = _transformCount

            // mesh asset override
            // Override is not visible in GlmEntityTransform because it's handled at rendering time with the .CAA
            uint32_t _expandCount;
            float (*_expands)[3];
            uint32_t* _expandArrayStartIndex; // size = _transformCount
            uint32_t* _expandArrayCount;      // size = _transformCount

            // trajectory/.. per frame translation&orientation
            uint32_t _perFramePosOriCount;
            float (*_frameCurvePos)[3];
            float (*_frameCachePos)[3];
            float (*_framePos)[3];
            float (*_frameOri)[4];
            uint32_t* _perFramePosOriArrayStartIndex; // size = _transformCount
            uint32_t* _perFramePosOriArrayCount;      // size = _transformCount

            // additional scale
            // work the same way entityIds work
            uint32_t _scaleRangeCount;
            float* _scaleRanges;
            uint32_t* _scaleRangeArrayStartIndex; // size = _transformCount
            uint32_t* _scaleRangeArrayCount;      // size = _transformCount
            // it's present here for storage and maniupulation (enable/disable)
            // mesh asset override
            // Override is not visible in GlmEntityTransform because it's handled at rendering time with the .CAA
            // it's present here for storage and maniupulation (enable/disable)
            uint32_t _meshAssetsOverrideTotalCount;  // total count of mesh asset for all entities
            uint32_t* _meshAssetsOverride;           // list all the mesh asset override. size = _meshAssetsOverrideTotalCount
            uint32_t* _meshAssetsOverrideStartIndex; // index of first mesh assets override in _meshAssetsOverride. size = _entityCount
            uint32_t* _meshAssetsOverrideCount;      // count of mesh assets override in _meshAssetsOverride. size = _entityCount

            // entity type hierarchical bones. use _iBoneOffsetPerEntityType from simulation data to retrieve local orientation/position
            uint32_t _localBoneCount;
            float (*_localBoneOrientation)[4]; // size = _localBoneCount
            float (*_localBonePosition)[3];    // size = _localBoneCount
            uint32_t* _localBoneParent;        // size = _localBoneCount

            uint32_t _localBoneOffsetCount; // == _entityTypeCount
            uint32_t* _localBoneOffset;     // per entityType size = _entityTypeCount

            // postures editing
            uint32_t _postureCount;
            uint32_t _postureTotalBoneCount; // = _postureTotalBoneCount * count of bones in the posture. posture bone count =  _totalPostureBoneCount / _totalPostureCount
            uint32_t* _posturesFrameCount;   // count of uint32_t. Array size = _transformCount
            uint32_t* _posturesFrameStart;   // index in _posturesFrames. Array size = _transformCount

            uint32_t* _posturesFrames; // size = sum of all _posturesFrameCount == _totalPosturesCount

            float (*_posturesPositions)[3];
            float (*_posturesOrientations)[4];

            // frame offsets
            uint32_t _frameOffsetCount;
            float* _frameOffsets;
            uint32_t* _frameOffsetArrayStartIndex; // size = _transformCount
            uint32_t* _frameOffsetArrayCount;      // size = _transformCount

            // time warp
            uint32_t _frameWarpCount;
            float* _frameWarps;
            uint32_t* _frameWarpArrayStartIndex; // size = _transformCount
            uint32_t* _frameWarpArrayCount;      // size = _transformCount

            // operation Mode. Used for time offset/time warp (add/set modes)
            uint32_t* _operationMode;

            // frame transform paramters
            float* _frameOffsetMin; // size = _transformCount
            float* _frameOffsetMax; // size = _transformCount
            float* _frameWarpMin;   // size = _transformCount
            float* _frameWarpMax;   // size = _transformCount

            // scale range min/max
            float* _scaleRangeMin; // size = _transformCount
            float* _scaleRangeMax; // size = _transformCount

            // frame start/count for per frame pos/ori
            uint32_t* _startFrame; // size = _transformCount
            uint32_t* _frameCount; // size = _transformCount

            char (*_snapToTarget)[GSC_PP_MAX_NAME_LENGTH];     // name of the target object, array size first dimension = _transformCount, second dimension = GSC_PP_MAX_NAME_LENGTH
            char (*_snapToEntityType)[GSC_PP_MAX_NAME_LENGTH]; // name of the target object, array size first dimension = _transformCount, second dimension = GSC_PP_MAX_NAME_LENGTH
            uint32_t* _snapToGroup;                            // size = _transformCount
            uint32_t _snapToTotalCount;                        // total count of snapTo Target for all entities
            uint32_t* _snapToStartIndex;                       // size = _transformCount
            uint32_t* _snapToCount;                            // size = _transformCount
            float (*_snapToPositions)[3];                      // size = _snapToTotalCount
            float (*_snapToRotations)[4];                      // size = _snapToTotalCount

            char (*_shaderAttribute)[GSC_PP_MAX_NAME_LENGTH]; // name of the target object, array size first dimension = _transformCount, second dimension = GSC_PP_MAX_NAME_LENGTH
            void* _terrainMeshSource;                         // used at rendering time. not serialized
            void* _terrainMeshDestination;                    // used at rendering time. not serialized

            uint16_t* _replaceShaderOperation; // size = _transformCount, gives index on below _replaceShaderCount arrays
            uint16_t _replaceShaderCount;      // information for serialization (allocation)
            char** _replaceShaderString;       // size = _replaceShaderCount

            void** _parameter; // size = _transformCount, array of pointers to a parameter struct like GlmTrajectory_Smooth
        } GlmHistory_v0;

        // create a transform layer
        extern GLM_CROWDIO_API void glmCreateHistory_v0(GlmHistory_v0** history, unsigned int transformCount, unsigned int transformGroupCount, unsigned int entityCount, unsigned int totalPostureCount, unsigned int totalPostureBoneCount, unsigned int totalEntityTypesBoneCount, unsigned int totalMeshAssetsOverride, unsigned int duplicatedEntityCount, unsigned int totalEntityTypeCount, unsigned int expandCount, unsigned int totalFrameOffsetCount, unsigned int totalFrameWarpCount, unsigned int scaleRangeCount, unsigned int perFramePosOriCount, unsigned int snapToTotalCount, unsigned int totalReplaceShaderCount);

        // deallocate history and set it to NULL
        extern GLM_CROWDIO_API void glmDestroyHistory_v0(GlmHistory_v0** history);

        // write *frameData in a JSON .gscla file
        // return GSC_SUCCESS || GSC_FILE_OPEN_FAILED
        //extern GLM_CROWDIO_API glm::crowdio::GlmSimulationCacheStatus glmWriteHistoryJSON_v0(const char* file, GlmHistory_v0* history, const uint32_t licenseHashKey);

        extern GLM_CROWDIO_API glm::crowdio::GlmSimulationCacheStatus glmCreateAndReadHistoryJSON_v0(GlmHistory_v0** history, const char* file);
        extern GLM_CROWDIO_API glm::crowdio::GlmSimulationCacheStatus glmCreateAndParseHistoryJSON_v0(GlmHistory_v0** history, const void* jsonvalue);

        // allocate and initialize *history from a older history version
        // return GSC_SUCCESS || GSC_FILE_OPEN_FAILED || GSC_FILE_MAGIC_NUMBER_ERROR || GSC_FILE_VERSION_ERROR
        extern GLM_CROWDIO_API glm::crowdio::GlmSimulationCacheStatus glmCreateAndConvertHistoryJSON(glm::crowdio::GlmHistory_v1** dstHistory, GlmHistory_v0* srcHistory);
    } // namespace crowdio
} // namespace glm

#endif // GLM_CROWD_LEGACY_INCLUDE_H
