#include "graphicalnode.h"
#include "scenetree.h"
#include "glm/ext.hpp"
#include <iostream>

void GraphicalNode::setSceneTree(SceneTree *tree)
{
    if(isVisible())
    {
        if(m_scene != nullptr)
            m_scene->removeFromIndex(this);
        if(tree != nullptr)
            tree->addToIndex(this);
    }
    m_scene = tree;
}

void GraphicalNode::resetTransform()
{
    setTransform(glm::mat4());
}

// tools
void GraphicalNode::moveTo(const glm::vec3 &position)
{
    m_transform = glm::translate(glm::mat4(), position);
    m_transformChanged = true;
}

void GraphicalNode::translate(const glm::vec3 &vector)
{
    m_transform = glm::translate(m_transform, vector);
    m_transformChanged = true;
}

void GraphicalNode::lookAt(const glm::vec3 &target, const glm::vec3 &upVector)
{
    glm::vec3 pos = glm::vec3(m_transform[3]);
    m_transform = glm::lookAt(pos, target, upVector);
    m_transformChanged = true;
}

void GraphicalNode::rotate(float angle, const glm::vec3 &vector)
{
    m_transform = glm::rotate(m_transform, angle, vector);
    m_transformChanged = true;
}

void GraphicalNode::scale(const glm::vec3 &scaleFactor)
{
    m_transform = glm::scale(m_transform, scaleFactor);
    m_transformChanged = true;
}

void GraphicalNode::moveTo2D(const glm::vec2 &position)
{
    setTransform(glm::translate(m_transform,glm::vec3(position.x,position.y,0) - glm::vec3(m_transform[3])));
}

void GraphicalNode::resize2D(const glm::vec2 oldDimension, glm::vec2 newDimension)
{
    scale2D(glm::vec2(newDimension / oldDimension));
}

void GraphicalNode::scale2D(const glm::vec2 scaleFactor)
{
    setTransform(glm::scale(m_transform, glm::vec3(scaleFactor.x,scaleFactor.y,1)));
}

void GraphicalNode::rotate2D(const glm::vec2 &center, float angle)
{
    setTransform(glm::rotate(m_transform,angle,glm::vec3(0,0,1)));
}

// setters
void GraphicalNode::setTransform(const glm::mat4 &transform)
{
    m_transform = transform;
    m_transformChanged = true;
}

// could be optimised by just storing a pointer, but unexpected behavior may happen ?
void GraphicalNode::setParentTransform(const glm::mat4 &transform)
{
    m_parentTransform = transform;
    m_transformChanged = true;
}

void GraphicalNode::toggleVisibility()
{
    setVisible(!m_visible);
}

void GraphicalNode::setVisible(bool visible)
{
    if(m_parentVisible)
    {
        if(m_visible && !visible)
            updateVisibility(false);
        if(visible && !m_visible)
            updateVisibility(true);
    }
    m_visible = visible;
}

void GraphicalNode::setParentVisible(bool visible)
{
    if(m_visible)
    {
        if(m_parentVisible && !visible)
            updateVisibility(false);
        if(visible && !m_parentVisible)
            updateVisibility(true);
    }
    m_parentVisible = visible;
}

void GraphicalNode::updateVisibility(bool visible)
{
    if(!m_scene)
        return;
    if(visible)
        m_scene->addToIndex(this);
    else
        m_scene->removeFromIndex(this);
}

void GraphicalNode::SparrowMotionState::getWorldTransform(btTransform& worldTrans ) const
{
    worldTrans.setFromOpenGLMatrix(glm::value_ptr(m_node->getTransform()));
}

void GraphicalNode::SparrowMotionState::setWorldTransform(const btTransform& worldTrans)
{
    glm::mat4 t;
    worldTrans.getOpenGLMatrix(glm::value_ptr(t));
    m_node->setTransform(t);
}
