local mod = {}

local settings = require('common.settings')
local colors = settings.colors
local fonts = settings.fonts
local lap = require('sectors.lap')
local players = require('common.players')

local storage = nil
local save_settings = false

MFD_Row1 = table.new(10,0)
MFD_Row2 = table.new(10,0)
MFD_Row3 = table.new(10,0)
MFD_Row4 = table.new(10,0)
MFD_Row5 = table.new(10,0)

MFD_PRESETS = table.new(10,0)


local mfd_preset_count_storage = ac.storage('MFD_PresetCount', 0)
MFD_PresetCount = 0
MFD_PresetIndex = 0
MFD_Save_Preset_Car = false


MFDAbs              = 0 -- will be replaced later
MFDTractionControl  = 0 -- will be replaced later
MFDTractionControl2 = 0 -- will be replaced later
MFDBrakeBias        = 0 -- will be replaced later
MFDWipers           = 0 -- will be replaced later
MFDLights           = 0 -- will be replaced later
MFDTurningLights    = 0 -- will be replaced later
MFDPitLimiter       = 0 -- will be replaced later
MFDFuelPerLap       = 0 -- will be replaced later
MFDFuelTimeLeft     = 0 -- will be replaced later
MFDFuelForWholeRace = 0 -- will be replaced later
MFDFuelToAdd        = 0 -- will be replaced later
MFDRacePosition     = 0 -- will be replaced later
MFDPitlaneTimer     = 0 -- will be replaced later



MFD_Type = {
    ABS = 0,
    BRAKE_BIAS = 1,
    LIGHTS = 2,
    PIT_LIMITER = 3,
    TRACTION_CONTROL = 4,
    TRACTION_CONTROL2 = 5,
    TURNING_LIGHTS = 6,
    WIPERS = 7,
    FUEL_PER_LAP = 8,
    FUEL_TIME_REMAINING = 9,
    FUEL_TO_COMPLETE_WHOLE_RACE = 10,
    FUEL_TO_ADD_TO_FINISH_RACE = 11,
    PLAYER_RACE_POSITION = 12,
    PITLANE_TIMER = 13,
}

Deltabar_Modes = {
    SESSION_LAP=0,
    SESSION_OPTIMAL=1,
    FASTEST_LAP=2,
    FASTEST_OPTIMAL=3,
    PREVIOUS_LAP=4,
    MULTIPLAYER_LAP=5
}

Deltabar_ShowSectorsPerMode = table.new(table.nkeys(Deltabar_Modes), 0) -- if false visualize data on the ENTIRE lap
Gearbox_MGUKModeStartTime = -10
Leaderboard_Extended_ThisFrame = false

Sectors_UserRequestedFastestLap = false
Sectors_UserRequestedFastestLapTime = -10

Leaderboard_Multiclass_EnabledTags = table.new(20, 0)
Leaderboard_Multiclass_EnabledTime = -1
Leaderboard_Multiclass_UpdateTags = true
Leaderboard_Relative_ChangedThisFrame = false
local color_buttons = table.new(8, 0)
local editing_color = false -- enabled when user is making is own custom color
local editing_color_idx = -1

local function append_tag(name, color)
    Leaderboard_Multiclass_EnabledTags[table.nkeys(Leaderboard_Multiclass_EnabledTags)] = {
        name=name, color=color,
    }
end

-- multiclass colors
local mc_color1 = rgbm(110 / 255, 255 / 255, 87  / 255, 1) -- green
local mc_color2 = rgbm(87  / 255, 162 / 255, 255 / 255, 1) -- blue
local mc_color3 = rgbm(255 / 255, 88  / 255, 87  / 255, 1) -- red
local mc_color4 = rgbm(233 / 255, 255 / 255, 87  / 255, 1) -- yellow
local mc_color5 = rgbm(87  / 255, 249 / 255, 255 / 255, 1) -- cyan
local mc_color6 = rgbm(255 / 255, 87  / 255, 192 / 255, 1) -- magenta
local mc_color7 = rgbm(255 / 255, 164 / 255, 87  / 255, 1) -- orange
local mc_color_count_storage = ac.storage("Multiclass_ExtraColors", 0)
local mc_tags_count_storage = ac.storage("Multiclass_TagsData", 3)

---@class LayoutData
---@field name string @Layout name
---@field app_positions table @Layout positions for each app (aka map<APPNAME, vec2>)
---@field deltabar_size number|nil @Horizontal deltabar size
---@field apps_settings table @Table<settings_name, CurrentSetting> of all the CMRT settings that we load/store in the layout.
---@field binding ac.ControlButton @Binding to activate this layout specifically

CustomLayout_CurrentIndex = 0 -- default layout is 0, from 1 upwards your custom ones
local layouts_count = 0
local layout_count_storage = ac.storage("CustomLayout_Count", 0)
local layout_name_editing_index = -1
local last_used_layout_storage = ac.storage("CustomLayout_LastUsed_v1", 0)

---@type LayoutData[]
CustomLayouts_Data = table.new(5, 0)

-- TAG: StorageSavesOnlyNumbers
-- because we want dynamic layout storage we can't use ac.storage{ pos = vec2(), ...}
-- and since we have to use the string we can't save a vec2 because when we load it we get a 
-- string that we cannot parse, so we split on the x and y axis, which saves 2 numbers
-- which when we read are strings too but at least we can convert them to number...
-- This has been an issue even before, but I'm explaining it in this comment now.
--                          Cogno 2024/08/20
-- UPDATE: 1
-- I did some minor investigation. If we save a number using ac.storage("any", 0) then we 
-- will get back a number, but if we save using ac.storage("any", nil) then we will get back 
-- a string instead. The nil seems to change the context from "just numbers" to "can be nil so we 
-- use string instead". I haven't checked, but it might be that vec2() has that problem too
-- because we use nil. Maybe ac.storage("any", vec2()) will work and give back a vec2 instead?
--
-- Anyway, for our use cases we cannot use vec2() directly because the default vec2() is (0, 0),
-- which would mean moving each app in the top left corner, which we don't want.
--                          Cogno 2024/08/22


-- TAG: StorageSavesOnlyNumbers
local function get_layout_pos_from_storage(name, index)
    local x_value = ac.storage(string.format("V1_CustomLayout_Pos_%s_%d_x", name, index), nil):get()
    local y_value = ac.storage(string.format("V1_CustomLayout_Pos_%s_%d_y", name, index), nil):get()
    if x_value == nil or y_value == nil then return nil end
    local out = vec2(tonumber(x_value), tonumber(y_value))
    return out
end

-- TAG: StorageSavesOnlyNumbers
local function set_layout_pos_to_storage(name, index, pos)
    ac.storage(string.format("V1_CustomLayout_Pos_%s_%d_x", name, index), nil):set(pos.x)
    ac.storage(string.format("V1_CustomLayout_Pos_%s_%d_y", name, index), nil):set(pos.y)
end

local function get_deltabar_horizontal_size()
    local deltabar_win, deltabar_name = settings.get_window_and_name(APPNAMES.deltabar)
    if deltabar_win == nil then return nil end
    return deltabar_win:size().x
end

---@class CurrentSetting
---@field access_string string @String used to access the variable in the storage, also used to make dynamic storages by appending numbers
---@field value integer|boolean @Current/Saved value for the variable


---@class StorageSetting
---@field access_string string @String used to access the variable in the storage, also used to make dynamic storages by appending numbers
---@field default_value integer|boolean @Default value for the variable
---@field storage ac.StoredValue @Storage access to load/save values

---@param access_string string
---@param default_value integer|boolean
---@return StorageSetting
local function make_setting_storage(access_string, default_value)
    return {
        access_string=access_string,
        default_value=default_value,
        storage = ac.storage(access_string, default_value)
    }
end

-- TAG: AddingANewSettingVariable
-- If you want to add a new settings, you have to change (as of now) 3 spots.
-- 1. This table below, add a new variable with a new name and it's default value.
-- 2. In function apply_apps_settings() load your variable into the GlobalVariable, so your app can use it
-- 3. In function make_table_from_current_settings() set the GlobalVariable into your variable
-- Each of these 3 has pretty obvious patterns to follow (like GlobalVariable = settings.<your_variable_name>.value at step 2).
--
-- I obviously very gladly accept suggestions on how to make this simpler.
--
--                                 Cogno 2024/08/22
local settings_data = {
    apps_auto_scale                       = make_setting_storage("Settings_General_AutoScaleApps", true),

    semaphores_scale                      = make_setting_storage("Settings_Semaphores_Scale", 1),
    semaphores_enabled                    = make_setting_storage("Settings_Semaphores_Enabled", true),

    gearbox_scale                         = make_setting_storage("Settings_Gearbox_Scale", 1),
    gearbox_dots_window                   = make_setting_storage("Settings_Gearbox_DotsWindow", true),
    gearbox_mguk_mode                     = make_setting_storage("Settings_Gearbox_MGUKMode", false),
    gearbox_info_mode                     = make_setting_storage("Settings_Gearbox_InfoMode", true),
    gearbox_mguk_info_mode                = make_setting_storage("Settings_Gearbox_MGUK_Info_Mode", false),
    gearbox_ers_mode                      = make_setting_storage("Settings_Gearbox_ERSMode", false),
    gearbox_mph_storage                   = make_setting_storage("Gearbox_ShowMph_v2", false), -- this comes from a previous transition, no need to do it again
    gearbox_gal_storage                   = make_setting_storage("Gearbox_ShowGal_v2", false), -- this comes from a previous transition, no need to do it again
    gearbox_peak_rpm_enabled              = make_setting_storage("Gearbox_PeakRPMEnabled", false),

    pctime_scale                          = make_setting_storage("Settings_PcTime_Scale", 1),
    pctime_bg                             = make_setting_storage("Settings_PcTime_Bg", true),
    pctime_bar                            = make_setting_storage("Settings_PcTime_Bar", false),
    
    maptime_scale                         = make_setting_storage("Settings_Maptime_Scale", 1),
    maptime_bg                            = make_setting_storage("Settings_Maptime_Bg", true),
    maptime_bar                           = make_setting_storage("Settings_Maptime_Bar", true),
    
    sectors_scale                         = make_setting_storage("Settings_Sectors_Scale", 1),
    sectors_anim_duration                 = make_setting_storage("Settings_Sectors_Anim_Duration", 8),

    leaderboard_scale                     = make_setting_storage("Settings_Leadeboard_Scale", 1),
    leaderboard_anim_duration             = make_setting_storage("Settings_Leadeboard_Anim_Duration", 18),
    leaderboard_fah                       = make_setting_storage("Settings_Leadeboard_Fah", false),
    leaderboard_show_tyres                = make_setting_storage("Settings_Leadeboard_ShowTyres", true),
    leaderboard_refresh_rate              = make_setting_storage("Settings_Leadeboard_RefreshRate", 2000),
    leaderboard_people_count              = make_setting_storage("Settings_Leadeboard_PeopleCount", 2),
    leaderboard_hotlap_count              = make_setting_storage("Settings_Leadeboard_HotlapCount", 5),
    leaderboard_show_extended             = make_setting_storage("Settings_Leadeboard_Extended", false),
    leaderboard_show_air_temp             = make_setting_storage("Settings_Leadeboard_ShowAirTemp", true),
    leaderboard_show_tarmac_temp          = make_setting_storage("Settings_Leadeboard_ShowTarmacTemp", true),
    leaderboard_show_grip_precent         = make_setting_storage("Settings_Leadeboard_ShowGripPercent", false),
    leaderboard_show_wind_info            = make_setting_storage("Settings_Leadeboard_ShowWindInfo", false),
    leaderboard_session_scrolling_speed   = make_setting_storage("Settings_Leadeboard_SessionScrollingSpeed", 0),
    leaderboard_relative                  = make_setting_storage("Settings_Leadeboard_Relative", false),
    leaderboard_relative_refresh_rate     = make_setting_storage("Settings_Leadeboard_Relative_RefreshRate", 2000),
    leaderboard_people_count_relative     = make_setting_storage("Settings_Leadeboard_Relative_PeopleCount", 2),
    leaderboard_multiclass_enabled        = make_setting_storage("Settings_Leadeboard_Multiclass_Enabled", false),
    leaderboard_multiclass_filter_enabled = make_setting_storage("Settings_Leadeboard_Multiclass_FilterEnabled", true),
    leaderboard_show_player_count         = make_setting_storage("Settings_Leaderboard_ShowPlayerCount", false),
    leaderboard_show_weather              = make_setting_storage("Settings_Leaderboard_ShowWeather", false),
    leaderboard_scroll_longnames          = make_setting_storage("Settings_Leaderboard_Scroll_LongNames", false),
    leaderboard_show_carnames             = make_setting_storage("Settings_Leaderboard_ShowCarNames", false),

    tyres_scale                           = make_setting_storage("Settings_Tyres_Scale", 1),
    tyres_show_pedals                     = make_setting_storage("Settings_Tyres_ShowPedals", true),
    tyres_show_fah                        = make_setting_storage("Settings_Tyres_ShowFah", false),
    tyres_show_mph                        = make_setting_storage("Settings_Tyres_ShowMph", false),
    tyres_temp_colored                    = make_setting_storage("Settings_Tyres_TemperatureColored", true),
    tyres_pressure_delta                  = make_setting_storage("Settings_Tyres_PressureDelta", true),
    tyres_show_info_panel                 = make_setting_storage("Settings_Tyres_ShowInfoPanel", false),
    tyres_click_priority                  = make_setting_storage("Settings_Tyres_ClickPriority", false),
    tyres_auto_info_panel                 = make_setting_storage("Settings_Tyres_AutoInfoPanel", true),
    tyres_flip_info_panel                 = make_setting_storage("Settings_Tyres_FlipInfoPanel", false),

    map_scale                             = make_setting_storage("Settings_Map_Scale", 1),
    map_low_profile                       = make_setting_storage("Settings_Map_LowProfile", true),
    map_relative                          = make_setting_storage("Settings_Map_Relative", false),
    map_remove_bg                         = make_setting_storage("Settings_Map_RemoveBg", false),
    map_remove_bg_when_data_missing       = make_setting_storage("Settings_Map_RemoveBgWhenDataMissing", false),
    map_show_drs                          = make_setting_storage("Settings_Map_ShowDRS", false),
    
    pedals_scale                          = make_setting_storage("Settings_Pedals_Scale", 1),
    pedals_show_gas                       = make_setting_storage("Settings_Pedals_ShowGas", true),
    pedals_show_brk                       = make_setting_storage("Settings_Pedals_ShowBrake", true),
    pedals_show_handbrk                   = make_setting_storage("Settings_Pedals_ShowHandbrake", false),
    pedals_show_clt                       = make_setting_storage("Settings_Pedals_ShowClutch", false),
    pedals_show_ffb                       = make_setting_storage("Settings_Pedals_ShowFfb", false),
    pedals_show_telemetry                 = make_setting_storage("Settings_Pedals_ShowTelemetry", false),
    pedals_show_gear_shifts               = make_setting_storage("Settings_Pedals_ShowGearShifts", false),
    
    radar_scale                           = make_setting_storage("Settings_Radar_Scale", 1),
    radar_show_dots                       = make_setting_storage("Settings_Radar_ShowDots", true),
    radar_show_double_lines               = make_setting_storage("Settings_Radar_ShowDoubleLines", true),
    radar_show_players                    = make_setting_storage("Settings_Radar_ShowPlayers", true),
    radar_rotate_cars                     = make_setting_storage("Settings_Radar_RotateCars", false),
    radar_extra_warning                   = make_setting_storage("Settings_Radar_ExtraWarning", false),
    radar_always_visible                  = make_setting_storage("Settings_Radar_AlwaysVisible", false),
    radar_show_extended                   = make_setting_storage("Settings_Radar_ShowExtended", false),
    
    deltabar_scale                        = make_setting_storage("Settings_Deltabar_Scale", 1),
    deltabar_practice_mode                = make_setting_storage("Settings_Deltabar_PracticeMode", 0),
    deltabar_qualify_mode                 = make_setting_storage("Settings_Deltabar_QualifyMode", 0),
    deltabar_race_mode                    = make_setting_storage("Settings_Deltabar_RaceMode", 0),
    deltabar_anim_duration                = make_setting_storage("Settings_Deltabar_AnimDuration", 8),
    deltabar_save_on_close                = make_setting_storage("Settings_Deltabar_SaveOnClose", false),
    deltabar_minimized                    = make_setting_storage("Settings_Deltabar_Minimized", false),
    deltabar_position                     = make_setting_storage("Settings_Deltabar_Position", 1),

    damage_panel_scale                    = make_setting_storage("Settings_DamagePanel_Scale", 1),
    always_show_damage_panel              = make_setting_storage("Settings_DamagePanel_ShowAlways", false),

    mfd_scale                             = make_setting_storage("Settings_MFD_Scale", 1),
    mfd_abs                               = make_setting_storage("Settings_MFD_Abs", 0),
    mfd_traction_control                  = make_setting_storage("Settings_MFD_TC", 0),
    mfd_traction_control2                 = make_setting_storage("Settings_MFD_TC2", 0),
    mfd_brake_bias                        = make_setting_storage("Settings_MFD_BrakeBias", 0),
    mfd_wipers                            = make_setting_storage("Settings_MFD_Wipers", 0),
    mfd_lights                            = make_setting_storage("Settings_MFD_Lights", 0),
    mfd_turning_lights                    = make_setting_storage("Settings_MFD_TurningLights", 0),
    mfd_pit_limiter                       = make_setting_storage("Settings_MFD_PitLimiter", 0),
    mfd_show_gal                          = make_setting_storage("Settings_MFD_ShowGal", false),

    audio_master_volume                   = make_setting_storage("Settings_Audio_MasterVolume", 1.0),
    audio_fastest_lap_volume              = make_setting_storage("Settings_Audio_FastestLapVolume", 1.0),
    audio_gearbox_blinking_volume         = make_setting_storage("Settings_Audio_GearboxBlinkingVolume", 1.0),
    audio_semaphores_on_volume            = make_setting_storage("Settings_Audio_SemaphoresOnVolume", 1.0),
    audio_session_ended_volume            = make_setting_storage("Settings_Audio_SessionEnded", 1.0),
    audio_drs_volume                      = make_setting_storage("Settings_Audio_DRS", 1.0),

    audio_master_enabled                  = make_setting_storage("Settings_Audio_MasterVolume", true),
    audio_fastest_lap_enabled             = make_setting_storage("Settings_Audio_FastestLapVolume", true),
    audio_gearbox_blinking_enabled        = make_setting_storage("Settings_Audio_GearboxBlinkingVolume", false),
    audio_semaphores_on_enabled           = make_setting_storage("Settings_Audio_SemaphoresOnVolume", false),
    audio_session_ended_enabled           = make_setting_storage("Settings_Audio_SessionEnded", false),
    audio_drs_enabled                     = make_setting_storage("Settings_Audio_DRS", false),
}
-- TAG: AddingANewSettingVariable, You can read above how to make a new variable

