#ifndef GRAPHICALNODE_H
#define GRAPHICALNODE_H

#include "scenenode.h"
#include <glm/mat4x4.hpp>
#include <glm/vec3.hpp>
#include "LinearMath/btMotionState.h"

class SceneTree;

class GraphicalNode : public SceneNode
{
public:
    class SparrowMotionState : public btMotionState
    {
        GraphicalNode* m_node;

    public:
        SparrowMotionState(GraphicalNode* node) : m_node(node) {}

        virtual void getWorldTransform(btTransform& worldTrans ) const;

        //Bullet only calls the update of worldtransform for active objects
        virtual void setWorldTransform(const btTransform& worldTrans);
    };

protected:
    // m_parentTransform is the base transform for this element
    glm::mat4 m_parentTransform;
    // m_transform is the relative transformation matrix of this node
    glm::mat4 m_transform;

    bool m_parentVisible;
    bool m_visible;

    bool m_transformChanged;

    SparrowMotionState m_motionState;

    virtual void updateVisibility(bool visible);

public:
    GraphicalNode(bool visible = true) : m_parentVisible(true), m_visible(visible), m_transformChanged(true), m_motionState(this) {}
    virtual ~GraphicalNode() { setVisible(false); }

    virtual void setSceneTree(SceneTree* tree);

    // transform methods
    void setTransform(const glm::mat4 &transform);
    const glm::mat4& getTransform() { return m_transform; }
    void setParentTransform(const glm::mat4 &transform);
    const glm::mat4& getParentTransform() { return m_parentTransform; }
    void resetTransform();

    // visibility methods
    bool isVisible(){return m_parentVisible && m_visible;}
    void toggleVisibility();
    void setVisible(bool visible);
    void setParentVisible(bool visible);

    // transformation tools :
    void moveTo(const glm::vec3 &position);
    void translate(const glm::vec3 &vector);
    void lookAt(const glm::vec3 &target, const glm::vec3 &upVector = glm::vec3(0, 1, 0));
    void rotate(float angle, const glm::vec3 &vector);
    void scale(const glm::vec3 &scaleFactor);

    //2D tools:
    void moveTo2D(const glm::vec2 &position);
    void rotate2D(const glm::vec2 &center, float angle);
    void scale2D(const glm::vec2 scaleFactor);
    void resize2D(const glm::vec2 oldDimension, glm::vec2 newDimension);

    // this is used to synchronize a bullet rigidbody's transform with a GraphicalNode transform
    SparrowMotionState* getMotionState() { return &m_motionState; }
};

#endif // GRAPHICALNODE_H
