/*****************************
File:      DampedDynamic.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 DampedDynamic.h
/// \brief Header file for DampedDynamic, a Dynamic that is forgiving of latency.


#ifndef DampedDynamic_H
#define DampedDynamic_H

#include "H3DNetworkingUtils/Config.h"
#include "H3DNetworkingUtils/GrabableDynamic.h"
#include <H3DUtil/AutoRef.h>
#include <iostream>
#include <functional>
#include <H3D/Transform.h>
#include <H3D/TraverseInfo.h>
#include <H3D/Scene.h>
#include <H3D/H3DTypes.h>

namespace H3DNetworkingUtils {

/// \class DampedDynamic
/// The DampedDynamic class is a (Grabbable)Dynamic that behaves like a simple Dynamic that is very highly
/// damped. It is so damped that it never overshoots its equilibrium and therefore its 
/// momentum is not used in the position calculation. The object moves as long as forces act 
/// on it, and stops as soon as they don't. This assumption allows some algorithmic 
/// short-cuts that makes the calculation of position much faster and 
/// also makes it resiliant to frame rate (sampling) changes.
/// It is designed to be used in a networked environment where network latency can produce
/// stability problems when normal Newtonian physics is applied.
/// This behaviour is suited to scenarios where objects do not need to travel unaided along 
/// trajectories, such as in simulating ball sports or missiles. Moving objects on a frictional 
/// surface such as a table, or manipulating body organs in surgery are two areas where a 
/// this node could be used successfully.    \n
///
/// WARNING: Do not set linearDamping or rotationalDamping.  \n
/// <b>Examples:</b>
///   - <a href="../../examples/DampedDynamicTestServer.x3d">BufferedSFieldTestServer.x3d</a>
///   - <a href="../../examples/DampedDynamicTestClient.x3d">BufferedSFieldTestClient.x3d</a>

class H3D_NETWORKING_UTILS_DLL_SPEC DampedDynamic : public GrabableDynamic {
public:

    /// SFMotion: We override the SFMotion from DynamicTransform to take out the momentum
    class H3D_NETWORKING_UTILS_DLL_SPEC SFMotion: public  GrabableDynamic::SFMotion  {
    protected:
       virtual void update();
       virtual void updateState(H3D::LMState &state, H3D::H3DTime dt);
    };

  /// Constructor
  DampedDynamic(
            H3D::Inst< AddChildren              > _addChildren        = 0,
            H3D::Inst< RemoveChildren           > _removeChildren     = 0,
            H3D::Inst< MFChild                  > _children           = 0,
            H3D::Inst< H3D::SFNode              > _metadata           = 0,
            H3D::Inst< SFBound                  > _bound              = 0,
            H3D::Inst< H3D::SFVec3f             > _bboxCenter         = 0,
            H3D::Inst< H3D::SFVec3f             > _bboxSize           = 0,
            H3D::Inst< SFTransformedBound       > _transformedBound   = 0,
            H3D::Inst< SFMatrix4f               > _matrix             = 0,
            H3D::Inst< SFMatrix4f               > _accumulatedForward = 0,
            H3D::Inst< SFMatrix4f               > _accumulatedInverse = 0,
            H3D::Inst< H3D::SFVec3f             > _position           = 0,
            H3D::Inst< H3D::SFRotation          > _orientation        = 0,
            H3D::Inst< SFVelocity               > _velocity           = 0,
            H3D::Inst< H3D::SFVec3f             > _momentum           = 0,

            H3D::Inst< H3D::SFVec3f             > _force              = 0,
            H3D::Inst< SFAngularVelocity        > _angularVelocity    = 0,
            H3D::Inst< H3D::SFVec3f             > _angularMomentum    = 0, 
            H3D::Inst< SFSpin                   > _spin               = 0,
            H3D::Inst< H3D::SFVec3f             > _torque             = 0,
            H3D::Inst< H3D::SFFloat             > _mass               = 0,
            H3D::Inst< H3D::SFMatrix3f          > _inertiaTensor      = 0,
            H3D::Inst< SFMotion                 > _motion             = 0,
            
            H3D::Inst<H3D::MFVec3f              > _contactForces      = 0,
            H3D::Inst<H3D::MFVec3f              > _contactTorques     = 0,
            H3D::Inst<SumMFVec3f                > _totalContactForce  = 0,
            H3D::Inst<SumMFVec3f                > _totalContactTorque = 0,
            H3D::Inst<SumForces                 > _externalForces     = 0,
            H3D::Inst<SumTorques                > _externalTorques    = 0,
            H3D::Inst<H3D::SFVec3f              > _freedom            = 0,
            H3D::Inst<H3D::SFVec3f              > _angularFreedom     = 0,
            H3D::Inst<H3D::SFFloat              > _linearDamping      = 0,
            H3D::Inst<H3D::SFFloat              > _rotationalDamping  = 0,
            H3D::Inst<H3D::SFFloat              > _linearSpringStiffness = 0,
            H3D::Inst<H3D::SFFloat              > _angularSpringStiffness = 0,
            H3D::Inst<H3D::SFVec3f              > _globalPosition = 0,

            H3D::Inst<MFCollidableGeometry      > _collisionSpheres  = 0,
            H3D::Inst<H3D::SFFloat              > _collisionStiffness = 0,
            H3D::Inst< H3D::SFFloat             > _collisionResolution   = 0,
            H3D::Inst<H3D::SFBool               > _grabbed = 0,
            H3D::Inst<H3D::SFVec3f              > _grabPoint = 0,
            H3D::Inst<H3D::SFFloat              > _grabStrength = 0,
            H3D::Inst<H3D::SFFloat              > _grabSlackRadius = 0,
            H3D::Inst<GrabForce						> _grabForce = 0,
            H3D::Inst<Inverter                  > _grabReactionForce = 0,
            H3D::Inst<MovedPos                  > _grabSpringAnchorPt = 0,
            H3D::Inst<GrabTorque                > _grabTorque = 0,
				H3D::Inst<H3D::SFInt32              > _grabSmoothing = 0,
				H3D::Inst<H3D::SFFloat              > _grabDamping = 0,
				H3D::Inst<SlaveSwitch					> _slaveMode = 0,
            H3D::Inst<SumVec3f                 > _appliedForce = 0,
            H3D::Inst<SumVec3f                 > _appliedTorque = 0);

   /// Database
   static H3D::H3DNodeDatabase database;
  
   virtual void traverseSG(H3D::TraverseInfo & ti);
  
};

typedef H3D::TypedSFNode< DampedDynamic > SFDampedDynamic;
}
   
#endif
