#include "pch.h"

#include "legacy_canvas_tool_services.h"

#include "app.h"
#include "legacy_history_services.h"

namespace pp::panopainter {
namespace {

void set_canvas_tool_button_active(Node* button, bool active)
{
    if (auto* custom = dynamic_cast<NodeButtonCustom*>(button)) {
        custom->set_active(active);
        return;
    }
    if (auto* regular = dynamic_cast<NodeButton*>(button)) {
        regular->set_active(active);
    }
}

void select_canvas_tool_button(Node* main, Node* button)
{
    main->find<NodeButtonCustom>("btn-pen")->set_active(false);
    main->find<NodeButtonCustom>("btn-erase")->set_active(false);
    main->find<NodeButtonCustom>("btn-line")->set_active(false);
    main->find<NodeButton>("btn-cam")->set_active(false);
    main->find<NodeButton>("btn-grid")->set_active(false);
    main->find<NodeButton>("btn-copy")->set_active(false);
    main->find<NodeButton>("btn-cut")->set_active(false);
    main->find<NodeButtonCustom>("btn-mask-free")->set_active(false);
    main->find<NodeButtonCustom>("btn-mask-line")->set_active(false);
    main->find<NodeButtonCustom>("btn-bucket")->set_active(false);
    set_canvas_tool_button_active(button, false);
}

kCanvasMode canvas_mode_from_tool(pp::app::CanvasToolMode mode)
{
    switch (mode) {
    case pp::app::CanvasToolMode::draw:
        return kCanvasMode::Draw;
    case pp::app::CanvasToolMode::erase:
        return kCanvasMode::Erase;
    case pp::app::CanvasToolMode::line:
        return kCanvasMode::Line;
    case pp::app::CanvasToolMode::camera:
        return kCanvasMode::Camera;
    case pp::app::CanvasToolMode::grid:
        return kCanvasMode::Grid;
    case pp::app::CanvasToolMode::copy:
        return kCanvasMode::Copy;
    case pp::app::CanvasToolMode::cut:
        return kCanvasMode::Cut;
    case pp::app::CanvasToolMode::fill:
        return kCanvasMode::Fill;
    case pp::app::CanvasToolMode::mask_free:
        return kCanvasMode::MaskFree;
    case pp::app::CanvasToolMode::mask_line:
        return kCanvasMode::MaskLine;
    case pp::app::CanvasToolMode::flood_fill:
        return kCanvasMode::FloodFill;
    }
    return kCanvasMode::Draw;
}

class LegacyCanvasToolServices final : public pp::app::CanvasToolServices {
public:
    LegacyCanvasToolServices(App* app, Node* toolbar_button = nullptr) noexcept
        : app_(app)
        , toolbar_button_(toolbar_button)
    {
    }

    void select_toolbar_button(pp::app::CanvasToolMode) override
    {
        if (app_ && toolbar_button_)
            select_canvas_tool_button(app_->layout[app_->main_id], toolbar_button_);
    }

    void set_transform_action(pp::app::CanvasToolTransformAction action) override
    {
        if (!app_ || !app_->canvas || !app_->canvas->m_canvas)
            return;

        if (action == pp::app::CanvasToolTransformAction::copy) {
            auto* transform = static_cast<CanvasModeTransform*>(
                app_->canvas->m_canvas->modes[(int)kCanvasMode::Copy][0]);
            transform->m_action = CanvasModeTransform::ActionType::Copy;
        } else if (action == pp::app::CanvasToolTransformAction::cut) {
            auto* transform = static_cast<CanvasModeTransform*>(
                app_->canvas->m_canvas->modes[(int)kCanvasMode::Cut][0]);
            transform->m_action = CanvasModeTransform::ActionType::Cut;
        }
    }

    void set_canvas_mode(pp::app::CanvasToolMode mode) override
    {
        Canvas::set_mode(canvas_mode_from_tool(mode));
    }

    void toggle_picking() override
    {
        if (!app_ || !app_->canvas || !app_->canvas->m_canvas)
            return;

        auto* mode = static_cast<CanvasModePen*>(
            app_->canvas->m_canvas->modes[(int)kCanvasMode::Draw][0]);
        if (mode)
            mode->m_picking = !mode->m_picking;
    }

    void toggle_touch_lock() override
    {
        if (!app_ || !app_->canvas || !app_->canvas->m_canvas)
            return;

        app_->canvas->m_canvas->m_touch_lock = !app_->canvas->m_canvas->m_touch_lock;
    }

private:
    App* app_ = nullptr;
    Node* toolbar_button_ = nullptr;
};

class LegacyCanvasInputToolServices final : public pp::app::CanvasToolServices {
public:
    void select_toolbar_button(pp::app::CanvasToolMode) override
    {
    }

    void set_transform_action(pp::app::CanvasToolTransformAction) override
    {
    }

    void set_canvas_mode(pp::app::CanvasToolMode mode) override
    {
        switch (mode) {
        case pp::app::CanvasToolMode::draw:
            Canvas::set_mode(kCanvasMode::Draw);
            return;
        case pp::app::CanvasToolMode::erase:
            Canvas::set_mode(kCanvasMode::Erase);
            return;
        default:
            return;
        }
    }

    void toggle_picking() override
    {
    }

    void toggle_touch_lock() override
    {
    }
};

class LegacyCanvasHotkeyServices final : public pp::app::CanvasHotkeyServices {
public:
    pp::foundation::Status execute_tool(const pp::app::CanvasToolPlan& plan) override
    {
        return execute_legacy_canvas_input_tool_plan(plan);
    }

    pp::foundation::Status execute_history(const pp::app::HistoryUiPlan& plan) override
    {
        return execute_legacy_history_plan(plan);
    }

    void save_document(pp::app::DocumentSaveIntent intent) override
    {
        if (App::I)
            App::I->save_document(intent);
    }

    void toggle_ui() override
    {
        if (App::I)
            App::I->toggle_ui();
    }

    void adjust_brush_size(float delta) override
    {
        if (!App::I || !App::I->stroke || !App::I->stroke->m_tip_size)
            return;

        const float value = App::I->stroke->m_tip_size->get_value();
        const float next_value = glm::clamp<float>(value + delta, 0.0F, 1.0F);
        App::I->stroke->set_size(next_value, true, true);
    }

    void show_cursor() override
    {
        if (App::I)
            App::I->show_cursor();
    }
};

} // namespace

pp::foundation::Status execute_legacy_canvas_tool_plan(
    App& app,
    const pp::app::CanvasToolPlan& plan,
    Node* toolbar_button)
{
    LegacyCanvasToolServices services(&app, toolbar_button);
    return pp::app::execute_canvas_tool_plan(plan, services);
}

pp::foundation::Status execute_legacy_canvas_input_tool_plan(
    const pp::app::CanvasToolPlan& plan)
{
    LegacyCanvasInputToolServices services;
    return pp::app::execute_canvas_tool_plan(plan, services);
}

pp::foundation::Status execute_legacy_canvas_hotkey_plan(
    const pp::app::CanvasHotkeyPlan& plan)
{
    LegacyCanvasHotkeyServices services;
    return pp::app::execute_canvas_hotkey_plan(plan, services);
}

} // namespace pp::panopainter
