#include "menudrop.h"
#include "core/corefactory.h"

MenuDrop::MenuDrop(const std::shared_ptr<kku::CoreFactory>& factory) :
    _is_locked(false),
    _button_height(27),
    _button_index(0)
{
    _is_visible = false;
    _content_rect = factory->getRectangle();
    _content_rect->setColor(kku::Color{200, 200, 200, 255});
}

void MenuDrop::input(const kku::SystemEvent& event)
{
    if (!_is_visible)
        return;

    Widget::input(event);

    switch (event.type)
    {
    default:
        break;

    case kku::SystemEvent::Type::MouseRelease:
    {
        const auto position = std::get<kku::SystemEvent::Mouse>(event.data).position;
        if (isUnderMouse(position))
        {
            setVisibility(false);
            for (auto& submenu : _submenus)
            {
                submenu->unlock();
                submenu->setVisibility(false);
            }
        }
        break;
    }

    case kku::SystemEvent::Type::MouseMove:
    {
        const auto position = std::get<kku::SystemEvent::Mouse>(event.data).position;
        if (!isUnderMouse(position))
        {
            if (!isLocked() && !hasActiveSubmenus())
                setVisibility(false);
        }
        break;
    }
    }
}

bool MenuDrop::hasActiveSubmenus() const
{
    return std::any_of(_submenus.begin(), _submenus.end(),
                       [](const auto& submenu) -> bool
                       {
                           return submenu->_is_visible;
                       });
}

void MenuDrop::update(const kku::microsec& dt)
{
    Widget::update(dt);
}

void MenuDrop::display() const
{
    if (_is_visible)
        _content_rect->display();

    Widget::display();
}

void MenuDrop::setRect(const kku::Area<float>& rect)
{
    _content_rect->setRect(rect);
}

void MenuDrop::setPosition(const kku::Point& position)
{
    _content_rect->setPosition(position);
}

void MenuDrop::move(const kku::Vector2<float>& delta)
{
    _content_rect->move(delta);

    Widget::move(delta);

    for (auto& submenu : _submenus)
        submenu->move(delta);
}

bool MenuDrop::isUnderMouse(const kku::Point& position) const
{
    return _is_visible && _content_rect->contains(position);
}

void MenuDrop::setVisibility(bool is_visible)
{
    Widget::setVisibility(is_visible);

    if (!is_visible)
        _is_locked = false;
}

void MenuDrop::addPushButton(const std::shared_ptr<PushButton>& button)
{
    add(button);
}

void MenuDrop::addCascadeButton(const std::shared_ptr<CascadeMenuButton>& button)
{
    auto& submenu = button->submenu();
    _submenus.emplace_back(submenu);
    add(button);

    submenu->setParent(_parent);
}

void MenuDrop::addSeparator(const std::shared_ptr<MenuSeparator>& separator)
{
    add(separator);
}

void MenuDrop::add(const std::shared_ptr<Widget> &widget)
{
    const auto& parent_rect = _content_rect->getRect();

    widget->setRect(kku::Area<float>{parent_rect.left,
                                     parent_rect.top + (parent_rect.height * _button_index),
                                     parent_rect.width,
                                     static_cast<float>(_button_height)});

    addChild(widget);
    ++_button_index;
}

void MenuDrop::lock()
{
    _is_locked = true;
}

void MenuDrop::unlock()
{
    _is_locked = false;
}

bool MenuDrop::isLocked() const
{
    return _is_locked;
}

kku::Area<float> MenuDrop::getRect() const
{
    return _content_rect->getRect();
}

kku::Point MenuDrop::getPosition() const
{
    return _content_rect->getPosition();
}
