/*=========================================================================

  Program:   ParaView
  Module:    vtkPythonRunLoop.h

  Copyright (c) Kitware, Inc.
  All rights reserved.
  See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/**
 * @class vtkPythonRunLoop
 * @brief rxcpp event loop that connects to Python's asyncio event loop.
 *
 * A drop-in replacement of rxcpp:runloop that allows to
 * share the application's main thread with python asyncio event loop
 * which enables to process rxcpp events while `awaiting` on a result
 * in python.
 *
 */

#ifndef vtkPythonRunLoop_h
#define vtkPythonRunLoop_h

#include "vtkPython.h" // include first

#include "vtkObject.h"
#include "vtkRemotingPythonAsyncCoreModule.h" // for exports

#include "vtk_rxcpp.h" // for rxcpp
// clang-format off
#include VTK_REMOTING_RXCPP(rx.hpp)
// clang-format on

#include <memory>

class VTKREMOTINGPYTHONASYNCCORE_EXPORT vtkPythonRunLoop : public vtkObject
{
public:
  static vtkPythonRunLoop* New();
  vtkTypeMacro(vtkPythonRunLoop, vtkObject);
  void PrintSelf(ostream& os, vtkIndent indent) override;

  /**
   * Provides access to the singleton.
   */
  static vtkPythonRunLoop* GetInstance();

  // rxcpp_run_loop API
  rxcpp::schedulers::scheduler get_scheduler() const;
  rxcpp::observe_on_one_worker observe_on_run_loop() const;
  bool empty() const;

  // Check whether asyncio is imported
  bool IsAsyncInitialized();

  // Check to see if a running loop is associated with this object
  bool HasRunningLoop();

  // Connect this runloop with asyncio.get_running_loop()
  void AcquireRunningLoopFromPython();

  // Create a future on this loop.
  // This method is NOT threadsafe
  PyObject* CreateFuture();

  PyObject* CreateAsyncIterator();

  // TODO hide from user API
  static PyObject* ScheduleCallback();

protected:
  vtkPythonRunLoop();
  ~vtkPythonRunLoop() override;

private:
  vtkPythonRunLoop(const vtkPythonRunLoop&) = delete;
  void operator=(const vtkPythonRunLoop&) = delete;

  class vtkInternals;
  std::unique_ptr<vtkInternals> Internals;

  static vtkPythonRunLoop* Singleton;
};
#endif