local function load_layouts()
    layouts_count = layout_count_storage:get()
    for i=0, layouts_count-1 do
        local layout_name = ac.storage("CustomLayout_Name_"..i, nil):get()
        local positions = table.new(0, 12)
        positions[APPNAMES.deltabar]     = get_layout_pos_from_storage(APPNAMES.deltabar,     i)
        positions[APPNAMES.gearbox]      = get_layout_pos_from_storage(APPNAMES.gearbox,      i)
        positions[APPNAMES.leaderboard]  = get_layout_pos_from_storage(APPNAMES.leaderboard,  i)
        positions[APPNAMES.map]          = get_layout_pos_from_storage(APPNAMES.map,          i)
        positions[APPNAMES.real_time]    = get_layout_pos_from_storage(APPNAMES.real_time,    i)
        positions[APPNAMES.pedals]       = get_layout_pos_from_storage(APPNAMES.pedals,       i)
        positions[APPNAMES.radar]        = get_layout_pos_from_storage(APPNAMES.radar,        i)
        positions[APPNAMES.sectors]      = get_layout_pos_from_storage(APPNAMES.sectors,      i)
        positions[APPNAMES.local_time]   = get_layout_pos_from_storage(APPNAMES.local_time,   i)
        positions[APPNAMES.tyres]        = get_layout_pos_from_storage(APPNAMES.tyres,        i)
        positions[APPNAMES.damage_panel] = get_layout_pos_from_storage(APPNAMES.damage_panel, i)
        positions[APPNAMES.MFD]          = get_layout_pos_from_storage(APPNAMES.MFD, i)

        local settings = table.new(0, 150)
        for k,v in pairs(settings_data) do
            local v_storage = ac.storage("CustomLayout_"..v.access_string.."_"..i, v.default_value) -- we use default value so when we :get() we receive a number/bool instead of a string
            settings[k] = {value=v_storage:get(), access_string=v.access_string }
        end

        local deltabar_size = ac.storage("CustomLayout_DeltabarSize_"..i, nil):get()
        if deltabar_size ~= nil then deltabar_size = tonumber(deltabar_size) end
        CustomLayouts_Data[i] = {
            name          = layout_name,
            app_positions = positions,
            deltabar_size = deltabar_size,
            apps_settings = settings,
            binding = ac.ControlButton("cmrt.complete/Custom Layout Apply " .. (i + 1)) -- 0 is reserved for our default one
        }
    end
end

local function save_layouts()
    layout_count_storage:set(layouts_count)
    for i=0, layouts_count-1 do
        local to_save = CustomLayouts_Data[i]
        local positions = to_save.app_positions
        set_layout_pos_to_storage(APPNAMES.deltabar,     i, positions[APPNAMES.deltabar])
        set_layout_pos_to_storage(APPNAMES.gearbox,      i, positions[APPNAMES.gearbox])
        set_layout_pos_to_storage(APPNAMES.leaderboard,  i, positions[APPNAMES.leaderboard])
        set_layout_pos_to_storage(APPNAMES.map,          i, positions[APPNAMES.map])
        set_layout_pos_to_storage(APPNAMES.real_time,    i, positions[APPNAMES.real_time])
        set_layout_pos_to_storage(APPNAMES.pedals,       i, positions[APPNAMES.pedals])
        set_layout_pos_to_storage(APPNAMES.radar,        i, positions[APPNAMES.radar])
        set_layout_pos_to_storage(APPNAMES.sectors,      i, positions[APPNAMES.sectors])
        set_layout_pos_to_storage(APPNAMES.local_time,   i, positions[APPNAMES.local_time])
        set_layout_pos_to_storage(APPNAMES.tyres,        i, positions[APPNAMES.tyres])
        set_layout_pos_to_storage(APPNAMES.damage_panel, i, positions[APPNAMES.damage_panel])
        set_layout_pos_to_storage(APPNAMES.MFD         , i, positions[APPNAMES.MFD])
        ac.storage("CustomLayout_Name_"..i, nil):set(to_save.name)
        ac.storage("CustomLayout_DeltabarSize_"..i, nil):set(to_save.deltabar_size)
        for setting_name, setting_data in pairs(to_save.apps_settings) do
            ac.storage("CustomLayout_"..setting_data.access_string.."_"..i, setting_data.value):set(setting_data.value)
        end
        -- no need to save bindings, csp handles it
    end
end

local function get_app_positions()
    local positions = table.new(0, 12)
    positions[APPNAMES.deltabar]     = settings.get_window_pos(APPNAMES.deltabar)
    positions[APPNAMES.gearbox]      = settings.get_window_pos(APPNAMES.gearbox)
    positions[APPNAMES.leaderboard]  = settings.get_window_pos(APPNAMES.leaderboard)
    positions[APPNAMES.map]          = settings.get_window_pos(APPNAMES.map)
    positions[APPNAMES.real_time]    = settings.get_window_pos(APPNAMES.real_time)
    positions[APPNAMES.pedals]       = settings.get_window_pos(APPNAMES.pedals)
    positions[APPNAMES.radar]        = settings.get_window_pos(APPNAMES.radar)
    positions[APPNAMES.sectors]      = settings.get_window_pos(APPNAMES.sectors)
    positions[APPNAMES.local_time]   = settings.get_window_pos(APPNAMES.local_time)
    positions[APPNAMES.tyres]        = settings.get_window_pos(APPNAMES.tyres)
    positions[APPNAMES.damage_panel] = settings.get_window_pos(APPNAMES.damage_panel)
    positions[APPNAMES.MFD]          = settings.get_window_pos(APPNAMES.MFD)
    return positions
end

-- NOTE(cogno): table.remove(table, 0) doesn't seem to work, so we have to do this instead...
local function table_remove(to_remove_from, idx)
    -- NOTE(cogno): table.remove doesn't work with index 0, if you figure out why this becomes a single line of code
    local table_len = table.nkeys(to_remove_from)
    for i=idx, table_len-2 do
        to_remove_from[i] = to_remove_from[i+1]
    end
    to_remove_from[table_len-1] = nil
end

local function confirm_dialog(popup_string_id, text_message, msg1, msg2, disable_button, confirm_function)
    ui.itemPopup(popup_string_id, ui.MouseButton.Left, function()
        ui.newLine(-5)
        ui.text(text_message)
        ui.newLine(-5)

        if disable_button then
            ui.pushDisabled()
            ui.button("Yes")
            ui.popDisabled()
        else
            if ui.button("Yes") then
                confirm_function()
                ui.closePopup()
            end
        end
        ui.sameLine()
        
        if ui.button("No") then
            ui.closePopup()
        end

        ui.columns(1)

        -- NOTE(cogno): if we use textWrapped the confirm dialog doesn't appear where you click, but much higher up.
        -- probably a bug from csp, so we'll just split the message into 2 texts
        if msg1 ~= nil then
            ui.text(msg1)
        end
        if msg2 ~= nil then
            ui.text(msg2)
        end
    end)
end

-- Default as false, if no laps folder exists (or if user manually resets) we change to true and move them one by one later inside each one.
-- We cannot move them immediately using win:move(new_pos) because if the app is hidden it won't be moved.
-- So instead we save that we have to move it, then do so when the app is actually visible on screen.
CanMoveApps = {
    [APPNAMES.deltabar]     = false,
    [APPNAMES.gearbox]      = false,
    [APPNAMES.leaderboard]  = false,
    [APPNAMES.map]          = false,
    [APPNAMES.real_time]    = false,
    [APPNAMES.pedals]       = false,
    [APPNAMES.radar]        = false,
    [APPNAMES.sectors]      = false,
    [APPNAMES.local_time]   = false,
    [APPNAMES.tyres]        = false,
    [APPNAMES.damage_panel] = false,
    [APPNAMES.MFD]          = false,
}
CanResizeDeltabar = false

local function move_all_apps()
    CanMoveApps[APPNAMES.deltabar]     = true
    CanMoveApps[APPNAMES.gearbox]      = true
    CanMoveApps[APPNAMES.leaderboard]  = true
    CanMoveApps[APPNAMES.map]          = true
    CanMoveApps[APPNAMES.real_time]    = true
    CanMoveApps[APPNAMES.pedals]       = true
    CanMoveApps[APPNAMES.radar]        = true
    CanMoveApps[APPNAMES.sectors]      = true
    CanMoveApps[APPNAMES.damage_panel] = true
    CanMoveApps[APPNAMES.local_time]   = true
    CanMoveApps[APPNAMES.tyres]        = true
    CanMoveApps[APPNAMES.MFD]          = true
end

-- input is a Table<setting_name, CurrentSetting>
local function apply_apps_settings(settings)
    -- API(cogno): if we make the table itself global we can avoid setting every single
    -- variable and instead make each app access the global settings struct

    -- TAG: AddingANewSettingVariable, You can read above how to make a new variable work
    SemaphoresScale = settings.semaphores_scale.value
    SemaphoresEnabled = settings.semaphores_enabled.value
    Gearbox_ShowMph = settings.gearbox_mph_storage.value
    Gearbox_ShowGal = settings.gearbox_gal_storage.value
    GearboxScale = settings.gearbox_scale.value
    Gearbox_DotsWindow = settings.gearbox_dots_window.value
    PcTime_ShowBar  = settings.pctime_bar.value
    PcTime_ShowBg   = settings.pctime_bg.value
    MapTime_ShowBar = settings.maptime_bar.value
    MapTime_ShowBg  = settings.maptime_bg.value
    MapTimeScale = settings.maptime_scale.value
    PcTimeScale = settings.pctime_scale.value
    SectorsScale = settings.sectors_scale.value
    Sectors_AnimDuration = settings.sectors_anim_duration.value
    Leaderboard_AnimDuration = settings.leaderboard_anim_duration.value
    LeaderboardScale = settings.leaderboard_scale.value
    Leaderboard_ShowFah = settings.leaderboard_fah.value
    Leaderboard_ShowTyres = settings.leaderboard_show_tyres.value
    Leaderboard_RefreshRate = settings.leaderboard_refresh_rate.value
    Leaderboard_Relative_RefreshRate = settings.leaderboard_relative_refresh_rate.value
    Leaderboard_PeopleCount = settings.leaderboard_people_count.value
    Leaderboard_HotlapCount = settings.leaderboard_hotlap_count.value
    Leaderboard_PeopleCount_Relative = settings.leaderboard_people_count_relative.value
    Leaderboard_ShowExtended = settings.leaderboard_show_extended.value
    Leaderboard_ShowAirTemp = settings.leaderboard_show_air_temp.value
    Leaderboard_ShowTarmacTemp = settings.leaderboard_show_tarmac_temp.value
    Leaderboard_ShowGripPercent = settings.leaderboard_show_grip_precent.value
    Leaderboard_ShowWindInfo = settings.leaderboard_show_wind_info.value
    Leaderboard_ShowPlayerCount = settings.leaderboard_show_player_count.value
    Leaderboard_ShowWeather = settings.leaderboard_show_weather.value
    Leaderboard_ShowCarNames = settings.leaderboard_show_carnames.value
    Leaderboard_ScrollLongNames = settings.leaderboard_scroll_longnames.value
    Leaderboard_SessionScrollingSpeed = settings.leaderboard_session_scrolling_speed.value
    TyresScale = settings.tyres_scale.value
    MapScale = settings.map_scale.value
    DeltabarScale = settings.deltabar_scale.value
    PedalsScale = settings.pedals_scale.value
    RadarScale = settings.radar_scale.value
    Tyres_ShowPedals = settings.tyres_show_pedals.value
    Pedals_ShowGas = settings.pedals_show_gas.value
    Pedals_ShowBrake = settings.pedals_show_brk.value
    Pedals_ShowHandbrake = settings.pedals_show_handbrk.value
    Pedals_ShowClutch = settings.pedals_show_clt.value
    Pedals_ShowFfb = settings.pedals_show_ffb.value
    Pedals_ShowGearShifts = settings.pedals_show_gear_shifts.value
    Tyres_ShowFah = settings.tyres_show_fah.value
    Tyres_TempColored = settings.tyres_temp_colored.value
    Tyres_PressureDelta = settings.tyres_pressure_delta.value
    Tyres_ShowMph = settings.tyres_show_mph.value
    Radar_ShowDots = settings.radar_show_dots.value
    Radar_ShowDoubleLines = settings.radar_show_double_lines.value
    Radar_ShowPlayers = settings.radar_show_players.value
    Radar_RotateCars = settings.radar_rotate_cars.value
    Radar_MultiWarningLines = settings.radar_extra_warning.value
    Radar_AlwaysVisible = settings.radar_always_visible.value
    Radar_ShowExtended = settings.radar_show_extended.value
    Map_LowProfile = settings.map_low_profile.value
    Deltabar_PracMode = settings.deltabar_practice_mode.value
    Deltabar_QualMode = settings.deltabar_qualify_mode.value
    Deltabar_RaceMode = settings.deltabar_race_mode.value
    Deltabar_AnimDuration = settings.deltabar_anim_duration.value
    Deltabar_SaveOnClose = settings.deltabar_save_on_close.value
    Deltabar_Minimized = settings.deltabar_minimized.value
    Deltabar_Position = settings.deltabar_position.value
    Apps_AutoScale = settings.apps_auto_scale.value
    Map_Relative = settings.map_relative.value
    Leaderboard_Multiclass_Enabled = settings.leaderboard_multiclass_enabled.value
    Leaderboard_Multiclass_FilterEnabled = settings.leaderboard_multiclass_filter_enabled.value
    Leaderboard_Relative = settings.leaderboard_relative.value
    Tyres_ShowInfoPanel = settings.tyres_show_info_panel.value
    Tyres_ClickPriority = settings.tyres_click_priority.value
    Tyres_AutoInfoPanel = settings.tyres_auto_info_panel.value
    Tyres_FlipInfoPanel = settings.tyres_flip_info_panel.value
    Pedals_ShowTelemetry = settings.pedals_show_telemetry.value
    Gearbox_MGUKMode =  settings.gearbox_mguk_mode.value
    Gearbox_InfoMode = settings.gearbox_info_mode.value
    Gearbox_MGUKInfoMode = settings.gearbox_mguk_info_mode.value
    Gearbox_ERSMode = settings.gearbox_ers_mode.value
    Gearbox_ShowPeakShift = settings.gearbox_peak_rpm_enabled.value
    DamagePanel_Scale = settings.damage_panel_scale.value
    MapRemoveBG = settings.map_remove_bg.value
    MapRemoveBGWhenDataMissing = settings.map_remove_bg_when_data_missing.value
    Map_ShowDRS = settings.map_show_drs.value
    AlwaysShowDamagePanel = settings.always_show_damage_panel.value
    MFDScale = settings.mfd_scale.value
    MFDShowGal = settings.mfd_show_gal.value
    Audio_MasterVolume = settings.audio_master_volume.value
    Audio_FastestLapVolume = settings.audio_fastest_lap_volume.value
    Audio_GearboxBlinkingVolume = settings.audio_gearbox_blinking_volume.value
    Audio_SemaphoresOnVolume = settings.audio_semaphores_on_volume.value
    Audio_SessionEndedVolume = settings.audio_session_ended_volume.value
    Audio_DRSVolume = settings.audio_drs_volume.value
    Audio_DRSEnabled = settings.audio_drs_enabled.value
    Audio_MasterEnabled = settings.audio_master_enabled.value
    Audio_FastestLapEnabled = settings.audio_fastest_lap_enabled.value
    Audio_GearboxBlinkingEnabled = settings.audio_gearbox_blinking_enabled.value
    Audio_SemaphoresOnEnabled = settings.audio_semaphores_on_enabled.value
    Audio_SessionEndedEnabled = settings.audio_session_ended_enabled.value
    
    -- TAG: AddingANewSettingVariable, You can read above how to make a new variable work
end


