/***************************************************************************
*                                                                          *
*  Copyright (C) Golaem S.A.  All Rights Reserved.                         *
*                                                                          *
***************************************************************************/

#pragma once

#include "glmCoreAPI.h"
#include "glmSmartPointer.h"

namespace glm
{
    class CloneFactory;
    //************************************************************
    /*! @name Visual Feedback
	*/
    //*********************************************************
    //@{
    //------------------------------------------------------------
    //! Crowd Visual Feedback Flags
    //------------------------------------------------------------
    struct VisualFeedbackFlags
    {
        enum Value
        {
            //---------------------------------------------------
            // Global VF
            //---------------------------------------------------
            // Enable/Disable the visualfeedback
            ENABLE_BEHAVIOR_VF = 0,

            //---------------------------------------------------
            // Maya Viewport VF
            //---------------------------------------------------
            // Draw on entity
            SELECTED_ENTITY,
            SPECIFIC_ENTITIES,

            ENTITY_BODYORI,
            ENTITY_MOVEORI,
            ENTITY_REFUP,
            ENTITY_GROUND_CELL,

            // Goto vf
            PATH_TO_TARGET,
            FINAL_TARGET,
            LOCAL_TARGET,
            LOCAL_PLATTERLIFTTRIANGLE,

            // Navigation vf
            ENTITY_RADIUS,
            ENTITY_PERSONAL_SPACE,
            ENTITY_VELOCITY,
            ENTITY_NEIGHBORS_VELOCITY,
            ENTITY_LOCAL_OBSTACLES,
            ENTITY_VELOCITY_MODEL,
            ENTITY_COVERED_CELLS,

            // Locomotion vf
            SKELETON_PARTICLE_LINK,

            // Formation vf
            ENTITIES_FORMATION,

            // Boid vf
            BOID_SPEED,
            BOID_LAST_STEERING,
            BOID_OBSTACLES_RAYCAST,
            BOID_PERCEPTION_VOLUME,
            BOID_PERCHING_POSITION,
            BOID_PERCHING_CELL,

            // Show/Hide extended vf
            SHOW_EXTENDED_VF,

            // Motion vf
            CURRENT_MOTIONCLIPS,
            ALL_MOTIONCLIPS,
            PREDICTED_FOOTPRINTS,
            PREDICTED_FOOTPRINTS_DEBUG,
            TRAJECTORY_PREDICTION,
            TRAJECTORY_CANDIDATES,
            TRAJECTORY_DISMISSEDCANDIDATES,

            /// Locomotion vf
            LOCOMOTION_MODEL,
            ENTITY_BOUNDINGBOX,

            /// Perception vf
            PERCEPTION_ENTITY_VOXELS,
            PERCEPTION_SENSOR_VOXELS,
            PERCEPTION_SENSOR_GEOMETRY,
            PERCEPTION_OBJECTS,

            /// Traffic VF
            TRAFFIC_BOX,
            TRAFFIC_OBSTACLE,
            TRAFFIC_TRAJECTORY,
            TRAFFIC_PATHPLANNING,

            /// misc
            ENTITIES_TO_SELECT,
            DRAW_GROUND,
            DRAW_PERCEPTION_ENTITIES,
            SENSORS_TO_DISPLAY,

            END
        };
    };
    //@}

    class AbstractGraphicalContainerNode;

    // AbstractGraphicalNode comments
    class GLM_CORE_API AbstractGraphicalNode : public ReferenceCounter
    {

        friend class AbstractGraphicalContainerNode;

    public:
        /// Smart pointer definition
        typedef SmartPointer<AbstractGraphicalNode> SP;

        // Type describing the different run status of a graphical node
        struct RunStatus
        {
            enum Value
            {
                UNKNOWN = 0,
                IDLE = 1,
                START = 2,
                RUN = 3,
                STOP = 4
            };
        };

        // Type describing the different result of a graphical node
        struct DebugStatus
        {
            enum Value
            {
                VALID = 0,
                WARNING = 1,
                FAILED = 2,
                CRITICAL = 3
            };
        };

    public:
        /// The node is mark as selected or not
        bool _selected;
        /// The node is mark as avoided or not (not in the flow)
        bool _avoided;
        /// The node is enabled or not (maybe still in the flow)
        bool _enabled;
        /// The node is handled or not
        bool _handled;

