set(asio_classes)
set(asio_nowrap_headers)
set(asio_private_headers)
set(asio_private_classes)
set(asio_nowrap_classes)

set(remoting_overrides
  Service
  ServiceEndpoint
  ServicesEngine)

if (APV_ENABLE_ASIO)
set(asio_classes
  vtkAsioService
  vtkAsioServiceEndpoint
  vtkAsioServicesEngine
  vtkServicesAsioLogVerbosity)

set(asio_nowrap_headers
  vtkAsioInternalsEngineSideTypes.h
  )

set(asio_private_headers
  vtkAsioInternalsRxCommunicator.h
  )

set(asio_private_classes
  vtkAsioInternalsConnection
  vtkAsioInternalsEngine
  vtkAsioInternalsResponder
  vtkAsioInternalsScheduler
  )

set(asio_nowrap_classes
  vtkAsioInternalsNetworkPacket # left open to public for tests.
  )

# registers Asio overrides
foreach (override IN LISTS remoting_overrides)
  vtk_object_factory_declare(
    BASE "vtk${override}"
    OVERRIDE "vtkAsio${override}")
endforeach()
endif()

set(thallium_classes)
set(thallium_private_classes)

if (APV_ENABLE_THALLIUM)
set(thallium_classes
  vtkThalliumService
  vtkThalliumServiceEndpoint
  vtkThalliumServicesEngine)

set(thallium_private_classes
  vtkThalliumServicesEngineInternals
  vtkThalliumRunLoop)

# register Thallium overrides
foreach (override IN LISTS remoting_overrides)
  vtk_object_factory_declare(
    BASE "vtk${override}"
    OVERRIDE "vtkThallium${override}")
endforeach()
endif()
  
  set (intial_cpp_code
    "
    int use_thallium = 0\;
    int use_asio = 0\;
    // defaults
    #if defined(WIN32)  || defined(_WIN32) || defined(__WIN32__) || defined(__APPLE__)
      use_asio = 1\;
    #else
      use_thallium = 1\;
    #endif
    // Query the enviromental for backend to use 
    if(const char* p = std::getenv(\"APV_COMMUNICATION_BACKEND\"))
    {
      #if defined(WIN32)  || defined(_WIN32) || defined(__WIN32__)
       vtkLogF(ERROR,\"Switchable backends are supported only on Linux & MacOS\")\;
      #else
      const std::string backend(p)\;
      if(backend == \"THALLIUM\")
      {
        #ifndef APV_ENABLE_THALLIUM
        vtkLogF(ERROR,\"THALLIUM backend requested but the THALLIUM backend was not compiled\")\;
        #else
        use_asio = 0\;
        use_thallium = 1\;
        #endif
      }
      else if(backend == \"ASIO\")
      {
        #ifndef APV_ENABLE_ASIO
        vtkLogF(ERROR,\"ASIO backend requested but the ASIO backend was not compiled\")\;
        #else
        use_asio = 1\;
        use_thallium = 0\;
        #endif
      }
      else
      {
       vtkLogF(ERROR,\"Unknown backend '%p' using defaults\",backend.c_str())\;
      }
      #endif
    }
     // register the factory before modyfing the overrrides so it is found below
    vtkServicesBackendObjectFactory* servicesFactory = vtkServicesBackendObjectFactory::New()\;
    if (servicesFactory)
    {
      // vtkObjectFactory keeps a reference to the factory,
      vtkObjectFactory::RegisterFactory(servicesFactory)\;
      servicesFactory->Delete()\;
    }
    vtkObjectFactory* object_factory\;
    vtkCollectionSimpleIterator osit\;
    for (vtkObjectFactory::GetRegisteredFactories()->InitTraversal(osit)\;
        (object_factory = vtkObjectFactory::GetRegisteredFactories()->GetNextObjectFactory(osit))\;)
    {
      if (object_factory->HasOverride(\"vtkService\"))
      {
        object_factory->SetEnableFlag(use_asio, \"vtkService\", \"vtkAsioService\")\;
        object_factory->SetEnableFlag(use_thallium, \"vtkService\", \"vtkThalliumService\")\;
      }
      if (object_factory->HasOverride(\"vtkServiceEndpoint\"))
      {
        object_factory->SetEnableFlag(use_asio, \"vtkServiceEndpoint\", \"vtkAsioServiceEndpoint\")\;
        object_factory->SetEnableFlag(use_thallium, \"vtkServiceEndpoint\", \"vtkThalliumServiceEndpoint\")\;
      }
      if (object_factory->HasOverride(\"vtkServicesEngine\"))
      {
        object_factory->SetEnableFlag(use_asio, \"vtkServicesEngine\", \"vtkAsioServicesEngine\")\;
        object_factory->SetEnableFlag(use_thallium, \"vtkServicesEngine\", \"vtkThalliumServicesEngine\")\;
      }
    }"
  )

vtk_object_factory_configure(
  SOURCE_FILE vtk_object_factory_source
  HEADER_FILE vtk_object_factory_header
  EXPORT_MACRO "VTKSERVICESBACKEND_EXPORT"
  EXTRA_INCLUDES "<vtkCollection.h>" "<vtkObjectFactoryCollection.h>" "<vtkLogger.h>" "<cstdlib>" "<vtkServicesBackendConfigure.h>"
  INITIAL_CODE ${intial_cpp_code})

# Configure the module specific settings into a module configured header.
configure_file(
  "${CMAKE_CURRENT_SOURCE_DIR}/vtkServicesBackendConfigure.h.in"
  "${CMAKE_CURRENT_BINARY_DIR}/vtkServicesBackendConfigure.h")

set(headers 
  "${CMAKE_CURRENT_BINARY_DIR}/vtkServicesBackendConfigure.h")


vtk_module_add_module(AsyncParaView::ServicesBackend
  CLASSES         ${asio_classes} ${thallium_classes}
  HEADERS         ${headers}
  NOWRAP_HEADERS  ${asio_nowrap_headers}
  NOWRAP_CLASSES  ${asio_nowrap_classes}
  PRIVATE_CLASSES ${asio_private_classes} ${thallium_private_classes}
  SOURCES         ${vtk_object_factory_source}
  PRIVATE_HEADERS ${vtk_object_factory_header}
                  ${asio_private_headers})


if (APV_ENABLE_ASIO)
include(FetchContent)
FetchContent_Declare(
  asio
  GIT_REPOSITORY "https://github.com/chriskohlhoff/asio.git"
  GIT_TAG 147f7225a96d45a2807a64e443177f621844e51c # asio-1-24-0
)
FetchContent_MakeAvailable(asio)
set(ASIO_INCLUDE_DIR "${asio_SOURCE_DIR}/asio/include")
vtk_module_include(AsyncParaView::ServicesBackend
  PRIVATE        ${ASIO_INCLUDE_DIR})
endif()

if (APV_ENABLE_THALLIUM)
vtk_module_find_package(PACKAGE thallium)
vtk_module_link(AsyncParaView::ServicesBackend
  PRIVATE
    thallium)
endif()

vtk_module_remoting_exclude()