-- output is Table<setting_name, CurrentSetting>
local function make_table_from_current_settings()
    -- API(cogno): if we make the table itself global we can avoid converting every single variable
    local out = table.new(0, 150)
    for k,v in pairs(settings_data) do
        out[k] = { access_string = v.access_string } -- value is filled manually just below from global variables
    end

    -- TAG: AddingANewSettingVariable, You can read above how to make a new variable work
    out.semaphores_scale.value = SemaphoresScale
    out.semaphores_enabled.value = SemaphoresEnabled
    out.gearbox_gal_storage.value = Gearbox_ShowGal
    out.gearbox_mph_storage.value = Gearbox_ShowMph
    out.gearbox_scale.value = GearboxScale
    out.maptime_bar.value = MapTime_ShowBar
    out.maptime_bg.value = MapTime_ShowBg
    out.pctime_bar.value = PcTime_ShowBar
    out.pctime_bg.value = PcTime_ShowBg
    out.maptime_scale.value = MapTimeScale
    out.pctime_scale.value = PcTimeScale
    out.gearbox_dots_window.value = Gearbox_DotsWindow
    out.sectors_scale.value = SectorsScale
    out.sectors_anim_duration.value = Sectors_AnimDuration
    out.leaderboard_anim_duration.value = Leaderboard_AnimDuration
    out.leaderboard_scale.value = LeaderboardScale
    out.leaderboard_fah.value = Leaderboard_ShowFah
    out.leaderboard_show_tyres.value = Leaderboard_ShowTyres
    out.leaderboard_refresh_rate.value = Leaderboard_RefreshRate
    out.leaderboard_relative_refresh_rate.value = Leaderboard_Relative_RefreshRate
    out.tyres_scale.value = TyresScale
    out.map_scale.value = MapScale
    out.deltabar_scale.value = DeltabarScale
    out.pedals_scale.value = PedalsScale
    out.radar_scale.value = RadarScale
    out.tyres_show_pedals.value = Tyres_ShowPedals
    out.pedals_show_gas.value = Pedals_ShowGas
    out.pedals_show_brk.value = Pedals_ShowBrake
    out.pedals_show_handbrk.value = Pedals_ShowHandbrake
    out.pedals_show_clt.value = Pedals_ShowClutch
    out.pedals_show_ffb.value = Pedals_ShowFfb
    out.pedals_show_gear_shifts.value = Pedals_ShowGearShifts
    out.tyres_show_fah.value = Tyres_ShowFah
    out.tyres_temp_colored.value = Tyres_TempColored
    out.tyres_pressure_delta.value = Tyres_PressureDelta
    out.tyres_show_mph.value = Tyres_ShowMph
    out.radar_show_dots.value = Radar_ShowDots
    out.radar_show_double_lines.value = Radar_ShowDoubleLines
    out.radar_show_players.value = Radar_ShowPlayers
    out.radar_rotate_cars.value = Radar_RotateCars
    out.radar_extra_warning.value = Radar_MultiWarningLines
    out.radar_always_visible.value = Radar_AlwaysVisible
    out.radar_show_extended.value = Radar_ShowExtended
    out.map_low_profile.value = Map_LowProfile
    out.map_relative.value = Map_Relative
    out.deltabar_practice_mode.value = Deltabar_PracMode
    out.deltabar_qualify_mode.value = Deltabar_QualMode
    out.deltabar_race_mode.value = Deltabar_RaceMode
    out.deltabar_anim_duration.value = Deltabar_AnimDuration
    out.deltabar_save_on_close.value = Deltabar_SaveOnClose
    out.deltabar_minimized.value = Deltabar_Minimized
    out.deltabar_position.value = Deltabar_Position
    out.apps_auto_scale.value = Apps_AutoScale
    out.leaderboard_multiclass_enabled.value = Leaderboard_Multiclass_Enabled
    out.leaderboard_multiclass_filter_enabled.value = Leaderboard_Multiclass_FilterEnabled
    out.leaderboard_relative.value = Leaderboard_Relative
    out.leaderboard_people_count.value = Leaderboard_PeopleCount
    out.leaderboard_hotlap_count.value = Leaderboard_HotlapCount
    out.leaderboard_people_count_relative.value = Leaderboard_PeopleCount_Relative
    out.leaderboard_show_extended.value = Leaderboard_ShowExtended
    out.leaderboard_show_air_temp.value = Leaderboard_ShowAirTemp
    out.leaderboard_show_tarmac_temp.value = Leaderboard_ShowTarmacTemp
    out.leaderboard_show_grip_precent.value = Leaderboard_ShowGripPercent
    out.leaderboard_show_wind_info.value = Leaderboard_ShowWindInfo
    out.leaderboard_show_player_count.value = Leaderboard_ShowPlayerCount
    out.leaderboard_show_weather.value = Leaderboard_ShowWeather
    out.leaderboard_show_carnames.value = Leaderboard_ShowCarNames
    out.leaderboard_scroll_longnames.value = Leaderboard_ScrollLongNames
    out.tyres_show_info_panel.value = Tyres_ShowInfoPanel
    out.tyres_click_priority.value = Tyres_ClickPriority
    out.pedals_show_telemetry.value = Pedals_ShowTelemetry
    out.gearbox_mguk_mode.value = Gearbox_MGUKMode
    out.gearbox_info_mode.value = Gearbox_InfoMode
    out.gearbox_ers_mode.value = Gearbox_ERSMode
    out.gearbox_peak_rpm_enabled.value = Gearbox_ShowPeakShift
    out.tyres_auto_info_panel.value = Tyres_AutoInfoPanel
    out.tyres_flip_info_panel.value = Tyres_FlipInfoPanel
    out.damage_panel_scale.value = DamagePanel_Scale
    out.map_remove_bg.value = MapRemoveBG
    out.leaderboard_session_scrolling_speed.value = Leaderboard_SessionScrollingSpeed
    out.map_remove_bg_when_data_missing.value = MapRemoveBGWhenDataMissing
    out.map_show_drs.value = Map_ShowDRS
    out.always_show_damage_panel.value = AlwaysShowDamagePanel
    out.mfd_scale.value = MFDScale
    out.mfd_show_gal.value = MFDShowGal
    out.audio_master_volume.value = Audio_MasterVolume
    out.audio_fastest_lap_volume.value = Audio_FastestLapVolume
    out.audio_gearbox_blinking_volume.value = Audio_GearboxBlinkingVolume
    out.audio_semaphores_on_volume.value = Audio_SemaphoresOnVolume
    out.audio_session_ended_volume.value = Audio_SessionEndedVolume
    out.audio_drs_volume.value = Audio_DRSVolume
    out.audio_drs_enabled.value = Audio_DRSEnabled
    out.audio_master_enabled.value = Audio_MasterEnabled
    out.audio_fastest_lap_enabled.value = Audio_FastestLapEnabled
    out.audio_gearbox_blinking_enabled.value = Audio_GearboxBlinkingEnabled
    out.audio_semaphores_on_enabled.value = Audio_SemaphoresOnEnabled
    out.audio_session_ended_enabled.value = Audio_SessionEndedEnabled
    -- TAG: AddingANewSettingVariable, You can read above how to make a new variable work

    return out
end

-- applyes on screen a given layout from its id
-- id 0 is default layout (made manually by us),
-- id > 0 is CustomLayout_Data[id - 1]
local function apply_layout(layout_id)
    CustomLayout_CurrentIndex = layout_id
    move_all_apps()
    CanResizeDeltabar = true
    Deltabar_NewSize = 700 -- default layout has a 700px deltabar (got from manifest default size)
    if layout_id > 0 then
        local layout_data = CustomLayouts_Data[layout_id - 1]
        if layout_data ~= nil then
            Deltabar_NewSize = layout_data.deltabar_size
            local apps_settings = layout_data.apps_settings
            apply_apps_settings(apps_settings)
        end
    end
    last_used_layout_storage:set(layout_id)
    save_settings = true -- so we get back to the settings we just applied
end


-- Gets each value in storage into a table with the proper names set in the settings_storages table.
-- In other words if you have gearbox_scale = ac.storage(...) the output table
-- will have for example gearbox_scale = { value=1, access_string="Settings_Gearbox_Scale" }.
local function get_settings_table()
    local out = table.new(0, 150)
    for k, v in pairs(settings_data) do
        out[k] = {
            value=v.storage:get(),
            access_string=v.access_string,
        }
    end
    return out
end


local function transition_old_settings()
    -- NOTE(cogno): since this is all old settings which transition into the new system you shouldn't have to touch any of these
    storage = ac.storage{
        gearbox_scale = 1,
        gearbox_show_mph = false, -- DEPRECATED(cogno): old value, replaced by :get() and :set(...)
        gearbox_dots_window = true,
        pctime_bg = true,
        pctime_bar = false,
        maptime_bg = true,
        maptime_bar = true,
        maptime_scale = 1,
        pctime_scale = 1,
        sectors_scale = 1,
        sectors_anim_duration = 8,
        leaderboard_anim_duration = 18,
        leaderboard_scale = 1,
        leaderboard_fah = false,
        leaderboard_show_tyres = true,
        leaderboard_refresh_rate = 2000, -- in ms
        leaderboard_relative_refresh_rate = 2000, -- in ms
        leaderboard_multiclass_enabled = false,
        leaderboard_multiclass_filter_enabled = true,
        leaderboard_relative = false,
        leaderboard_people_count = 2,
        leaderboard_people_count_relative = 2,
        leaderboard_show_extended = false,
        leaderboard_show_air_temp = true,
        leaderboard_show_tarmac_temp = true,
        leaderboard_show_grip_precent = false,
        leaderboard_show_wind_info = false,
        leaderboard_session_scrolling_speed = 0,
        tyres_scale = 1,
        map_scale = 1,
        deltabar_scale = 1,
        pedals_scale = 1,
        radar_scale = 1,
        tyres_show_pedals = true,
        pedals_show_gas = true,
        pedals_show_brk = true,
        pedals_show_handbrk = false,
        pedals_show_clt = false,
        pedals_show_ffb = false,
        tyres_show_fah = false,
        tyres_show_mph = false,
        tyres_temp_colored = true,
        tyres_pressure_delta = true,
        radar_show_dots = true,
        radar_show_double_lines = true,
        radar_show_players = true,
        radar_rotate_cars = false,
        radar_extra_warning = false,
        map_low_profile = true,
        map_relative = false,
        map_remove_bg = false,
        deltabar_practice_mode = 0,
        deltabar_qualify_mode = 0,
        deltabar_race_mode = 0,
        deltabar_anim_duration = 8,
        deltabar_save_on_close = false,
        deltabar_minimized = false,
        deltabar_position = 1,
        apps_auto_scale = true,
        tyres_show_info_panel = false,
        tyres_click_priority = false,
        tyres_auto_info_panel = true,
        pedals_show_telemetry = false,
        gearbox_mguk_mode = false,
        gearbox_info_mode = true,
        gearbox_mguk_info_mode = false,
        gearbox_ers_mode = false,
        damage_panel_scale = 1,
        always_show_damage_panel = false,
        map_remove_bg_when_data_missing = false,
        mfd_scale = 1,
        mfd_abs = 0,
        mfd_traction_control = 0,
        mfd_traction_control2 = 0,
        mfd_brake_bias = 0,
        mfd_wipers = 0,
        mfd_lights = 0,
        mfd_turning_lights = 0,
        mfd_pit_limiter = 0,
    }
    settings_data.gearbox_scale.storage:set(storage.gearbox_scale)
    settings_data.gearbox_dots_window.storage:set(storage.gearbox_dots_window)
    settings_data.pctime_bg.storage:set(storage.pctime_bg)
    settings_data.pctime_bar.storage:set(storage.pctime_bar)
    settings_data.maptime_bg.storage:set(storage.maptime_bg)
    settings_data.maptime_bar.storage:set(storage.maptime_bar)
    settings_data.maptime_scale.storage:set(storage.maptime_scale)
    settings_data.pctime_scale.storage:set(storage.pctime_scale)
    settings_data.sectors_scale.storage:set(storage.sectors_scale)
    settings_data.sectors_anim_duration.storage:set(storage.sectors_anim_duration)
    settings_data.leaderboard_anim_duration.storage:set(storage.leaderboard_anim_duration)
    settings_data.leaderboard_scale.storage:set(storage.leaderboard_scale)
    settings_data.leaderboard_fah.storage:set(storage.leaderboard_fah)
    settings_data.leaderboard_show_tyres.storage:set(storage.leaderboard_show_tyres)
    settings_data.leaderboard_refresh_rate.storage:set(storage.leaderboard_refresh_rate)
    settings_data.leaderboard_relative_refresh_rate.storage:set(storage.leaderboard_relative_refresh_rate)
    settings_data.leaderboard_multiclass_enabled.storage:set(storage.leaderboard_multiclass_enabled)
    settings_data.leaderboard_multiclass_filter_enabled.storage:set(storage.leaderboard_multiclass_filter_enabled)
    settings_data.leaderboard_relative.storage:set(storage.leaderboard_relative)
    settings_data.leaderboard_people_count.storage:set(storage.leaderboard_people_count)
    settings_data.leaderboard_people_count_relative.storage:set(storage.leaderboard_people_count_relative)
    settings_data.leaderboard_show_extended.storage:set(storage.leaderboard_show_extended)
    settings_data.leaderboard_show_air_temp.storage:set(storage.leaderboard_show_air_temp)
    settings_data.leaderboard_show_tarmac_temp.storage:set(storage.leaderboard_show_tarmac_temp)
    settings_data.leaderboard_show_grip_precent.storage:set(storage.leaderboard_show_grip_precent)
    settings_data.leaderboard_show_wind_info.storage:set(storage.leaderboard_show_wind_info)
    settings_data.leaderboard_session_scrolling_speed.storage:set(storage.leaderboard_session_scrolling_speed)
    settings_data.tyres_scale.storage:set(storage.tyres_scale)
    settings_data.map_scale.storage:set(storage.map_scale)
    settings_data.deltabar_scale.storage:set(storage.deltabar_scale)
    settings_data.pedals_scale.storage:set(storage.pedals_scale)
    settings_data.radar_scale.storage:set(storage.radar_scale)
    settings_data.tyres_show_pedals.storage:set(storage.tyres_show_pedals)
    settings_data.pedals_show_gas.storage:set(storage.pedals_show_gas)
    settings_data.pedals_show_brk.storage:set(storage.pedals_show_brk)
    settings_data.pedals_show_handbrk.storage:set(storage.pedals_show_handbrk)
    settings_data.pedals_show_clt.storage:set(storage.pedals_show_clt)
    settings_data.pedals_show_ffb.storage:set(storage.pedals_show_ffb)
    settings_data.tyres_show_fah.storage:set(storage.tyres_show_fah)
    settings_data.tyres_show_mph.storage:set(storage.tyres_show_mph)
    settings_data.tyres_temp_colored.storage:set(storage.tyres_temp_colored)
    settings_data.tyres_pressure_delta.storage:set(storage.tyres_pressure_delta)
    settings_data.radar_show_dots.storage:set(storage.radar_show_dots)
    settings_data.radar_show_double_lines.storage:set(storage.radar_show_double_lines)
    settings_data.radar_show_players.storage:set(storage.radar_show_players)
    settings_data.radar_rotate_cars.storage:set(storage.radar_rotate_cars)
    settings_data.radar_extra_warning.storage:set(storage.radar_extra_warning)
    settings_data.map_low_profile.storage:set(storage.map_low_profile)
    settings_data.map_relative.storage:set(storage.map_relative)
    settings_data.map_remove_bg.storage:set(storage.map_remove_bg)
    settings_data.deltabar_practice_mode.storage:set(storage.deltabar_practice_mode)
    settings_data.deltabar_qualify_mode.storage:set(storage.deltabar_qualify_mode)
    settings_data.deltabar_race_mode.storage:set(storage.deltabar_race_mode)
    settings_data.deltabar_anim_duration.storage:set(storage.deltabar_anim_duration)
    settings_data.deltabar_save_on_close.storage:set(storage.deltabar_save_on_close)
    settings_data.deltabar_minimized.storage:set(storage.deltabar_minimized)
    settings_data.deltabar_position.storage:set(storage.deltabar_position)
    settings_data.apps_auto_scale.storage:set(storage.apps_auto_scale)
    settings_data.tyres_show_info_panel.storage:set(storage.tyres_show_info_panel)
    settings_data.tyres_click_priority.storage:set(storage.tyres_click_priority)
    settings_data.tyres_auto_info_panel.storage:set(storage.tyres_auto_info_panel)
    settings_data.pedals_show_telemetry.storage:set(storage.pedals_show_telemetry)
    settings_data.gearbox_mguk_mode.storage:set(storage.gearbox_mguk_mode)
    settings_data.gearbox_info_mode.storage:set(storage.gearbox_info_mode)
    settings_data.gearbox_mguk_info_mode.storage:set(storage.gearbox_mguk_info_mode)
    settings_data.gearbox_ers_mode.storage:set(storage.gearbox_ers_mode)
    settings_data.damage_panel_scale.storage:set(storage.damage_panel_scale)
    settings_data.always_show_damage_panel.storage:set(storage.always_show_damage_panel)
    settings_data.map_remove_bg_when_data_missing.storage:set(storage.map_remove_bg_when_data_missing)
    -- NOTE(cogno): since this is all old settings which transition into the new system you shouldn't have to touch any of these
end



local function load_app_settings()
    local transition_storage = ac.storage("AllSettingsTransitioned_v1", false)
    local transitioned = transition_storage:get()
    if not transitioned then
        transition_old_settings()
        transition_storage:set(true) -- so we don't do it again
    end

    return get_settings_table()
end


local gearbox_wanted_rpm_storage = nil
Gearbox_WantedRpm = nil -- we do not put it in settings because it's related to the car, not the layout
local app_version = ""
function mod.init()
    local app_settings = load_app_settings()
    apply_apps_settings(app_settings)

    for i=0, table.nkeys(Deltabar_Modes)-1 do
        local access_string = "deltabar_mode"..i
        local stored = ac.storage(access_string, false)
        Deltabar_ShowSectorsPerMode[i] = stored:get()
    end

    -- get the length of the tags saved by the player
    local mc_tags_count = mc_tags_count_storage:get()
    if mc_tags_count >= 1 then -- I'm scared of negative numbers, I don't know why honestly...
        -- API(cogno): find a better way instead of using the :get and :set, it looks so dumb...
        for i=0, mc_tags_count-1 do
            local s_tagname = ac.storage("Multiclass_TagsData_TagName"..i, ''):get()
            local default_color = nil
            if i % 7 == 0 then default_color = mc_color1 end
            if i % 7 == 1 then default_color = mc_color2 end
            if i % 7 == 2 then default_color = mc_color3 end
            if i % 7 == 3 then default_color = mc_color4 end
            if i % 7 == 4 then default_color = mc_color5 end
            if i % 7 == 5 then default_color = mc_color6 end
            if i % 7 == 6 then default_color = mc_color7 end
            -- TAG(cogno): StorageSavesOnlyNumbers
            local s_color_r = ac.storage("Multiclass_TagsData_TagColor_r"..i, "" .. default_color.r):get() -- convertion to string looks mega dumb, but it's for the stringify.parse later...
            local s_color_g = ac.storage("Multiclass_TagsData_TagColor_g"..i, "" .. default_color.g):get() -- convertion to string looks mega dumb, but it's for the stringify.parse later...
            local s_color_b = ac.storage("Multiclass_TagsData_TagColor_b"..i, "" .. default_color.b):get() -- convertion to string looks mega dumb, but it's for the stringify.parse later...
            local s_color_m = ac.storage("Multiclass_TagsData_TagColor_m"..i, "" .. default_color.mult):get() -- convertion to string looks mega dumb, but it's for the stringify.parse later...
            local s_color = rgbm(stringify.parse(s_color_r), stringify.parse(s_color_g), stringify.parse(s_color_b), stringify.parse(s_color_m))
            append_tag(s_tagname, s_color:clone())
        end
    end

    -- the player cannot edit the first 7, so we always put them here without going through save files
    color_buttons[0] = mc_color1:clone()
    color_buttons[1] = mc_color2:clone()
    color_buttons[2] = mc_color3:clone()
    color_buttons[3] = mc_color4:clone()
    color_buttons[4] = mc_color5:clone()
    color_buttons[5] = mc_color6:clone()
    color_buttons[6] = mc_color7:clone()


    -- next we get player edited colors from files
    local extra_colors = mc_color_count_storage:get()
    local current_color_buttons_length = 7
    for i=0, extra_colors-1 do
        -- TAG(cogno): StorageSavesOnlyNumbers
        local saved_color_storage_r = ac.storage("Multiclass_ExtraColor_v1_r"..i, nil)
        local saved_color_storage_g = ac.storage("Multiclass_ExtraColor_v1_g"..i, nil)
        local saved_color_storage_b = ac.storage("Multiclass_ExtraColor_v1_b"..i, nil)
        local saved_color_storage_m = ac.storage("Multiclass_ExtraColor_v1_m"..i, nil)
        local saved_r = saved_color_storage_r:get()
        local saved_g = saved_color_storage_g:get()
        local saved_b = saved_color_storage_b:get()
        local saved_m = saved_color_storage_m:get()
        if saved_r ~= nil and saved_g ~= nil and saved_b ~= nil and saved_m ~= nil  then
            color_buttons[current_color_buttons_length] = rgbm(stringify.parse(saved_r), stringify.parse(saved_g), stringify.parse(saved_b), stringify.parse(saved_m))
            current_color_buttons_length = current_color_buttons_length + 1
        end
    end

    local complete_first_time_storage = ac.storage("First_Time_Opening_Complete", false)
    local was_already_opened = complete_first_time_storage:get()
    if not was_already_opened then
        -- it's the first time opening the app EVER
        -- set that apps should be moved
        move_all_apps()
        complete_first_time_storage:set(true) -- our work is done!
    end

    -- automatically gather app version so we propagate it to files
    local changelog_string = io.load("apps/lua/CMRT-Complete-HUD/CHANGELOG.txt")
    local splitted = changelog_string:split("\n")
    app_version = splitted[1]

    load_layouts()
    MFD_PresetCount = mfd_preset_count_storage:get()

    -- peak rpm the user manually put
    local carname = ac.getCarName(0)
    gearbox_wanted_rpm_storage       = ac.storage("Gearbox_WantedRPM_"..carname, nil) -- so it's specific to this car
    local rpm_string = gearbox_wanted_rpm_storage:get()
    if rpm_string ~= nil then
        Gearbox_WantedRpm = tonumber(rpm_string)
    else
        Gearbox_WantedRpm = ac.getCar(0).rpmLimiter - 300
    end
