#include "ListBox.h"
#include "Button.h"
#include "Label.h"

#include <string>
#include <vector>


class ListBox::ListBoxButton : public Button {
    friend class ListBox;
public:
    ListBoxButton(Window* parent);
    virtual ~ListBoxButton();
};

ListBox::ListBoxButton::ListBoxButton(Window* parent)
: Button(parent, true)
{
    Size parentSize = _parent->getSize();

    setPosition(Point(parentSize.w() - 17.0f, 0.0f));
    setSize(Size(17.0f, parentSize.h()));

    _normalTexture = ResourceManager::instance().loadTexture(L"textures/gui/listbox_button.dds");
    _highlightedTexture = ResourceManager::instance().loadTexture(L"textures/gui/listbox_button_highlighted.dds");
    _depressedTexture = ResourceManager::instance().loadTexture(L"textures/gui/listbox_button_depressed.dds");
    _disabledTexture = ResourceManager::instance().loadTexture(L"textures/gui/listbox_button_disabled.dds");

    _texture = _normalTexture;
}

ListBox::ListBoxButton::~ListBoxButton()
{

}


class ListBox::DropDownList : public Window {
    friend class ListBox;
public:
    DropDownList(Window* parent);
    virtual ~DropDownList();

    void addItem(const wchar_t* item);
    const wchar_t* getItem(int index);

    int getSelection();
    void setSelection(int selection);

    void setRolloverItem(Window* item);

protected:
    void onListItemMouseEnter(Event& event);
    void onMouseMove(Event& event);

    int _rolloverIndex;
    std::vector<Label*> _items;
};


ListBox::DropDownList::DropDownList(Window* parent)
: Window(parent), _rolloverIndex(-1)
{
    Size parentSize = _parent->getSize();

    setPosition(Point(0.0f, parentSize.h()));
    setSize(Size(parentSize.w(), 0.0f));

    _texture = ResourceManager::instance().loadTexture(L"textures/default.dds");

    _visible = false;
}

ListBox::DropDownList::~DropDownList()
{

}

void ListBox::DropDownList::setRolloverItem(Window* item) 
{
    _rolloverIndex = -1;

    for (size_t i = 0; i < _items.size(); ++i) {
        if (item == _items[i]) {
            _rolloverIndex = (int)i;
            return;
        }
    }
}

void ListBox::DropDownList::addItem(const wchar_t* item)
{
    Size parentSize = _parent->getSize();
    setPosition(Point(0.0f, parentSize.h()));
    setSize(Size(parentSize.w(), 16.0f * (_items.size() + 1)));

    class ItemLabel : public Label {
    public:
        ItemLabel(Window* parent) : Label(parent, true) {
            connectEvent(Event::MOUSE_ENTER, this, (EventHandler)&ItemLabel::onMouseEnter);
        }

        void onMouseEnter(Event& event) {
            if (ListBox::DropDownList* parent = dynamic_cast<ListBox::DropDownList*>(_parent)) {
                parent->setRolloverItem(this);
            }
        }
    };

    ItemLabel* itemLabel = new ItemLabel(this);
    itemLabel->setPosition(Point(0.0f, 16.0f * _items.size()));
    itemLabel->setSize(Size(_size.w(), 16.0f));
    itemLabel->setCaption(item);
    _parent->connectEvent(Event::MOUSE_LEFT_CLICK, itemLabel, (EventHandler)&ListBox::onDropDownListLeftClick);


    _items.push_back(itemLabel);
}


const wchar_t* ListBox::DropDownList::getItem(int index)
{
    if ((index >= 0) && (index < (int)_items.size()))
        return _items[index]->getCaption()->getText();
    else
        return 0;
}

int ListBox::DropDownList::getSelection()
{
    return _rolloverIndex;
}

void ListBox::DropDownList::setSelection(int selection)
{
    if ((_rolloverIndex >= 0) && (_rolloverIndex < (int)_items.size())) {
        _items[_rolloverIndex]->highlight(false);
    }

    _rolloverIndex = selection;

    _items[_rolloverIndex]->highlight(true);
}


ListBox::ListBox(Window *parent)
: Window(parent), _selection(-1), _normalTexture(0), _disabledTexture(0)
{
    setPosition(Point(0.0f, 0.0f));
    setSize(Size(121.0f, 22.0f));

    _normalTexture = ResourceManager::instance().loadTexture(L"textures/gui/listbox.dds");
    _disabledTexture = ResourceManager::instance().loadTexture(L"textures/gui/listbox_disabled.dds");

    _texture = _normalTexture;

    _caption->setFont(L"Microsoft Sans Serif", L"000000", 13.0f, Text::FONT_STYLE_REGULAR, Text::H_ALIGN_LEFT | Text::V_ALIGN_CENTER);
    
    _caption->setPosition(Vector3(5.0f / _size.w(), 0.0f, 0.0f));
    _caption->setScale(Vector3((_size.w() - 5.0f) / _size.w(), 1.0f, 1.0f));
    _caption->setMaxWidth(_size.w() - 5.0f);
    _caption->setMaxHeight(_size.h());


    _button = new ListBoxButton(this);
    _list = new DropDownList(this);

    connectEvent(Event::MOUSE_LEFT_CLICK, _button, (EventHandler)&ListBox::onListBoxButtonLeftClick);
    connectEvent(Event::MOUSE_LEFT_CLICK, _list,   (EventHandler)&ListBox::onDropDownListLeftClick);
    connectEvent(Event::MOUSE_LEFT_CLICK, this,    (EventHandler)&ListBox::onLeftClick);
}

ListBox::~ListBox()
{
    delete _button;
    delete _list;
}

void ListBox::enable(bool enabled)
{
    Window::enable(enabled);

    if (_enabled) {
        _texture = _normalTexture;
    }
    else {
        _texture = _disabledTexture;
    }
}

void ListBox::setSize(Size& size)
{
    Window::setSize(size);
    _caption->setPosition(Vector3(5.0f / _size.w(), 0.0f, 0.0f));
    _caption->setScale(Vector3((_size.w() - 5.0f) / 5.0f, 1.0f, 1.0f));
    _caption->setMaxWidth(_size.w() - 5.0f);
    _caption->setMaxHeight(_size.h());
}

void ListBox::addItem(const wchar_t* item)
{
    _list->addItem(item);
}

const wchar_t* ListBox::getItem(int index)
{
    return _list->getItem(index);
    return L"";
}

int ListBox::getSelection()
{
    return _selection;
}

void ListBox::setSelection(int selection)
{
    _selection = selection;
    _list->setSelection(_selection);
    setCaption(_list->getItem(_selection));

    Event evtValueChanged;
    memset(&evtValueChanged, 0, sizeof(Event));
    evtValueChanged.type = Event::VALUE_CHANGED;
    handleEvent(evtValueChanged);
}

void ListBox::onListBoxButtonLeftClick(Event& event)
{
    _list->setVisible(_button->isToggled());
}

void ListBox::onDropDownListLeftClick(Event& event)
{
    _selection = _list->getSelection();

    _list->setVisible(false);
    _button->onMouseLeftClick(event);
    _button->onMouseLeave(event);

    setCaption(_list->getItem(_selection));

    Event evtValueChanged;
    memset(&evtValueChanged, 0, sizeof(Event));
    evtValueChanged.type = Event::VALUE_CHANGED;
    handleEvent(evtValueChanged);
}

void ListBox::onLeftClick(Event& event)
{
    _button->onMouseLeftClick(event);
    _button->onMouseLeave(event);
    _list->setVisible(_button->isToggled());
}

