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

  Program:   Visualization Toolkit
  Module:    vtkPTSPipelineBuilder.h

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm 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 vtkPTSPipelineBuilder
 * @brief A class to create proxy pipelines
 *
 * vtkPTSPipelineBuilder allows to create different types of proxies while
 * taking care of registering and initializing the proxy with a ParaViewPipelineController.
 */

#ifndef vtkPTSPipelineBuilder_h
#define vtkPTSPipelineBuilder_h

#include "vtkRemotingApplicationModule.h" // for exports

#include "vtkObject.h"
#include "vtkSmartPointer.h"

#include "vtkPythonObservableWrapper.h" // for VTK_REMOTING_MAKE_PYTHON_OBSERVABLE
#include "vtkSMSourceProxy.h" // current python wrapping infastructure of the observable requires full definition in order to be able to deduce that vtkSMSourceProxy is a vtkObject.
#ifdef VTK_MODULE_ENABLE_ParaView_RemotingServerManagerViews
#include "vtkSMViewProxy.h"
#else
class vtkSMViewProxy;
#endif

#include <memory> // for std::unique_ptr

#include "vtk_rxcpp.h" // for rxcpp
// clang-format off
// ideally, we include rx-lite.hpp here.
#include VTK_REMOTING_RXCPP(rx.hpp)
// clang-format on

class vtkClientSession;

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

  /**
   * @brief Construct and initialize a source proxy.
   *
   * This function constructs a proxy and intiializes all of its properties using default values.
   *
   * @section Triggers Triggers
   *
   * * on_next: once the operation completes, returns a pointer to the newly created proxy.
   *
   * * on_error: if session is not set or if any error occured during the
   * initialization proccess. Check the `std::exception_ptr` argument for
   * details.
   *
   * * on_completed: right after on_next since this is a single value observable
   */
  rxcpp::observable<vtkSMSourceProxy*> CreateSource(
    const std::string& group, const std::string& name);

  VTK_REMOTING_MAKE_PYTHON_OBSERVABLE(
    vtkObject*, CreateSource(const std::string& group, const std::string& name));

  /**
   * @brief Construct and initialize a filter
   *
   * This function constructs a proxy sets \p input as value of its `Input`
   * property and intilalizes all of its other properties using default values.
   *
   * @section Triggers Triggers
   *
   * * on_next: once the operation completes, returns a pointer to the newly created proxy.
   *
   * * on_error: if session is not set or if any error occured during the
   * initialization proccess. Check the `std::exception_ptr` argument for
   * details.
   *
   * * on_completed: right after on_next since this is a single value observable
   *
   * @todo add support for multiple inputs
   */
  rxcpp::observable<vtkSMSourceProxy*> CreateFilter(
    const std::string& group, const std::string& name, vtkSMSourceProxy* input);

  VTK_REMOTING_MAKE_PYTHON_OBSERVABLE(vtkObject*,
    CreateFilter(const std::string& group, const std::string& name, vtkSMSourceProxy* input));

  /**
   * @brief Construct and initialize a reader proxy.
   *
   * This function constructs a proxy sets \p filename as value of its `FileName`
   * property and intilalizes all of its other properties using default values.
   *
   * @section Triggers Triggers
   *
   * * on_next: once the operation completes, returns a pointer to the newly created proxy.
   *
   * * on_error: if session is not set or if any error occured during the
   * initialization proccess. Check the `std::exception_ptr` argument for
   * details.
   *
   * * on_completed: right after on_next since this is a single value observable
   *
   * @todo add support for file series. Or Reader that have a special proeprty name for setting the
   * filename see `pqObjectBuilder::createReader`
   */
  rxcpp::observable<vtkSMSourceProxy*> CreateReader(
    const std::string& group, const std::string& name, const std::string& filename);

  VTK_REMOTING_MAKE_PYTHON_OBSERVABLE(vtkObject*,
    CreateReader(const std::string& group, const std::string& name, const std::string& filename));

  /**
   * @brief Construct and initialize a view proxy.
   *
   * @section Triggers Triggers
   *
   * * on_next: once the operation completes, returns a pointer to the newly created proxy.
   *
   * * on_error: if session is not set or if any error occured during the
   * initialization proccess. Check the `std::exception_ptr` argument for
   * details.
   *
   * * on_completed: right after on_next since this is a single value observable
   */
#ifdef VTK_MODULE_ENABLE_ParaView_RemotingServerManagerViews
  rxcpp::observable<vtkSMViewProxy*> CreateView(const std::string& group, const std::string& name);

  VTK_REMOTING_MAKE_PYTHON_OBSERVABLE(
    vtkObject*, CreateView(const std::string& group, const std::string& name));
#else
  rxcpp::observable<vtkSMProxy*> CreateView(const std::string& group, const std::string& name);
#endif

  /**
   * Show the output data in the view. If data cannot be shown in the view,
   * returns nullptr. If \p view is nullptr, the preferred view is used.
   * \p representationType specifies which representation should be instantiated,
   * if nullptr, a default representation will be created based on hints in the XML.
   *
   * @note This function simply forwards arguments to
   * vtkSMParaViewPipelineControllerWithRendering::Show. It is included here for completeness.
   *
   * @sa vtkSMParaViewPipelineControllerWithRendering
   *
   * @section Triggers Triggers
   *
   * * on_next: once the operation completes, returns a pointer to the newly created proxy.
   *
   * * on_error: if session is not set or if any error occured during the
   * initialization proccess. Check the `std::exception_ptr` argument for
   * details.
   *
   * * on_completed: right after on_next since this is a single value observable
   */
  rxcpp::observable<vtkSMProxy*> CreateRepresentation(vtkSMSourceProxy* producer, int outputPort,
    vtkSMViewProxy* view = nullptr, const char* representationType = nullptr);

  VTK_REMOTING_MAKE_PYTHON_OBSERVABLE(vtkObject*,
    CreateRepresentation(vtkSMSourceProxy* producer, int outputPort, vtkSMViewProxy* view,
      const char* representationType));

  /**
   * Delete a proxy. Deletion will fail if the proxy has consumers associated with it.
   *
   * @section Triggers Triggers
   *
   * * on_next: once the operation completes, returns true if deletion was successful, false
   * otherwise.
   *
   * * on_error: if session is not set or if the proxy is nullptr.
   *
   * * on_completed: right after on_next since this is a single value observable
   */
  rxcpp::observable<bool> DeleteProxy(vtkSMProxy* proxy);
  VTK_REMOTING_MAKE_PYTHON_OBSERVABLE(bool, DeleteProxy(vtkSMProxy* proxy));

  ///@{
  /**
   */
  void SetSession(vtkClientSession* session);
  vtkClientSession* GetSession() const;
  ///@}

protected:
  vtkPTSPipelineBuilder();
  ~vtkPTSPipelineBuilder() override;

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

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

#endif