end


local lb_full_button_toggle   = ac.ControlButton("cmrt.complete/Leaderboard Extended Toggle")
local lb_full_button_hold     = ac.ControlButton("cmrt.complete/Leaderboard Extended Hold")
local lb_button_rectract_hold = ac.ControlButton("cmrt.complete/Leaderboard Retract Hold")
local lb_button_extend        = ac.ControlButton("cmrt.complete/Leaderboard Extended")
local lb_button_rectract      = ac.ControlButton("cmrt.complete/Leaderboard Retracted")

local lb_carnames_buttons = {
    ac.ControlButton("cmrt.complete/Leaderboard Carname Show Toggle"),
    ac.ControlButton("cmrt.complete/Leaderboard Carname Show Hold"),
    ac.ControlButton("cmrt.complete/Leaderboard Carname Hide Hold"),
    ac.ControlButton("cmrt.complete/Leaderboard Carname Show"),
    ac.ControlButton("cmrt.complete/Leaderboard Carname Hide"),
}


local lb_multiclass_buttons = {
    ac.ControlButton("cmrt.complete/Leaderboard Multiclass Extended Toggle"),
    ac.ControlButton("cmrt.complete/Leaderboard Multiclass Extended Hold"),
    ac.ControlButton("cmrt.complete/Leaderboard Multiclass Retract Hold"),
    ac.ControlButton("cmrt.complete/Leaderboard Multiclass Open"),
    ac.ControlButton("cmrt.complete/Leaderboard Multiclass Close"),
}

local lb_multiclass_filter_buttons = {
    ac.ControlButton("cmrt.complete/Leaderboard Multiclass Filter Toggle"),
    ac.ControlButton("cmrt.complete/Leaderboard Multiclass Filter Enable Hold"),
    ac.ControlButton("cmrt.complete/Leaderboard Multiclass Filter Disable Hold"),
    ac.ControlButton("cmrt.complete/Leaderboard Multiclass Filter Enable"),
    ac.ControlButton("cmrt.complete/Leaderboard Multiclass Filter Disable"),
}

local lb_relative_buttons = {
    ac.ControlButton("cmrt.complete/Leaderboard Relative Toggle"),
    ac.ControlButton("cmrt.complete/Leaderboard Relative Enabled Hold"),
    ac.ControlButton("cmrt.complete/Leaderboard Relative Disabled Hold"),
    ac.ControlButton("cmrt.complete/Leaderboard Relative Enabled"),
    ac.ControlButton("cmrt.complete/Leaderboard Relative Disabled"),
}

local gb_full_button_toggle = ac.ControlButton("cmrt.complete/Gearbox Extended Toggle")
local gb_button_ers_hold    = ac.ControlButton("cmrt.complete/Gearbox ERS Mode Hold")
local gb_button_rpm_hold    = ac.ControlButton("cmrt.complete/Gearbox RPM Mode Hold")
local gb_button_ers_mode    = ac.ControlButton("cmrt.complete/Gearbox ERS Mode")
local gb_button_rpm_mode    = ac.ControlButton("cmrt.complete/Gearbox RPM Mode")

local map_relative_buttons = {
    ac.ControlButton("cmrt.complete/Map Display Mode"),
    ac.ControlButton("cmrt.complete/Map Relative Hold"),
    ac.ControlButton("cmrt.complete/Map Absolute Hold"),
    ac.ControlButton("cmrt.complete/Map Display Mode Relative"),
    ac.ControlButton("cmrt.complete/Map Display Mode Absolute"),
}

local tyres_button_info_panel_toggle    = ac.ControlButton("cmrt.complete/Tyres Info Panel Toggle")
local tyres_button_show_info_panel_hold = ac.ControlButton("cmrt.complete/Tyres Info Panel Hold")
local tyres_button_show_info_panel      = ac.ControlButton("cmrt.complete/Tyres Show Info Panel")
local tyres_button_hide_info_panel      = ac.ControlButton("cmrt.complete/Tyres Hide Info Panel")

local pedals_telemetry_button_toggle = ac.ControlButton("cmrt.complete/Pedals Telemetry Toggle")
local pedals_telemetry_button_hold   = ac.ControlButton("cmrt.complete/Pedals Telemetry Hold")
local pedals_telemetry_button_show   = ac.ControlButton("cmrt.complete/Pedals Telemetry Show")
local pedals_telemetry_button_hide   = ac.ControlButton("cmrt.complete/Pedals Telemetry Hide")

local sectors_button_panel_toggle    = ac.ControlButton("cmrt.complete/Sectors Panel Toggle")
local sectors_button_show_panel_hold = ac.ControlButton("cmrt.complete/Sectors Panel Hold")
local sectors_button_show_panel      = ac.ControlButton("cmrt.complete/Sectors Show Panel")
local sectors_button_hide_panel      = ac.ControlButton("cmrt.complete/Sectors Hide Panel")

local custom_layout_previous      = ac.ControlButton("cmrt.complete/Custom Layout Previous")
local custom_layout_next          = ac.ControlButton("cmrt.complete/Custom Layout Next")
local custom_layout_apply_default = ac.ControlButton("cmrt.complete/Custom Layout Apply 0")

local function lb_multiclass_open()
    if Leaderboard_Multiclass_Enabled == false then
        Leaderboard_Multiclass_EnabledTime = Time
    end
    Leaderboard_Multiclass_Enabled = true
    save_settings = true
end

local function lb_multiclass_close()
    if Leaderboard_Multiclass_Enabled == true then
        Leaderboard_Multiclass_EnabledTime = Time
    end
    Leaderboard_Multiclass_Enabled = false
    save_settings = true
end

local function lb_show_carnames_open()
    Leaderboard_ShowCarNames = true
    save_settings = true
end

local function lb_show_carnames_close()
    Leaderboard_ShowCarNames = false
    save_settings = true
end

local function lb_multiclass_filter_enable()
    Leaderboard_Multiclass_FilterEnabled = true
    save_settings = true
end

local function lb_multiclass_filter_disable()
    Leaderboard_Multiclass_FilterEnabled = false
    save_settings = true
end

local function lb_relative_enable()
    if Leaderboard_Relative == false then
        Leaderboard_Relative_ChangedThisFrame = true
    end
    Leaderboard_Relative = true
    save_settings = true
end

local function lb_relative_disable()
    if Leaderboard_Relative then
        Leaderboard_Relative_ChangedThisFrame = true
    end
    Leaderboard_Relative = false
    Leaderboard_Relative_ChangedThisFrame = true
    save_settings = true
end

local function map_relative_enable()
    if Map_Relative == false then
        Map_Relative_SwitchTime = Time
    end
    Map_Relative = true
    save_settings = true
end

local function map_relative_disable()
    if Map_Relative == true then
        Map_Relative_SwitchTime = Time
    end
    Map_Relative = false
    save_settings = true
end

-- button list is a list of 5 buttons, 
-- list[1] is a toggle
-- list[2] is a hold to open
-- list[3] is a hold to close
-- list[4] is to open
-- list[5] is to close
-- is_open is a bool to know if what the buttons touch is open or not
-- open_func and close_func are 2 functions that are automatically called to open or close
local function multi_button_update(button_list, is_open, open_func, close_func)
    if button_list[1]:pressed() then
        if is_open then close_func() else open_func() end
    end

    if button_list[2]:down() then open_func() end
    if button_list[2]:released() then close_func() end
    
    if button_list[3]:down() then close_func() end
    if button_list[3]:released() then open_func() end

    if button_list[4]:pressed() then open_func() end
    if button_list[5]:pressed() then close_func() end
end

local initted_layout = false
local first_frame_passed = false
function mod.update()
    if not initted_layout and first_frame_passed then
        initted_layout = true
        -- NOTE(cogno): for some reason the entire first frame of gameplay we are able to 
        -- get each app position, but not their size, so we do it the SECOND frame instead.
        -- If we don't this custom layout automatically made is fucked forever.

        local first_layout_storage = ac.storage("First_Time_Saving_Layout_v1", false)
        local first_layout_saved = first_layout_storage:get()
        if not first_layout_saved then
            -- this is the first time the user is opening the app with the custom layouts enabled,
            -- we're going to save his current app position as a new layout, so he won't loose it.

            layouts_count = 1 -- only the one we're making right now
            local positions = get_app_positions()
            CustomLayouts_Data[0] = {
                name="Custom 1",
                app_positions = positions,
                deltabar_size = get_deltabar_horizontal_size(),
                apps_settings = make_table_from_current_settings(),
                binding = ac.ControlButton("cmrt.complete/Custom Layout Apply " .. 1) -- 0 is reserved for our default one
            }

            save_layouts()
            first_layout_storage:set(true) -- so we don't do it again
        end
    end
    if not first_frame_passed then first_frame_passed = true end -- AFTER the check above, so it gets made one frame later


    -- input updates
    -- Leaderboard Extended (Toggle)
    if lb_full_button_toggle:pressed() then
        Leaderboard_ShowExtended = not Leaderboard_ShowExtended
        Leaderboard_Extended_ThisFrame = true
        Leaderboard_Extended_StartTime = Time
        save_settings = true
    end

    -- Leaderboard Extended (Hold)
    if lb_full_button_hold:down() then
        if Leaderboard_ShowExtended == false then
            Leaderboard_Extended_StartTime = Time
            Leaderboard_Extended_ThisFrame = true
        end
        Leaderboard_ShowExtended = true
        save_settings = true
    end

    if lb_full_button_hold:released() then
        Leaderboard_ShowExtended = false
        Leaderboard_Extended_ThisFrame = true
        Leaderboard_Extended_StartTime = Time
        save_settings = true
    end

    -- Leaderboard Retract (Hold)
    if lb_button_rectract_hold:down() then
        if Leaderboard_ShowExtended == true then
            Leaderboard_Extended_StartTime = Time
            Leaderboard_Extended_ThisFrame = true
        end
        Leaderboard_ShowExtended = false
        save_settings = true
    end

    if lb_button_rectract_hold:released() then
        Leaderboard_ShowExtended = true
        Leaderboard_Extended_ThisFrame = true
        Leaderboard_Extended_StartTime = Time
        save_settings = true
    end
    

    -- Leaderboard Extend
    if lb_button_extend:pressed() then
        if Leaderboard_ShowExtended == false then
            Leaderboard_Extended_StartTime = Time
        end
        Leaderboard_ShowExtended = true
        Leaderboard_Extended_ThisFrame = true
        save_settings = true
    end

    -- Leaderboard Retract
    if lb_button_rectract:pressed() then
        if Leaderboard_ShowExtended == true then
            Leaderboard_Extended_StartTime = Time
        end
        Leaderboard_ShowExtended = false
        Leaderboard_Extended_ThisFrame = true
        save_settings = true
    end

    multi_button_update(
        lb_multiclass_buttons,
        Leaderboard_Multiclass_Enabled,
        lb_multiclass_open,
        lb_multiclass_close
    )
    multi_button_update(
        lb_multiclass_filter_buttons,
        Leaderboard_Multiclass_FilterEnabled,
        lb_multiclass_filter_enable,
        lb_multiclass_filter_disable
    )
    multi_button_update(
        lb_relative_buttons,
        Leaderboard_Relative,
        lb_relative_enable,
        lb_relative_disable
    )
    multi_button_update(
        lb_carnames_buttons,
        Leaderboard_ShowCarNames,
        lb_show_carnames_open,
        lb_show_carnames_close
    )

    local my_car = ac.getCar(0)
    if my_car.kersPresent then
        -- Gearbox Mode (Toggle)
        if gb_full_button_toggle:pressed() then
            if Gearbox_MGUKMode == false and Gearbox_InfoMode == false then
                Gearbox_InfoMode = true
                Gearbox_MGUKInfoMode = false
                Gearbox_ElementsOffsetTime = Time
                Gearbox_InfoOpacityTime = Time
                Gearbox_MGUKInfoOpacityTime = Time
                Gearbox_MGUKModeStartTime = -10
            else
                Gearbox_MGUKMode = not Gearbox_MGUKMode
                Gearbox_InfoMode = not Gearbox_InfoMode
                Gearbox_MGUKInfoMode = not Gearbox_MGUKInfoMode
                Gearbox_ElementsOffsetTime = Time
                Gearbox_InfoOpacityTime = Time
                Gearbox_MGUKInfoOpacityTime = Time
                Gearbox_MGUKModeStartTime = -10
            end
            save_settings = true
        end

        -- Gearbox Display ERS Mode
        if gb_button_ers_mode:pressed() then
            if Gearbox_MGUKMode == false and Gearbox_InfoMode == false then
                Gearbox_MGUKMode = true
                Gearbox_InfoMode = false
                Gearbox_MGUKInfoMode = true
                Gearbox_MGUKModeStartTime = -10
                save_settings = true
            else
                if Gearbox_MGUKMode == false then
                    Gearbox_ElementsOffsetTime = Time
                    Gearbox_InfoOpacityTime = Time
                    Gearbox_MGUKInfoOpacityTime = Time
                end
                Gearbox_MGUKMode = true
                Gearbox_InfoMode = false
                Gearbox_MGUKInfoMode = true
                Gearbox_MGUKModeStartTime = -10
                save_settings = true
            end
        end

        -- Gearbox Display RPM Mode
        if gb_button_rpm_mode:pressed() then
            if Gearbox_MGUKMode == false and Gearbox_InfoMode == false then
                Gearbox_InfoMode = true
                Gearbox_MGUKInfoMode = false
                Gearbox_ElementsOffsetTime = Time
                Gearbox_InfoOpacityTime = Time
                Gearbox_MGUKInfoOpacityTime = Time
                Gearbox_MGUKModeStartTime = -10
            else
                if Gearbox_MGUKMode == true then
                    Gearbox_ElementsOffsetTime = Time
                    Gearbox_InfoOpacityTime = Time
                    Gearbox_MGUKInfoOpacityTime = Time
                end

                Gearbox_MGUKMode = false
                Gearbox_InfoMode = true
                Gearbox_MGUKInfoMode = false
                Gearbox_MGUKModeStartTime = -10
            end
            save_settings = true
        end

        -- Gearbox ERS Mode Hold
        if gb_button_ers_hold:down() then
            if Gearbox_MGUKMode == false and Gearbox_InfoMode == true then
                Gearbox_ElementsOffsetTime = Time
                Gearbox_InfoOpacityTime = Time
                Gearbox_MGUKInfoOpacityTime = Time
            end

            Gearbox_MGUKMode = true
            Gearbox_InfoMode = false
            Gearbox_MGUKInfoMode = true
            Gearbox_MGUKModeStartTime = -10
            save_settings = true
        end

        if gb_button_ers_hold:released() then
            if Gearbox_MGUKMode == true then
                Gearbox_ElementsOffsetTime = Time
                Gearbox_InfoOpacityTime = Time
                Gearbox_MGUKInfoOpacityTime = Time
            end

            Gearbox_MGUKMode = false
            Gearbox_InfoMode = true
            Gearbox_MGUKInfoMode = false
            Gearbox_MGUKModeStartTime = -10
            save_settings = true
        end

        -- Gearbox RPM Mode Hold
        if gb_button_rpm_hold:down() then
            if Gearbox_MGUKMode == true then
                Gearbox_ElementsOffsetTime = Time
                Gearbox_InfoOpacityTime = Time
                Gearbox_MGUKInfoOpacityTime = Time
            end

            Gearbox_MGUKMode = false
            Gearbox_InfoMode = true
            Gearbox_MGUKInfoMode = false
            Gearbox_MGUKModeStartTime = -10
            save_settings = true
        end

        if gb_button_rpm_hold:released() then
            if Gearbox_MGUKMode == false then
                Gearbox_ElementsOffsetTime = Time
                Gearbox_InfoOpacityTime = Time
                Gearbox_MGUKInfoOpacityTime = Time
            end

            Gearbox_MGUKMode = true
            Gearbox_InfoMode = false
            Gearbox_MGUKInfoMode = true
            Gearbox_MGUKModeStartTime = -10
            save_settings = true
        end
    end

    multi_button_update(
        map_relative_buttons,
        Map_Relative,
        map_relative_enable,
        map_relative_disable
    )

    -- Tyres
    -- Info panel (Toggle)
    if tyres_button_info_panel_toggle:pressed() then
        Tyres_ShowInfoPanel = not Tyres_ShowInfoPanel
        Tyres_ShowInfoPanelTime = Time
        Tyres_ClickPriority = true
        save_settings = true
    end


    -- Info panel (Hold)
    if tyres_button_show_info_panel_hold:down() then
        if (Tyres_ShowInfoPanel == false) then
            Tyres_ShowInfoPanelTime = Time
        end
        Tyres_ShowInfoPanel = true
        Tyres_ClickPriority = true
        save_settings = true
    end


    if tyres_button_show_info_panel_hold:released() then
        Tyres_ShowInfoPanel = false
        Tyres_ShowInfoPanelTime = Time
        Tyres_ClickPriority = false
        save_settings = true
    end

    -- Show Info panel
    if tyres_button_show_info_panel:pressed() then
        if Tyres_ShowInfoPanel == false then
            Tyres_ShowInfoPanelTime = Time
        end
        Tyres_ShowInfoPanel = true
        Tyres_ClickPriority = true
        save_settings = true
    end

    -- Hide Info panel
    if tyres_button_hide_info_panel:pressed() then
        if Tyres_ShowInfoPanel == true then
            Tyres_ShowInfoPanelTime = Time
        end
        Tyres_ShowInfoPanel = false
        Tyres_ClickPriority = false
        save_settings = true
    end

    -- Pedals
    -- Pedals Telemetry Toggle
    if pedals_telemetry_button_toggle:pressed() then
        Pedals_ShowTelemetry = not Pedals_ShowTelemetry
        Pedals_ShowTelemetryTime = Time
        save_settings = true
    end

    -- Pedals Telemetry Hold
    if pedals_telemetry_button_hold:down() then
        if (Pedals_ShowTelemetry == false) then
            Pedals_ShowTelemetryTime = Time
        end
        Pedals_ShowTelemetry = true
        save_settings = true
    end

    if pedals_telemetry_button_hold:released() then
        Pedals_ShowTelemetry = false
        Pedals_ShowTelemetryTime = Time
        save_settings = true
    end

    -- Pedals Telemetry Show
    if pedals_telemetry_button_show:pressed() then
        if Pedals_ShowTelemetry == false then
            Pedals_ShowTelemetryTime = Time
        end
        Pedals_ShowTelemetry = true
        save_settings = true
    end

    -- Pedals Telemetry Hide
    if pedals_telemetry_button_hide:pressed() then
        if Pedals_ShowTelemetry == true then
            Pedals_ShowTelemetryTime = Time
        end
        Pedals_ShowTelemetry = false
        save_settings = true
    end

    -- Sectors
    -- Fastest Lap (Toggle)
    if sectors_button_panel_toggle:pressed() then
        Sectors_UserRequestedFastestLap = not Sectors_UserRequestedFastestLap
        Sectors_UserRequestedFastestLapTime = Time
        save_settings = true
    end

    -- Fastest Lap (Hold)
    if sectors_button_show_panel_hold:down() then
        if Sectors_UserRequestedFastestLap == false then
            Sectors_UserRequestedFastestLapTime = Time
        end
        Sectors_UserRequestedFastestLap = true
        save_settings = true
    end
    if sectors_button_show_panel_hold:released() then
        Sectors_UserRequestedFastestLap = false
        Sectors_UserRequestedFastestLapTime = Time
        save_settings = true
    end

    -- Show Fastest Lap
    if sectors_button_show_panel:pressed() then
        if Sectors_UserRequestedFastestLap == false then
            Sectors_UserRequestedFastestLapTime = Time
        end
        Sectors_UserRequestedFastestLap = true
        save_settings = true
    end

    -- Hide Fastest Lap
    if sectors_button_hide_panel:pressed() then
        if Sectors_UserRequestedFastestLap == true then
            Sectors_UserRequestedFastestLapTime = Time
        end
        Sectors_UserRequestedFastestLap = false
        save_settings = true
    end

    --
    -- Custom Layouts
    --
    if custom_layout_previous:pressed() then
        local last_used = last_used_layout_storage:get()
        local number_of_layouts = layouts_count + 1 -- remember our own
        local layout_to_apply = (last_used - 1) % number_of_layouts
        while layout_to_apply < 0 do layout_to_apply = layout_to_apply + number_of_layouts end
        apply_layout(layout_to_apply)
    end

    if custom_layout_next:pressed() then
        local last_used = last_used_layout_storage:get()
        local number_of_layouts = layouts_count + 1 -- remember our own
        local layout_to_apply = (last_used + 1) % number_of_layouts
        apply_layout(layout_to_apply)
    end

    if custom_layout_apply_default:pressed() then
        apply_layout(0) -- apply default
    end

    for i=0, layouts_count-1 do
        local layout_data = CustomLayouts_Data[i]
        if layout_data ~= nil then
            if layout_data.binding ~= nil and layout_data.binding:pressed() then
                apply_layout(i+1)
            end
        end
    end
