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

//! \file DtCDBKeyToIndirectGeometryMap.inl
//! \brief DtCDBKeyToIndirectGeometryMap
#include <osgdb_osgearth_model_cdb/DtCDBKeyToIndirectGeoMap.h>
#include <vrvMath/DtAssert.h>

namespace makVrv
{
   namespace oe 
   {
      namespace CDB
      {
         template<class EntryType, class ...ConstructorArgs>
         EntryType* DtCDBKeyToEntryTypeMapWithArgs<EntryType, ConstructorArgs...>::getEntry(CdbGroupNode* cdbGroupNode)
         {
            Threading::ScopedMutexLock lock( myKeyToEntryMapMutex );
            typename _KeyToEntryTypeMap::iterator it = myKeyToEntryTypeMap.find(cdbGroupNode);
            if (it == myKeyToEntryTypeMap.end())
            {
               return nullptr;
            }
            return it->second;
         }

         template<class EntryType, class ...ConstructorArgs>
         EntryType* DtCDBKeyToEntryTypeMapWithArgs<EntryType, ConstructorArgs...>::createEntry(CdbGroupNode* cdbGroupNode, ConstructorArgs... args)
         {
#if DTCDBKEYTOENTRYTYPEMAP_DEBUG
            std::cout << "Created Indirect Geometry for: " << key << std::endl;
#endif
            ASSERT_PREDICATE(cdbGroupNode->getObserver() == 0);

            EntryType* entry = new EntryType( myDe, args... );;
            ASSERT_PREDICATE( entry );
            
            Threading::ScopedMutexLock lock( myKeyToEntryMapMutex );
            auto rtnPair = myKeyToEntryTypeMap.emplace( cdbGroupNode, entry );

            cdbGroupNode->setObserver( this );

            return entry;
         }

         template<class EntryType, class ...ConstructorArgs>
         EntryType* DtCDBKeyToEntryTypeMapWithArgs<EntryType, ConstructorArgs...>::getOrCreateEntry( CdbGroupNode* cdbGroupNode, ConstructorArgs... args, bool& created )
         {
            EntryType* info = getEntry(cdbGroupNode);
            if (info)
            {
               created = false;
               return info;
            }

            info = createEntry(cdbGroupNode, args...);

            created = true;
            return info;
         }

         template<class EntryType, class ...ConstructorArgs>
         DtCDBKeyToEntryTypeMapWithArgs<EntryType, ConstructorArgs...>::DtCDBKeyToEntryTypeMapWithArgs(DtDe& de)
            : myDe(de)
         {
#if DTCDBKEYTOENTRYTYPEMAP_DEBUG
            std::cout << "DtCDBKeyToEntryTypeMap<EntryType>::DtCDBKeyToEntryTypeMap<EntryType>" << std::endl;
#endif
         }

         template<class EntryType, class ...ConstructorArgs>
         DtCDBKeyToEntryTypeMapWithArgs<EntryType, ConstructorArgs...>::~DtCDBKeyToEntryTypeMapWithArgs()
         {
            deleteEntries();
         }

         template<class EntryType, class ...ConstructorArgs>
         void DtCDBKeyToEntryTypeMapWithArgs<EntryType, ConstructorArgs...>::CdbGroupNode_Deleted(CdbGroupNode* cdbGroupNode)
         {
            ASSERT_PREDICATE(cdbGroupNode->getObserver() == this);

            Threading::ScopedMutexLock lock(myKeyToEntryMapMutex);

            auto it = myKeyToEntryTypeMap.find( cdbGroupNode );
            if( it != myKeyToEntryTypeMap.end() )
            {
               delete it->second;
               myKeyToEntryTypeMap.erase( it );
            }
         }

         template<class EntryType, class ...ConstructorArgs>
         void DtCDBKeyToEntryTypeMapWithArgs<EntryType, ConstructorArgs...>::deleteEntries()
         {
            Threading::ScopedMutexLock lock( myKeyToEntryMapMutex );
            int i = 0;
            for (typename _KeyToEntryTypeMap::iterator it = myKeyToEntryTypeMap.begin(); it != myKeyToEntryTypeMap.end(); ++it, ++i)
            {
               CdbGroupNode* cdbGroupNode = it->first;
               ASSERT_PREDICATE(cdbGroupNode->getObserver() == this);
               cdbGroupNode->setObserver(0);
               EntryType* entry = it->second;
#if DTCDBKEYTOENTRYTYPEMAP_DEBUG
               std::cout << "key: " << i << std::endl;
               entry->printInfo();
#endif
               delete entry;
            }
            myKeyToEntryTypeMap.clear();
#if DTCDBKEYTOENTRYTYPEMAP_DEBUG
            std::cout << "DtCDBKeyToEntryTypeMap<EntryType>::~DtCDBKeyToEntryTypeMap<EntryType>; Num of entries deleted: " << myKeyToEntryTypeMap.size() << std::endl;
#endif
         }
      }
   }
}