#include "pch.h"
#include "node_panel_floating.h"
#include "legacy_ui_overlay_services.h"
#include "log.h"

Node* NodePanelFloating::clone_instantiate() const
{
    return new this_class;
}

void NodePanelFloating::clone_finalize(Node* dest) const
{
    parent::clone_finalize(dest);
    auto n = static_cast<this_class*>(dest);
    n->init_controls();
}

void NodePanelFloating::init()
{
    parent::init();
    init_template_file("data/dialogs/panel-floating.xml", "tpl-panel-floating");
    init_controls();
}

void NodePanelFloating::init_controls()
{
    SetPositioning(YGPositionTypeAbsolute);
    SetPosition({ 0, 0 });
    m_mouse_ignore = false;
    m_flood_events = true;
    m_capture_children = true;
    m_container = find("container");
    m_title = find<NodeText>("title");
    m_button_minimize = find<NodeButton>("button-minimize");
    m_button_minimize->on_click = [this](Node*) {
        m_container->ToggleVisibility();
        if (m_container->m_display)
        {
            SetHeight(m_extended_size.y);
        }
        else
        {
            m_extended_size.y = GetHeight();
            SetHeight(YGUndefined);
        }
    };
    m_button_close = find<NodeButton>("button-close");
    m_button_close->on_click = [this](Node*) {
        m_container->remove_all_children();
        pp::panopainter::close_legacy_dialog_node(*this);
    };
}

void NodePanelFloating::handle_parent_resize(glm::vec2 old_size, glm::vec2 new_size)
{
    if (m_dock.expired())
    {
        auto newsize = glm::clamp(GetSize(), { 0, 0 }, m_parent->m_size);
        SetHeight(newsize.y);
        auto newpos = glm::clamp(GetPosition(), { 0, 0 }, m_parent->m_size - m_size);
        SetPosition(newpos);
    }
}