end

local function draw_keybind(text, keybind)
    ui.text(text)
    ui.nextColumn()
    keybind:control()
    ui.nextColumn()
end

local function display_buttons(buttons_list, title, show_text, hide_text)
    ui.columns(1)

    ui.setNextTextBold()
    ui.newLine(-5)
    ui.text(title)
    ui.newLine(-5)
    ui.columns(2)
    ui.setColumnWidth(0, 180)

    draw_keybind(string.format("%s (Toggle)", title),   buttons_list[1])
    draw_keybind(string.format("%s (Hold)", show_text), buttons_list[2])
    draw_keybind(string.format("%s (Hold)", hide_text), buttons_list[3])
    draw_keybind(show_text,                             buttons_list[4])
    draw_keybind(hide_text,                             buttons_list[5])
    
    ui.columns(1)
end

local function keybinds_settings()
    ui.newLine(-5)
    ui.newLine(-5)

    
    ui.tabBar("kybinds bar", ui.TabBarFlags.FittingPolicyScroll, function()
        ui.tabItem("Layouts##layouts_bindings", function()
            ui.newLine(-5)

            ui.columns(2)
            ui.setColumnWidth(0, 180)
            
            draw_keybind("Previous Layout", custom_layout_previous)
            draw_keybind("Next Layout", custom_layout_next)
            draw_keybind("Apply Default Layout", custom_layout_apply_default)
            
            for i=0, layouts_count-1 do
                local layout_data = CustomLayouts_Data[i]
                if layout_data ~= nil and layout_data.name ~= nil then
                    draw_keybind("Apply Layout " .. layout_data.name, layout_data.binding)
                end
            end

            ui.columns(1) -- reset columns so we don't bleed into other settings
        end)
        ui.tabItem("Leaderboard##binding_start", function()
            ui.newLine(-5)

            --
            -- Extended Leaderboard
            --
            ui.setNextTextBold()
            ui.text("Extended Leaderboard")
            ui.newLine(-5)
            ui.columns(2)
            ui.setColumnWidth(0, 180)
            
            draw_keybind("Full Leaderboard (Toggle)",  lb_full_button_toggle)
            draw_keybind("Full Leaderboard (Hold)",    lb_full_button_hold)
            draw_keybind("Leaderboard Retract (Hold)", lb_button_rectract_hold)
            draw_keybind("Leaderboard Extend",         lb_button_extend)
            draw_keybind("Leaderboard Retract",        lb_button_rectract)
            
            --
            -- Multiclass
            --
            display_buttons(lb_multiclass_buttons, "Multiclass", "Show Multiclass", "Hide Multiclass")
            display_buttons(lb_multiclass_filter_buttons, "Multiclass Filter", "Enable Multiclass Filter", "Disable Multiclass Filter")
            display_buttons(lb_relative_buttons, "Relative", "Show Relative", "Hide Relative")
            display_buttons(lb_carnames_buttons, "Car Names", "Show Car Names", "Hide Car Names")

            ui.columns(1) -- reset columns so we don't bleed into other settings
        end)
        ui.tabItem("Gearbox##binding_start", function()
            ui.newLine(-5)
            ui.columns(2)
            ui.setColumnWidth(0, 180)

            draw_keybind("Gearbox Mode (Toggle)", gb_full_button_toggle)
            draw_keybind("ERS Mode (Hold)",       gb_button_ers_hold)
            draw_keybind("RPM Mode (Hold)",       gb_button_rpm_hold)
            draw_keybind("Display ERS Mode",      gb_button_ers_mode)
            draw_keybind("Display RPM Mode",      gb_button_rpm_mode)

            ui.columns(1) -- reset columns so we don't bleed into other settings
        end)

        ui.tabItem("Map##binding_start", function()
            ui.newLine(-5)
            ui.columns(2)
            ui.setColumnWidth(0, 180)
            
            draw_keybind("Map Display Mode (Toggle)", map_relative_buttons[1])
            draw_keybind("Map Relative (Hold)",       map_relative_buttons[2])
            draw_keybind("Map Absolute (Hold)",       map_relative_buttons[3])
            draw_keybind("Display Map Relative",      map_relative_buttons[4])
            draw_keybind("Display Map Absolute",      map_relative_buttons[5])

            ui.columns(1) -- reset columns so we don't bleed into other settings
        end)

        ui.tabItem("Tyres##binding_start", function()
            ui.newLine(-5)
            ui.columns(2)
            ui.setColumnWidth(0, 180)

            draw_keybind("Info panel (Toggle)",    tyres_button_info_panel_toggle)
            draw_keybind("Show Info panel (Hold)", tyres_button_show_info_panel_hold)
            draw_keybind("Show Info panel",        tyres_button_show_info_panel)
            draw_keybind("Hide Info panel",        tyres_button_hide_info_panel)

            ui.columns(1) -- reset columns so we don't bleed into other settings
        end)

        ui.tabItem("Pedals##binding_start", function()
            ui.newLine(-5)
            ui.columns(2)
            ui.setColumnWidth(0, 180)

            draw_keybind("Telemetry (Toggle)", pedals_telemetry_button_toggle)
            draw_keybind("Telemetry (Hold)",   pedals_telemetry_button_hold)
            draw_keybind("Show Telemetry",     pedals_telemetry_button_show)
            draw_keybind("Hide Telemetry",     pedals_telemetry_button_hide)

            ui.columns(1) -- reset columns so we don't bleed into other settings
        end)

        ui.tabItem("Sectors##binding_start", function()
            ui.newLine(-5)
            ui.columns(2)
            ui.setColumnWidth(0, 180)

            draw_keybind("Fastest Lap (Toggle)", sectors_button_panel_toggle)
            draw_keybind("Fastest Lap (Hold)",   sectors_button_show_panel_hold)
            draw_keybind("Show Fastest Lap",     sectors_button_show_panel)
            draw_keybind("Hide Fastest Lap",     sectors_button_hide_panel)

            ui.columns(1) -- reset columns so we don't bleed into other settings
        end)
    end)

    ui.columns(1) -- reset columns so we don't bleed into other settings
end

local function increase_value(to_change)
    return math.clamp(to_change + 0.1, 0.5, 2)
end

local function decrease_value(to_change)
    return math.clamp(to_change - 0.1, 0.5, 2)
end

local bound_msg1 = nil
local bound_msg2 = nil
local function general_settings()
    ui.newLine(-5)
    ui.setNextTextBold()
    ui.text("Apps scale:")

    ui.pushStyleColor(ui.StyleColor.Text, colors.SETTINGS_TEXT)
    ui.text(string.format("Change scale for all apps"))
    ui.popStyleColor()
    ui.newLine(-5)
    
    if ui.button("-", vec2(40)) then
        save_settings = true
        SemaphoresScale = decrease_value(SemaphoresScale)
        GearboxScale = decrease_value(GearboxScale)
        PcTimeScale  = decrease_value(PcTimeScale)
        MapTimeScale = decrease_value(MapTimeScale)
        SectorsScale = decrease_value(SectorsScale)
        LeaderboardScale = decrease_value(LeaderboardScale)
        TyresScale       = decrease_value(TyresScale)
        MapScale         = decrease_value(MapScale)
        DeltabarScale    = decrease_value(DeltabarScale)
        PedalsScale      = decrease_value(PedalsScale)
        RadarScale       = decrease_value(RadarScale)
        DamagePanel_Scale   = decrease_value(DamagePanel_Scale)
        MFDScale   = decrease_value(MFDScale)
    end
    ui.sameLine()
    if ui.button(" + ", vec2(40)) then
        save_settings = true
        SemaphoresScale = increase_value(SemaphoresScale)
        GearboxScale = increase_value(GearboxScale)
        PcTimeScale  = increase_value(PcTimeScale)
        MapTimeScale = increase_value(MapTimeScale)
        SectorsScale = increase_value(SectorsScale)
        LeaderboardScale = increase_value(LeaderboardScale)
        TyresScale       = increase_value(TyresScale)
        MapScale         = increase_value(MapScale)
        DeltabarScale    = increase_value(DeltabarScale)
        PedalsScale      = increase_value(PedalsScale)
        RadarScale       = increase_value(RadarScale)
        DamagePanel_Scale   = increase_value(DamagePanel_Scale)
        MFDScale   = increase_value(MFDScale)
    end
    
    ui.newLine(-5)
    if ui.button("Reset Scales") then
        save_settings = true
        SemaphoresScale = 1
        GearboxScale = 1
        PcTimeScale = 1
        MapTimeScale = 1
        SectorsScale = 1
        LeaderboardScale = 1
        TyresScale = 1
        MapScale = 1
        DeltabarScale = 1
        PedalsScale = 1
        RadarScale = 1
        DamagePanel_Scale = 1
        MFDScale = 1
    end
    ui.newLine(-5)
    
    if ui.checkbox("Scale Automatically", Apps_AutoScale) then
        Apps_AutoScale = not Apps_AutoScale
        save_settings = true
    end
    ui.newLine(-5)
    ui.newLine(-5)
    
    ui.setNextTextBold()
    ui.text("HUD Layout:")
    ui.pushStyleColor(ui.StyleColor.Text, colors.SETTINGS_TEXT)
    ui.textWrapped(string.format("Save and Edit your custom layouts. Every layout will save the position of each app and all CMRT Settings. You can make how many layouts you want."))
    ui.popStyleColor()
    
    
    
    ui.newLine(-5)
    if ui.button("Default Layout") then
        -- player wants to move the apps
        apply_layout(0)
    end
    if ui.itemHovered() then
        ui.tooltip(function()
        ui.text("Default Layout will not overwrite any settings.")
        end)
    end
    ui.sameLine()
    ui.button("Reset settings##custom_layout")
    confirm_dialog("reset all cmrt settings", "Overwrite all settings with default ones?", nil, nil, false, function()
        for k,v in pairs(settings_data) do
            v.storage:set(v.default_value)
        end
        apply_apps_settings(get_settings_table())
    end)
    ui.newLine(-5)
    ui.newLine(-5)


    --
    -- custom layouts
    --
    ui.columns(3)
    local index_to_remove = -1
    for i=0, layouts_count-1 do
        local layout_data = CustomLayouts_Data[i]

        if layout_name_editing_index ~= i then
            -- user is not editing this button, show it
            if ui.button(layout_data.name) then
                apply_layout(i + 1)
            end
            if ui.itemHovered() then
                ui.tooltip(function()
                ui.text("Right click for more options.")
                end)
            end
        else
            -- user is editing the name of this layout, let him do it
            local layout_new_name, _, enter_pressed = ui.inputText("##layout_name"..i, layout_data.name, ui.InputTextFlags.AutoSelectAll)
            if enter_pressed then
                CustomLayouts_Data[i].name = layout_new_name
                layout_name_editing_index = -1 -- no button to edit
                save_layouts()
            end
        end
        
        -- right click menu
        ui.itemPopup("layout right click menu##" .. i, ui.MouseButton.Right, function()
            
            ui.setNextTextBold()
            ui.text(layout_data.name)
            
            ui.newLine(-5)
            local close_popup = false
            if ui.button("Rename##custom_layout") then
                layout_name_editing_index = i -- start editing this name
                close_popup = true
            end
            ui.sameLine()

            ui.button("Overwrite##custom_layout")
            confirm_dialog("layout confirm overwrite##" .. i, "Overwrite this layout with current settings?", nil, nil, false, function()
                layout_data.app_positions = get_app_positions() -- override positions
                layout_data.deltabar_size = get_deltabar_horizontal_size()
                layout_data.apps_settings = make_table_from_current_settings()
                last_used_layout_storage:set(i + 1) -- we've just overwritten this layout, aka that's the one we're using now!
                save_layouts()
                close_popup = true
            end)
            ui.sameLine()

            if ui.button("Clone##clone layout") then
                local copied = table.clone(CustomLayouts_Data[i], true)
                copied.name = copied.name .. " (Copy)"
                copied.binding = ac.ControlButton("cmrt.complete/Custom Layout Apply " .. (layouts_count + 1)) -- 0 is reserved for our default one
                CustomLayouts_Data[layouts_count] = copied
                layouts_count = layouts_count + 1
                save_layouts()
                close_popup = true
            end
            ui.newLine(-5)

            local bound_to = layout_data.binding:boundTo()
            bound_msg1 = nil
            bound_msg2 = nil
            if bound_to ~= nil then
                bound_msg1 = string.format("This layout is bound to %s.", bound_to)
                bound_msg2 = "Remove the binding first."
            end
            ui.button("Delete##custom_layout")
            confirm_dialog("layout confirm delete##" .. i, "Are you sure you want to delete this layout?", bound_msg1, bound_msg2, bound_to ~= nil, function()
                if bound_to == nil then
                    -- layout not bound to anything, we can close confirm dialog and delete the layout
                    index_to_remove = i
                    close_popup = true
                end
            end)
            

            if close_popup then ui.closePopup() end -- so it closes even if we start from inner popups
        end)
        ui.nextColumn()
    end

    ui.columns(1)
    ui.newLine(-5)

    if ui.button("Save current layout") then
        -- save current layout as a new one
        local positions = get_app_positions()
        CustomLayouts_Data[layouts_count] = {
            name          = "Custom " .. (layouts_count + 1),
            app_positions = positions,
            deltabar_size = get_deltabar_horizontal_size(),
            apps_settings = get_settings_table(),
            binding = ac.ControlButton("cmrt.complete/Custom Layout Apply " .. (layouts_count + 1)) -- 0 is reserved for our default one
        }
        layouts_count = layouts_count + 1
        save_layouts()
    end

    if index_to_remove >= 0 then
        table_remove(CustomLayouts_Data, index_to_remove)
        layouts_count = layouts_count - 1 -- so we don't edit the data we iterate on
        save_layouts()
    end
    
    
    ui.newLine(-5)
    ui.newLine(-5)
    
    

    ui.newLine(15)
    ui.drawImage(settings.get_asset("cmrt_complete_logo"), ui.getCursor(), ui.getCursor() + vec2(146, 30))
    ui.setCursor(ui.getCursor() + vec2(0, 40))
    
    ui.pushStyleColor(ui.StyleColor.Text, colors.SETTINGS_TEXT)
    ui.text(app_version)
    ui.popStyleColor()
end

