#include "include/controller_state.hpp"
#include <PSX/GPU/gpu.hpp>
#include <PSX/SPU/spu.hpp>

namespace ControllerTest {
    using DigitalButton = Periphery::AnalogeController::Button;
    using namespace JabyEngine;

    static void set_active(GPU::SPRT_16::Linked& sprt, bool is_active) {
        sprt->tex_offset.y = is_active ? 16 : 0;
        if(is_active) {
            SPU::voice[1].play_if_end();
        }
    }

    static void set_active(GPU::POLY_FT4::Linked& poly, bool is_active) {
        poly->tex_offset0.y = is_active ? 16 : 0;
        poly->tex_offset1.y = is_active ? 16 : 0;
        poly->tex_offset2.y = is_active ? 32 : 16;
        poly->tex_offset3.y = is_active ? 32 : 16;

        if(is_active) {
            SPU::voice[1].play_if_end();
        }
    }

    static const char* get_type_name(Periphery::ControllerType type) {
        switch(type) {
            case Periphery::ControllerType::Unkown:
                return "Unkown";

            case Periphery::ControllerType::Mouse:
                return "Mouse";

            case Periphery::ControllerType::NegCon:
                return "NegCon";

            case Periphery::ControllerType::HyperBlaster:
                return "HyperBlaster";

            case Periphery::ControllerType::Controller:
                return "Digital Controller";

            case Periphery::ControllerType::ArcadeFlightStick:
                return "Flight Stick";

            case Periphery::ControllerType::GCon:
                return "GCon";

            case Periphery::ControllerType::DualShock:
                return "DualShock";

            case Periphery::ControllerType::MultiTap:
                return "MultiTap";

            default:
                return "???";
        }
    }

    void ControllerState :: setup() {
        for(size_t n = 0; n < 2; n++) {
            GPU::LinkHelper::link_array(GPU::LinkHelper::link_array(&this->tex_page[n], this->buttons[n]), this->arrows[n]);
        }
    }
    
    void ControllerState :: update(const Periphery::AnalogeController* controller, JabyEngine::FontWriter& font_writer) {
        static const DigitalButton ButtonSprtMap[] = {
            DigitalButton::Triangle, DigitalButton::Circle, DigitalButton::Cross, DigitalButton::Square,
            DigitalButton::ST, DigitalButton::SEL, DigitalButton::L1, DigitalButton::L2, DigitalButton::R1, DigitalButton::R2,
            DigitalButton::L3, DigitalButton::R3
        };
        static const DigitalButton ArrowPolyMap[] = {
            DigitalButton::Up, DigitalButton::Right, DigitalButton::Down, DigitalButton::Left
        };

        auto& cur_button_sprts  = this->buttons[GPU::update_id()];
        auto& cur_arrow_poly    = this->arrows[GPU::update_id()];

        if(controller) {
            for(size_t n = 0; n < sizeof(ButtonSprtMap)/sizeof(ButtonSprtMap[0]); n++) {
                set_active(cur_button_sprts[n], controller->button.is_down(ButtonSprtMap[n]));
            }
            for(size_t n = 0; n < sizeof(ArrowPolyMap)/sizeof(ArrowPolyMap[0]); n++) {
                set_active(cur_arrow_poly[n], controller->button.is_down(ArrowPolyMap[n]));
            }

            set_active(cur_button_sprts[12], controller->header.state == Periphery::RawController::State::Disconnected);

            // Text stuff down here
            const auto offset_point = cur_button_sprts[1]->position;
            const auto left_stick   = controller->get_left_stick_pos();
            const auto right_stick  = controller->get_right_stick_pos();

            auto cursor = Cursor::create(offset_point.move(16, 0), 0);
            font_writer.write(cursor, "Right: %i, %i\nLeft : %i, %i\n", right_stick.x, right_stick.y, left_stick.x, left_stick.y);
            font_writer.write(cursor, "[%s]", get_type_name(static_cast<Periphery::ControllerType>(controller->get_type())));
        }

        else {
            auto cursor = Cursor::create(Make::PositionI16(cur_arrow_poly[3]->vertex0.x, cur_button_sprts[0]->position.y), 0);
            font_writer.write(cursor, "!!This Port is not\nenabled in JabyEngine!!", GPU::Color24::Red());
            this->tex_page[GPU::update_id()].terminate();
        }
    }
    
    void ControllerState :: render() {
        GPU::render(this->tex_page[GPU::render_id()]);
    }
}