/*****************************
File:      RemoteMF.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 RemoteMF.h
/// \brief Header file for RemoteMF, abstract base class for remote multi valued field.

#ifndef RemoteMF_H
#define RemoteMF_H


#include "H3DNetworkingUtils/Config.h"
#include "H3DUtil/H3DMath.h"
#include "H3D/X3DChildNode.h"
#include "H3DUtil/Threads.h"
#include "H3DNetworkingUtils/RemoteField.h"
#include "H3DNetworkingUtils/BufferedMField.h"

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

namespace H3DNetworkingUtils {
   
/// \class RemoteMF
/// The RemoteMF class is a template class which is a node containing a multiple field which sends and
/// receives its value to/from another the field of another RemoteMF<T> 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, RemoteMFVec3f, RemoteMFBool, RemoteMFRotation, 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/RemoteMFTestServer.x3d">RemoteMFTestServer.x3d</a>
///   - <a href="../../examples/RemoteMFTestClient.x3d">RemoteMFTestClient.x3d</a>

   template <class M>
class H3D_NETWORKING_UTILS_DLL_SPEC RemoteMF : public RemoteField {
public:
   /// X3D interface
   static H3D::H3DNodeDatabase database;

   /// Initialize values
   virtual void initialize();

   /// This class gets input values and sends them on trhe network
   class H3D_NETWORKING_UTILS_DLL_SPEC MFSender : public H3D::AutoUpdate< M >  {
   public:
     MFSender() : send_on_change(false) {}
     virtual void update( );
     virtual void setValue( const std::vector<typename M::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
   
   /// This field value is sent to the other application when it changes   \n
   /// access type: inputOnly \n
   /// basic type: SFString \n
   /// default value: 
   auto_ptr<MFSender             > toBeSent;
   
   /// This is received from the other application when the remote value changes   \n
   /// This needs to be a BufferedMField because it gets changed in a thread that 
   /// is not the graphics thread, and also may need to be buffered \n
   /// access type: outputOnly \n
   /// basic type: SFString \n
   /// default value: 
   auto_ptr<BufferedMField<M>    > 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 \n
  ///This is since it is an abstract class.
  RemoteMF(H3D::X3DTypes::X3DType t, 
           H3D::Inst<MFSender> _toBeSent = 0,
           H3D::Inst< BufferedMField<M> > _received = 0);

  virtual ~RemoteMF();
  
  /// 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 \n
  /// 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(std::vector<typename M::value_type> const & 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 H3DFloat & val) {conP->writeH3DFloat(val);}

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

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

};

}

#endif



