/*****************************
File:      RemoteClient.h
Language:   C++ (header)
Project:    H3DNetworkingUtils
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/

Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
License for the specific language governing rights and limitations
under the License.

The Original Code is H3DNetworkingUtils v1.0.

The Initial Developer of the Original Code is CSIRO.
Portions created by the Initial Developer are Copyright (C) 1009 CSIRO. All Rights Reserved.
Contributor(s):
    Chris Gunn  <Chris.Gunn@csiro.au> <ChrisJGunn@gmail.com>
***************************/

/// \file RemoteClient.h
/// \brief Header file for RemoteClient, a base class for the client end of networking connections.

#ifndef RemoteClient_H
#define RemoteClient_H


#include "H3DNetworkingUtils/RemoteConnection.h"
#include "H3DNetworkingUtils/RemoteField.h"
//#include "Macro.h"
#include "H3DNetworkingUtils/sockwrap.h"

// This next line is needed because H3DAPI.dll instantiates this template but this class does not see the header with 
// the instantiation in it. So without the line, this class would instantiate an identical one and there would
// be a multiply defined symbol in the link stage.
template struct __declspec(dllimport) H3D::AutoUpdate <H3D::SFBool>;

namespace H3D {
  H3D_VALUE_EXCEPTION( const char *, CantConnect );
}

namespace H3DNetworkingUtils {
   
/// \class RemoteClient
/// Network connections involve client software conecting across a network to server software.
/// The RemoteClient class is a base class for remote clients using UDP or TCP sockets.
/// It tries to connect to a RemoteServer node on the given host using
/// the given port, then continues with the base class's behaviour.
/// When open is changed from false to true, the connection is attempted.
/// When it is changed from true to false, the connection is closed.
/// At present, only one remote connection is handled. 
/// It may be possible to handle multiple connections by including multiple RemoteClients in a scenegraph.

class H3D_NETWORKING_UTILS_DLL_SPEC RemoteClient : public RemoteConnection {
public:

  /// Handles a connection attempt when it is set to true.
   struct H3D_NETWORKING_UTILS_DLL_SPEC OpenHandler : public H3D::AutoUpdate<H3D::SFBool> {
      virtual void setValue(bool const & val, int id = 0);
      virtual void update();
  };

  /// Constructor
   RemoteClient( string socket_type = "TCP",
                H3D::Inst<H3D::SFString> remoteHost = 0,
                H3D::Inst<H3D::SFInt32> remotePort = 0,
                H3D::Inst<OpenHandler>  open = 0,
                H3D::Inst<H3D::SFBool>  autoReconnect = 0);

  static H3D::H3DNodeDatabase database;

  virtual void initialize();

   /// The host running a server that this client will connect to \n
   /// access type: inputOutput \n
   /// basic type: SFString \n
   /// default value: localhost
   auto_ptr<H3D::SFString> remoteHost;

   /// The port number on the remote host that this client will connect to - the server should be listening on that port \n
   /// access type: inputOutput \n
   /// basic type: SFInt32 \n
   /// default value: 9876
   auto_ptr<H3D::SFInt32>  remotePort;

   /// When true, starts a connection to a server on the remote host \n
   /// It is valid for it to be true at startup - connection will occur after initialization \n
   /// access type: inputOutput \n
   /// basic type: SFBool \n
   /// default value: FALSE
   auto_ptr<OpenHandler>   open;

   /// If autoReconnect is true, whenever a connection to the remote host fails, \n
   /// a reconnection will be attempted periodically \n
   /// If a RemoteClient starts before the remote host's server starts, this autoReconnect capability \n
   /// will enable successful connect once the server does start \n
   /// access type: inputOutput \n
   /// basic type: SFBool \n
   /// default value: TRUE
   auto_ptr<H3D::SFBool>   autoReconnect;

protected:

  bool openedBefore() const {return opened_once;}
  // Returns true if the client socket has been opened before.

  virtual void startClient(string host, int port_number);
  // Connects the client to the server.

  void requestRestart() {restart_requested = true;}
  // Signals the reading thread to reconnect its socket.

  virtual void restartClient() = 0;
  // Restarts the client reading and writing to a new socket.
  // Provided by sub-classes.

  virtual bool doClosedActions();
  // Do any actions that are required while the connection is closed.
  // This class returns false, to tell the receive loop not to break out when
  // the connection is closed.

  virtual void close();
  // Close the client.

  bool restart_requested;

  char addr[400];

private:
  bool opened_once;
  string socket_type;
  bool start_called;
  H3DTime last_connect_attempt_time;

};

}

#endif
