#include "Layer.hpp"
#include "BehaviourScripts/Renderable.hpp"
#include "elements/BehaviourScript.hpp"
#include "IdGenerator.hpp"

void HandleObject(TSE::Transformable* trans, TSE::TransformationStack& stack, TSE::IRenderer& rnd)
{
    using namespace TSE;
    if(!trans->IsEnabled()) return;
    //OPTIMIZE this if statement
    if(trans->HasBehaviourScript(RENDERABLE) && trans->GetBehaviourScript(RENDERABLE)->IsEnabled() && ((Renderable*)trans->GetBehaviourScript(RENDERABLE))->GetMaterial() != nullptr && ((Renderable*)trans->GetBehaviourScript(RENDERABLE))->GetMaterial()->GetShader() != nullptr)
    {
        rnd.Submit(*trans, ((Renderable*)trans->GetBehaviourScript(RENDERABLE))->GetMaterial()->GetShader(), stack);
    }
    if(trans->GetChildren().size() > 0)
    {
        stack.Push(trans->GetLocalMatrix());
        for(auto child : trans->GetChildren())
        {
            HandleObject(child, stack, rnd);
        }
        stack.Pop();
    }
}

TSE::Layer::Layer(const string &n)
{
    ID = GenerateRandomUUID();
    name = n;
}

void TSE::Layer::Render(IRenderer &rnd) const
{
    TransformationStack stack;
    for(auto obj : objectsToRender)
    {
        HandleObject(obj, stack, rnd);
    }
}

void TSE::Layer::AddTransformable(Transformable *t)
{
    objectsToRender.push_back(t);
}

bool TSE::Layer::HasTransformable(const Transformable *t) const
{
    for(auto trans2 : objectsToRender)
    {
        if(t->id == trans2->id)
        {
            return true;
        }
    }
    return false;
}

void TSE::Layer::RemoveTransformable(const Transformable *t)
{
    RemoveTransformable(t->id);
}

void TSE::Layer::RemoveTransformable(const uuids::uuid id)
{
    auto it = objectsToRender.begin();
    for(auto trans : objectsToRender)
    {
        if(trans->id == id)
        {
            objectsToRender.erase(it);
            break;
        }
        it++;
    }
}

TSE::string TSE::Layer::GetName() const
{
    return name;
}

void TSE::Layer::SetName(const string &n)
{
    name = n;
}

std::vector<TSE::Transformable *> &TSE::Layer::GetAllObjects()
{
    return objectsToRender;
}

void TSE::Layer::Update()
{
    for(auto trans : objectsToRender)
    {
        trans->Update();
    }
}

void TSE::Layer::SetNonVisual(bool v)
{
    nonVisual = v;
}

bool TSE::Layer::IsVisual()
{
    return !nonVisual;
}
