#include "pch.h"
#include "log.h"
#include "node_scroll.h"
#include "event.h"
#include "shader.h"

NodeScroll::NodeScroll()
{
    m_drag_start = glm::vec2(0);
    m_offset_start = glm::vec2(0);
    m_offset = glm::vec2(0);
    m_mask = glm::vec2(0, 1);
}

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

void NodeScroll::fix_scroll()
{
    auto pad = GetPadding();
    glm::vec2 padoff = { pad.y + pad.w, pad.x + pad.z };
    auto rect = get_children_rect();
    m_offset = glm::clamp(m_offset, - zw(rect) + zw(m_clip_uncut) - padoff, { 0, 0 });
    m_pos_offset_childred = m_offset;
}

void NodeScroll::on_tick(float dt)
{
    auto pad = GetPadding();
    auto rect = get_children_rect();
    // fix scrollbar
    float sz = m_size.y - (pad[0] + pad[2]);
    float new_pad = rect.w == 0 || rect.w <= sz ? 5 : 35;
    if (pad[1] != new_pad)
    {
        YGNodeStyleSetPadding(y_node, YGEdgeRight, new_pad);
        app_redraw();
    }
}

void NodeScroll::draw()
{
    NodeBorder::draw();
    fix_scroll();
    glm::vec4 rect = get_children_rect();
    glm::vec4 pad = GetPadding();
    float sz = m_size.y - (pad[0] + pad[2]);
    float h = sz / rect.w * sz;
    float offset_percent = m_offset.y / (rect.w - sz);
    float pr = YGNodeLayoutGetPadding(y_node, YGEdgeRight) - 5;
    glDisable(GL_BLEND);
    ShaderManager::use(kShader::Color);
    ShaderManager::u_mat4(kShaderUniform::MVP, m_proj 
        * glm::translate(glm::vec3(m_pos.x + m_size.x - pr, m_pos.y - offset_percent * (sz - h) + pad[0], 0))
        * glm::scale(glm::vec3(pr, h, 1)) 
        * glm::translate(glm::vec3(.5, .5, 0))
    );
    ShaderManager::u_vec4(kShaderUniform::Col, { .3, .3, .3, 1 });
    m_plane.draw_fill();
}

kEventResult NodeScroll::handle_event(Event* e)
{
    NodeBorder::handle_event(e);
    auto me = static_cast<MouseEvent*>(e);
    auto ge = static_cast<GestureEvent*>(e);
    //auto loc = (me->m_pos - m_pos) * root()->m_zoom;
    switch (e->m_type)
    {
    case kEventType::MouseDownL:
        m_dragging = true;
        m_drag_start = me->m_pos;
        m_offset_start = m_offset;
        // if click on the scroll area use scrolling direction, otherwise natural
        m_scroll_dir = (me->m_pos.x - m_pos.x) > (m_size.x - YGNodeLayoutGetPadding(y_node, YGEdgeRight)) ? -1 : 1;
        mouse_capture();
        break;
    case kEventType::MouseMove:
        if (m_dragging)
        {
            glm::vec4 rect = get_children_rect();
            glm::vec4 pad = GetPadding();
            float speed = m_scroll_dir < 0 ? rect.w / (m_size.y - (pad[0] + pad[2])) : 1;
            m_offset = m_offset_start + (me->m_pos - m_drag_start) * m_mask * m_scroll_dir * speed;
            fix_scroll();
        }
        break;
    case kEventType::MouseUpL:
        mouse_release();
        m_dragging = false;
        break;
     case kEventType::MouseScroll:
        m_offset += me->m_scroll_delta * 50 * m_mask;
        fix_scroll();
        break;
    case kEventType::GestureStart:
        m_offset_start = m_offset;
        mouse_capture();
        break;
    case kEventType::GestureMove:
        m_offset = m_offset_start + ge->m_pos_delta * m_mask;
        fix_scroll();
        break;
    case kEventType::GestureEnd:
        mouse_release();
        break;
    case kEventType::MouseCancel:
        mouse_release();
        m_dragging = false;
        break;
    default:
        return kEventResult::Available;
        break;
    }
    return kEventResult::Consumed;
}
