/*****************************************************************************
 * $LastChangedDate: 2011-04-09 21:58:06 -0400 (Sat, 09 Apr 2011) $
 * @file
 * @author  Jim E. Brooks  http://www.palomino3d.org
 * @brief   Physics model.
 *//*
 * LEGAL:   COPYRIGHT (C) 2007 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL 2).
 *****************************************************************************/

#ifndef PHYSICS_AIRCRAFT_PHYSICS_HH
#define PHYSICS_AIRCRAFT_PHYSICS_HH 1

#include "object/module.hh"
//#include "object/aircraft.hh"
namespace object { class Aircraft; }
using namespace object;
#include "physics/aircraft_specs.hh"

namespace physics {

////////////////////////////////////////////////////////////////////////////////
/// @brief AircraftPhysics model.
///
/// Thrust/drag/lift:
/// The AircraftPhysics class doesn't need to transform thrust/drag/lift (excluding weight).
/// These force vectors are relative to a Aircraft and therefore exist in local space.
/// Ultimately these are passed to Aircraft::Translate(Vector3) which transforms them.
///
/// Weight:
/// The direction of the weight vector is fixed/absolute of course.
/// Weight acceleration can be applied  using Object::GetPosition()/SetPosition()
/// to directly add weight vector in terms of a world vertex.
///
/// Compute() methods:
/// Many methods that just get a value are named Compute()
/// since ideally they would compute a physical parameter.
///
/// Aircraft state enums:
/// The state enums (flying, landing, etc) are kept in the Aircraft class.
/// Both Aircraft and AircraftPhysics can affect the state.
///
class AircraftPhysics
{
COPYABLE(AircraftPhysics)

private:
    CLASS_CONST int THRUST_DIR = -1;  ///< multiplier/sign
    CLASS_CONST int LIFT_DIR   =  1;  ///< multiplier/sign

public:
                        AircraftPhysics( SafePtr<Aircraft> aircraft, const AircraftSpecs& specs );
                        ~AircraftPhysics();

// Enable, reset:
// Physics can be globally disabled.
public:
    void                Enable( bool enable );
    bool                IfEnabled( void );
    void                Reset( void );

// Object animation:
public:
    void                Tick( const Milliseconds timeElapsed );
private:
    bool                AnimateAircraft( const Milliseconds timeElapsed );
    bool                AnimateAircraftLanding( const Milliseconds timeElapsed );

// Speed, velocity (Speed type is meters/second):
public:
    void                SetSpeed( const Speed speed );
    Speed               ComputeSpeed( void );
    Speed               ComputeMaxSpeed( void );
    Velocity            ComputeVelocity( void ) { return mWorld.mVelocity; }
    Speed               ComputeStallSpeed( void ) { return physics::conv::KPH2Speed(mSpecs.mStallSpeed); }
    Speed               ComputeLiftoffSpeed( void ) { return physics::conv::KPH2Speed(mSpecs.mLiftoffSpeed); }
private:
    bool                IfVelocity( void );
    bool                IfForwardVelocity( const Matrix& aircraftMatrix );
    bool                IfDownwardVelocity( void );

// Thrust:
public:
    void                SetThrust( const Newton1 thrust );  // magnitude
    Newton1             ComputeMaxThrust( void ) { return mSpecs.mMaxThrustMag; }

// Drag:
public:
    void                EnableBrakes( const bool enable ) { mBrakes = enable; }
    bool                IfBrakes( void ) { return mBrakes; }
    bool                IfWheelBrakes( void );
    bool                IfAirBrakes( void ) { return IfBrakes() and not IfWheelBrakes(); }

// Fundamental forces:
public:
    Newton              ComputeThrustForce( void ) { return mWorld.mThrustForce; }
    Newton              ComputeDragForce( void )   { return mWorld.mDragForce; }
    Newton              ComputeLiftForce( void )   { return mWorld.mLiftForce; }
    Newton              ComputeWeightForce( void ) { return mWorld.mWeightForce; }
private:
    Vector3             AircraftAxisThrust( const Matrix& m );
    Vector3             AircraftAxisLift( const Matrix& m );

// Angle-of-attack, rotation rates:
public:
    Degree              ComputeAngleOfAttack( const bool ifVelocity );
    Degree              ComputeAngleOfAttack( void )
                        { return ComputeAngleOfAttack(IfVelocity()); }
    Degree              ComputeRollRate( void );
    Degree              ComputePitchRate( void );
    Degree              ComputeYawRate( void );
private:
    fp                  ComputeRotationFactor( void );

// Turning:
public:
    enum eTurning { eNotTurning, eTurningLeft, eTurningRight };
    eTurning            ComputeTurningDir( void );
    bool                IfTurning( void );

// Stalling:
public:
    bool                IfStall( void );
    fp                  ComputeStall( void );

private:
    ////////////////////////////////////////////////////////////////////////////
    /// @brief Defines motion in a coordinate system.
    ///
    /// MotionSpace is a vestige, but one that remains useful, from when
    /// PhysicsAircraft used to do computations in both local and world spaces.
    ///
    struct MotionSpace
    {
        MotionSpace( void );
        void Reset( void );

        Newton          mThrustForce, mDragForce, mLiftForce, mWeightForce;
        Acceleration    mThrustAccel, mDragAccel, mLiftAccel, mWeightAccel;
        Acceleration    mNetAccel;
        Velocity        mVelocity;
    };

/// Reference-counting problem:
/// AircraftPhysics is a member of Aircraft.
/// A reference-counted class cannot have any reference to itself
/// else it would never be destroyed.  Therefore, AircraftPhysics has
/// a SafePtr<Aircraft> back to Aircraft.
private:
    bool                mEnable;            ///< enable this instance
    SafePtr<Aircraft>   mAircraft;          ///< (cannot be shptr!!) the Object this AircraftPhysics instance controls
    AircraftSpecs       mSpecs;             ///< specifications/characteristics of a type of Aircraft
    Milliseconds        mPrevTick;
    MotionSpace         mWorld;             ///< motion in world space
    Newton1             mThrustMag;         ///< magnitude (current thrust)
    bool                mBrakes;
public:
    DECLARE_TYPESIG(TYPESIG_AIRCRAFT_PHYSICS)
};

} // namespace physics

#endif // PHYSICS_AIRCRAFT_PHYSICS_HH
