/*****************************************************************************
 * $LastChangedDate: 2011-04-09 21:58:06 -0400 (Sat, 09 Apr 2011) $
 * @file
 * @author  Jim E. Brooks  http://www.palomino3d.org
 * @brief   Aircraft base class.
 *//*
 * 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 OBJECT_AIRCRAFT_HH
#define OBJECT_AIRCRAFT_HH 1

#include "object/craft.hh"
#include "physics/module.hh"
#include "physics/physics_aircraft.hh"
using namespace physics;
#include "graph/module.hh"
#include "graph/subgraph.hh"
using namespace graph;

namespace object {

////////////////////////////////////////////////////////////////////////////////
/// @brief Aircraft class.
///
/// This class is unusual:
/// - Aircraft has both a virtual and class method to get AircraftSpecs.
/// - Derivatives have a class method ClassGetSpecs() used for instantiating themselves.
///
/// mThrottle is a fp {0.0,...,1.0}.
/// mStep is a world coordinate.
/// Speed (translation increment) is determined by mThrottle * mStep.
///
/// Aircraft state enums:
/// The state enums (flying, landing, etc) are kept in the Aircraft class.
/// Both Aircraft and AircraftPhysics can affect the state.
///
class Aircraft : public Craft
{
PREVENT_COPYING(Aircraft)
typedef Craft Parent;
friend class shptr<Aircraft>; friend class shptr0<Aircraft>;
// Axises as defined by 3D model files.
public:                         enum { MODEL_AXIS_PITCH = ZZ,
                                       MODEL_AXIS_ROLL  = XX,
                                       MODEL_AXIS_YAW   = YY };
public:                         enum eState
                                {
                                    eState_PARKED,
                                    eState_TAKEOFF,
                                    eState_FLYING,
                                    eState_LANDING,
                                };
// Only derivatives can access Aircraft ctor.
protected:                      Aircraft( shptr<Graph> graph, const WorldVertex& pos, const AircraftSpecs& specs );
public:    virtual              ~Aircraft();
public:    CLASS_METHOD shptr<Graph> LoadModel( const AircraftSpecs& specs, const bool loadCopy );
public:    virtual void         Reset( void );
public:    virtual const string GetName( void ) { return string("Aircraft"); }

// Spatial:
public:    virtual void         SetPosition( const WorldVertex& position );
public:    virtual void         Translate( uint axis, fp inc );
public:    virtual void         Translate( const Vector3& v );
public:    virtual void         Rotate( uint axis, Radian rad );

// Transformation:
public:    virtual void         SetMatrix( const Matrix& matrix, Dyna::eMatrixChange change );

// Control:
public:    virtual void         PhysicalRotate( uint axis, fp controlFraction, Milliseconds controlFreq );
public:    virtual void         RotateControlSurfaces( const uint axis, const fp frac ) { }
public:    virtual void         SetThrottle( const fp throttle );
public:    virtual fp           GetThrottle( void ) { CHECK_TYPESIG(this,TYPESIG_AIRCRAFT); return mThrottle; }
public:    virtual void         EnableBrakes( const bool enable );
public:    virtual bool         IfBrakes( void );
public:    virtual bool         IfWheelBrakes( void );
public:    virtual bool         IfAirBrakes( void );
public:    virtual void         SetLandingGear( const bool down );
public:    virtual bool         IfLandingGear( void );  // true if extended down
public:    virtual void         SwingWings( const float fraction ) { }     // 0.0:forward...1.0:back
public:    virtual void         SwingBayDoors( const float fraction ) { }  // 0.0:close...1.0:open

// AircraftPhysics:
public:    virtual AircraftPhysics& GetPhysics( void ) { CHECK_TYPESIG(this,TYPESIG_AIRCRAFT);
                                                         return mPhysics; }
public:    void                 EnableCoordinatedTurn( const bool enable );
public:    bool                 IfCoordinatedTurnEnabled( void ) const;
public:    bool                 IfCoordinatedTurnExecuting( void ) const;

// Animation, sounds:
protected: virtual void         Tick( const Milliseconds millisecElapsed );
protected: virtual void         AnimateStall( void );
public:    virtual void         PlayEngineSound( const fp volume );
public:    virtual void         StopEngineSound( void );
public:    virtual void         SetShadowCaster( const bool enable = true );

// Control surfaces (graphical):
protected: enum eAileron { LEFT_AILERON = 1, RIGHT_AILERON = -1 };  // direction
protected: enum eRudder { SINGLE_RUDDER = 0, LEFT_RUDDER = 1, RIGHT_RUDDER = -1 };
protected: void                 RotateAileron( Subgraph& subgraph, const fp controlFraction, const eAileron aileron );
protected: void                 RotateAileron( Subgraph& subgraph, const fp controlFraction, const eAileron aileron, const Vector3& aileronOffset );
protected: void                 RotateElevator( Subgraph& subgraph, const fp controlFraction );
protected: void                 RotateRudder( Subgraph& subgraph, const fp controlFraction, const eRudder = SINGLE_RUDDER );

// States: collision-detection and contact force.
// Dyna has basic collision-detection.
// Aircraft determines what kind of collision: safe contact or fatal collision.
public:    virtual void         SetState( const eState state );
public:    virtual eState       GetState( void );
public:    bool                 IfFlying( void );
public:    virtual void         SetCollision( const Object::eCollision collision );
public:    virtual bool         IfCollisionRunway( void );
protected: virtual void         HandleCollisions( const Dyna::Colliders& colliders );
private:   void                 MoreCrashDetermination( void );
private:   void                 UpdateState( const Milliseconds millisecElapsed );  // subroutine of Tick()

// Info:
public:    virtual NodeSort     GetNodeSort( void );
public:    virtual fp           GetHeight( void );
public:    bool                 IfCanSetLandingGear( const bool down );
public:    virtual const AircraftSpecs& GetSpecs( void ) = 0;
public:    virtual bool         IfHasPropeller( void ) = 0;
public:    virtual bool         IfHasGuns( void ) { return true; }

// Data:
private:   Matrix               mSavedMatrix;               ///< restored by Reset()
public:    AircraftPhysics      mPhysics;                   ///< physics model (public to use AircraftPhysics interface)
private:   eState               mState;                     ///< general states { parked, landing, etc }
private:   Milliseconds         mStateUpdateTime;           ///< timestamp when state was updated
private:   bool                 mOnRunway;
private:   bool                 mCoordinatedTurnEnabled;    ///< if coordinated turn is enabled
private:   bool                 mCoordinatedTurnExecuting;  ///< if program is performing a coordinated turn
private:   fp                   mThrottle;                  ///< {0.0,..,1.0}
protected: bool                 mLandingGearDown;
protected: bool                 mShadowCaster;              ///< will affect Aircraft::GetNodeSort()
public:    DECLARE_TYPESIG( TYPESIG_AIRCRAFT )
};

} // namespace object

#endif // OBJECT_AIRCRAFT_HH
