/**
 * @file Layout.cpp
 * @author apio (cloudapio.eu)
 * @brief Layout widgets to organize content.
 *
 * @copyright Copyright (c) 2023, the Luna authors.
 *
 */

#include <stdlib.h>
#include <ui/Layout.h>

namespace ui
{
    HorizontalLayout::HorizontalLayout(AdjustHeight adjust_height, AdjustWidth adjust_width)
        : m_adjust_height(adjust_height), m_adjust_width(adjust_width)
    {
    }

    Result<EventResult> HorizontalLayout::handle_mouse_move(Point position)
    {
        EventResult result = ui::EventResult::DidNotHandle;

        for (auto widget : m_widgets)
        {
            if (widget->rect().contains(position)) result = TRY(widget->handle_mouse_move(position));
            else
                TRY(widget->handle_mouse_leave(position));
        }

        return result;
    }

    Result<EventResult> HorizontalLayout::handle_mouse_leave(Point position)
    {
        for (auto widget : m_widgets) TRY(widget->handle_mouse_leave(position));

        return ui::EventResult::DidNotHandle;
    }

    Result<EventResult> HorizontalLayout::handle_mouse_up(Point position, int buttons)
    {
        for (auto widget : m_widgets)
        {
            if (widget->rect().contains(position)) return widget->handle_mouse_up(position, buttons);
        }

        return ui::EventResult::DidNotHandle;
    }

    Result<EventResult> HorizontalLayout::handle_mouse_down(Point position, int buttons)
    {
        for (auto widget : m_widgets)
        {
            if (widget->rect().contains(position)) return widget->handle_mouse_down(position, buttons);
        }

        return ui::EventResult::DidNotHandle;
    }

    Result<void> HorizontalLayout::draw(Canvas& canvas)
    {
        for (auto widget : m_widgets)
        {
            ui::Rect rect = { m_rect.relative(widget->rect().pos), widget->rect().width, widget->rect().height };
            auto subcanvas = canvas.subcanvas(rect);
            TRY(widget->draw(subcanvas));
        }

        return {};
    }

    Result<void> HorizontalLayout::add_widget(Widget& widget)
    {
        TRY(m_widgets.try_append(&widget));

        if (m_adjust_width == AdjustWidth::No)
        {
            widget.rect().pos.x = m_rect.pos.x + m_used_width;
            m_used_width += widget.rect().width;
        }
        else
        {
            int used_width = 0;
            div_t result = div(m_rect.width, (int)m_widgets.size());
            for (auto w : m_widgets)
            {
                w->rect().pos.x = m_rect.pos.x + used_width;
                w->rect().width = result.quot;
                used_width += result.quot;
            }
            m_widgets[m_widgets.size() - 1]->rect().width += result.rem;
        }

        widget.rect().pos.y = m_rect.pos.y;

        if (m_adjust_height == AdjustHeight::Yes) { widget.rect().height = m_rect.height; }

        widget.set_parent(this);

        return {};
    }

    VerticalLayout::VerticalLayout(AdjustHeight adjust_height, AdjustWidth adjust_width)
        : m_adjust_height(adjust_height), m_adjust_width(adjust_width)
    {
    }

    Result<EventResult> VerticalLayout::handle_mouse_move(Point position)
    {
        EventResult result = ui::EventResult::DidNotHandle;

        for (auto widget : m_widgets)
        {
            if (widget->rect().contains(position)) result = TRY(widget->handle_mouse_move(position));
            else
                TRY(widget->handle_mouse_leave(position));
        }

        return result;
    }

    Result<EventResult> VerticalLayout::handle_mouse_leave(Point position)
    {
        for (auto widget : m_widgets) TRY(widget->handle_mouse_leave(position));

        return ui::EventResult::DidNotHandle;
    }

    Result<EventResult> VerticalLayout::handle_mouse_up(Point position, int buttons)
    {
        for (auto widget : m_widgets)
        {
            if (widget->rect().contains(position)) return widget->handle_mouse_up(position, buttons);
        }

        return ui::EventResult::DidNotHandle;
    }

    Result<EventResult> VerticalLayout::handle_mouse_down(Point position, int buttons)
    {
        for (auto widget : m_widgets)
        {
            if (widget->rect().contains(position)) return widget->handle_mouse_down(position, buttons);
        }

        return ui::EventResult::DidNotHandle;
    }

    Result<void> VerticalLayout::draw(Canvas& canvas)
    {
        for (auto widget : m_widgets)
        {
            ui::Rect rect = { m_rect.relative(widget->rect().pos), widget->rect().width, widget->rect().height };
            auto subcanvas = canvas.subcanvas(rect);
            TRY(widget->draw(subcanvas));
        }

        return {};
    }

    Result<void> VerticalLayout::add_widget(Widget& widget)
    {
        TRY(m_widgets.try_append(&widget));

        if (m_adjust_height == AdjustHeight::No)
        {
            widget.rect().pos.y = m_rect.pos.y + m_used_height;
            m_used_height += widget.rect().height;
        }
        else
        {
            int used_height = 0;
            div_t result = div(m_rect.height, (int)m_widgets.size());
            for (auto w : m_widgets)
            {
                w->rect().pos.y = m_rect.pos.y + used_height;
                w->rect().height = result.quot;
                used_height += result.quot;
            }
            m_widgets[m_widgets.size() - 1]->rect().height += result.rem;
        }

        widget.rect().pos.x = m_rect.pos.x;

        if (m_adjust_width == AdjustWidth::Yes) { widget.rect().width = m_rect.width; }

        widget.set_parent(this);

        return {};
    }
}