/*
 * Gearcoleco - ColecoVision Emulator
 * Copyright (C) 2021  Ignacio Sanchez

 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses/
 *
 */

#ifndef CONFIG_H
#define CONFIG_H

#include <SDL3/SDL.h>
#include "gearcoleco.h"
#define MINI_CASE_SENSITIVE
#include "ini.h"
#include "imgui.h"

#ifdef CONFIG_IMPORT
    #define EXTERN
#else
    #define EXTERN extern
#endif

static const int config_version = 4;
static const int config_max_recent_roms = 10;
static const int config_memory_editor_count = 5;

enum config_ShaderMode
{
    config_ShaderMode_PixelPerfect = 0,
    config_ShaderMode_External = 1
};

enum config_Theme
{
    config_Theme_Light = 0,
    config_Theme_Dark = 1,
    config_Theme_Count = 2
};

enum config_VideoSync
{
    config_VideoSync_Disabled = 0,
    config_VideoSync_Fixed = 1,
    config_VideoSync_VRR = 2
};

struct config_Emulator
{
    bool maximized = false;
    bool fullscreen = false;
    int fullscreen_mode = 0;
    bool always_show_menu = false;
    int theme = config_Theme_Dark;
    bool paused = false;
    int save_slot = 0;
    bool start_paused = false;
    bool pause_when_inactive = true;
    bool ffwd = false;
    int ffwd_speed = 1;
    int runahead = 0;
    int region = 0;
    bool show_info = false;
    std::string recent_roms[config_max_recent_roms];
    std::string bios_path;
    int savefiles_dir_option = 0;
    std::string savefiles_path;
    int savestates_dir_option = 0;
    std::string savestates_path;
    int screenshots_dir_option = 0;
    std::string screenshots_path;
    std::string last_open_path;
    int window_width = 770;
    int window_height = 600;
    int spinner = 0;
    int spinner_sensitivity = 4;
    bool capture_mouse = false;
    bool status_messages = false;
    int mcp_tcp_port = 7777;
    std::string mcp_http_address = "127.0.0.1";
};

struct config_Video
{
    int scale = 0;
    int scale_manual = 1;
    int ratio = 1;
    int overscan = 1;
    bool fps = false;
    bool sprite_limit = false;
    int sync_mode = config_VideoSync_Disabled;
    float background_color[config_Theme_Count][3] = {
        {128.0f / 255.0f, 128.0f / 255.0f, 128.0f / 255.0f},
        {0.1f, 0.1f, 0.1f}
    };
    float background_color_debugger[config_Theme_Count][3] = {
        {160.0f / 255.0f, 160.0f / 255.0f, 160.0f / 255.0f},
        {0.2f, 0.2f, 0.2f}
    };
    int palette = 0;
    int shader_mode = config_ShaderMode_PixelPerfect;
    std::string shader_preset_path;
    GC_Color color[16] = {
        {255, 0, 255}, {0, 0, 0}, {33, 200, 66}, {94, 220, 120},
        {84, 85, 237}, {125, 118, 252}, {212, 82, 77}, {66, 235, 245},
        {252, 85, 84}, {255, 121, 120}, {212, 193, 84}, {230, 206, 128},
        {33, 176, 59}, {201, 91, 186}, {204, 204, 204}, {255, 255, 255}
    };
};

struct config_Audio
{
    bool enable = true;
    bool sync = true;
    float master_volume = 1.0f;
    int buffer_count = 3;
};

struct config_Rewind
{
    bool enabled = true;
    int buffer_seconds = 10;
    int frames_per_snapshot = 1;
    float speed = 2.0f;
};

struct config_Input
{
    SDL_Scancode key_left;
    SDL_Scancode key_right;
    SDL_Scancode key_up;
    SDL_Scancode key_down;
    SDL_Scancode key_left_button;
    SDL_Scancode key_right_button;
    SDL_Scancode key_blue;
    SDL_Scancode key_purple;
    SDL_Scancode key_0;
    SDL_Scancode key_1;
    SDL_Scancode key_2;
    SDL_Scancode key_3;
    SDL_Scancode key_4;
    SDL_Scancode key_5;
    SDL_Scancode key_6;
    SDL_Scancode key_7;
    SDL_Scancode key_8;
    SDL_Scancode key_9;
    SDL_Scancode key_asterisk;
    SDL_Scancode key_hash;
    bool allow_up_down;
    bool gamepad;
    int gamepad_directional;
    bool gamepad_invert_x_axis;
    bool gamepad_invert_y_axis;
    int gamepad_left_button;
    int gamepad_right_button;
    int gamepad_blue;
    int gamepad_purple;
    int gamepad_x_axis;
    int gamepad_y_axis;
    int gamepad_1;
    int gamepad_2;
    int gamepad_3;
    int gamepad_4;
    int gamepad_5;
    int gamepad_6;
    int gamepad_7;
    int gamepad_8;
    int gamepad_9;
    int gamepad_0;
    int gamepad_asterisk;
    int gamepad_hash;
};

