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

  Copyright (c) Kitware, Inc.
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/VolViewCopyright.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.

=========================================================================*/
#ifndef __vtkKWRemoteIOManager_h
#define __vtkKWRemoteIOManager_h

#include "vtkObject.h"
#include "vtkObjectFactory.h"
#include "vtkUnsignedLongArray.h"
#include "vtkIntArray.h"
#include "vtkCallbackCommand.h"
#include "vtkKWDataTransfer.h"
#include "vtkKWCacheManager.h"
#include "vtkCollection.h"
#include "vtkSmartPointer.h"

// I would've liked to keep this as a Tcl - independent class. The
// only reason why this line is there is so that we can use a Tcl Timer
// for periodic progress.
#include "vtkTcl.h"

class vtkMutexLock;
class vtkMultiThreader;
class vtkKWRemoteIOTask;
//BTX
class ProcessingTaskQueue;
//ETX

class VTK_EXPORT vtkKWRemoteIOManager : public vtkObject 
{
public:
  static vtkKWRemoteIOManager *New();
  vtkTypeRevisionMacro(vtkKWRemoteIOManager,vtkObject);
  void PrintSelf(ostream& os, vtkIndent indent);

  // Description:
  // The cache manager
  vtkGetObjectMacro(CacheManager, vtkKWCacheManager);
  vtkSetObjectMacro(CacheManager, vtkKWCacheManager);

  // Description:
  // Create a new data transfer
  virtual vtkKWDataTransfer *CreateNewDataTransfer();

  // Description:
  // Add a new data transfer object to the collection
  virtual void AddDataTransfer(vtkKWDataTransfer *transfer);

  // Description:
  // Remove a data transfer object from the collection
  virtual void RemoveDataTransfer(vtkKWDataTransfer *transfer);
  virtual void RemoveDataTransfer(int transferID);

  // Description:
  // Get number of data transfer objects
  virtual int GetNumberOfDataTransfers();

  // Description:
  // Get an individual data transfer by id or transfer identifier, see
  // class vtkKWDataTransfer
  // (one is a unique integer, the other a string, I find it mind boggling too)
  virtual vtkKWDataTransfer *GetDataTransferByTransferID(int transferID);
  virtual vtkKWDataTransfer *GetDataTransferByIdentifier(const char *);

  // Description:
  // Do something that Karthik may one day document
  virtual void AllTransfersClearedFromCache();

  // Description:
  // Clear all data transfers from the collection; called after
  // the cache is cleared.
  virtual void ClearDataTransfers();

  // Description:
  // Get a unique id to assign to a new data transfer.
  virtual int GetUniqueTransferID();

  // Description:
  // Set the status of a data transfer (Idle, Scheduled, Cancelled Running,
  // Completed, see constants in vtkKWDataTransfer.h)..
  virtual void SetTransferStatus(vtkKWDataTransfer *transfer, int status);
  virtual int GetTransferStatus(vtkKWDataTransfer *transfer);
  virtual const char* GetTransferStatusString(vtkKWDataTransfer *transfer)
    {
    return (transfer->GetTransferStatusString());
    };

  //BTX
  enum
    {
    RemoteReadEvent = 19001,
    RemoteWriteEvent,
    LocalReadEvent,
    LocalWriteEvent,
    NewTransferEvent,
    TransferUpdateEvent,
    TransferStatusChangedEvent,
    SettingsUpdateEvent,
    };

  // Description:
  // Begin a data transfer. Depending on the state of the "syncrhonous"
  // flag on the "transfer", this will begin the remote download on the
  // main thread or a seperate thread.
  virtual int QueueRead(vtkKWDataTransfer *transfer);
  
  // Description:
  // The user may set a callback to be invoked every time the transfer 
  // status of any transfer managed by this Manager changes.
  // The 'obj' is the object on which the callback is invoked.
  virtual void SetTransferStatusChangedCallback(
    void (*f)(vtkObject *caller, unsigned long eid,
              void *clientdata, void *calldata), vtkObject *obj);
  
  // Description:
  // The user may set a callback to be invoked every time the transfer 
  // updates itself, usually for progress reporting.
  // The 'obj' is the object on which the callback is invoked.
  virtual void SetTransferUpdateCallback(
    void (*f)(vtkObject *caller, unsigned long eid,
              void *clientdata, void *calldata), vtkObject *obj);
  //ETX
  
  // Description:
  // Timer callback. This is internally invoked every 1 second, whenever
  // there is a RemoteIO happening on a thread other than the main thread.
  // Use this method for any periodic notifications to the main thread.
  virtual void TimerCallback();

protected:
  vtkKWRemoteIOManager();
  virtual ~vtkKWRemoteIOManager();

  // Description:
  // Create a thread for processing
  virtual void CreateProcessingThread();

  // Description:
  // Shutdown the processing thread 
  virtual void TerminateProcessingThread();
  
  // Description:
  // Schedule a task to run in the processing thread. Returns true if
  // task was successfully scheduled. ScheduleTask() is called from the
  // main thread to run something in the processing thread.
  virtual int ScheduleTask(vtkKWRemoteIOTask *);
  
  // Description:
  // The real transfer work happens here.
  virtual void ApplyTransfer(void *clientdata);

  // Description:
  // All data transfers managed by us are added to this collection.
  vtkGetObjectMacro(DataTransferCollection, vtkCollection);
  vtkSetObjectMacro(DataTransferCollection, vtkCollection);

  // Description:
  // Callback used by a MultiThreader to start a processing thread
  static VTK_THREAD_RETURN_TYPE ProcessingThreaderCallback(void *);

  // Description:
  // Callback used by a MultiThreader to start a networking thread
  static VTK_THREAD_RETURN_TYPE NetworkingThreaderCallback(void *);
  
  // Description:
  // Task processing loop that is run in the processing thread
  virtual void ProcessProcessingTasks();

  // Description:
  // Networking Task processing loop that is run in a networking thread. This
  // method, if invoked, will be invoked on a thread seperate from the main
  // thread.
  virtual void ProcessNetworkingTasks();

  vtkSetMacro(InUpdateCallbackFlag, int);
  vtkGetMacro(InUpdateCallbackFlag, int);

  // Description:
  // Thread stfuff
  vtkMultiThreader          * ProcessingThreader;
  vtkMutexLock              * ProcessingThreadActiveLock;
  vtkMutexLock              * ProcessingTaskQueueLock;
  ProcessingTaskQueue       * InternalTaskQueue;
  int                         ProcessingThreadId;
  int                         ProcessingThreadActive;

  //BTX
  std::vector<int>            NetworkingThreadIDs;
  //ETX  

  vtkCollection             * DataTransferCollection;
  vtkKWCacheManager         * CacheManager;
  int                         InUpdateCallbackFlag;
  Tcl_TimerToken              TimerToken;
  int                         TimerDelay; // delay in milliseconds
  vtkCallbackCommand        * TransferUpdateCommand;
  vtkCallbackCommand        * TransferStatusChangedCommand;

private:
  vtkKWRemoteIOManager(const vtkKWRemoteIOManager&);
  void operator=(const vtkKWRemoteIOManager&);
};

#endif

