/*****************************
File:      RemoteSF.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 RemoteSF.h
/// \brief Header file for RemoteSF, an abstract base class for all single value remote fields.

#ifndef RemoteSF_H
#define RemoteSF_H

#include "H3DNetworkingUtils/Config.h"
#include "H3DUtil/H3DMath.h"
#include <H3D/X3DChildNode.h>
#include <H3DUtil/Threads.h>
#include <H3D/X3DTypes.h>
#include "H3DNetworkingUtils/RemoteField.h"
#include "H3DNetworkingUtils/BufferedSField.h"

#ifdef _WIN32
#ifdef H3DNetworkingUtils_EXPORTS
#include "H3DNetworkingUtils/BufferedSField.cpp"
#endif
#endif

namespace H3DNetworkingUtils {
   
/// \class RemoteSF
/// The RemoteSF class is a template class which is a node containing a single field which sends and
/// receives its value to/from another the field of another RemoteSF<S> node
/// running on another application on another host.
/// This node operates in stand-alone mode as a member of a RemoteClient or
/// RemoteServer remoteFields field.
/// It is, however, an abstract class.  In order to work, the inheriting
/// classes, RemoteSFVec3f, RemoteSFBool, RemoteSFRotation, need to be
/// instantiated.  They only differ from each other in the work that they do in
/// reading and writing values.  \n
/// <b>Examples:</b>
///   - <a href="../../examples/RemoteSFTestServer.x3d">RemoteMFTestServer.x3d</a>
///   - <a href="../../examples/RemoteSFTestClient.x3d">RemoteMFTestClient.x3d</a>

template <class S>
class H3D_NETWORKING_UTILS_DLL_SPEC RemoteSF : public RemoteField {
public:
  /// The X3D interface
   static H3D::H3DNodeDatabase database;

  /// Initialize
   virtual void initialize();

  /// Sends the field value across the network
  class H3D_NETWORKING_UTILS_DLL_SPEC SFSender : public H3D::AutoUpdate< S >  {
  public:
     SFSender() : send_on_change(false), x3d_type (H3D::X3DTypes::UNKNOWN_X3D_TYPE) {}
     virtual void update();
     virtual void setValue( const typename S::value_type & val, int id = 0 );
     void setX3DType(H3D::X3DTypes::X3DType t) {x3d_type = t;}
     virtual H3D::X3DTypes::X3DType getX3DType() { return x3d_type; }

     bool send_on_change;
  private:
     H3D::X3DTypes::X3DType x3d_type;
  };

  // Public fields

  /// The value to be sent \n
  /// Value will be sent when it changes or on a timer, depending on the value of the 
  /// containing server or client's periodicSend field
  /// access type: inputOnly \n
  /// basic type: S \n
  /// default value:  
  auto_ptr<SFSender             > toBeSent;

  /// The value received from the network \n
  /// This needs to be a BufferedSField field because it gets changed in a thread that   \n 
  /// is not the graphics thread, and also may need to be buffered   \n
  /// access type: outputOnly \n
  /// basic type: S \n
  /// default value:  
  auto_ptr<BufferedSField<S>    > received;

protected:
  /// Constructor is protected so that it can not explicitly be called:
  /// rather it should be implicely called from an inheriting class's
  /// constructor. This is since it is an abstract class.
  RemoteSF(H3D::X3DTypes::X3DType t, 
           H3D::Inst<SFSender> _toBeSent = 0,
           H3D::Inst< BufferedSField<S> > _received = 0);

  /// Destructor
  virtual ~RemoteSF();
  
  /// Start or stop the field being sent each time it is changed.
  virtual void setSendOnChange(bool val) {toBeSent->send_on_change = val;}

  /// Called from traverseSG in the graphics loop to check for any changes
  /// in the received field and to update the field appropriately.
  /// Alternatively called from a dummy force function in the haptics loop to check for any changes
  /// in the received field and to update the field appropriately.
  virtual void checkForChange() {received->checkForChange(id);}

  /// Write a field to the packet.
  void writeField();

  /// Must be supplied for specific instantiations, to send the
  /// correct parts of the value.
  virtual void writeValue(const typename S::value_type & val ) = 0;

  /// Read a double from the socket or packet.
  double readDouble() {return conP->readDouble();}

  /// Read a H3DFloat from the socket or packet.
  H3D::H3DFloat readH3DFloat() {return conP->readH3DFloat();}

  /// Write a double to the socket or packet.
  void writeDouble(const double & val) {conP->writeDouble(val);}

  /// Write a H3DFloat to the socket or packet.
  void writeH3DFloat(const H3D::H3DFloat & val) {conP->writeH3DFloat(val);}

  void lockWriteThread() {conP->lockWriteThread();}
  void unlockWriteThread() {conP->unlockWriteThread();}
};

}

#endif

