/*****************************************************************************
 * $LastChangedDate: 2011-04-09 21:58:06 -0400 (Sat, 09 Apr 2011) $
 * @file
 * @author  Jim E. Brooks  http://www.palomino3d.org
 * @brief   Defines a sub-graph (partition/subtree).
 *//*
 * 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 GRAPH_SUBGRAPH_HH
#define GRAPH_SUBGRAPH_HH

#include "graph/graph_enablement.hh"

namespace graph {

class Graph;

////////////////////////////////////////////////////////////////////////////////
/// @brief Defines a partition of a graph (subtree).
///
/// Subgraph, by default, allows unlimited rotation (by computing a matrix).
///
/// Limited rotation:
/// -----------------
/// Optionally, Subgraph can model a part that has a limited range of movement
/// such as landing gear.
/// Subgraph::SetRotationLimit( axis, minDegree, maxDegree ) limits the axis
/// and degree of rotation.
/// Subgraph::RotateLimited( Degree ) then does limited rotation
/// according to those stored parameters.
///
/// Implementation:
/// ---------------
/// The subgraph is found by a visitor that searches for a node by its name.
/// Then a MatrixTransform is spliced over the found node.
///
class Subgraph : public Shared, private GraphEnablement
{
PREVENT_COPYING(Subgraph)
public:
            Subgraph( shptr<Graph> graph, const string& name );
            ~Subgraph();

    RefPtr<Node>    GetRootNode( void ) { return mSwitchNode; }

// Enablement:
    void    Enable( const bool enable = true );
    bool    IfEnabled( void );

// Rotation, matrix:
    void    SetLimitedRotation( uint axis, const Degree degreeMin, const Degree degreeMax );
    void    Reset( void );
    void    Rotate( uint axis, Radian radian );
    void    Translate( uint axis, fp inc );
    void    Translate( const Vector3& v );
    void    SetMatrix( const Matrix& m );
    Matrix  GetMatrix( void );

private:
    bool    IfAllowRotation( uint axis, Radian radian );

private:
    /// @brief Defines rotation limited to one axis and a range of degrees.
    ///
    struct LimitedRotation
    {
        LimitedRotation( void )
        : mEnabled(false), mAxis(0), mDegree(0), mDegreeMin(0), mDegreeMax(0) { }
        bool    mEnabled;
        uint    mAxis;
        Degree  mDegree;        ///< current rotation
        Degree  mDegreeMin;
        Degree  mDegreeMax;
    };

private:
    RefPtr<osg::Switch>             mSwitchNode;        ///< spliced over the subgraph
    RefPtr<osg::MatrixTransform>    mTransformNode;     ///< also spliced over the subgraph
    LimitedRotation                 mLimitedRotation;
public:
    DECLARE_TYPESIG(TYPESIG_SUBGRAPH)  // final member
};

} // namespace graph

#endif // GRAPH_SUBGRAPH_HH