kEventResult NodePanelFloating::handle_event(Event* e)
{
    parent::handle_event(e);
    kEventResult ret = kEventResult::Available;
    auto me = static_cast<MouseEvent*>(e);
    switch (e->m_type)
    {
    case kEventType::MouseDownL:
        m_dragging = true;
        if (me->m_pos.y - m_pos.y > m_size.y - 20.f)
        {
            if (m_dock.expired() && me->m_pos.x - m_pos.x > m_size.x - 20.f)
            {
                m_action = kDragAction::Resize;
            }
            else
            {
                m_action = kDragAction::Reheight;
            }
            m_drag_start_pos = GetSize();
        }
        else
        {
            m_drag_start_pos = GetPosition();
            m_action = kDragAction::Move;
            m_outline = root()->add_child<NodeBorder>();
            m_outline->SetPositioning(YGPositionTypeAbsolute);
            m_outline->SetPosition(m_pos);
            m_outline->SetSize(GetSize());
            m_outline->m_color = { 0, 0, 0, 0.25 };
            m_outline->m_thinkness = 1;
            m_drop_placeholder = std::make_shared<NodeBorder>();
            m_drop_placeholder->SetSize(350, 10);
            m_drop_placeholder->m_color = { 0, 0, 0, 0.1 };
            m_drop_placeholder->m_thinkness = 1;
        }
        m_drag_start_cur = me->m_pos;
        mouse_capture();
        if (m_dock.expired())
            m_parent->move_child_front(this);
        ret = kEventResult::Consumed;
        break;
    case kEventType::MouseMove:
        if (m_dragging)
        {
            if (m_action == kDragAction::Move)
            {
                auto newpos = glm::clamp(m_drag_start_pos + me->m_pos - m_drag_start_cur, { 0, 0 }, m_parent->m_size - m_size);
                if (m_dock.expired())
                    SetPosition(newpos);
                m_outline->SetPosition(m_parent->m_pos + m_drag_start_pos + me->m_pos - m_drag_start_cur);
                m_outline->SetSize(GetSize());

                bool docked = false;
                if (m_droppable)
                {
                    std::vector<std::shared_ptr<Node>> nodes;
                    if (auto uir = root()->find("ui-root"))
                        nodes = uir->get_children_at_point(me->m_pos);
                    for (auto const& c : nodes)
                    {
                        if (c->m_nodeID_s.find("drop") == 0)
                        {
                            m_outline->SetPosition(c->m_pos);
                            m_outline->SetSize(c->m_size);
                            pp::panopainter::detach_legacy_node_from_parent(*m_drop_placeholder);
                            int i = 0;
                            float y = 0;
                            for (; i < c->m_children.size(); i++)
                            {
                                if (c->m_children[i] == m_drop_placeholder)
                                    continue;
                                float y = c->m_children[i]->m_pos.y - c->m_pos.y + c->m_children[i]->m_size.y / 2.f;
                                float my = me->m_pos.y - c->m_pos.y;
                                if (my <= y)
                                    break;
                            }
                            i = std::min(i, (int)c->m_children.size());
                            if (/*m_parent != c.get() && */m_drop_placeholder->m_parent != c.get())
                            {
                                c->add_child(m_drop_placeholder, i);
                            }
                            else
                            {
                                c->move_child(m_drop_placeholder.get(), i);
                            }
                            docked = true;
                            break;
                        }
                    }
                }
                if (!docked && m_drop_placeholder->m_parent)
                    pp::panopainter::detach_legacy_node_from_parent(*m_drop_placeholder);
            }
            else if (m_action == kDragAction::Reheight)
            {
                auto newsize = glm::clamp(m_drag_start_pos + me->m_pos - m_drag_start_cur, { 0, 0 }, m_parent->m_size);
                SetHeight(newsize.y);
            }
            else if (m_action == kDragAction::Resize)
            {
                auto newsize = glm::clamp(m_drag_start_pos + me->m_pos - m_drag_start_cur, { 0, 0 }, m_parent->m_size);
                SetSize(newsize);
            }
            ret = kEventResult::Consumed;
        }
        break;
    case kEventType::MouseUpL:
        m_dragging = false;
        if (m_action == kDragAction::Move)
        {
            glm::vec2 outline_pos(0);
            if (m_outline)
            {
                outline_pos = m_outline->m_pos;
                pp::panopainter::close_legacy_dialog_node(*m_outline);
            }
            int drop_pos = 0;
            if (m_drop_placeholder)
            {
                if (m_drop_placeholder->m_parent)
                    drop_pos = std::max(0, m_drop_placeholder->m_parent->get_child_index(m_drop_placeholder.get()));
                pp::panopainter::destroy_legacy_node(*m_drop_placeholder);
                pp::panopainter::detach_legacy_node_from_parent(*m_drop_placeholder);
            }
            bool docked = false;
            if (m_droppable)
            {
                std::vector<std::shared_ptr<Node>> nodes;
                if (auto uir = root()->find("ui-root"))
                    nodes = uir->get_children_at_point(me->m_pos);
                for (auto const& c : nodes)
                {
                    if (c->m_nodeID_s.find("drop") == 0)
                    {
                        SetPositioning(YGPositionTypeRelative);
                        SetPosition(0, 0);
                        if (m_dock.lock() != c)
                        {
                            SetWidth(350);
                            c->add_child(shared_from_this(), drop_pos);
                            m_dock = c;
                        }
                        else
                        {
                            c->move_child(this, std::min((int)c->m_children.size() - 1, drop_pos));
                        }
                        docked = true;
                        break;
                    }
                }
            }
            if (!docked && !m_dock.expired())
            {
                auto cont = root()->find("floatings");
                SetPositioning(YGPositionTypeAbsolute);
                auto newpos = glm::clamp(outline_pos - cont->m_pos, { 0, 0 }, cont->m_size - m_size);
                SetPosition(newpos);
                cont->add_child(shared_from_this());
                m_dock.reset();
            }
            m_outline = nullptr;
            m_drop_placeholder = nullptr;
        }
        pp::panopainter::release_legacy_mouse_capture(*this);
        ret = kEventResult::Consumed;
        break;
    default:
        break;
    }
    return ret;
}