        /// This node accept multiple next nodes
        bool _multipleNextNodes;

        /// The run status of the node
        RunStatus::Value _runStatus;
		Vector4 _backgroundColor;

        // for dimming according to oldness of this node update in the frame. 0.0f to 1.f coefficient. If it is -1, it has not been enabled last frame.
        float _updatedThisFrameCoefficient;

        /// The debug status of the node
        DebugStatus::Value _debugStatus;
        glm::GlmString _statusInfo;

        /// \name VisualFeedbacks
        ///@{
        /// VisualFeedback flags
        glm::PODArray<int> _visualFeedbackFlags;
        Vector4 _color;
        ///@}

        int _executionPriority; // used in Maya to be able to control parallel children order

        /// node type name
        glm::GlmString _typeName;

    protected:
        /// Next node
        glm::Array<AbstractGraphicalNode::SP> _nextNodes;

        /// node name
        glm::GlmString _name;

        /// Node parent of the current node
        AbstractGraphicalContainerNode* _parentNode;

    public:
        GLM_ABSTRACTCLASS_STAT_ID( glm::MemoryStatIds::Editors)

        // default constructor
        AbstractGraphicalNode();

        // destructor
        virtual ~AbstractGraphicalNode();

        // Get const next nodes
        const glm::Array<AbstractGraphicalNode::SP>& getNextNodes() const;

        // Get id of a given node within the next node pool
        int retrieveNextNodeId(AbstractGraphicalNode* node) const;

        // Check if a given node is already set as next node
        bool hasNextNode(AbstractGraphicalNode* node) const;

        // Add a node as next node
        virtual void addNextNode(AbstractGraphicalNode* node);
        virtual void insertNextNode(int index, AbstractGraphicalNode* node);
        virtual void setNextNode(int index, AbstractGraphicalNode* node);

        // Remove a node previously added as next node
        virtual void removeNextNode(AbstractGraphicalNode* node);
        virtual void removeNextNodeAt(int nodeIndex);

        // Get the container behavior parent of the current behavior
        const AbstractGraphicalContainerNode* getParentNode() const;

        // Get the container behavior parent of the current behavior
        AbstractGraphicalContainerNode* touchParentNode();

        // Check if a given node is an ancestor of current node
        bool hasAncestorNode(const AbstractGraphicalContainerNode* ancestorNode) const;

        // Get the container behavior parent of the current behavior
        AbstractGraphicalContainerNode* touchFirstAncestor();

        // accessor to the name
        inline virtual const char* getName() const;

        // set accessor to the name
        inline virtual void setName(const char* name);

        virtual size_t getTypeHash() const;

    protected:
        // cloning
        friend class CloneFactory;
        virtual void cloneImpl(AbstractGraphicalNode* clone, CloneFactory* factory) const;
        inline virtual AbstractGraphicalNode* create() const;

    private:
        GLM_DISALLOW_COPY_AND_ASSIGN(AbstractGraphicalNode);
    };

    //-------------------------------------------------------------------------
    inline const char* AbstractGraphicalNode::getName() const
    {
        return _name.c_str();
    }

    //-------------------------------------------------------------------------
    inline void AbstractGraphicalNode::setName(const char* name)
    {
        _name = glm::GlmString(name);
    }

    //-------------------------------------------------------------------------
    inline const AbstractGraphicalContainerNode* AbstractGraphicalNode::getParentNode() const
    {
        return _parentNode;
    }

    //-------------------------------------------------------------------------
    inline AbstractGraphicalContainerNode* AbstractGraphicalNode::touchParentNode()
    {
        return _parentNode;
    }

    //-------------------------------------------------------------------------
    inline const glm::Array<AbstractGraphicalNode::SP>& AbstractGraphicalNode::getNextNodes() const
    {
        return _nextNodes;
    }

    //-------------------------------------------------------------------------
    inline AbstractGraphicalNode* AbstractGraphicalNode::create() const
    {
        AbstractGraphicalNode* myNewAbstractGraphicalNode = GLM_NEW(AbstractGraphicalNode, myNewAbstractGraphicalNode, getClassMemoryStatId());
        return myNewAbstractGraphicalNode;
    }
} // namespace glm
