#include "listBox.h"
#include "graphics.hpp"
#include <iostream>
#include <math.h>

using namespace genv;
using namespace std;

int listBox::cnt;

enum pressed_type { none, increase, decrease };

/// ------------------------------------------ Események ----------------------------------------------------------
void listBox::onClick(int posX, int posY, char button)
{
    if (myScrollBar->x <= posX && posX <= myScrollBar->x + myScrollBar->width &&
        myScrollBar->y <= posY && posY <= myScrollBar->y + myScrollBar->height)
            myScrollBar->onClick(posX, posY, button);

    if (posX < x + width - myScrollBar->width || !myScrollBar->visible)
    {
        for (unsigned int i = 0; i < items.size(); i++)
        {
            if (items[i]->visible && items[i]->y < posY && posY < items[i]->y + itemHeight)
            {
                listIndex = i;
                break;
            }
        }
    }
}

void listBox::onMouseUp(int posX, int posY, char button)
{
    myScrollBar->onMouseUp(posX, posY, button);
}

void listBox::onMouseMove(int posX, int posY)
{
    if (myScrollBar->x <= posX && posX <= myScrollBar->x + myScrollBar->width &&
        myScrollBar->y <= posY && posY <= myScrollBar->y + myScrollBar->height)
            myScrollBar->onMouseMove(posX, posY);
}

void listBox::onKeyPress(char keyCode)
{
    switch (keyCode)
    {
    case (char)key_down :
        if (listIndex < items.size() - 1) listIndex++;
        if (myScrollBar->getValue() + myScrollBar->getValueWidth() <= listIndex) myScrollBar->setValue(myScrollBar->getValue() + 1);
        keyDown = increase;
        waitCounter = 0;
        break;
    case (char)key_up :
        if (0 < listIndex) listIndex--;
        if (listIndex < myScrollBar->getValue()) myScrollBar->setValue(myScrollBar->getValue() - 1);
        keyDown = decrease;
        waitCounter = 0;
        break;
    case (char)key_pgdn :
        listIndex = items.size() - 1;
        if (myScrollBar->getValue() < myScrollBar->getMaxValue() - myScrollBar->getValueWidth())
            myScrollBar->setValue(myScrollBar->getMaxValue() - myScrollBar->getValueWidth());
        break;
    case (char)key_pgup :
        listIndex = 0;
        if (myScrollBar->getValue()) myScrollBar->setValue(0);
        break;
    }
}

void listBox::onKeyUp(char keyCode)
{
    keyDown = none;
}

void listBox::onTick()
{
    myScrollBar->onTick();
    if (waitCounter*t < waitInterval)
        waitCounter++;
    else
    {
        if (keyDown == increase)
        {
            if (listIndex < items.size() - 1) listIndex++;
            if (myScrollBar->getValue() + myScrollBar->getValueWidth() <= listIndex) myScrollBar->setValue(myScrollBar->getValue() + 1);
        }
        else if (keyDown == decrease)
        {
            if (0 < listIndex) listIndex--;
            if (listIndex < myScrollBar->getValue()) myScrollBar->setValue(myScrollBar->getValue() - 1);
        }
    }
}
/// ----------------------------------------------------------------------------------------------------------------


/// ---------------------------------------- Konstruktorok ----------------------------------------------------------
listBox::listBox(int x0, int y0, unsigned int width0, unsigned int height0, vector<string> items0) :
    widget(x0, y0, width0, height0)
{
    cnt++;

    tabStop = true;
    height -= height % itemHeight;

    myScrollBar = new scrollBar(x + width, y, height, vertical ,0 , items0.size());
    myScrollBar->x -= myScrollBar->width; // csak a konstruktora lefutása után tudom megmondani a scrollBar szélességét
    myScrollBar->setValueWidth(height / itemHeight);
    if (myScrollBar->getMaxValue() == myScrollBar->getValueWidth()) myScrollBar->visible = false;

    for (unsigned int i = 0; i < items0.size(); i++)
    {
        if (myScrollBar->visible) items.push_back(new label(x, y, width - myScrollBar->width, itemHeight, items0[i]));
        else  items.push_back(new label(x, y, width, itemHeight, items0[i]));
        items[i]->setMargin(5, 0);
        items[i]->background = true;
    }

    listIndex = 0;
}
/// ----------------------------------------------------------------------------------------------------------------


