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

//! \file DtCDBVector.h
//! \brief Abstract class to manage vector information
//! \ingroup osgearth_cdb_utils
#pragma once

#include <osgearth_cdb_utils/DtCDBExport.h>
#include <osgEarth/Map>
#include <osgEarth/Progress>
#include <osgEarth/MapNodeObserver>

#include <vrvOsg/DtRenderingMethod.h>

#include <osgearth_cdb_utils/DtCDBClassRow.h>
#include <osgearth_cdb_utils/DtCDBSigSizeTable.h>
#include <osgearth_cdb_utils/DtCDBDatabase.h>
#include <osgearth_cdb_utils/DtCDBDatasetInfo.h>
#include <osgearth_cdb_utils/DtCDBMcod.h>
#include <osgearth_cdb_utils/DtCDBBaseMaterialTable.h>
#include <osgearth_cdb_utils/DtCDBDbfConfig.h>

#include <tbb/concurrent_hash_map.h>

#include <Vect/Cee_VectFeature.h>
#include <Cee_CdbDB.h>

namespace osgEarth
{
   class SpatialReference;
}

namespace makVrv
{
   class DtIndirectGeometryRegistrar;
   class DtIndirectGeometry;
   class DtOsgGraphMergeOperation;

   namespace oe {
      namespace CDB {

         class DatasetInfo;
         class CDBTileKey;
         class CDBTileVerbose;
         class CDBModelOptions;
         class CdbGroupNode;
         class CDBDatasets;
         class DtCDBClassIndex;
         class DtCDBInstanceIndex;
         class DtCdbGroupNodeProgress;


         //! \brief Abstract Vector handler class
         //! \ingroup osgearth_cdb_utils
         class DT_DLL_OSGEARTH_CDB_UTILS DtCDBVector : public osg::Referenced
         {
         public:
            //! \brief CTOR
            DtCDBVector(const DatasetInfo& CurrentDataset, osg::ref_ptr<DtCDBDatabase> cdbDb, const osgDB::Options* dbOptions, DtDe& de);
            //! \brief DTOR
            ~DtCDBVector();
            
            //! \brief Read the index of the needed fields and set myIsInitialized flag to true
            virtual void initialize(const std::string& shpInstanceFile, DtCDBInstanceIndex& instanceAttrIndexes,
               const std::string& dbfClassFile, DtCDBClassIndex& classAttrIndexes,
               const std::string& dbfExtendedFile) = 0;
            //! \brief Check if initialize() was called
            virtual bool isInitialized() const { return myIsInitialized; };

            //! \brief Read instance dbf indexes and information
            virtual void readInstance(const std::string& dbfClassFile, DtCDBInstanceIndex& instanceAttrIndexes, const CDBTileKey& key,
               const std::string& shpInstanceFile, VectFile* shpVector, VecInstancesDbfRow& vecInstanceRow, const MapStringToClassDbfRow& classMap) = 0;

            //! \brief Read class dbf indexes and information
            virtual void readClass(const std::string& dbfClassFile, DtCDBClassIndex& classAttrIndexes, const CDBTileKey& key, MapStringToClassDbfRow& classMap) = 0;

            //! \brief Process the feature list (read models or light type)
            virtual void processFeature(const std::string& dbfClassFile, const CDBTileKey& key, CdbGroupNode* groupNode, VecInstancesDbfRow& vecInstanceRow,
               DtCdbGroupNodeProgress* progress, bool& wasModelFound) = 0;

           
         protected:

            // Thread-safe "warn once" registry keyed by arbitrary strings.
            struct WarnOnceRegistry {
               void warn_once(const std::string& classname, const std::string& key, const std::string& message)
               {
                  std::lock_guard<Threading::Mutex> lock(mutex_);
                  auto it = keys_.find(key);
                  if (it == keys_.end()) {
                     OE_WARN << classname << " " << message << " (this message will appear only once)" << std::endl;
                     keys_.insert(key);
                  }
               }

               void warn_once_missingfield(const std::string& classname, const std::string& key, const std::string& field, const std::string& file)
               {
                  std::lock_guard<Threading::Mutex> lock(mutex_);
                  auto it = keys_.find(key);
                  if (it == keys_.end()) {
                     OE_WARN << classname << " Unable to find [" << field << "] field in file: " << file << " (this message will appear only once)" << std::endl;
                     keys_.insert(key);
                  }
               }

            private:
               Threading::Mutex mutex_;
               std::unordered_set<std::string> keys_;
            };

            // Single instance for this translation unit.
            WarnOnceRegistry& getWarnOnceRegistry()
            {
               static WarnOnceRegistry reg;
               return reg;
            }

            WarnOnceRegistry& myWarnOnceRegistry;

            //! \brief Was the indexes read
            bool myIsInitialized;

            //! \brief Static class with predefine information
            static const DtCDBDbfConfig myVectorConfig;

            //! \brief   Spatial reference pointer geocentric
            osg::ref_ptr< osgEarth::SpatialReference > myWgs84;
            //! \brief Dataset information
            DatasetInfo myCurrentDataset;
            //! \brief The cache path for the data set
            //std::string myDatasetCachePath;
            //! \brief Dbf instance filename 
            std::string myShpInstanceFile;
            //! \brief Dbf class filename 
            std::string myDbfClassFile;
            //! \brief Dbf extented attributes filename 
            std::string myDbfExtendedFile;
            //! \brief Valid CDB database pointer
            osg::ref_ptr<DtCDBDatabase> myCdbDatabase;
            //! \brief  Database option
            osg::ref_ptr<osgDB::Options>  myDbOptions;
            //! \brief Copy of CDB root path 
            std::string myCDBRootPath;
            //! \brief Feature Attribute Classification Code field value (common attributes)
            std::string myFACC;
            //! \brief FACC Sub Code field value (common attributes)
            std::string myFSC;
            //! \brief Class Name field value (common attributes)
            std::string myCNAM;
            //! \brief Composite Material Index field value (common attributes)
            unsigned int myCMIX;

            ////! \brief (Class) CNAM Column index
            //int myClassIndexCNAM;
            ////! \brief (Class) Feature Attribute Classification Code Column index
            //int myClassIndexFACC;
            ////! \brief (Class) FACC Sub Code Column index
            //int myClassIndexFSC;
            ////! \brief (Class) Composite Material Index Column index
            //int myClassIndexCMIX;
            
            //! \brief CDB Dataset information manager
            CDBDatasets* myCDBDatasets;

            //! \brief keep a copy of the current tile CDB LOD
            int myTileLod;

            //! \brief Is linear dataset
            bool myIsLinearDataset;
            //! \brief Is areal dataset
            bool myIsArealDataset;

            //! \brief Reference to DtDe
            DtDe& myDe;
         };
         
      }
   }
}