#include "TemplateElements.h"

#include "StringUtils.h"
#include "TemplateSubstitutionContext.h"

#include <iostream>

TemplateExtends::TemplateExtends(TemplateNode* parent, const std::string& path)
    : TemplateNode(parent)
{
    mPath = StringUtils::stripQuotes(path);
};

std::string TemplateExtends::getRawContent() const
{
    return "TemplateExtends: " + mPath;
}

std::string TemplateExtends::getPath() const
{
    return mPath;
}

TemplateBlock::TemplateBlock(TemplateNode* parent, const std::string& name)
    : TemplateNode(parent),
    mName(name)
{

}

void TemplateBlock::addLine(const std::string& line)
{
    mBody.push_back(line);
}

std::string TemplateBlock::getRawContent() const
{
    std::string content = "TemplateBlock: " + mName + " - Start \n";
    content += TemplateNode::getRawContent();
    content += "TemplateBlock: " + mName + " - End";
    return content;
}

std::string  TemplateBlock::getIdentifier() const
{
    return mName;
}

std::string TemplateBlock::renderAsParent(TemplateSubstitutionContext* substitutions, TemplateBlock* base)
{
    std::string content;
    for (auto& child : mChildren)
    {
        if (child->getType() == Type::EXPRESSION)
        {
            auto expression = dynamic_cast<TemplateExpression*>(child.get());
            if (expression->getContent() == "super()")
            {
                content += base->render(substitutions, nullptr);
            }
        }
        else if(child->getType() == Type::TEXT_BODY)
        {
            content += child->render(substitutions, nullptr);
        }
    }
    return content;
}

std::string TemplateBlock::renderAsLeaf(TemplateSubstitutionContext* substitutions)
{
    std::string content;
    for (auto& child : mChildren)
    {
        if(child->getType() == Type::TEXT_BODY)
        {
            content += child->render(substitutions, nullptr);
        }
    }
    return content;
}

std::string TemplateBlock::render(TemplateSubstitutionContext* substitutions, TemplateNode* parentContext)
{
    std::string content;
    if (parentContext)
    {
        if (auto parent_node = parentContext->getFirstChildShallow(Type::BLOCK, getIdentifier()))
        {
            content = dynamic_cast<TemplateBlock*>(parent_node)->renderAsParent(substitutions, this);
        }
        else
        {
            content= renderAsLeaf(substitutions);
        }
    }
    else
    {
        content= renderAsLeaf(substitutions);
    }
    return content;
}

TemplateExpression::TemplateExpression(TemplateNode* parent, const std::string& content)
    : TemplateNode(parent),
    mContent(content)
{

}

const std::string& TemplateExpression::getContent() const
{
    return mContent;
}

std::string TemplateExpression::render(TemplateSubstitutionContext* substitutions, TemplateNode*)
{
    if (substitutions && substitutions->hasSubstitution(mContent))
    {
        return substitutions->getSubstitution(mContent);
    }
    return {};
}

std::string TemplateExpression::getRawContent() const
{
    return "TemplateExpression: " + mContent;
}

TemplateTextBody::TemplateTextBody(TemplateNode* parent)
        : TemplateNode(parent)
{

}

void TemplateTextBody::addLine(const std::string& content)
{
    mContent.push_back(content);
}

bool TemplateTextBody::hasContent() const
{
    return !mContent.empty();
}

std::string TemplateTextBody::render(TemplateSubstitutionContext*, TemplateNode*)
{
    std::string content;
    for(unsigned idx=0; idx<mContent.size(); idx++)
    {
        content += mContent[idx];
        if(idx != mContent.size() - 1)
        {
            content += '\n';
        }
    }
    return content;
}

std::string TemplateTextBody::getRawContent() const
{
    std::string content;
    for(unsigned idx=0; idx<mContent.size(); idx++)
    {
        content += "Template Body L-" + std::to_string(idx) + ": " + mContent[idx];
        if(idx != mContent.size() - 1)
        {
            content += '\n';
        }
    }
    return content;
}