/// --------------------------------------------- Get/Set ----------------------------------------------------------
void listBox::addItem(string newItem)
{
    myScrollBar->setRange(0, items.size() + 1);

    // Ha látható a scrollBar, mert amúgy nem férnek el az elemek
    if (myScrollBar->visible)
    {
        items.push_back( new label(x, y, width - myScrollBar->width, itemHeight, newItem) );
        myScrollBar->setValueWidth(height / itemHeight);
    }
    // Ha ugyan nem látszik, de már nem férnének el
    else if (height / itemHeight < myScrollBar->getMaxValue())
    {
        myScrollBar->visible = true;
        myScrollBar->setValueWidth(height / itemHeight);
        unsigned int tempWidth = width - myScrollBar->width;
        items.push_back( new label(x, y, tempWidth, itemHeight, newItem) );
        for (unsigned int i = 0; i < items.size(); i++)
        {
            items[i]->width = tempWidth;
            items[i]->setText(items[i]->getText());
        }
    }
    // Ha még így is elférnek
    else
        items.push_back( new label(x, y, width, itemHeight, newItem) );


    // mindenesetre legyen háttere, és ne legyen felső margója
    items[items.size()-1]->setMargin(5, 0);
    items[items.size()-1]->background = true;

}

string listBox::getItem(unsigned int i)
    { return items[i]->getText(); }

int listBox::getCount()
    { return items.size(); }

bool listBox::setIndex(unsigned int newValue)
{
    if (newValue < items.size())
    {
        listIndex = newValue;
        return true;
    }
    else
    {
        listIndex = items.size() - 1;
        cerr << "Given index is greater than the number of items! : listBox" + convert(cnt) + " - listBox::setIndex" << std::endl;
        return false;
    }
}

inline int listBox::getIndex()
    { return listIndex; }
/// ----------------------------------------------------------------------------------------------------------------


/// --------------------------------- Mûködéshez szükséges függvények ------------------------------------------------
void listBox::draw() const
{
    if (!visible) return;

    if (X < x + width) cerr << "Object is out of window! (X < x + width) - scrollBar" + convert(cnt) + " - scrollBar::draw" << endl;
    else if (Y < y + height) cerr << "Object is out of window! (Y < y + height) - scrollBar" + convert(cnt) + " - scrollBar::draw" << endl;

    colorize(White);
    gout << move_to(x, y) << box(width, height);

    if (myScrollBar->visible)
    {
        // Nem látható elemek elrejtése (az onClick eseményben lesz szükség rá, hogy tudjuk, melyik látható)
        for (unsigned int i = 0; i < myScrollBar->getValue(); i++)
            items[i]->visible = false;

        // Látható elemek kirajzolása
        for (unsigned int i = myScrollBar->getValue(); i < myScrollBar->getValue() + myScrollBar->getValueWidth(); i++)
        {
            if (focus && listIndex == i) items[i]->backgroundColor = ActiveColor;
            else if (listIndex == i) items[i]->backgroundColor = Gray;
            else items[i]->backgroundColor = White;
            items[i]->y = y + (i - myScrollBar->getValue())*itemHeight;
            items[i]->draw();
            items[i]->visible = true;
        }

        // Nem látható elemek elrejtése (az onClick eseményben lesz szükség rá, hogy tudjuk, melyik látható)
        for (unsigned int i = myScrollBar->getValue() + myScrollBar->getValueWidth(); i < items.size(); i++)
            items[i]->visible = false;
    }
    else
    {
        for (unsigned int i = 0; i < items.size(); i++)
        {
            if (focus && listIndex == i) items[i]->backgroundColor = ActiveColor;
            else if (listIndex == i) items[i]->backgroundColor = Gray;
            else items[i]->backgroundColor = White;
            items[i]->y = y + (i - myScrollBar->getValue())*itemHeight;
            items[i]->draw();
            items[i]->visible = true;
        }
    }

    rectange(x, y, width, height);
    myScrollBar->draw();

}
/// ----------------------------------------------------------------------------------------------------------------


/// ----------------------------------------- Detruktorok ----------------------------------------------------------
listBox::~listBox()
{
    for (unsigned int i = 0; i < items.size(); i++)
        delete items[i];
    delete myScrollBar;
}
/// ----------------------------------------------------------------------------------------------------------------



