// Dear ImGui + SDL3 + OpenGL3
#include <cmath>
#include <iostream>
#include <SDL3/SDL.h>
#include <SDL3/SDL_opengl.h>

#include "imgui_themes.h"
#include "imgui.h"
#include "imgui_impl_sdl3.h"
#include "imgui_impl_opengl3.h"

#include "digital_modulation_fr.hpp"
#include "engine.h"
#include "imgui_utils.h"
#include "modulations.h"
#include "application.h"


static void showApplicationQuitMenu()
{
    if (ImGui::BeginMenu(APPLICATION_MENU_HEAD))
    {
        if (ImGui::MenuItem(APPLICATION_QUIT, APPLICATION_QUIT_SHORTCUT) )
        {
            SDL_Event event;
            event.type = SDL_EVENT_QUIT;
            SDL_PushEvent( &event );
        }
        ImGui::EndMenu();
    }
}


int main(void)
{
    // démarrage de l'application
    Application app;
    Application *  p_app = &app;

    // --------------------- SDL INIT ---------------------
    if (!SDL_Init(SDL_INIT_VIDEO))
    {
        fprintf(stdout, "SDL init error: %s\n", SDL_GetError());
        return -1;
    }

    Engine engine;

    // -----------------IMGUI INIT---------------------------
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();

    ImGuiIO& io = ImGui::GetIO();
    ImGui::StyleColorsLight();

    ImGui_ImplSDL3_InitForOpenGL(engine.getWindow(), engine.getGL_Context());
    ImGui_ImplOpenGL3_Init(engine.get_glsl_version());

    ImGuiStyle& style = ImGui::GetStyle();
    style.FontSizeBase = 22.0f;
    io.Fonts->AddFontFromFileTTF("../fonts/DroidSans.ttf");

    // Création d'une instance de la classe DigitalModulation
    // (son initialisation est réalisée par le constructeur de la classe)
    DigitalModulation dmod;
    // Pointeur, utilisé par les différents menus
    DigitalModulation *  p_dmod = &dmod;

    // ----------------------  MAIN LOOP ----------------------
    bool done = false;

    while (!done)
    {
        SDL_Event event;
        while (SDL_PollEvent(&event))
        {
            ImGui_ImplSDL3_ProcessEvent(&event);

            switch (event.type) 
            {
                case SDL_EVENT_QUIT:
                    done = true;
                  break;

                case SDL_EVENT_WINDOW_RESIZED:
                {
                    SDL_SetWindowSize(engine.getWindow(), event.window.data1, event.window.data2);
                }
                  break;

                default:
                  break;
            }
        }

        ImGui_ImplOpenGL3_NewFrame();
        ImGui_ImplSDL3_NewFrame();
        ImGui::NewFrame();

        // Corrige le redimensionnement (se voit quand on change de thème)
        ImGui::SetNextWindowPos(ImVec2(0,27), ImGuiCond_Always);
        ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize, ImGuiCond_Always);

        ImGui::Begin( "Modulation numerique",
                      nullptr,
                      ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar 
                     | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize
                    );

        // some geometry to avoid hidden main application menu
        // on commence par calculer la place disponible et on soustrait 23.0 pixels en y
        ImVec2 windowSize(ImGui::GetIO().DisplaySize.x, ImGui::GetIO().DisplaySize.y - 23.0f);
        ImGui::SetNextWindowSize(windowSize);

        // On décale ensuite le contenu de 23.0 pixels vers le bas, ce qui représente 1 ligne environ
        ImVec2 main_viewport_pos = ImGui::GetMainViewport()->Pos;
        ImGui::SetNextWindowPos(ImVec2(main_viewport_pos.x,main_viewport_pos.y + 23.0f));

        if (ImGui::BeginMainMenuBar())
        {
            showApplicationQuitMenu();
            selectThemeMenu(p_app);
            selectFrameSize(p_dmod);
            ImGui::EndMainMenuBar();
        }

        ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_NoTooltip;

        int anErr = 0;
        if (ImGui::BeginTabBar("Modulation Numérique d'Amplitude", tab_bar_flags))
        {
            if (ImGui::BeginTabItem("Modulation numérique d'Amplitude"))
            {
                app.set_current_tab(Amplitude_TAB);
                static int am_bits[WORD_SIZE_MAX] = {0};
                static float am_carrier_freq = 2.0f;

                dmod.setDigitalModulationType(Amplitude_TAB, MOD_OOK_TYPE);
                static DigitalModulationType aType = dmod.get_AM_DigitalModulationType();

                anErr = dmod.AmplitudeDigitalModulation(&am_carrier_freq, &am_bits[0], &aType);

                if (anErr != EXIT_SUCCESS)
                {
                    std::cout << "Problème !!" << "\n";
                    return (-1);
                }
                ImGui::EndTabItem();
            }

            if (ImGui::BeginTabItem("Modulation numérique de fréquence"))
            {
                app.set_current_tab(Frequency_TAB);
                static int fm_bits[WORD_SIZE_MAX] = {0};
                static float fm_carrier_freq = 2.0f;
                dmod.setDigitalModulationType(Frequency_TAB, MOD_FSK_TYPE);

                static DigitalModulationType fm_Type = dmod.get_FM_DigitalModulationType();

                anErr = dmod.FrequencyDigitalModulation(&fm_carrier_freq, &fm_bits[0], &fm_Type);

                if (anErr != EXIT_SUCCESS)
                {
                    std::cout << "Problème !!" << "\n";
                    return (-1);
                }
                ImGui::EndTabItem();
            }

            if (ImGui::BeginTabItem("Modulation numérique de phase"))
            {
                app.set_current_tab(Phase_TAB);
                static int pm_bits[WORD_SIZE_MAX] = {0};
                static float pm_carrier_freq = 2.0f;

                dmod.setDigitalModulationType(Phase_TAB, MOD_BPSK_TYPE);
                static DigitalModulationType pm_Type = p_dmod->get_PM_DigitalModulationType();

                anErr = dmod.PhaseDigitalModulation(&pm_carrier_freq, &pm_bits[0], &pm_Type);

                if (anErr != EXIT_SUCCESS)
                {
                    std::cout << "Problème !!" << "\n";
                    return (-1);
                }
                ImGui::EndTabItem();
            }

            if (ImGui::BeginTabItem("Modulation numérique M-QAM"))
            {
                app.set_current_tab(M_QAM_TAB);
                static int pm_bits[WORD_SIZE_MAX] = {0};
                static float pm_carrier_freq = 2.0f;

                dmod.setDigitalModulationType(M_QAM_TAB, MOD_4_QAM_TYPE);
                static DigitalModulationType pm_Type = p_dmod->getM_QAM_DigitalModulationType();

                anErr = dmod.M_QAM_DigitalModulation(&pm_carrier_freq, &pm_bits[0], &pm_Type);

                if (anErr != EXIT_SUCCESS)
                {
                    std::cout << "Problème !!" << "\n";
                    return (-1);
                }
                ImGui::EndTabItem();
            }
            ImGui::EndTabBar();
        }
        ImGui::End();

        // -----------------------RENDER ----------------------
        ImGui::Render();
        glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
        glClearColor(0.95f, 0.95f, 0.95f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
        SDL_GL_SwapWindow(engine.getWindow());
    }

    // ------------------ CLEANUP ------------------
    ImGui_ImplOpenGL3_Shutdown();
    ImGui_ImplSDL3_Shutdown();
    ImGui::DestroyContext();
    engine.~Engine();
    dmod.~DigitalModulation();
    app.~Application();
    SDL_Quit();

    return 0;
}

