#include "pch.h"
#include "log.h"
#include "util.h"
#include "app.h"
#include "canvas.h"
#include "legacy_ui_overlay_services.h"
#include "node_dialog_picker.h"
#include <stdlib.h>

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

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

void NodeColorPicker::init()
{
    init_template_file("data/dialogs/color-picker.xml", "color-picker");
    init_controls();
}

void NodeColorPicker::draw()
{
    NodeBorder::draw();
//    glm::vec3 rgb = glm::vec3(Canvas::I->m_current_brush.m_tip_color);
//    glm::vec3 hsv = convert_rgb2hsv(rgb);
//    m_slider_h->m_values = hsv.x;
//    m_slider_s->m_values = hsv.y;
//    m_slider_v->m_values = hsv.z;
//    m_slider_r->m_values = rgb.x;
//    m_slider_g->m_values = rgb.y;
//    m_slider_b->m_values = rgb.z;
//    m_wheel->m_hsv = hsv;
}

void NodeColorPicker::added(Node* parent)
{
    m_interacted = false;
}

kEventResult NodeColorPicker::handle_event(Event* e)
{
    switch (e->m_type)
    {
    case kEventType::MouseLeave:
        if (!m_interacted || !m_autohide)
            break;
        // else fall through 
    case kEventType::MouseUpL:
        if (!m_mouse_inside)
        {
            pp::panopainter::release_legacy_mouse_capture(*this);
            if (m_parent)
            {
                pp::panopainter::detach_legacy_node_from_parent(*this);
            }
            if (m_color_cur->m_color != m_color_old->m_color)
            {
                m_color_old2->m_color = m_color_old1->m_color;
                m_color_old1->m_color = m_color_old->m_color;
                m_color_old->m_color = m_color_cur->m_color;
            }
            if (on_popup_close)
            {
                on_popup_close(this);
            }
        }
        break;
    default:
        return kEventResult::Available;
        break;
    }
    return kEventResult::Available;
}

void NodeColorPicker::init_controls()
{
    m_slider_h = find<NodeSliderH>("hsv-h");
    m_slider_s = find<NodeSliderH>("hsv-s");
    m_slider_v = find<NodeSliderH>("hsv-v");
    m_slider_r = find<NodeSliderH>("rgb-r");
    m_slider_g = find<NodeSliderH>("rgb-g");
    m_slider_b = find<NodeSliderH>("rgb-b");
    m_wheel = find<NodeColorWheel>("wheel");
    m_color_cur = find<NodeBorder>("color-cur");
    m_color_old = find<NodeBorder>("color-old");
    m_color_old1 = find<NodeBorder>("color-old1");
    m_color_old2 = find<NodeBorder>("color-old2");
    m_btn_copy = find<NodeButton>("btn-hex-copy");
    m_btn_paste = find<NodeButton>("btn-hex-paste");
    m_txt_hex = find<NodeText>("txt-hex");

    m_btn_paste->on_click = [this](Node*)
    {
        std::string s = App::I->clipboard_get_text();
        std::regex r("#?([\\dabcdefABCDEF]{6})");
        std::smatch m;
        if (std::regex_search(s, m, r))
        {
            unsigned long ul = std::stoul(m[1].str(), nullptr, 16);
            uint8_t b = (ul >>  0) & 0xFF;
            uint8_t g = (ul >>  8) & 0xFF;
            uint8_t r = (ul >> 16) & 0xFF;
            auto rgb = glm::vec3(r, g, b) / 255.f;
            set_color(rgb);
            if (on_color_change)
                on_color_change(this, rgb);
        }
    };

    m_btn_copy->on_click = [this](Node*)
    {
        App::I->clipboard_set_text(m_txt_hex->m_text);
    };

    m_wheel->on_value_changed = [this](Node*, glm::vec3 hsv)
    {
        m_slider_h->m_value = hsv.x;
        m_slider_s->m_value = hsv.y;
        m_slider_v->m_value = hsv.z;
        glm::vec3 rgb = convert_hsv2rgb(hsv);
        m_slider_r->set_value(rgb.x);
        m_slider_g->set_value(rgb.y);
        m_slider_b->set_value(rgb.z);
        m_color_cur->m_color = { rgb, 1 };
        if (on_color_change)
            on_color_change(this, rgb);
        m_interacted = true;
        update_hex(rgb);
    };
    auto hsv_setter = [this](Node* target, float v)
    {
        auto hsv = get_hsv();
        m_wheel->m_hsv = hsv;
        glm::vec3 rgb = convert_hsv2rgb(hsv);
        m_color_cur->m_color = { rgb, 1 };
        m_slider_r->m_value = rgb.x;
        m_slider_g->m_value = rgb.y;
        m_slider_b->m_value = rgb.z;
        if (on_color_change)
            on_color_change(this, rgb);
        m_interacted = true;
        update_hex(rgb);
    };
    m_slider_h->on_value_changed = hsv_setter;
    m_slider_s->on_value_changed = hsv_setter;
    m_slider_v->on_value_changed = hsv_setter;

    auto rgb_setter = [this](Node* target, float v)
    {
        glm::vec3 rgb = get_rgb();
        glm::vec3 hsv = convert_rgb2hsv(rgb);
        m_wheel->m_hsv = hsv;
        m_color_cur->m_color = { rgb, 1 };
        m_slider_h->set_value(hsv.x);
        m_slider_s->set_value(hsv.y);
        m_slider_v->set_value(hsv.z);
        if (on_color_change)
            on_color_change(this, rgb);
        m_interacted = true;
        update_hex(rgb);
    };
    m_slider_r->on_value_changed = rgb_setter;
    m_slider_g->on_value_changed = rgb_setter;
    m_slider_b->on_value_changed = rgb_setter;
}

void NodeColorPicker::update_hex(glm::vec3 rgb)
{
    char tmp[32];
    snprintf(tmp, sizeof(tmp), "%x", convert_rgb_long(rgb));
    m_txt_hex->set_text_format("#%s", tmp);
}

void NodeColorPicker::set_color(glm::vec3 rgb)
{
    auto hsv = convert_rgb2hsv(rgb);
    m_slider_h->set_value(hsv.x);
    m_slider_s->set_value(hsv.y);
    m_slider_v->set_value(hsv.z);
    m_slider_r->set_value(rgb.x);
    m_slider_g->set_value(rgb.y);
    m_slider_b->set_value(rgb.z);
    m_wheel->m_hsv = hsv;
    m_color_cur->m_color = { rgb, 1 };
    m_color_old->m_color = { rgb, 1 };
    update_hex(rgb);
}

glm::vec3 NodeColorPicker::get_hsv() const
{
    float h = m_slider_h->get_value();
    float s = m_slider_s->get_value();
    float v = m_slider_v->get_value();
    return glm::vec3(h, s, v);
}

glm::vec3 NodeColorPicker::get_rgb() const
{
    float r = m_slider_r->get_value();
    float g = m_slider_g->get_value();
    float b = m_slider_b->get_value();
    return glm::vec3(r, g, b);
}