local function scale_settings(old_value)
    ui.newLine(-5)
    ui.text(string.format("Change scale: %.0f%%", old_value * 100))
    
    ui.newLine(-5)
    if ui.button("-", vec2(40)) then
        old_value = old_value - 0.1
        save_settings = true
    end
    ui.sameLine()
    if ui.button(" + ", vec2(40)) then
        old_value = old_value + 0.1
        save_settings = true
    end
    
    ui.newLine(-5)
    if ui.button("Reset") then
        old_value = 1
        save_settings = true
    end
    ui.newLine(-5)
    ui.newLine(-5)
    
    old_value = math.clamp(old_value, 0.5, 2)
    return old_value
end

local function semaphores_settings()
    SemaphoresScale = scale_settings(SemaphoresScale)

    if ui.checkbox("Semaphores Enabled", SemaphoresEnabled) then
        SemaphoresEnabled = not SemaphoresEnabled
        save_settings = true
    end
    ui.newLine(-5)
end

Gearbox_MGUKInfoOpacityTime = -10
Gearbox_InfoOpacityTime = -10
Gearbox_ElementsOffsetTime = -10
local function gearbox_settings()
    GearboxScale = scale_settings(GearboxScale)
    
    ui.setNextTextBold()
    ui.text("Preferences")
    ui.newLine(-5)
    local can_edit_lights = false
    if Gearbox_PeakRpmDetected == nil then
        ui.pushDisabled()
        ui.checkbox("RPM Lights at Power Peak (No Data Available)", Gearbox_ShowPeakShift)
        ui.popDisabled()
        can_edit_lights = true
    else
        if ui.checkbox("RPM Lights at Power Peak", Gearbox_ShowPeakShift) then
            Gearbox_ShowPeakShift = not Gearbox_ShowPeakShift
            save_settings = true
        end
        can_edit_lights = not Gearbox_ShowPeakShift
    end

    if not can_edit_lights then
        ui.pushDisabled()
        ui.checkbox("RPM lights at limiter", true)
        ui.popDisabled()
    else
        if ui.checkbox("RPM lights at limiter", Gearbox_DotsWindow) then
            Gearbox_DotsWindow = not Gearbox_DotsWindow
            save_settings = true
        end
    end

    local my_car = ac.getCar(0)
 	if ui.checkbox("Show ERS by Default", Gearbox_ERSMode) then
        Gearbox_ERSMode = not Gearbox_ERSMode
        save_settings = true
        if my_car.kersPresent then
            if Gearbox_MGUKMode ~= Gearbox_ERSMode then
                Gearbox_ElementsOffsetTime = Time
                Gearbox_InfoOpacityTime = Time
                Gearbox_MGUKInfoOpacityTime = Time
            end
            Gearbox_MGUKMode = Gearbox_ERSMode
            Gearbox_InfoMode = not Gearbox_ERSMode
            Gearbox_MGUKInfoMode = Gearbox_ERSMode
        else
            if Gearbox_MGUKMode == true then
                Gearbox_MGUKMode = false
                Gearbox_InfoMode = true
                Gearbox_MGUKInfoMode = false
                Gearbox_ElementsOffsetTime = Time
                Gearbox_InfoOpacityTime = Time
                Gearbox_MGUKInfoOpacityTime = Time
            end
        end
    end

    ui.newLine(-5)
    ui.setNextTextBold()
    ui.text("Lights Settings Per Car:")
    ui.newLine(-5)

    

    if not can_edit_lights then
        ui.pushDisabled()
        ui.text("RPM Lights Selector")
        if Gearbox_PeakRpmDetected ~= nil then
            ui.slider("##rpm_lights_unavailable", Gearbox_PeakRpmDetected, 300, ac.getCar(0).rpmLimiter - 250, "%.0f")
        else
            ui.slider("##rpm_lights_no_data", nil, 300, ac.getCar(0).rpmLimiter - 250, "No Data")
        end
        ui.popDisabled()
    else
        ui.text("RPM Lights Selector")
        local value, changed = ui.slider("##rpm_lights_editable", Gearbox_WantedRpm, 300, ac.getCar(0).rpmLimiter - 250, "%.0f")
        ui.sameLine()
        
        if changed then
            gearbox_wanted_rpm_storage:set(value)
            Gearbox_WantedRpm = value
        end
        
        local default_peak = ac.getCar(0).rpmLimiter - 300
        if value == default_peak then
            ui.pushDisabled()
            ui.iconButton(ui.Icons.Restart)
            ui.popDisabled()
        else
            if ui.iconButton(ui.Icons.Restart) then
                -- reset to default values (peak rpm)
                gearbox_wanted_rpm_storage:set(nil)
                Gearbox_WantedRpm = default_peak
            end
        end
    end

    ui.newLine(-5)
    
    
    
    ui.newLine(-5)


    ui.text("Speed measurement units:")
    if ui.radioButton("KMH##mph", not Gearbox_ShowMph) then
        Gearbox_ShowMph = false
        save_settings = true
    end
    if ui.radioButton("MPH##mph", Gearbox_ShowMph) then
        Gearbox_ShowMph = true
        save_settings = true
    end
    ui.newLine(-5)

    ui.text("Fuel measurement units:")
    if ui.radioButton("Liters##gal", not Gearbox_ShowGal) then
        Gearbox_ShowGal = false
        save_settings = true
    end
    if ui.radioButton("Gallons##gal", Gearbox_ShowGal) then
        Gearbox_ShowGal = true
        save_settings = true
    end
end

local function maptime_settings()
    MapTimeScale = scale_settings(MapTimeScale)
    if ui.checkbox("show background", MapTime_ShowBg) then
        MapTime_ShowBg = not MapTime_ShowBg
        save_settings = true
    end
    
    if ui.checkbox("show bar", MapTime_ShowBar) then
        MapTime_ShowBar = not MapTime_ShowBar
        save_settings = true
    end
end
local function pctime_settings()
    PcTimeScale = scale_settings(PcTimeScale)
    if ui.checkbox("show background", PcTime_ShowBg) then
        PcTime_ShowBg = not PcTime_ShowBg
        save_settings = true
    end
    
    if ui.checkbox("show bar", PcTime_ShowBar) then
        PcTime_ShowBar = not PcTime_ShowBar
        save_settings = true
    end
end

local function sectors_settings()
    SectorsScale = scale_settings(SectorsScale)
    
    ui.text("Fastest Lap notification:")
    local value, changed = ui.slider("##sectors_anim_length", Sectors_AnimDuration, 5, 40, "%.0f seconds")
    Sectors_AnimDuration = value
    if changed then save_settings = true end
end

local function save_extra_colors()
    -- TAG(cogno): StorageSavesOnlyNumbers
    local extra_colors = table.nkeys(color_buttons) - 7 -- the 7 default cannot be edited nor removed
    mc_color_count_storage:set(extra_colors)
    for i=0, extra_colors-1 do
        local to_save = color_buttons[i+7]
        local saved_color_storage_r = ac.storage("Multiclass_ExtraColor_v1_r"..i, nil)
        local saved_color_storage_g = ac.storage("Multiclass_ExtraColor_v1_g"..i, nil)
        local saved_color_storage_b = ac.storage("Multiclass_ExtraColor_v1_b"..i, nil)
        local saved_color_storage_m = ac.storage("Multiclass_ExtraColor_v1_m"..i, nil)
        saved_color_storage_r:set(to_save.r)
        saved_color_storage_g:set(to_save.g)
        saved_color_storage_b:set(to_save.b)
        saved_color_storage_m:set(to_save.mult)
    end
end

local function save_multiclass_tags()
    -- TAG(cogno): StorageSavesOnlyNumbers
    Leaderboard_Multiclass_UpdateTags = true
    local list_len = table.nkeys(Leaderboard_Multiclass_EnabledTags)
    mc_tags_count_storage:set(list_len)
    for i=0, list_len-1 do
        local to_save = Leaderboard_Multiclass_EnabledTags[i]
        local tagname = to_save.name
        local tagcolor = to_save.color
        local saved_color_storage_r = ac.storage("Multiclass_TagsData_TagColor_r"..i, nil)
        local saved_color_storage_g = ac.storage("Multiclass_TagsData_TagColor_g"..i, nil)
        local saved_color_storage_b = ac.storage("Multiclass_TagsData_TagColor_b"..i, nil)
        local saved_color_storage_m = ac.storage("Multiclass_TagsData_TagColor_m"..i, nil)
        local saved_tag_storage = ac.storage("Multiclass_TagsData_TagName"..i, nil)
        saved_color_storage_r:set(tagcolor.r)
        saved_color_storage_g:set(tagcolor.g)
        saved_color_storage_b:set(tagcolor.b)
        saved_color_storage_m:set(tagcolor.mult)
        saved_tag_storage:set(tagname)
    end
end

