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

  Program:   ParaView
  Module:    vtkClientSession.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 vtkClientSession
 * @brief session for a ParaView client.
 *
 */

#ifndef vtkClientSession_h
#define vtkClientSession_h
#include "vtkRemotingServerManagerModule.h"

#include "vtkEventual.h"             // for vtkEventual
#include "vtkRemoteObjectProvider.h" // for vtkRemoteObjectProvider::vtkProgressItem
#include "vtkSession.h"

#include <initializer_list> // for std::initializer_list
#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 vtkPacket;
class vtkServiceEndpoint;
class vtkSMSessionProxyManager;
class vtkSMReaderFactory;

class VTKREMOTINGSERVERMANAGER_EXPORT vtkClientSession : public vtkSession
{
public:
  static vtkClientSession* New();
  vtkTypeMacro(vtkClientSession, vtkSession);
  void PrintSelf(ostream& os, vtkIndent indent) override;

  enum ServiceTypes
  {
    DATA_SERVER = 0x01,
    RENDER_SERVER = 0x02,
    CLIENT = 0x04
  };

  /**
   * Collection of all services to ease iteration.
   */
  static const std::initializer_list<vtkTypeUInt32> ServiceTypeList;

  /**
   * Connect to a server session.
   */
  rxcpp::observable<bool> Connect(const std::string& url = std::string{});

  /**
   * Returns the URL the client is connected to. This will be empty when
   * connected to services on the same process aka "builtin".
   */
  const std::string& GetURL() const;

  /**
   * Provides access to the session's proxy-manager.
   */
  vtkSMSessionProxyManager* GetProxyManager() const;

  /**
   * Provides access to the reader factory.
   */
  vtkSMReaderFactory* GetReaderFactory() const;

  /**
   * Send a message to services identified by the destination
   */
  void SendMessage(vtkTypeUInt32 destination, const vtkPacket& packet) const;

  /**
   * Sends a request and returns a response. If destination identifies multiple
   * services, the "root" location is used.
   */
  vtkEventual<vtkPacket> SendRequest(vtkTypeUInt32 destination, const vtkPacket& packet) const;

  static vtkTypeUInt32 GetRootDestination(vtkTypeUInt32 destination);

  /**
   * A convenience method to get the scheduler to use to schedule actions
   * on the applications main thread.
   */
  rxcpp::observe_on_one_worker GetCoordination() const;

  /**
   * Returns the end point for a specific type.
   */
  vtkServiceEndpoint* GetEndpoint(ServiceTypes type) const;

  /**
   * Returns the end point for a specific type.
   */
  std::vector<vtkServiceEndpoint*> GetEndpoints(int type) const;

  /**
   * Returns an observable that can be used to observe progress events.
   * The tuple contains the following:
   */
  rxcpp::observable<std::tuple<std::string, vtkRemoteObjectProvider::vtkProgressItem>>
  GetProgressObservable() const;

  /**
   * Returns true if the client is connected to a remote server i.e. the
   * services are running on a different process.
   */
  bool GetIsRemote() const;

protected:
  vtkClientSession();
  ~vtkClientSession() override;

  /**
   * Give subclasses an opportunity to setup an endpoint.
   */
  virtual void InitializeServiceEndpoint(vtkServiceEndpoint* endpoint);

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

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

#endif
