#include <RuntimeStateCache/RuntimeStateCache.hpp>
#include <Sound/Sound.hpp>
#include <Widget/TabList/TabList.hpp>
#include <ToolTip/ToolTip.hpp>

void TabList::initState(std::string url)
{
    state = RuntimeStateCache::get<State>(url);
}

TabList::Page* TabList::getCurrentPage()
{
    return m_pages[std::min(state->currentPageIndex, (unsigned int) m_pages.size() - 1)];
}   

TabList::~TabList()
{
    for (Page* page : m_pages)
    {
        delete page;
    }
}

void TabList::draw(GraphicsContext &context)
{
    context.color = glm::vec4(1.0f);
    context.drawRect(0, m_size.y-1, m_size.x, 1);
    context.drawRect(0, tabHeight, 1, m_size.y - tabHeight);
    context.drawRect(m_size.x-1, tabHeight, 1, m_size.y - tabHeight);

    context.color = Color::innerBackground;
    context.drawRect(1, tabHeight, m_size[0]-2, m_size[1]-tabHeight-1);

    int plotX = 0;
    for (Page *page : m_pages)
    {
        if (page == getCurrentPage())
        {
            context.color = Color::innerBackground;
            context.drawRect(plotX+1, 1, tabWidth-2, tabHeight-1);
            context.color = glm::vec4(1.0f);
            context.drawRect(plotX, 0, tabWidth, 1);
            context.drawRect(plotX, 0, 1, tabHeight);
            context.drawRect(plotX + tabWidth - 1, 0, 1, tabHeight);
            context.drawRect(plotX + tabWidth, tabHeight-1, 2, 1);
        }
        else
        {
            context.color = Color::faded;
            context.drawRect(plotX, 0, tabWidth, 1);
            context.drawRect(plotX, 0, 1, tabHeight);
            context.drawRect(plotX + tabWidth - 1, 0, 1, tabHeight);
            context.color = Color::tabBackground;
            context.drawRect(plotX+1, 1, tabWidth-2, tabHeight-2);
            context.color = glm::vec4(1.0f);
            context.drawRect(plotX, tabHeight-1, tabWidth+2, 1);
        }

        context.drawMaterial(page->icon, plotX+4, 4);

        if (m_mousePos[0] > plotX && m_mousePos[0] < plotX+tabWidth && m_mousePos[1] >= 0 && m_mousePos[1] < tabHeight)
        {
            ToolTip &tip = context.createToolTip();
            tip.addLine(glm::vec4(1.0f), page->tip);
        }

        plotX += tabWidth + tabSpacing;
    }

    context.drawRect(plotX, tabHeight-1, m_size.x, 1);

    context.pushViewport();
    context.clipViewport(glm::ivec2(bodyMargin, tabHeight+bodyMargin-1), m_size - glm::ivec2(2*bodyMargin, tabHeight+2*bodyMargin-1));
    getCurrentPage()->body->draw(context);
    context.popViewport();
}

glm::ivec2 TabList::getMinSize()
{
    int longestPageWidth = 0, longestPageHeight = 0;

    for (Page *page : m_pages)
    {
        glm::ivec2 pageMinSize = page->body->getMinSize();
        longestPageWidth = std::max(longestPageWidth, pageMinSize[0]);
        longestPageHeight = std::max(longestPageHeight, pageMinSize[1]);
    }

    return glm::ivec2(
        std::max(longestPageWidth + 2 * bodyMargin, (int) m_pages.size() * (tabWidth + tabSpacing)),
        tabHeight + longestPageHeight + 2 * bodyMargin
    );
}

void TabList::onResize(glm::ivec2 newSize)
{
    Widget::onResize(newSize);

    glm::ivec2 clientSize = newSize;
    clientSize[0] -= 2 * bodyMargin;
    clientSize[1] -= (tabHeight + 2 * bodyMargin - 1);
    
    // All pages need resizing.
    for (Page *page : m_pages)
    {
        page->body->onResize(clientSize);
    }
}

void TabList::onMouseMoved(glm::ivec2 pos)
{
    Widget::onMouseMoved(pos);

    glm::ivec2 bodyPos = glm::ivec2(bodyMargin, tabHeight+bodyMargin-1);
    getCurrentPage()->body->onMouseMoved(pos - bodyPos);
}

void TabList::onMouseUp(Uint8 button)
{
    Widget::onMouseUp(button);

    getCurrentPage()->body->onMouseUp(button);
}

void TabList::onMouseDown(Uint8 button)
{
    if (button == SDL_BUTTON_LEFT && m_mousePos[1] < tabHeight && m_mousePos[1] >= 0 && m_mousePos[0] >= 0)
    {
        Widget::onMouseDown(button);

        int newTabIndex = m_mousePos[0] / (tabWidth+tabSpacing);
        if (newTabIndex >= (int) m_pages.size())
        {
            return;
        }

        int offset = m_mousePos[0] % (tabWidth+tabSpacing);
        if (offset >= tabWidth)
        {
            return;
        }

        if (getCurrentPage() != m_pages[newTabIndex])
        {
            Sound::pageFlip.play();
        }

        state->currentPageIndex = newTabIndex;
        return;
    }

    getCurrentPage()->body->onMouseDown(button);
}

void TabList::onScroll(int delta)
{
    Widget::onScroll(delta);
    getCurrentPage()->body->onScroll(delta);
}

void TabList::getInternalTabOrder(std::vector<Widget*> &tabOrder)
{
    getCurrentPage()->body->getInternalTabOrder(tabOrder);
}