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

#pragma once

#include <glmVector3.h>
#include <glmPODArray.h>
#include <glmQuaternion.h>
#include "glmSDKAPI.h"

#define GLM_MAX_OCTREE_DIMENSION 1024 // must be a pow of 2, cell count in one dimension.

namespace glm
{
    // --- Octree class specialized for scatter neighborhood ---
    class GLM_SDK_API ScatterOctree
    {

    public:
        // ---------------------------------------
        struct ScatterOctreeElement
        {
            int _data;                             // usefull for leaves only.
            int _octreeFirstOfHeightChildrenIndex; // points to first index of the 8 children in _octreeElementsArray (all children follows)
        };

        // members
        // ---------------------------------------
        Vector3 _octreeBaseCorner;        // is min value of BBox;
        unsigned int _octreeDimension;    // dimensions in cells, in x, y and z directions
        unsigned int _exactDimensions[3]; // dimensions in cells, in x, y and z directions
        unsigned int _octreeDepth;
        float _cellSize;
        ScatterOctreeElement _octreeRoot;
        PODArray<ScatterOctreeElement> _octreeElementsArray; // to optimize allocations
        // Note : no recycling arrays, we will never delete single items (only clear struture)

        ScatterOctree();
        void clear();

        // allocate to a correct size for current stuff
        void init(float cellSize, const Vector3& bboxMin, const Vector3& bboxMax);

        // get a position in the octree leaves, based on the 3D Position clamped to the octree position + size
        void getRoundedOctreePosFromPosition(const Vector3& position, unsigned int (&leafPos)[3]) const;

        // return an octreeElement or NULL if it does not exist and createIfMissing is false
        const ScatterOctreeElement* getExistingElement(const unsigned int (&octreePos)[3]) const;
        ScatterOctreeElement* getOrCreateElement(const unsigned int (&octreePos)[3]);

        // return true if empty (not existing or cell data is -1)
        bool isEmpty(const unsigned int (&octreePos)[3]) const;
        bool isEmpty(const Vector3& position) const;

        // return true if added, false if it was already occupied. Position is clamped to the octree dimension.
        bool addIfEmpty(const unsigned int (&octreePos)[3], int cellId);
        bool addIfEmpty(const Vector3& position, int cellId);

        // find all neighbor data from position -size to +size in all directions
        void findNeighbors(const unsigned int (&octreePos)[3], PODArray<int>& foundCellIds, unsigned int size) const;

        // find all neighbor data from position -size to +size in all directions
        void findNeighbors(const Vector3& position, PODArray<int>& foundCellIds, unsigned int size) const;
    };
} // namespace glm