/*****************************
File:      RemoteUDPClient.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 RemoteUDPClient.h
/// \brief Header file for RemoteUDPClient, a client communications link that uses UDP/IP network protocol.

#ifndef RemoteUDPClient_H
#define RemoteUDPClient_H


#include "H3DNetworkingUtils/RemoteClient.h"
#include "H3DNetworkingUtils/lockwrap.h"

namespace H3DNetworkingUtils {

/// \class RemoteUDPClient
/// The RemoteUDPClient class starts a Remote client using a UDP port.
/// It connects to a given server and port.
/// It has a send loop, receive loop and a 'pulse' loop which tells the server
/// it is still alive. Each loop runs in a different thread.
/// At present, only one remote connection is handled at a time.
/// IMPORTANT NOTE: Do not route from anything in the haptics loop to a remote
/// field if you have periodicSend FALSE. This is because it will then try to
/// send whenever the value changes - i.e. from the haptics loop itself. This will
/// fail. You probably don't want it to interrupt haptics to do socket
/// stuff anyway. Make sure you set periodic send true if you are routing in from
/// the haptics thread.
/// When the client first connects, it sends a pulse packet to the server. The
/// servers responds with a pulse.  \n
/// <b>Examples:</b>
///   - <a href="../../examples/RealtimeAttractorTestServer.x3d">RealtimeAttractorTestServer.x3d</a>
///   - <a href="../../examples/RealtimeAttractorTestClient.x3d">RealtimeAttractorTestClient.x3d</a>

class H3D_NETWORKING_UTILS_DLL_SPEC RemoteUDPClient : public RemoteClient {
public:

  /// The period between heartbeats for a UDP socket.
  static const H3D::H3DFloat PULSE_PERIOD; 

  /// Constructor
  RemoteUDPClient();

  /// Destructor
  virtual ~RemoteUDPClient();

  /// X3D interface
  static H3D::H3DNodeDatabase database;

protected:
  /// Send a single packet
   virtual void sendThisPacket(Packet & packet);

  /// Restarts the client reading and writing to a new socket.
  virtual void restartClient();

  /// Wait and receive packets.
  virtual void receiveLoop();

  /// Send packets. Also send a 'pulse' packet, if no send has happened for a PULSE_PERIOD.
  virtual void sendLoop();

  /// Request for the connection to close
  virtual void requestClose();

private:
  Packet pulse_packet;
  char ack[20];
  int msg_count;
  bool connect_requested;
  Mutex send_packet_lock;
  double accumulated_time_to_kill;
};

}

#endif