Leaderboard_Extended_StartTime = -1
local popup_call_time = -1
local function leaderboard_settings()
    ui.newLine(-5)
    ui.tabBar("Tab", function()
        ui.tabItem("General", function()
            LeaderboardScale = scale_settings(LeaderboardScale)
            
            
            ui.text("Temperature Indicator:")
            if ui.radioButton("Celsius", not Leaderboard_ShowFah) then
                Leaderboard_ShowFah = false
                save_settings = true
            end
            if ui.radioButton("Fahrenheit", Leaderboard_ShowFah) then
                Leaderboard_ShowFah = true
                save_settings = true
            end
            
            
            ui.newLine(-5)
            ui.text("Fastest Lap notification:")
            local value, changed = ui.slider("##sectors_anim_length", Leaderboard_AnimDuration, 5, 40, "%.0f seconds")
            Leaderboard_AnimDuration = value
            if changed then save_settings = true end
            
            ui.newLine(-5)
            ui.text("Interval refresh rate:")
            local value, changed = ui.slider("##leaderb_interv_refresh_rate", Leaderboard_RefreshRate / 1000, 0.1, 60, "%.1f s")
            Leaderboard_RefreshRate = value * 1000
            if changed then save_settings = true end

            ui.newLine(-5)
            ui.text("Relative Interval refresh rate:")
            local value, changed = ui.slider("##leaderb_relative_interv_refresh_rate", Leaderboard_Relative_RefreshRate / 1000, 0.1, 60, "%.1f s")
            Leaderboard_Relative_RefreshRate = value * 1000
            if changed then save_settings = true end
        end)
        ui.tabItem("Display", function()
            ui.newLine(-5)
            ui.newLine(-5)

            if ui.checkbox("Show tyres compound", Leaderboard_ShowTyres) then
                Leaderboard_ShowTyres = not Leaderboard_ShowTyres
                save_settings = true
            end
            if ui.checkbox("Make Long Names Scroll", Leaderboard_ScrollLongNames) then
                Leaderboard_ScrollLongNames = not Leaderboard_ScrollLongNames
                save_settings = true
            end
            if ui.checkbox("Show Car Names instead of Driver Names", Leaderboard_ShowCarNames) then
                Leaderboard_ShowCarNames = not Leaderboard_ShowCarNames
                save_settings = true
            end

            ui.newLine(-5)
            
            if ui.checkbox("Show Relative", Leaderboard_Relative) then
                Leaderboard_Relative = not Leaderboard_Relative
                Leaderboard_Relative_ChangedThisFrame = true
                save_settings = true
            end
            ui.newLine(-5)
            ui.text("Driver Count Relative:")
            local value2, change2 = ui.slider("##driver_count_relative", Leaderboard_PeopleCount_Relative, 1, 5, "%.0f people")
            Leaderboard_PeopleCount_Relative = value2
            if change2 then save_settings = true end
            ui.newLine(-5)

            if ui.checkbox("Show Extended", Leaderboard_ShowExtended) then
                Leaderboard_ShowExtended = not Leaderboard_ShowExtended
                save_settings = true
                Leaderboard_Extended_StartTime = Time
                Leaderboard_Extended_ThisFrame = true
            end
            ui.newLine(-5)

            if Leaderboard_ShowExtended then
                ui.pushDisabled()
                ui.text("Driver Count:")
                ui.slider("##driver_count_fake", Leaderboard_PeopleCount, 1, 5, "%.0f people")
                ui.popDisabled()
            else
                ui.text("Driver Count:")
                local value, changed = ui.slider("##driver_count", Leaderboard_PeopleCount, 1, 5, "%.0f people")
                Leaderboard_PeopleCount = value
                if changed then save_settings = true end
            end

            ui.text("Hotlap Lap Count:")
            local value, changed = ui.slider("##driver_count_hotlap", Leaderboard_HotlapCount, 1, 10, "%.0f laps")
            Leaderboard_HotlapCount = value
            if changed then save_settings = true end

            ui.newLine(10)
            ui.setNextTextBold()
            ui.text("Session Info:")
            if ui.checkbox("Show Air Temperature", Leaderboard_ShowAirTemp) then
                Leaderboard_ShowAirTemp = not Leaderboard_ShowAirTemp
                save_settings = true
            end

            if ui.checkbox("Show Tarmac Temperature", Leaderboard_ShowTarmacTemp) then
                Leaderboard_ShowTarmacTemp = not Leaderboard_ShowTarmacTemp
                save_settings = true
            end

            if ui.checkbox("Show Grip Percentage", Leaderboard_ShowGripPercent) then
                Leaderboard_ShowGripPercent = not Leaderboard_ShowGripPercent
                save_settings = true
            end

            if ui.checkbox("Show Wind Information", Leaderboard_ShowWindInfo) then
                Leaderboard_ShowWindInfo = not Leaderboard_ShowWindInfo
                save_settings = true
            end

            if ui.checkbox("Show Player Count", Leaderboard_ShowPlayerCount) then
                Leaderboard_ShowPlayerCount = not Leaderboard_ShowPlayerCount
                save_settings = true
            end

            if ui.checkbox("Show Weather", Leaderboard_ShowWeather) then
                Leaderboard_ShowWeather = not Leaderboard_ShowWeather
                save_settings = true
            end
            ui.newLine(-5)
            ui.text("Scrolling Speed:")
            local value, changed = ui.slider("##session_info_scrolling_speed", Leaderboard_SessionScrollingSpeed, -50, 50, "%.0f%%")
            Leaderboard_SessionScrollingSpeed = value
            if changed then save_settings = true end

        end)
        ui.tabItem("Multiclass", function()
            ui.newLine(-5)
            if ui.checkbox("Enabled", Leaderboard_Multiclass_Enabled) then
                Leaderboard_Multiclass_Enabled = not Leaderboard_Multiclass_Enabled
                save_settings = true
                Leaderboard_Multiclass_EnabledTime = Time
            end
            
            if Leaderboard_Multiclass_Enabled then
                if ui.checkbox("Show only drivers with my tag", Leaderboard_Multiclass_FilterEnabled) then
                    Leaderboard_Multiclass_FilterEnabled = not Leaderboard_Multiclass_FilterEnabled
                    save_settings = true
                end
                ui.pushStyleColor(ui.StyleColor.Text, colors.SETTINGS_TEXT)
                ui.textWrapped("Displays leaderboard data, sector data, focused drivers on the map and deltabar best times relative to your own class only.")
                ui.popStyleColor()
                ui.newLine(-5)
                ui.newLine(-5)
                
                ui.columns(4, false, "Multiclass Tags")
                ui.setColumnWidth(0, 50)
                ui.setColumnWidth(1, 200)
                ui.setColumnWidth(2, 35)
                
                local index_to_remove = -1
                local table_len = table.nkeys(Leaderboard_Multiclass_EnabledTags)
                for i = 0, table_len-1 do
                    local elem = Leaderboard_Multiclass_EnabledTags[i]
                    if elem ~= nil then
                        -- up/down
                        if ui.arrowButton(
                                'Up##' .. i,
                                ui.Direction.Up,
                                vec2(15, ui.frameHeight()),
                                i > 0 and ui.ButtonFlags.None or ui.ButtonFlags.Disabled) then
                            Leaderboard_Multiclass_EnabledTags[i] = Leaderboard_Multiclass_EnabledTags[i-1]
                            Leaderboard_Multiclass_EnabledTags[i-1] = elem
                            save_multiclass_tags()
                        end
                        ui.sameLine()
                        if ui.arrowButton(
                                'Down##' .. i,
                                ui.Direction.Down,
                                vec2(15, ui.frameHeight()),
                                i < table_len-1 and ui.ButtonFlags.None or ui.ButtonFlags.Disabled) then
                            Leaderboard_Multiclass_EnabledTags[i] = Leaderboard_Multiclass_EnabledTags[i+1]
                            Leaderboard_Multiclass_EnabledTags[i+1] = elem
                            save_multiclass_tags()
                        end
                        ui.nextColumn()

                        -- text
                        ui.setNextItemWidth(ui.availableSpaceX())
                        local classText, _, enterPressed = ui.inputText('##name' .. i, elem.name)
                        if ui.itemHovered() then
                            ui.tooltip(function()
                            ui.text("Case insensitive. Can contain multiple tags separated by comma.")
                            ui.text("Press enter to confirm changes.")
                            end)
                        end
                        if enterPressed then
                            elem.name = classText
                            save_multiclass_tags()
                        end
                        ui.nextColumn()
                        
                        -- color preview
                        ui.colorButton(
                            'Color##' .. i,
                            elem.color,
                            ui.ColorPickerFlags.None)
                        
                        
                        ui.itemPopup("popup##"..i, ui.MouseButton.Left, function()
                            popup_call_time = Time
                            ui.text("Choose color")
                            ui.newLine(-5)
                            local colors_count = table.nkeys(color_buttons)
                            for color_idx=0, colors_count-1 do
                                local color = color_buttons[color_idx]
                                if color ~= nil then
                                    if ui.colorButton("CMRT1##"..color_idx, color, ui.ColorPickerFlags.None) then
                                        elem.color = color:clone()
                                        editing_color = false
                                        save_multiclass_tags()
                                    end
                                    if color_idx >= 7 then -- we don't let you delete nor edit default colors
                                        ui.itemPopup("inner popup##" .. i .. "-"..color_idx, ui.MouseButton.Right, function()
                                            if ui.button("edit") then
                                                editing_color = true
                                                editing_color_idx = color_idx
                                                ui.closePopup()
                                                save_extra_colors()
                                            end
                                            if ui.button("delete") then
                                                ui.closePopup()
                                                table_remove(color_buttons, color_idx)
                                                editing_color = false -- deactivate so we don't get out of bounds, you can right click and edit anyway
                                                save_extra_colors()
                                            end
                                        end)
                                    end
                                    if color_idx % 7 ~= 6 then ui.sameLine() end
                                end
                            end
                            
                            if ui.iconButton(ui.Icons.Plus) then
                                editing_color = true
                                editing_color_idx = colors_count
                                color_buttons[colors_count] = colors.WHITE:clone() -- so we don't edit the original white for every app
                                save_extra_colors()
                            end
                            
                            if editing_color then
                                ui.newLine(-5)
                                local edited = ui.colorPicker("", color_buttons[editing_color_idx])
                                if edited then save_extra_colors() end
                            else
                                ui.newLine(50)
                            end

                            ui.pushAlignment(false, 1)
                            if ui.button("Ok") then
                                ui.closePopup()
                            end
                            ui.popAlignment()
                        end)
                        if Time - popup_call_time > 0.2 then editing_color = false end
                        ui.nextColumn()
    
                        -- buttons
                        if ui.iconButton(ui.Icons.Trash .. "##"..i, vec2(22, 22)) then
                            index_to_remove = i -- mark for removal (so we don't do it while iterating on it)
                        end
                        ui.nextColumn()
                    end
                end

                if index_to_remove >= 0 then
                    table_remove(Leaderboard_Multiclass_EnabledTags, index_to_remove)
                    save_multiclass_tags()
                end

                -- adding new elements
                ui.columns(3, false, "Example Id")
                ui.setColumnWidth(0, 120)
                ui.nextColumn()
                if ui.iconButton(ui.Icons.Plus .. "##mc_add", vec2(30, 20)) then
                    local new_color = nil
                    local colors_count = table.nkeys(Leaderboard_Multiclass_EnabledTags)
                    if colors_count % 7 == 0 then new_color = mc_color1:clone() end
                    if colors_count % 7 == 1 then new_color = mc_color2:clone() end
                    if colors_count % 7 == 2 then new_color = mc_color3:clone() end
                    if colors_count % 7 == 3 then new_color = mc_color4:clone() end
                    if colors_count % 7 == 4 then new_color = mc_color5:clone() end
                    if colors_count % 7 == 5 then new_color = mc_color6:clone() end
                    if colors_count % 7 == 6 then new_color = mc_color7:clone() end
                    append_tag("", new_color)
                    save_multiclass_tags()
                end
                ui.columns(1, false, "Example Id")
            end
        end)
    end)
end

Tyres_ShowInfoPanelTime = -10
local function tyres_settings()
    TyresScale = scale_settings(TyresScale)
    
    if ui.checkbox("Show attached pedals", Tyres_ShowPedals) then
        Tyres_ShowPedals = not Tyres_ShowPedals
        save_settings = true
    end
    if ui.checkbox("Show pressure delta from ideal", Tyres_PressureDelta) then
        Tyres_PressureDelta = not Tyres_PressureDelta
        save_settings = true
    end
    if ui.checkbox("Show core temperature gradient", Tyres_TempColored) then
        Tyres_TempColored = not Tyres_TempColored
        save_settings = true
    end
	if ui.checkbox("Open Info Panel automatically", Tyres_AutoInfoPanel) then
        Tyres_AutoInfoPanel = not Tyres_AutoInfoPanel
        save_settings = true
    end
    if ui.checkbox("Flip Info Panel", Tyres_FlipInfoPanel) then
        Tyres_FlipInfoPanel = not Tyres_FlipInfoPanel
        save_settings = true
    end
    ui.pushStyleColor(ui.StyleColor.Text, colors.SETTINGS_TEXT)
    ui.textWrapped(
    "Info Panel will open automatically when you enter the pitlane and close automatically 10 seconds after you've left the pitlane.")
    ui.popStyleColor()
    ui.newLine(-5)
    ui.text("Temperature Indicator:")
    if ui.radioButton("Celsius", not Tyres_ShowFah) then
        Tyres_ShowFah = false
        save_settings = true
    end
    if ui.radioButton("Fahrenheit", Tyres_ShowFah) then
        Tyres_ShowFah = true
        save_settings = true
    end
    
    ui.newLine(-5)
    ui.text("Speed Indicator:")
    if ui.radioButton("Metric", not Tyres_ShowMph) then
        Tyres_ShowMph = false
        save_settings = true
    end
    if ui.radioButton("Imperial", Tyres_ShowMph) then
        Tyres_ShowMph = true
        save_settings = true
    end
end

Map_Relative_SwitchTime = 0

local function map_settings()
    MapScale = scale_settings(MapScale)
    
    if ui.checkbox("Low Profile Mode", Map_LowProfile) then
        Map_LowProfile = not Map_LowProfile
        save_settings = true
    end
    ui.pushStyleColor(ui.StyleColor.Text, colors.SETTINGS_TEXT)
    ui.textWrapped("In low profile mode the map will show bigger only the leader, yourself and the two positions ahead and behind you. In normal mode, instead, the map will show bigger everyone.")
    ui.popStyleColor()

    ui.newLine(-5)
    if ui.checkbox("Relative", Map_Relative) then
        Map_Relative = not Map_Relative
        Map_Relative_SwitchTime = Time
        save_settings = true
    end

    ui.newLine(-5)
    if ui.checkbox("Remove Map Background", MapRemoveBG) then
        MapRemoveBG = not MapRemoveBG
        save_settings = true
    end

    if ui.itemHovered(ui.HoveredFlags.None) then
        ui.setTooltip("Here you go, Damgam.")
    end

    ui.newLine(-5)
    if ui.checkbox("Remove Map Background When Data Is Missing", MapRemoveBGWhenDataMissing) then
        MapRemoveBGWhenDataMissing = not MapRemoveBGWhenDataMissing
        save_settings = true
    end

    ui.newLine(-5)
    if ui.checkbox("Show DRS zones", Map_ShowDRS) then
        Map_ShowDRS = not Map_ShowDRS
        save_settings = true
    end
end

local barmode_names = {
    [0]="Session Best",
    "Session Optimal",
    "Record Best",
    "Record Optimal",
    "Previous Lap",
    "Session Record",
}

-- NOTE(cogno): be careful when you change these, because we have code that manually checks these values in deltabar.first
local barmode_choices = {
    [0]="Don't Change",
    "Session Best",
    "Session Optimal",
    "Record Best",
    "Record Optimal",
    "Previous Lap",
    "Session Record",
}

local barmode_dropdown = 0
local function deltabar_settings()
    ui.newLine(-5)
    ui.newLine(-5)
    ui.tabBar("Tab", function()
        ui.tabItem("General", function()
            DeltabarScale = scale_settings(DeltabarScale)
            
            ui.text("Info bar notification:")
            local value, changed = ui.slider("##deltabar_anim_length", Deltabar_AnimDuration, 2, 40, "%.0f seconds")
            Deltabar_AnimDuration = value
            if changed then save_settings = true end
            
            ui.newLine(-5)
            if ui.checkbox("Minimized ", Deltabar_Minimized) then
                Deltabar_Minimized = not Deltabar_Minimized
                save_settings = true
            end
            ui.pushStyleColor(ui.StyleColor.Text, colors.SETTINGS_TEXT)
            ui.textWrapped("Hides the delta bar itself, leaving only the delta on screen.")
            ui.popStyleColor()
            
            ui.newLine(-5)
            if Deltabar_Minimized then
                ui.text("Delta Position:")
                if ui.radioButton("Upper", Deltabar_Position == 0) then
                    Deltabar_Position = 0
                    save_settings = true
                end
                if ui.radioButton("Lower", Deltabar_Position == 2 or Deltabar_Position == 1) then
                    Deltabar_Position = 1
                    save_settings = true
                end
            else
                ui.text("Deltabar Position:")
                if ui.radioButton("Upper", Deltabar_Position == 0) then
                    Deltabar_Position = 0
                    save_settings = true
                end
                if ui.radioButton("Centered", Deltabar_Position == 1) then
                    Deltabar_Position = 1
                    save_settings = true
                end
                if ui.radioButton("Lower", Deltabar_Position == 2) then
                    Deltabar_Position = 2
                    save_settings = true
                end
            end

            ui.newLine(-5)
            if ui.checkbox("Save on Close", Deltabar_SaveOnClose) then
                Deltabar_SaveOnClose = not Deltabar_SaveOnClose
                save_settings = true
            end
            ui.pushStyleColor(ui.StyleColor.Text, colors.SETTINGS_TEXT)
            ui.textWrapped("Useful if notice stuttering at the end of each sector. With this setting enabled the lap/sectors data will be saved when the game closes instead of at the end of every sector.")
            ui.popStyleColor()
            ui.text("WARNING: ")
            ui.sameLine()
            ui.pushStyleColor(ui.StyleColor.Text, colors.SETTINGS_TEXT)
            ui.textWrapped("The data will be lost if the game crashes or closes unexpectedly (for example by using Alt+F4)")
            ui.popStyleColor()
        end)
        ui.tabItem("Preferences", function()
            ui.newLine(-5)
            ui.pushStyleColor(ui.StyleColor.Text, colors.SETTINGS_TEXT)
            ui.text("Choose the deltabar mode for each session")
            ui.popStyleColor()
            ui.newLine(-5)
            
            ui.text("Practice:")
            local practice_choice, prac_changed = ui.combo("##dtbar_1", Deltabar_PracMode, ui.ComboFlags.None, barmode_choices)
            Deltabar_PracMode = practice_choice
            if prac_changed then save_settings = true end

            ui.text("Qualify:")
            local qualify_choice, qual_changed = ui.combo("##dtbar_2", Deltabar_QualMode, ui.ComboFlags.None, barmode_choices)
            Deltabar_QualMode = qualify_choice
            if qual_changed then save_settings = true end
            
            ui.text("Race:")
            local race_choice, race_changed = ui.combo("##dtbar_3", Deltabar_RaceMode, ui.ComboFlags.None, barmode_choices)
            Deltabar_RaceMode = race_choice
            if race_changed then save_settings = true end
        end)
        
        ui.tabItem("Info panel", function()
            ui.newLine(-5)
            ui.pushStyleColor(ui.StyleColor.Text, colors.SETTINGS_TEXT)
            ui.text("Choose what the Info Panel shows for each mode")
            ui.popStyleColor()
            ui.newLine(-5)
            ui.text("Mode:")
            barmode_dropdown = ui.combo("##dtbar_4", barmode_dropdown, ui.ComboFlags.None, barmode_names)
            
            if ui.radioButton("Show sector", Deltabar_ShowSectorsPerMode[barmode_dropdown]) then
                Deltabar_ShowSectorsPerMode[barmode_dropdown] = true
                save_settings = true
            end
            if ui.radioButton("Show lap", not Deltabar_ShowSectorsPerMode[barmode_dropdown]) then
                Deltabar_ShowSectorsPerMode[barmode_dropdown] = false
                save_settings = true
            end
        end)
    end)
end

Pedals_ShowTelemetryTime = -10
local function pedals_settings()
    PedalsScale = scale_settings(PedalsScale)
    
    ui.setNextTextBold()
    ui.text("Telemetry:")
    if ui.checkbox("Show Throttle", Pedals_ShowGas) then
        Pedals_ShowGas = not Pedals_ShowGas
        save_settings = true
    end
    
    if ui.checkbox("Show Brake", Pedals_ShowBrake) then
        Pedals_ShowBrake = not Pedals_ShowBrake
        save_settings = true
    end

    if ui.checkbox("Show Handbrake", Pedals_ShowHandbrake) then
        Pedals_ShowHandbrake = not Pedals_ShowHandbrake
        save_settings = true
    end
    
    
    if ui.checkbox("Show Clutch", Pedals_ShowClutch) then
        Pedals_ShowClutch = not Pedals_ShowClutch
        save_settings = true
    end
    
    if ui.checkbox("Show Force Feedback", Pedals_ShowFfb) then
        Pedals_ShowFfb = not Pedals_ShowFfb
        save_settings = true
    end

    if ui.checkbox("Show Gear Shifts", Pedals_ShowGearShifts) then
        Pedals_ShowGearShifts = not Pedals_ShowGearShifts
        save_settings = true
    end
end

local function radar_settings()
    RadarScale = scale_settings(RadarScale)
    
    if ui.checkbox("Show background dots", Radar_ShowDots) then
        Radar_ShowDots = not Radar_ShowDots
        save_settings = true
    end
    if ui.checkbox("Show single horizontal line", not Radar_ShowDoubleLines) then
        Radar_ShowDoubleLines = not Radar_ShowDoubleLines
        save_settings = true
    end
    if ui.checkbox("Show other players rectangles", Radar_ShowPlayers) then
        Radar_ShowPlayers = not Radar_ShowPlayers
        save_settings = true
    end
    if Radar_ShowPlayers then
        if ui.checkbox("Rotate other players rectangles", Radar_RotateCars) then
            Radar_RotateCars = not Radar_RotateCars
            save_settings = true
        end
    end
    if ui.checkbox("Show extra warning bands", Radar_MultiWarningLines) then
        Radar_MultiWarningLines = not Radar_MultiWarningLines
        save_settings = true
    end
    if ui.checkbox("Always Visible##radar_visib", Radar_AlwaysVisible) then
        Radar_AlwaysVisible = not Radar_AlwaysVisible
        save_settings = true
    end
    if ui.checkbox("Show Extended##radar_show_extended", Radar_ShowExtended) then
        Radar_ShowExtended = not Radar_ShowExtended
        save_settings = true
    end
end

local function damage_panel_settings()
    DamagePanel_Scale = scale_settings(DamagePanel_Scale)
    if ui.checkbox("Always Show Damage Panel", AlwaysShowDamagePanel) then
        AlwaysShowDamagePanel = not AlwaysShowDamagePanel
        save_settings = true
    end
end

local function mfd_get_row(row_index)
    if row_index == 1 then return MFD_Row1 end
    if row_index == 2 then return MFD_Row2 end
    if row_index == 3 then return MFD_Row3 end
    if row_index == 4 then return MFD_Row4 end
    if row_index == 5 then return MFD_Row5 end
    return nil
end


local function mfd_add_to_row(old_row, new_row, mfd_type)
    local MFD_old_row = mfd_get_row(old_row)
    local MFD_new_row = mfd_get_row(new_row)

    if MFD_new_row ~= nil then
        local row_len = table.nkeys(MFD_new_row)
        MFD_new_row[row_len] = mfd_type
    end

    if MFD_old_row ~= nil then
        local old_row_len = table.nkeys(MFD_old_row)
        for i = 0, old_row_len -1 do
            if MFD_old_row[i] == mfd_type then
                table_remove(MFD_old_row, i)
            end
        end
    end

end

local function mfd_remove_from_row(new_row, mfd_type)
    local MFD_row = mfd_get_row(new_row)
    if MFD_row ~= nil then
        local row_len = table.nkeys(MFD_row)
        for i = 0, row_len -1 do
            if MFD_row[i] == mfd_type then
                table_remove(MFD_row, i)
            end
        end
    end
end 


local function mfd_checkbox(variable, check_id, row, mfd_type)
    local final_value = variable
    if ui.checkbox(check_id, variable == row) then
        save_settings = true
        if variable == row then
            final_value = 0
            mfd_remove_from_row(row, mfd_type)
        else
            mfd_add_to_row(final_value, row, mfd_type)
            final_value = row
        end
    end
    ui.nextColumn()
    return final_value
end

local function draw_mfd_checkboxes(variable, id, mfd_type)
    ui.text(id)
    ui.nextColumn()
    local final_value = variable
    for i = 0, 4 do
        final_value = mfd_checkbox(final_value, "##mdf_"..id..i, i+1, mfd_type)
    end
    return final_value
end

local function get_mfd_type_text(mfd_type)
    if mfd_type == MFD_Type.ABS                         then return "Abs"                end
    if mfd_type == MFD_Type.BRAKE_BIAS                  then return "Brake Bias"         end
    if mfd_type == MFD_Type.LIGHTS                      then return "Lights"             end
    if mfd_type == MFD_Type.PIT_LIMITER                 then return "Pit Limiter"        end
    if mfd_type == MFD_Type.TRACTION_CONTROL            then return "Traction Control"   end
    if mfd_type == MFD_Type.TRACTION_CONTROL2           then return "Traction Control 2" end
    if mfd_type == MFD_Type.TURNING_LIGHTS              then return "Turning Lights"     end
    if mfd_type == MFD_Type.WIPERS                      then return "Wipers"             end
    if mfd_type == MFD_Type.FUEL_PER_LAP                then return "Fuel Per Lap"       end
    if mfd_type == MFD_Type.FUEL_TIME_REMAINING         then return "Fuel Time Left"     end
    if mfd_type == MFD_Type.FUEL_TO_COMPLETE_WHOLE_RACE then return "Fuel to Race"       end
    if mfd_type == MFD_Type.FUEL_TO_ADD_TO_FINISH_RACE  then return "Fuel Missing"       end
    if mfd_type == MFD_Type.PLAYER_RACE_POSITION        then return "Race Position"      end
    if mfd_type == MFD_Type.PITLANE_TIMER               then return "Pitlane Timer"      end
end

local function mfd_position_control(MfdRow, index, row_len , row_index)
    local elem = MfdRow[index]
    if elem ~= nil then
        if ui.arrowButton(
                'Up##' .. index .. '_' .. row_index,
                ui.Direction.Up,
                vec2(15, ui.frameHeight()),
                index > 0 and ui.ButtonFlags.None or ui.ButtonFlags.Disabled) then
            MfdRow[index] = MfdRow[index - 1]
            MfdRow[index - 1] = elem
            save_multiclass_tags()
        end
        ui.sameLine()
        if ui.arrowButton(
                'Down##' .. index .. '_' .. row_index,
                ui.Direction.Down,
                vec2(15, ui.frameHeight()),
                index < row_len - 1 and ui.ButtonFlags.None or ui.ButtonFlags.Disabled) then
            MfdRow[index] = MfdRow[index + 1]
            MfdRow[index + 1] = elem
            save_multiclass_tags()
        end
        ui.sameLine()
        ui.text(get_mfd_type_text(elem))
    end
    ui.nextColumn()
end


local function mfd_settings()
    MFDScale = scale_settings(MFDScale)

    ui.text("Fuel measurement units:")
    if ui.radioButton("Liters##mfd_gal", not MFDShowGal) then
        MFDShowGal = false
        save_settings = true
    end
    if ui.radioButton("Gallons##mfd_gal", MFDShowGal) then
        MFDShowGal = true
        save_settings = true
    end
    ui.newLine(-5)

    if ui.checkbox("Save Preset for the car", MFD_Save_Preset_Car) then
        MFD_Save_Preset_Car = not MFD_Save_Preset_Car
        if MFD_Save_Preset_Car == false then
            table_remove(MFD_PRESETS, MFD_PresetIndex)
            MFD_PresetCount = MFD_PresetCount - 1
        else
            MFD_PresetCount = MFD_PresetCount + 1
            MFD_PRESETS[table.nkeys(MFD_PRESETS)] = {
                car_name = ac.getCarName(0),
                mfd_row1 = table.clone(MFD_Row1, true),
                mfd_row2 = table.clone(MFD_Row2, true),
                mfd_row3 = table.clone(MFD_Row3, true),
                mfd_row4 = table.clone(MFD_Row4, true),
                mfd_row5 = table.clone(MFD_Row5, true)
            }
        end
        save_settings = true
    end

    ui.columns(6)
    ui.setColumnWidth(0, 150)
    ui.setColumnWidth(1, 50)
    ui.setColumnWidth(2, 50)
    ui.setColumnWidth(3, 50)
    ui.setColumnWidth(4, 50)
    ui.setColumnWidth(5, 50)
    ui.nextColumn()
    ui.text("Row 1")
    ui.nextColumn()
    ui.text("Row 2")
    ui.nextColumn()
    ui.text("Row 3")
    ui.nextColumn()
    ui.text("Row 4")
    ui.nextColumn()
    ui.text("Row 5")
    ui.nextColumn()

    ui.columns(1)
    ui.columns(6)
    
    --API(cogno): why are these global? we never use them...
    MFDAbs              = draw_mfd_checkboxes(MFDAbs, "Abs:", MFD_Type.ABS)
    MFDTractionControl  = draw_mfd_checkboxes(MFDTractionControl, "Traction Control:", MFD_Type.TRACTION_CONTROL)
    MFDTractionControl2 = draw_mfd_checkboxes(MFDTractionControl2, "Traction Control 2:", MFD_Type.TRACTION_CONTROL2)
    MFDBrakeBias        = draw_mfd_checkboxes(MFDBrakeBias, "Brake Bias:", MFD_Type.BRAKE_BIAS)
    MFDWipers           = draw_mfd_checkboxes(MFDWipers, "Wipers:", MFD_Type.WIPERS)
    MFDLights           = draw_mfd_checkboxes(MFDLights, "Lights:", MFD_Type.LIGHTS)
    MFDTurningLights    = draw_mfd_checkboxes(MFDTurningLights, "Turning Lights:", MFD_Type.TURNING_LIGHTS)
    MFDPitLimiter       = draw_mfd_checkboxes(MFDPitLimiter, "Pit Limiter:", MFD_Type.PIT_LIMITER)
    MFDFuelPerLap       = draw_mfd_checkboxes(MFDFuelPerLap, "Fuel Per Lap:", MFD_Type.FUEL_PER_LAP)
    MFDFuelTimeLeft     = draw_mfd_checkboxes(MFDFuelTimeLeft, "Fuel Time Left:", MFD_Type.FUEL_TIME_REMAINING)
    MFDFuelForWholeRace = draw_mfd_checkboxes(MFDFuelForWholeRace, "Fuel to Race:", MFD_Type.FUEL_TO_COMPLETE_WHOLE_RACE)
    MFDFuelToAdd        = draw_mfd_checkboxes(MFDFuelToAdd, "Fuel to Add:", MFD_Type.FUEL_TO_ADD_TO_FINISH_RACE)
    MFDRacePosition     = draw_mfd_checkboxes(MFDRacePosition, "Race Position:", MFD_Type.PLAYER_RACE_POSITION)
    MFDPitlaneTimer     = draw_mfd_checkboxes(MFDPitlaneTimer, "Pitlane Timer:", MFD_Type.PITLANE_TIMER)
    ui.columns(1)

    ui.newLine(-5)
    ui.setNextTextBold()
    ui.text("Rows Management")

    local row1_len = table.nkeys(MFD_Row1)
    local row2_len = table.nkeys(MFD_Row2)
    local row3_len = table.nkeys(MFD_Row3)
    local row4_len = table.nkeys(MFD_Row4)
    local row5_len = table.nkeys(MFD_Row5)

    local maximum_len = math.max(row1_len, row2_len, row3_len)

    ui.columns(3)

    if row1_len > 0 then ui.text("ROW 1") end
    ui.nextColumn()

    if row2_len > 0 then ui.text("ROW 2") end
    ui.nextColumn()

    if row3_len > 0 then ui.text("ROW 3") end
    ui.nextColumn()

    ui.setColumnWidth(0, 200)
    ui.setColumnWidth(1, 200)
    ui.setColumnWidth(2, 200)
    for i = 0, maximum_len -1 do
        mfd_position_control(MFD_Row1, i, row1_len ,1)
        mfd_position_control(MFD_Row2, i, row2_len, 2)
        mfd_position_control(MFD_Row3, i, row3_len,3)
    end
    ui.columns(2)
    ui.setColumnWidth(0, 200)
    ui.setColumnWidth(1, 200)

    maximum_len = math.max(row4_len, row5_len)
    if row4_len > 0 then ui.text("ROW 4") end
    ui.nextColumn()

    if row5_len > 0 then ui.text("ROW 5") end
    ui.nextColumn()

    for i = 0, maximum_len -1 do
        mfd_position_control(MFD_Row4, i, row4_len ,4)
        mfd_position_control(MFD_Row5, i, row5_len, 5)
    end
end

local fastest_lap_glow_timer = 0
local gearbox_glow_timer = 0
local new_session_glow_timer = 0
local starting_lights_glow_timer = 0
local drs_glow_timer = 0
local current_playback_audio = nil
local function audio_playback(audio_name, audio_volume, timer_to_edit)
    if ui.itemClicked(ui.MouseButton.Left) then
        if current_playback_audio ~= nil then current_playback_audio:dispose() end
        current_playback_audio = settings.get_single_audio_asset(audio_name, audio_volume)
        current_playback_audio:start()
        return 0.3 -- set to 0.3s of timer
    end
    return timer_to_edit -- no changes
end

local function audio_settings()
    ui.newLine(-5)
    
    local clicked = ui.checkbox("Enable CMRT Sounds", Audio_MasterEnabled)
    if clicked then Audio_MasterEnabled = not Audio_MasterEnabled end
    if clicked then save_settings = true end
    
    ui.pushStyleColor(ui.StyleColor.Text, colors.SETTINGS_TEXT)
    ui.text("Click sound name for preview")
    ui.popStyleColor()

    if not Audio_MasterEnabled then ui.pushDisabled() end
    ui.newLine(-5)
    
    ui.columns(3)
    ui.setColumnWidth(0, 32)
    
    ui.nextColumn()
    ui.text("Master Volume")
    ui.nextColumn()
    local value, changed = ui.slider("##Audio Master", Audio_MasterVolume * 50, 0, 100, "%.0f%%")
    Audio_MasterVolume = value / 50
    if changed then save_settings = true end
    ui.newLine(-5)
    ui.nextColumn()
    

    
    local clicked = ui.checkbox("##Fastest Lap Notif Enabled", Audio_FastestLapEnabled)
    if clicked then Audio_FastestLapEnabled = not Audio_FastestLapEnabled end
    if clicked then save_settings = true end
    ui.nextColumn()
    ui.newLine(-11) -- for some reason having sliders on the same line fucks up text vertical positioning...
    
    if fastest_lap_glow_timer > 0 then ui.setNextTextBold() end
    ui.text("Fastest Lap Notification")
    local rnd = math.random(3)
    if rnd == 1 then     fastest_lap_glow_timer = audio_playback("CMRT UI player fastest lap", 5 * Audio_MasterVolume * Audio_FastestLapVolume, fastest_lap_glow_timer)
    elseif rnd == 2 then fastest_lap_glow_timer = audio_playback("CMRT UI player pb lap", 5 * Audio_MasterVolume * Audio_FastestLapVolume, fastest_lap_glow_timer)
    elseif rnd == 3 then fastest_lap_glow_timer = audio_playback("CMRT UI fastest lap", 5 * Audio_MasterVolume * Audio_FastestLapVolume, fastest_lap_glow_timer)
    end
    
    ui.nextColumn()
    if not Audio_FastestLapEnabled then ui.pushDisabled() end
    local value, changed = ui.slider("##Fastest Lap Notification Volume", Audio_FastestLapVolume * 50, 0, 100, "%.0f%%")
    Audio_FastestLapVolume       = value / 50
    if changed then save_settings = true end
    if not Audio_FastestLapEnabled then ui.popDisabled() end
    ui.nextColumn()
    


    local clicked = ui.checkbox("##Gearbox Blinking Enabled", Audio_GearboxBlinkingEnabled)
    if clicked then Audio_GearboxBlinkingEnabled = not Audio_GearboxBlinkingEnabled end
    if clicked then save_settings = true end
    ui.nextColumn()
    ui.newLine(-11) -- for some reason having sliders on the same line fucks up text vertical positioning...

    if gearbox_glow_timer > 0 then ui.setNextTextBold() end
    ui.text("Gearbox Blinking")
    gearbox_glow_timer = audio_playback("CMRT UI gearbox", 5 * Audio_MasterVolume * Audio_GearboxBlinkingVolume, gearbox_glow_timer)
    ui.nextColumn()
    if not Audio_GearboxBlinkingEnabled then ui.pushDisabled() end
    local value, changed = ui.slider("##Gearbox Blinking Volume", Audio_GearboxBlinkingVolume * 50, 0, 100, "%.0f%%")
    Audio_GearboxBlinkingVolume = value / 50
    if changed then save_settings = true end
    if not Audio_GearboxBlinkingEnabled then ui.popDisabled() end
    ui.nextColumn()
    


    local clicked = ui.checkbox("##Semaphores On Enabled", Audio_SemaphoresOnEnabled)
    if clicked then Audio_SemaphoresOnEnabled = not Audio_SemaphoresOnEnabled end
    if clicked then save_settings = true end
    ui.nextColumn()
    ui.newLine(-11) -- for some reason having sliders on the same line fucks up text vertical positioning...

    if starting_lights_glow_timer > 0 then ui.setNextTextBold() end
    ui.text("Starting Lights")
    local rnd = math.random(2)
    if rnd == 1 then     starting_lights_glow_timer = audio_playback("CMRT UI lights on", 5.6 * Audio_MasterVolume * Audio_SemaphoresOnVolume, starting_lights_glow_timer)
    elseif rnd == 2 then starting_lights_glow_timer = audio_playback("CMRT UI start",     5.6 * Audio_MasterVolume * Audio_SemaphoresOnVolume, starting_lights_glow_timer)
    end
    
    ui.nextColumn()
    if not Audio_SemaphoresOnEnabled then ui.pushDisabled() end
    local value, changed = ui.slider("##Semaphores On Volume", Audio_SemaphoresOnVolume * 50, 0, 100, "%.0f%%")
    Audio_SemaphoresOnVolume    = value / 50
    if changed then save_settings = true end
    if not Audio_SemaphoresOnEnabled then ui.popDisabled() end
    ui.nextColumn()
    


    local clicked = ui.checkbox("##Session Ended Enabled", Audio_SessionEndedEnabled)
    if clicked then Audio_SessionEndedEnabled = not Audio_SessionEndedEnabled end
    if clicked then save_settings = true end
    ui.nextColumn()
    ui.newLine(-11) -- for some reason having sliders on the same line fucks up text vertical positioning...

    if new_session_glow_timer > 0 then ui.setNextTextBold() end
    ui.text("Session Ended")
    new_session_glow_timer = audio_playback("CMRT UI new session", 4 * Audio_MasterVolume * Audio_SessionEndedVolume, new_session_glow_timer)
    ui.nextColumn()
    if not Audio_SessionEndedEnabled then ui.pushDisabled() end
    local value, changed = ui.slider("##Session Ended Volume", Audio_SessionEndedVolume * 50, 0, 100, "%.0f%%")
    Audio_SessionEndedVolume = value / 50
    if changed then save_settings = true end
    if not Audio_SessionEndedEnabled then ui.popDisabled() end
    ui.nextColumn()



    local clicked = ui.checkbox("##DRS Audio", Audio_DRSEnabled)
    if clicked then Audio_DRSEnabled = not Audio_DRSEnabled end
    if clicked then save_settings = true end
    ui.nextColumn()
    ui.newLine(-11) -- for some reason having sliders on the same line fucks up text vertical positioning...

    if drs_glow_timer > 0 then ui.setNextTextBold() end
    ui.text("DRS Detection")
    drs_glow_timer = audio_playback("CMRT UI DRS gained", 5.6 * Audio_MasterVolume * Audio_DRSVolume, drs_glow_timer)
    
    ui.nextColumn()
    if not Audio_DRSEnabled then ui.pushDisabled() end
    local value, changed = ui.slider("##DRS On Volume", Audio_DRSVolume * 50, 0, 100, "%.0f%%")
    Audio_DRSVolume    = value / 50
    if changed then save_settings = true end
    if not Audio_DRSEnabled then ui.popDisabled() end
    ui.nextColumn()
    






    
    if not Audio_MasterEnabled then ui.popDisabled() end
    
    ui.columns(1) -- reset for the rest of the app
    fastest_lap_glow_timer     = math.clamp(fastest_lap_glow_timer - Dt, 0, 1)
    gearbox_glow_timer         = math.clamp(gearbox_glow_timer - Dt, 0, 1)
    starting_lights_glow_timer = math.clamp(starting_lights_glow_timer - Dt, 0, 1)
    new_session_glow_timer     = math.clamp(new_session_glow_timer - Dt, 0, 1)
    drs_glow_timer             = math.clamp(drs_glow_timer - Dt, 0, 1)
end

function mod.main()
    ui.tabBar("main bar", ui.TabBarFlags.FittingPolicyScroll, function()
        ui.tabItem("General", general_settings)
        ui.tabItem("Keybinds", keybinds_settings)
        ui.tabItem("Audio", audio_settings)
        ui.tabItem("Starting Lights", semaphores_settings)
        ui.tabItem("Gearbox", gearbox_settings)
        ui.tabItem("Local time", maptime_settings)
        ui.tabItem("Real time", pctime_settings)
        ui.tabItem("Sectors", sectors_settings)
        ui.tabItem("Leaderboard", leaderboard_settings)
        ui.tabItem("Tyres", tyres_settings)
        ui.tabItem("Map", map_settings)
        ui.tabItem("Deltabar", deltabar_settings)
        ui.tabItem("Pedals", pedals_settings)
        ui.tabItem("Radar", radar_settings)
        ui.tabItem("DamagePanel", damage_panel_settings)
        ui.tabItem("MFD", mfd_settings)
    end)
    
    if save_settings then
        save_settings = false
        local old_scale_value = settings_data.apps_auto_scale.storage:get()
        local settings_to_save = make_table_from_current_settings()
        for k,v in pairs(settings_data) do
            v.storage:set(settings_to_save[k].value)
        end
    
        for i=0, table.nkeys(Deltabar_Modes)-1 do
            local access_string = "deltabar_mode"..i
            local stored = ac.storage(access_string, false)
            stored:set(Deltabar_ShowSectorsPerMode[i])
        end

        if old_scale_value ~= Apps_AutoScale then
            -- now that we have saved if apps scale or not, we can replace the file
            if Apps_AutoScale then
                -- scale automatically
                io.copyFile("apps/lua/CMRT-Complete-HUD/auto_resize.ini", "apps/lua/CMRT-Complete-HUD/manifest.ini", false)
            else
                -- scale manually
                io.copyFile("apps/lua/CMRT-Complete-HUD/manual_resize.ini", "apps/lua/CMRT-Complete-HUD/manifest.ini", false)
            end
        end

        local mfd_current_preset = MFD_PRESETS[MFD_PresetIndex]
        mfd_current_preset.mfd_row1 = table.clone(MFD_Row1, true)
        mfd_current_preset.mfd_row2 = table.clone(MFD_Row2, true)
        mfd_current_preset.mfd_row3 = table.clone(MFD_Row3, true)
        mfd_current_preset.mfd_row4 = table.clone(MFD_Row4, true)
        mfd_current_preset.mfd_row5 = table.clone(MFD_Row5, true)

        mfd_preset_count_storage:set(MFD_PresetCount)
        ac.storage('MFD_PresetCount', 0):set(MFD_PresetCount)
        for preset_index = 0, MFD_PresetCount - 1 do
            local preset = MFD_PRESETS[preset_index]
            local car_name_storage = ac.storage("MFD_PRESET_"..preset_index.."_car_name",nil)
            car_name_storage:set(preset.car_name)

            local mfd_row1_lenght_storage = ac.storage("MFD_PRESET_"..preset_index.."_Row1Lenght",0)
            mfd_row1_lenght_storage:set(table.nkeys(preset.mfd_row1))
            local mfd_row2_lenght_storage = ac.storage("MFD_PRESET_"..preset_index.."_Row2Lenght",0)
            mfd_row2_lenght_storage:set(table.nkeys(preset.mfd_row2))
            local mfd_row3_lenght_storage = ac.storage("MFD_PRESET_"..preset_index.."_Row3Lenght",0)
            mfd_row3_lenght_storage:set(table.nkeys(preset.mfd_row3))
            local mfd_row4_lenght_storage = ac.storage("MFD_PRESET_"..preset_index.."_Row4Lenght",0)
            mfd_row4_lenght_storage:set(table.nkeys(preset.mfd_row4))
            local mfd_row5_lenght_storage = ac.storage("MFD_PRESET_"..preset_index.."_Row5Lenght",0)
            mfd_row5_lenght_storage:set(table.nkeys(preset.mfd_row5))

            for i = 0, table.nkeys(preset.mfd_row1) - 1 do
                local data = ac.storage("MFD_PRESET_"..preset_index.."_ROW1_"..i,0)
                data:set(preset.mfd_row1[i])
            end
            for i = 0, table.nkeys(preset.mfd_row2) - 1 do
                local data = ac.storage("MFD_PRESET_"..preset_index.."_ROW2_"..i,0)
                data:set(preset.mfd_row2[i])
            end
            for i = 0, table.nkeys(preset.mfd_row3) - 1 do
                local data = ac.storage("MFD_PRESET_"..preset_index.."_ROW3_"..i,0)
                data:set(preset.mfd_row3[i])
            end
            for i = 0, table.nkeys(preset.mfd_row4) - 1 do
                local data = ac.storage("MFD_PRESET_"..preset_index.."_ROW4_"..i,0)
                data:set(preset.mfd_row4[i])
            end
            for i = 0, table.nkeys(preset.mfd_row5) - 1 do
                local data = ac.storage("MFD_PRESET_"..preset_index.."_ROW5_"..i,0)
                data:set(preset.mfd_row5[i])
            end
        end
        
    end
end

return mod
