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

  Program:   ParaView
  Module:    vtkSMThreadedSession.cxx

  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.

=========================================================================*/
#include "vtkSMThreadedSession.h"

#include "vtkMultiThreader.h"
#include "vtkNew.h"
#include "vtkObjectFactory.h"
#include "vtkPVThreadedSessionServer.h"
#include "vtkZeroMQController.h"
#include "vtkProcessModule.h"

#include <zmq.hpp>

namespace
{
  // All API on this class must be thread-safe!
  class ZeroMQInfo
    {
    zmq::context_t ZMQContext;
  public:
    ZeroMQInfo()
      : ZMQContext(2)
      {
      }
    ~ZeroMQInfo()
      {
      }

    zmq::context_t& GetContext()
      {
      return this->ZMQContext;
      }
    };

  static ZeroMQInfo ZeroMQ;
  static std::string URL;

  void* WorkerThread(void*)
    {
    const char* url = URL.c_str();
    vtkNew<vtkPVThreadedSessionServer> session;
    session->Connect(url);
    vtkProcessModule::UpdateProcessType(vtkProcessModule::PROCESS_SERVER,true);
    session->ProcessEvents();
    cout << "WorkerThread cleaned up" << endl;
    return NULL;
    }
};

class vtkSMThreadedSession::vtkInternals
{
public:
  vtkNew<vtkMultiThreader> Threader;
  vtkNew<vtkZeroMQController> Controller;
  int ChildId;
  vtkInternals()
    : ChildId(0)
    {
    }

  ~vtkInternals()
    {
    this->Controller->TriggerBreakRMIs();
    this->Controller->Finalize();
    if (this->ChildId)
      {
      this->Threader->TerminateThread(this->ChildId);
      this->ChildId = 0;
      }
    }
};

vtkStandardNewMacro(vtkSMThreadedSession);
//----------------------------------------------------------------------------
vtkSMThreadedSession::vtkSMThreadedSession()
  : Internals(new vtkSMThreadedSession::vtkInternals())
{

}

//----------------------------------------------------------------------------
vtkSMThreadedSession::~vtkSMThreadedSession()
{
  this->SetDataServerController(NULL);
  delete this->Internals;
  this->Internals = NULL;
}

//----------------------------------------------------------------------------
bool vtkSMThreadedSession::Connect(const char* url)
{
  this->SetURI(url);

  URL = url;
  this->Internals->Controller->Initialize();
  this->Internals->Controller->Bind(url);
  this->Internals->Controller->SetNumberOfProcesses(2);
  this->Internals->ChildId =
    this->Internals->Threader->SpawnThread(&WorkerThread,NULL);
  this->SetDataServerController(this->Internals->Controller.GetPointer());
  this->SetRenderServerController(NULL);
  this->Initialize();
  return true;

 // this->Internals->Controller->TriggerRMI(1, 99999);

 // int status = -1;
 // this->Internals->Controller->Receive(&status, 1, 1, 100000);
 // cout << "Session started!"  << status << endl;
}

//----------------------------------------------------------------------------
void vtkSMThreadedSession::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}