enum config_HotkeyIndex
{
    config_HotkeyIndex_OpenROM = 0,
    config_HotkeyIndex_ReloadROM,
    config_HotkeyIndex_Quit,
    config_HotkeyIndex_Reset,
    config_HotkeyIndex_Pause,
    config_HotkeyIndex_FFWD,
    config_HotkeyIndex_SaveState,
    config_HotkeyIndex_LoadState,
    config_HotkeyIndex_Screenshot,
    config_HotkeyIndex_Fullscreen,
    config_HotkeyIndex_CaptureMouse,
    config_HotkeyIndex_ShowMainMenu,
    config_HotkeyIndex_DebugStepInto,
    config_HotkeyIndex_DebugStepOver,
    config_HotkeyIndex_DebugStepOut,
    config_HotkeyIndex_DebugStepFrame,
    config_HotkeyIndex_DebugContinue,
    config_HotkeyIndex_DebugBreak,
    config_HotkeyIndex_DebugRunToCursor,
    config_HotkeyIndex_DebugBreakpoint,
    config_HotkeyIndex_DebugGoBack,
    config_HotkeyIndex_SelectSlot1,
    config_HotkeyIndex_SelectSlot2,
    config_HotkeyIndex_SelectSlot3,
    config_HotkeyIndex_SelectSlot4,
    config_HotkeyIndex_SelectSlot5,
    config_HotkeyIndex_Rewind,
    config_HotkeyIndex_Mute,
    config_HotkeyIndex_COUNT
};

struct config_Input_Gamepad_Shortcuts
{
    int gamepad_shortcuts[config_HotkeyIndex_COUNT];
};

struct config_Hotkey
{
    SDL_Scancode key;
    SDL_Keymod mod;
    char str[64];
};

struct config_Debug
{
    bool debug = false;
    bool show_screen = true;
    bool show_disassembler = true;
    bool show_processor = true;
    bool show_call_stack = false;
    bool show_breakpoints = false;
    bool show_symbols = false;
    bool show_memory = false;
    bool show_video = false;
    bool show_video_nametable = false;
    bool show_video_tiles = false;
    bool show_video_sprites = false;
    bool show_video_palettes = false;
    bool show_video_regs = false;
    bool show_psg = false;
    bool show_ay8910 = false;
    bool show_trace_logger = false;
    bool show_rewind = false;
    bool trace_counter = true;
    bool trace_bank = true;
    bool trace_registers = true;
    bool trace_flags = true;
    bool trace_bytes = true;
    bool trace_cpu = true;
    bool trace_cpu_irq = true;
    bool trace_vdp_write = true;
    bool trace_vdp_status = true;
    bool trace_psg = true;
    bool trace_ay8910 = true;
    bool trace_io_port = true;
    bool trace_sgm = true;
    bool dis_show_mem = true;
    bool dis_show_symbols = true;
    bool dis_show_segment = true;
    bool dis_show_bank = true;
    bool dis_show_auto_symbols = true;
    bool dis_dim_auto_symbols = false;
    bool dis_replace_symbols = true;
    bool dis_replace_labels = true;
    int dis_syntax = GC_Disassembler_Syntax_Gearcoleco;
    int dis_look_ahead_count = 20;
    int font_size = 0;
    int scale = 2;
    bool multi_viewport = false;
    bool single_instance = false;
    bool auto_debug_settings = false;
    int mem_editor_bytes_per_row[config_memory_editor_count] = {16, 16, 16, 16, 16};
    int mem_editor_preview_data_type[config_memory_editor_count] = {0, 0, 0, 0, 0};
    int mem_editor_preview_endianess[config_memory_editor_count] = {0, 0, 0, 0, 0};
    bool mem_editor_uppercase_hex[config_memory_editor_count] = {true, true, true, true, true};
    bool mem_editor_gray_out_zeros[config_memory_editor_count] = {true, true, true, true, true};
};

EXTERN mINI::INIFile* config_ini_file;
EXTERN mINI::INIStructure config_ini_data;
EXTERN const char* config_root_path;
EXTERN char config_emu_file_path[512];
EXTERN char config_imgui_file_path[512];
EXTERN config_Emulator config_emulator;
EXTERN config_Video config_video;
EXTERN config_Audio config_audio;
EXTERN config_Rewind config_rewind;
EXTERN config_Input config_input[2];
EXTERN config_Input_Gamepad_Shortcuts config_input_gamepad_shortcuts[2];
EXTERN config_Hotkey config_hotkeys[config_HotkeyIndex_COUNT];
EXTERN config_Debug config_debug;

EXTERN void config_init(void);
EXTERN void config_destroy(void);
EXTERN void config_read(void);
EXTERN void config_write(void);
EXTERN void config_load_defaults(void);
EXTERN void config_push_recent_media(const std::string& path);
EXTERN void config_update_hotkey_string(config_Hotkey* hotkey);
EXTERN bool config_read_shader_parameter(const char* preset_file, const char* parameter_name, float* value);
EXTERN void config_write_shader_parameter(const char* preset_file, const char* parameter_name, float value);

#undef CONFIG_IMPORT
#undef EXTERN
#endif /* CONFIG_H */
