/*****************************
File:      ToolsPosDetector.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 ToolPosDetector.h
/// \brief Header file for ToolPosDetector, gets the tool position at haptics rates.

#ifndef ToolPosDetector_H
#define ToolPosDetector_H

#include "H3DNetworkingUtils/Config.h"
#include <H3D/X3DChildNode.h>
#include <H3D/TraverseInfo.h>
#include <H3D/SFBool.h>
#include <H3D/SFInt32.h>
#include <H3D/SFVec3f.h>
#include <H3D/ThreadSafeFields.h>
#include <H3DUtil/Threads.h>
#include <HAPI/HAPIForceEffect.h> 
#include <H3DNetworkingUtils/lockwrap.h>

namespace H3DNetworkingUtils {

/// \class ToolPosDetector
/// \brief The ToolposDetector class detects tool posititon and makes this available in its output
/// fields at the haptic rate.
/// Note that there is an internal lock mechanism on the set update and get
/// functions of the output fields. This allows you to retrieve the fields from a
/// thread other than the haptics thread (e.g. one writing to a network).
/// Note, however, that it may be dangerous to retrieve the values in the
/// graphics loop, if you use it to change the scene graph.  You should use a
/// ThreadSafe (see H3D ThreadSafeSField.h) field to protect against those 
/// problems.  \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  ToolPosDetector : public H3D::X3DChildNode {
public:
  class ThreadSafeSFVec3f;

  /// Constructor
  ToolPosDetector ( H3D::Inst< H3D::SFBool >  _enabled = 0,
                    H3D::Inst< H3D::SFInt32 >  _deviceIndex = 0,
                    H3D::Inst< ThreadSafeSFVec3f >  _globalPos = 0,
                    H3D::Inst< ThreadSafeSFVec3f >  _localPos = 0);

  /// This class is designed to allow the value to be set in one thread and retrieved in another 
  /// (not necessarily the graphics and haptics threads - in our case it is the haptics thread and a network sending thread).
  class H3D_NETWORKING_UTILS_DLL_SPEC ThreadSafeSFVec3f : public H3D::SFVec3f {
  public:
     virtual void setValue(H3D::Vec3f const & v, int id = 0) {
       my_lock.lock();
       H3D::SFVec3f::setValue(v, id);
       my_lock.unlock();
    }
    virtual void update() {
       my_lock.lock();
       H3D::SFVec3f::update();
       my_lock.unlock();
    }
    virtual H3D::Vec3f const & getValue(int id = 0) {
       my_lock.lock();
       ret = H3D::SFVec3f::getValue(id);
       my_lock.unlock();
       return ret;
    }
    Mutex my_lock;
    H3D::Vec3f ret;
    bool in_set_value;
  };

  /// Switches the node on or off \n
  /// access type: inputOutput \n
  /// basic type: SFBool \n
  /// default value: FALSE \n
  /// \dotfile ToolPosDetector_enabled.dot
  auto_ptr<H3D::SFBool        > enabled;
  
  /// Specifies which haptic devicde to monitor \n
  /// access type: inputOutput \n
  /// basic type: SFInt32 \n
  /// default value: 0 \n
  /// \dotfile ToolPosDetector_deviceIndex.dot
  auto_ptr<H3D::SFInt32       > deviceIndex;
  
  /// The position in global coord system \n
  /// access type: inputOutput \n
  /// basic type: SFVec3f \n
  /// default value: 0 0 0 \n
  /// \dotfile ToolPosDetector_globalPos.dot
  auto_ptr<ThreadSafeSFVec3f  > globalPos;
  
  /// The position in local coord system \n
  /// access type: inputOutput \n
  /// basic type: SFVec3f \n
  /// default value: 0 0 0 \n
  /// \dotfile ToolPosDetector_localPos.dot
  auto_ptr<ThreadSafeSFVec3f  > localPos;

  /// The H3DNodeDatabase for this node.
  static H3D::H3DNodeDatabase database;
  
  virtual void traverseSG(H3D::TraverseInfo & ti);
  
protected:
   // This is modelled on a force effect, but does not actually produce any
   // force.  It is just a hook to get into the haptics cycle.
   class Detector: public HAPI::HAPIForceEffect {
   public:
      Detector(ToolPosDetector * tpdP,
               const H3D::Matrix4f & global_to_local,
               int node_id);
      
      HAPI::HAPIForceEffect::EffectOutput virtual calculateForces( const HAPI::HAPIForceEffect::EffectInput &input );
    
   private:
     H3D::AutoRef<ToolPosDetector> tpdP;
     int node_id;
     H3D::Matrix4f global_to_local;
     H3D::H3DTime creation_time;
   };
   
 private:
   H3D::H3DTime latest_creation_time; // Accessed from the haptics thread only!
   //Detector * latest_detP; 
   
};

}

#endif
