// ///////////////////  ***********************  \\\\\\\\\\\\\\\\\\\\ //
//
//  DsComputer, part of DSI (Distributed Scene Inventor)
//
//  DSI is an extension to popular Open Inventor and enpowers it
//  by distributed scene management
//
//  Copyright (C) 2001-2002 by PC John (pcjohn@email.cz).
//  All rights reserved.
//
//  This file is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public License
//  version 2.1 as published by the Free Software Foundation. See the
//  file LICENSE.LGPL at the root directory of the distribution for
//  more details.
//
// \\\\\\\\\\\\\\\\\\\  ***********************  //////////////////// //


#ifndef SO_COMPUTER_H_INCLUDED_
#define SO_COMPUTER_H_INCLUDED_


#include "SbNetBasic.h"
#include "SbTimeStamp.h"

class SbNetMessage;
class SoDistributionGroup;



class COIN_DLL_API SoComputer {
protected:
  SbNetConnection netc;

  SbInetAddr addr;
  SbInetAddr localAddr;
  enum { EMPTY, INVALID, CACHED } localAddrState;

  void *recvStreamBuf;
  char recvStreamType[4];
  uint32_t recvStreamSize;
  uint32_t recvStreamPos;
  SbTimeStamp largestTimeStamp;
  SbTimeStamp tsToSendAfterConnect;

public:
  enum State { DISCONNECTED = 0, CONNECTING, CONNECTED, DISCONNECTING, BROKEN_CON = -1 };
  virtual State getState();
  State peekState() const;
  SbBool isDisconnected() { return getState() <= 0; }

  enum ActiveState { NON_ACTIVE, ACTIVATING, ACTIVE };
  ActiveState getActiveState() const;
  void activate();
  void deactivate();

  SoComputer();
  SoComputer(SbNetConnection nc);
  virtual ~SoComputer();


  // Network API
  virtual int  recvData(void *buf, int size);
  virtual void sendData(const void *buf, int size);
  static void sendData(SoDistributionGroup *dg, const void *buf, int size, SbBool sendToNotActive = FALSE);
  static void sendData(SoDistributionGroup *dg, const void *buf, int size, const class SoMFComputer &list);


  virtual void sendMessage(SbNetMessage *msg); // FIXME: should it be possible to send transactions directly to the computers? (consistency reasons)
  virtual SbBool messageReceived();         //< Returns TRUE if there is a pending transaction received from the computer.
  virtual SbNetMessage* receiveMessage(SoDistributionGroup *dg);  //< Returns the transaction received from the computer. The transactions are received in the same order as they are send. If there is no pending transaction, NULL is returned.

  SbBool process();
  const SbTimeStamp& getLargestTimeStamp(); //< Returns the timestamp of the most recent transaction.
  void updateLargestTimeStamp(const SbTimeStamp &timeStamp);
  static void updateLinkTimesOfNonActiveComputers(const SbTimeStamp &ts, SoDistributionGroup *dg);

  SbInetAddr getAddr() const;
  SbInetAddr getLocalAddr() const;
  SbNetConnection getNetC() const;
  int getSocket() const;
  virtual SbBool isThisComputer() const;
  SbComputerIdentity getComputerIdentity(SoDistributionGroup *dg) const;
  SoDistributionGroup* getCurrentDistributionGroup() const;

  void connect(const SbInetAddr &addr);
  void connect(const SbInetAddr &addr, const SbInetAddr &localAddr);
  void connectByNetC(SbNetConnection netc);

  void disconnect();
  void dropConnection();
  void dataIntegrityFailure();

protected:
  ActiveState activeState;
private:
  friend class SoNetwork;
};



#endif /* SO_COMPUTER_H_INCLUDED_ */
