#include "sparrowshell.h"

#include "SparrowInput/input.h"
#include "scene/scenetree.h"
#include "scene/meshnode.h"
#include "scene/textnode.h"
#include "scene/gui/backgroundnode.h"
#include "scene/gui/textinputnode.h"
#include "scriptnode.h"

#include "SparrowRenderer/mesh.h"
#include "SparrowRenderer/pbrmaterial.h"

#include "tools/font.h"
#include "resourcemanager.h"
#include "tools/loader.h"
#include <string>

const unsigned int SparrowShell::BUFFER_MAX_LENGTH = 50;
const unsigned int SparrowShell::BUFFER_DISPLAYED_LINES = 15;
const unsigned int SparrowShell::SCROLLBAR_PIXEL_WIDTH = 10;
const float SparrowShell::SHELL_DEPTH = 10;
const float SparrowShell::DEFAULT_FONT_SIZE = 16.f;

SparrowShell::SparrowShell(sf::Window* window):
    m_buffer(new ShellBuffer(BUFFER_MAX_LENGTH)),
    m_text_color(glm::vec3(0.7,1,0.3)),
    m_inputActions({NO_ACTION, NO_ACTION, NO_ACTION, NO_ACTION})
{
    sf::Vector2u size = window->getSize();
    m_dimension = glm::ivec2(size.x,DEFAULT_FONT_SIZE*(BUFFER_DISPLAYED_LINES+1));
    m_buffer->setFontSize(DEFAULT_FONT_SIZE);

    setPosition(glm::vec2(0));
    setVisible(false);

    Font* fonte_des_neiges = Loader::loadFont("data/font/consolas.fnt", "font/consolas.png");
    RESOURCE_ADD(fonte_des_neiges, Font, "shellfont");

    //Create mesh for background
    m_background = new BackGroundNode(m_dimension,glm::vec3(0.1,0.1,0.1),0.75,SHELL_DEPTH);
    //Create mesh for scrollbar
    m_scrollbar = new ShellScrollBar(this);
    m_scrollbar->moveTo2D(glm::vec2(m_dimension.x-SCROLLBAR_PIXEL_WIDTH,0));

    m_script = new ScriptNode();

    m_input_node = new TextInputNode(glm::vec2(m_buffer->getFontSize(),size.y));
    m_input_node->setPosition(glm::vec2(0,m_buffer->getFontSize()*BUFFER_DISPLAYED_LINES));
    m_input_node->setCallBack(new InputCallBack(this,m_input_node));
    m_input_node->setTabCallBack(new AutocompletionCallBack(this,m_input_node));

    this->addChild(m_background);
    this->addChild(m_buffer);
    this->addChild(m_input_node);
    this->addChild(m_scrollbar);
    this->addChild(m_script);
}

SparrowShell::InputCallBack::InputCallBack(SparrowShell* shell,TextInputNode* textinput):
    m_shell(shell),
    m_text_input_node(textinput)
{
}

SparrowShell::AutocompletionCallBack::AutocompletionCallBack(SparrowShell* shell,TextInputNode* textinput):
    m_shell(shell),
    m_text_input_node(textinput)
{
}

void SparrowShell::AutocompletionCallBack::exec(){
    std::string text = m_text_input_node->getText();
    std::vector<std::string> result = m_shell->m_script->possibleCompletion(text);
    std::string output = "";
    for(std::string& fun : result)
        output+=fun+" ";
    m_shell->out(output,glm::vec3(1,1,0));
}

void SparrowShell::InputCallBack::exec(){
    std::string text = m_text_input_node->getText();
    m_shell->out(text);
    m_shell->m_script->execute(text);
    m_text_input_node->clearText();
}

// write string str in shell
void SparrowShell::out(std::string str)
{
    out(str,m_text_color);
}

void SparrowShell::out(std::string str,glm::vec3 color)
{
    if(!str.empty()){
        Font *shellfont = RESOURCE_GET(Font,"shellfont");
        TextNode* tnode = shellfont->getTextNode(str,color,m_buffer->getFontSize(),false);
        std::string name = "shellTextLine";
        name += m_buffer->size();
        tnode->getGeometryNode()->mesh->setName(name);
        tnode->setDepth(SHELL_DEPTH+1);
        m_buffer->push(tnode);
        scrollDown();
        if (m_buffer->size() > SparrowShell::BUFFER_DISPLAYED_LINES)
            m_scrollbar->setSize(m_buffer->size());
    }
}

void SparrowShell::scrollUp()
{
    if (m_buffer->getIndex() > 0){
        m_buffer->decreaseIndex();
        m_scrollbar->setIndex(m_buffer->getIndex());
    }
}

void SparrowShell::scrollDown()
{
    if (m_buffer->getIndex() + SparrowShell::BUFFER_DISPLAYED_LINES < m_buffer->size()){
        m_buffer->increaseIndex();
        m_scrollbar->setIndex(m_buffer->getIndex());
    }
}

void SparrowShell::setInputs(int cursor_left, int cursor_right, int history_up, int history_down){
    m_inputActions[MOVE_CURSOR_LEFT] = cursor_left;
    m_inputActions[MOVE_CURSOR_RIGHT] = cursor_right;
    m_inputActions[HISTORY_PREVIOUS] = history_up;
    m_inputActions[HISTORY_NEXT] = history_down;
    m_input_node->setMoveCursorLeft(cursor_left);
    m_input_node->setMoveCursorRight(cursor_right);
}

void SparrowShell::toggleShell()
{
    if(m_shellEnabled){
        getEngine().getInput()->setCurrentContext(m_previous_context);
    }else{
        m_previous_context = getEngine().getInput()->getCurrentContext();
        getEngine().getInput()->setCurrentContext("shell");
    }
    m_shellEnabled = !m_shellEnabled;
    setVisible(m_shellEnabled);
    getEngine().getWindow()->setKeyRepeatEnabled(m_shellEnabled);
    m_input_node->setFocus(m_shellEnabled);
  //  for(auto child : m_children)
   //     child->toggleVisibility();
//    m_buffer->toggleBuffer();
}

void SparrowShell::update()
{
    if(m_shellEnabled){
        auto input = getEngine().getInput();
        int scroll = input->getDeltaVerticalScroll();
        if(scroll < 0)
            scrollDown();
        else if(scroll > 0)
            scrollUp();
    }
    GUINode::update();
}

void SparrowShell::clear(){
    m_buffer->clear();
    m_scrollbar->setIndex(m_buffer->getIndex());
    m_scrollbar->setSize(m_buffer->size());
}
