/******************************************************************************
** Copyright(c) 2024 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/

//! \file DtCDGroupNode.h
//! \brief Osg CDB Specific group node
//! \ingroup osgdb_osgearth_model_cdb
#pragma once

#include <osg/Group>
#include <osg/MatrixTransform>

#include <osgearth_cdb_utils/DtCDBTileKey.h>

#include <vrvOsg/DtOsgThreadingUtils.h>

#include <atomic>

namespace makVrv 
{
   namespace oe 
   {
      namespace CDB
      {
         class CDBTileKey;
         class CdbGroupNode;
         
         class CdbGroupNodeObserver
         {
         public:
            virtual void CdbGroupNode_Deleted(CdbGroupNode* node) = 0;
         };

         //! \brief   CDB osg node class
         //! CdbGroupNode as the following structure for GT models
         //! Each quadrant does not have to be filled if there is no points under it
         //!                                
         //!                             osg::Group
         //!                                |
         //!       ---------------------------------------------------
         //!       |                |               |                |
         //!    mMtU0R0          mMtU0R1         mMtU1R0          mMtU1R1
         //!       |                |               |                |
         //!   ---------       -----------      --------          ------
         //!   |   |   |       |    |    |      |   |             |    |
         //!  pt  pt  ...     pt    pt  ...     pt  ..            pt   ..
         //!  
         class CdbGroupNode : public osg::Group
         {
         public:
            //! \brief CTOR
            CdbGroupNode(const CDBTileKey& key);
            //! \brief CTOR Will try to Reconstruct a CdbGroupNode from a standard node that was save to cache
            CdbGroupNode(const osg::Group& group, const CDBTileKey& key, int dataSet);
            //! \brief DTOR
            virtual ~CdbGroupNode();
            
         private:
            //! Copy Constructor not implemented  -- Copy Not Allowed      
            CdbGroupNode(const CdbGroupNode &other);
            //! Assignment Operator Not implemented – Assignment Not Allowed      
            CdbGroupNode &operator=(const CdbGroupNode &other);

         public:
            //! \brief Return the transform from a quadrant
            virtual osg::MatrixTransform*  getMTForQuadrant(Quadrant q);

            //! \brief Add points to a GT quadrant
            void addQuadrantChild(Quadrant quadrant, osg::Group* group);
            //! \brief Set GT points of a group from the parent quad tree
            void setQuadrantChild(Quadrant quadrant, CdbGroupNode* parentGroupNode);
            //! \brief set the top transform of the cdbgroup (same for the 4 child)
            //! \brief Are the points from in this quadrant from a parent node
            bool isFromParentQuadrant(Quadrant quadrant) const;
            //! \brief Get the quadrant attach point (under the Matrix Transform)
            osg::Group* getQuadrantAttachPoint(Quadrant quadrant);
            //! \brief Get the quadrant Top matrix transform)
            osg::MatrixTransform* getQuadrantMt(Quadrant quadrant);
            //! \brief set the flag if this CDB group have children node
            void setHasCdbChildren(bool hasChildren);
            //! \brief get the flag if this CDB group have children node
            bool getHasCdbChildren() const;
            //! \brief return the CDB tile key for this group
            const CDBTileKey& getKey(void) const;
            //! \brief associate a CdbGroupNodeObserver
            void setObserver(CdbGroupNodeObserver* observer);
            //! \brief return the CdbGroupNodeObserver of this group
            const CdbGroupNodeObserver* getObserver(void) const;
            //! \brief increment the number of GT point this CDB group contains
            void plusplusNumGTPoints(Quadrant quadrant);
            //! \brief return the number of GT point this CDB group contains 
            int numGTPoints(void) const;
            //! \brief return a specific quadrant of this group (used for GT). 
            //! If the quadrant does exist it will be created
            osg::Group* getOrCreateQuadrantNode(Quadrant quadrant, bool& created);

         protected:
            //! \brief Matrix transform Local to World (node not to be processed by instancing)
            osg::ref_ptr<osg::MatrixTransform> myMt[4];        
            //! \brief hold the 4 quadrand string ( "0", "1", "2", "3"
            //! this is used to save in osg cache to be able to rebuild the CDB group form cache
            static const std::vector<std::string> theQuadrantStrings;
            //! \brief Empty String to check is a quadrant is valid
            static const std::string theEmptyString;
            //! \brief String saved in osg cache when group is a copy of a parent quadrant
            static const std::string theFromParent;
            //! \brief String saved in osg cache when group is not a copy of a parent quadrant
            static const std::string theNotFromParent;
            //! \brief String saved in osg cache when there is a child
            static const std::string theHasChild;
            //! \brief String saved in osg cache when there is no child
            static const std::string theNoChild;
            //! \brief group observer
            CdbGroupNodeObserver* myObserver;
            //! \brief CDB tile key of this group
            CDBTileKey myKey;

         private:
#if DTCDGROUPNODE_DEBUG
            static std::atomic<int> myNumofCdbGroupNodes;
#endif
            //! \brief Get the quadrant string prefix 
            static const std::string& getQuadrantChildPrefix(Quadrant quadrant);
            //! \brief Return the quadrant index based on node name (from the cache)
            static Quadrant getQuadrantFromName(const std::string& name);
            //! \brief store the number of GT points in the group 
            std::atomic<int> myNumGTPoints[4];
            //! \brief group mutex
            Threading::Mutex myMutex;
         };
      }
   }
} // namespace makVrv::oe::CDB