local mod      = {}
local settings = require('common.settings')
local players  = require('common.players')
local fonts    = settings.fonts
local colors   = settings.colors

local on_show_animation_start = 0
local is_showing = true
local is_paused  = false
local dot_size = 0
local wipers_image_size = vec2(0, 0)

local abs_text_size                      = vec2(0, 0)
local traction_control_text_size         = vec2(0, 0)
local traction_control2_text_size        = vec2(0, 0)
local brake_bias_text_size               = vec2(0, 0)
local pit_limiter_text_size              = vec2(0, 0)
local fuel_per_lap_text_size             = vec2(0, 0)
local pitlane_timer_text_size            = vec2(0, 0)
local racepos_text_size                  = vec2(0, 0)
local fueltime_text_size                 = vec2(0, 0)
local fuel_to_full_race_text_size        = vec2(0, 0)
local fuel_to_finish_race_text_size      = vec2(0, 0)

local abs_value_text_size                = vec2(0, 0)
local traction_control_value_text_size   = vec2(0, 0)
local traction_control2_value_text_size  = vec2(0, 0)
local brake_bias_control_value_text_size = vec2(0, 0)
local lights_size                        = vec2(0, 0)
local arrow_light_size                   = vec2(0, 0)
local fuel_per_lap_value_size            = vec2(0, 0)
local racepos_value_size                 = vec2(0, 0)
local pitlane_timer_value_size           = vec2(0, 0)
local fueltime_value_size                = vec2(0, 0)
local fuel_to_full_race_value_size       = vec2(0, 0)
local fuel_to_finish_race_value_size     = vec2(0, 0)

local base_font     = fonts.archivo_medium
local value_font    = fonts.archivo_bold
local font_size     = 0
local temptexts_pad = 0

local pitlane_timers      = table.new(50, 0) -- pitlane timer for each player (because we can spectate them)
local was_in_pitlane_list = table.new(50, 0) -- was this player in pitlane last frame? used to reset pitlane timers when we enter it
local last_laptimes_list  = table.new(50, 0) -- list of the last 20 laptimes per each player, so we can do the average laptime

local player_saved_fuel_estimate = nil
local drivers_surpassed_finish_once = table.new(50, 0) -- used to know if each driver has surpassed the finish line ONCE in this race.
local old_drivers_real_splines = table.new(50, 0) -- real_spline_value of last frame

--animation variables
local abs_old_value = 0
local abs_display_value = 0
local abs_anim_time = -10
local abs_offset = 0
local abs_anim_state = false

local tractioncontrol_old_value = 0
local tractioncontrol_display_value = 0
local tractioncontrol_anim_time = -10
local tractioncontrol_offset = 0
local tractioncontrol_anim_state = false

local tractioncontrol2_old_value = 0
local tractioncontrol2_display_value = 0
local tractioncontrol2_anim_time = -10
local tractioncontrol2_offset = 0
local tractioncontrol2_anim_state = false

local brakebias_old_value = 0
local brakebias_display_value = 0
local brakebias_anim_time = -10
local brakebias_offset = 0
local brakebias_anim_state = false

local abs_bloom = 0
local tc_bloom = 0
local wipers_bloom = 0
local headlight_bloom = 0
local turn_left_bloom = 0
local turn_right_bloom = 0
local breakbias_bloom = 0

local function update_fuel_estimate()
    local trackname = ac.getTrackFullID("|||")
    local carname = ac.getCarName(0)
    local access_string = trackname .. " - " .. carname
    local fuel_estimate = ac.storage(access_string .. " :> fuel estimate", nil)
    player_saved_fuel_estimate = tonumber(fuel_estimate:get())
end

local function get_remaining_fueltime_estimate(car_index)
    local car_data = ac.getCar(car_index)
    if car_data == nil then return '-' end
    local last_laptimes = last_laptimes_list[car_index]
    if last_laptimes == nil then return '-' end
    
    local laptime_sum = 0
    local list_len = table.nkeys(last_laptimes)
    for i=0, list_len-1 do
        laptime_sum = laptime_sum + last_laptimes[i]
    end
    if list_len == 0 then return '-' end
    
    local avg_fuel_per_lap = car_data.fuelPerLap
    if avg_fuel_per_lap == 0 then
        -- try to check if we saved the estimate
        if car_index == 0 and player_saved_fuel_estimate ~= nil and player_saved_fuel_estimate > 0 then
            avg_fuel_per_lap = player_saved_fuel_estimate
        else
            return '-' -- nothing we can do, we don't have the data!
        end
    end
    
    local avg_laptime = laptime_sum / list_len
    local seconds_per_lap = avg_laptime / 1000
    local fuel_left = car_data.fuel
    local lapcount = fuel_left / avg_fuel_per_lap
    local time_left = lapcount * seconds_per_lap
    
    local min_left = math.floor(time_left / 60)
    time_left = time_left - min_left * 60
    local out = string.format("%d:%02.0fs", min_left, time_left)
    if min_left > 99 then out = "99:99s" end
    return out
end

local function get_full_race_fuel()
    if player_saved_fuel_estimate == nil or player_saved_fuel_estimate == 0 then return '-' end

    local session = players.get_current_session()
    if session.type ~= ac.SessionType.Race then return '-' end
    
    local race_lapcount = session.laps
    local liters_to_complete_race = race_lapcount * player_saved_fuel_estimate
    local out = ''
    if MFDShowGal then
        out = string.format("%.1f gal", liters_to_complete_race / 3.785)
    else
        out = string.format("%.1f L", liters_to_complete_race)
    end
    return out
end

local function get_real_spline(car_info)
    -- NOTE(cogno): since assetto corsa is fucking stupid, map splines
    -- start at 0 NOT at the finish line. For example in Grobnik the finish line is at
    -- more than 18% of the track (WTF!!).
    -- Since we want a better estimate of laps/fuel remaining for the race, we will
    -- do something simple. We shift the 0 to start at the real finish line.
    -- With this our current race percentage is just (lapcount + shifted_spline) / race_lap_count
    --              Cogno 2024/09/16 and before, this is not the first time
    local finish_line = players.get_sector_splits()[0]
    local real_spline = car_info.splinePosition - finish_line
    if real_spline < 0 then real_spline = real_spline + 1 end
    return real_spline
end


local function get_fuel_to_add(car_state)
    if car_state == nil then return '-' end -- shouldn't happen anyway
    local session = players.get_current_session()
    if session.type ~= ac.SessionType.Race then return '-' end
    
    local fuel_estimate = car_state.fuelPerLap
    if fuel_estimate <= 0 and car_state.index == 0 then fuel_estimate = player_saved_fuel_estimate end
    if fuel_estimate == nil or fuel_estimate <= 0 then return '-' end
    
    local player_lapcount = players.get_lapcount(car_state.index)
    if player_lapcount == 0 and drivers_surpassed_finish_once[car_state.index] == false then
        player_lapcount = player_lapcount - 1 -- we don't want to count the initial piece before the finish line as a lap about to be completed!
    end
    local player_lapcount_incremental = player_lapcount + get_real_spline(car_state)
    local race_lapcount = session.laps
    local remaining_laps = race_lapcount - player_lapcount_incremental
    if session.isTimedRace and session.hasAdditionalLap then remaining_laps = remaining_laps + 1 end

    local liters_to_finish_race = remaining_laps * fuel_estimate
    local liters_to_add = math.clamp(liters_to_finish_race - car_state.fuel, 0, car_state.maxFuel)
    return string.format("%.1f L", liters_to_add)
end

function mod.on_open()
    if is_paused == false then
        on_show_animation_start = Time
        is_showing = true
    end
    is_paused = false
end

function mod.on_close()
    is_paused = ac.getSim().isPaused
    if is_paused == false then
        is_showing = false
    end
end

local function mfd_set_checkbox_value(mfd_type, row)
    if mfd_type == MFD_Type.ABS                         then MFDAbs               = row end
    if mfd_type == MFD_Type.BRAKE_BIAS                  then MFDBrakeBias         = row end
    if mfd_type == MFD_Type.LIGHTS                      then MFDLights            = row end
    if mfd_type == MFD_Type.PIT_LIMITER                 then MFDPitLimiter        = row end
    if mfd_type == MFD_Type.TRACTION_CONTROL            then MFDTractionControl   = row end
    if mfd_type == MFD_Type.TRACTION_CONTROL2           then MFDTractionControl2  = row end
    if mfd_type == MFD_Type.TURNING_LIGHTS              then MFDTurningLights     = row end
    if mfd_type == MFD_Type.WIPERS                      then MFDWipers            = row end
    if mfd_type == MFD_Type.FUEL_PER_LAP                then MFDFuelPerLap        = row end
    if mfd_type == MFD_Type.FUEL_TIME_REMAINING         then MFDFuelTimeLeft      = row end
    if mfd_type == MFD_Type.FUEL_TO_COMPLETE_WHOLE_RACE then MFDFuelForWholeRace  = row end
    if mfd_type == MFD_Type.FUEL_TO_ADD_TO_FINISH_RACE  then MFDFuelToAdd         = row end
    if mfd_type == MFD_Type.PLAYER_RACE_POSITION        then MFDRacePosition      = row end
    if mfd_type == MFD_Type.PITLANE_TIMER               then MFDPitlaneTimer      = row end
end

local function apply_preset()
    local to_apply = MFD_PRESETS[MFD_PresetIndex]
    if to_apply == nil then return end -- no data (shouldn't happen anyway)

    for i=0, table.nkeys(to_apply.mfd_row1)-1 do
        mfd_set_checkbox_value(to_apply.mfd_row1[i], 1)
    end
    for i=0, table.nkeys(to_apply.mfd_row2)-1 do
        mfd_set_checkbox_value(to_apply.mfd_row2[i], 2)
    end
    for i=0, table.nkeys(to_apply.mfd_row3)-1 do
        mfd_set_checkbox_value(to_apply.mfd_row3[i], 3)
    end
    for i=0, table.nkeys(to_apply.mfd_row4)-1 do
        mfd_set_checkbox_value(to_apply.mfd_row4[i], 4)
    end
    for i=0, table.nkeys(to_apply.mfd_row5)-1 do
        mfd_set_checkbox_value(to_apply.mfd_row5[i], 5)
    end
end

function mod.init()
    update_fuel_estimate()

    local mfd_preset_count_storage = ac.storage('MFD_PresetCount', 0)
    MFD_PresetCount = mfd_preset_count_storage:get()
    
    for preset_index = 0, MFD_PresetCount - 1 do
        local preset = {
            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)
        }
        local car_name_storage = ac.storage("MFD_PRESET_"..preset_index.."_car_name",nil)

        local mfd_row1_lenght_storage = ac.storage("MFD_PRESET_"..preset_index.."_Row1Lenght",0)
        local mfd_row2_lenght_storage = ac.storage("MFD_PRESET_"..preset_index.."_Row2Lenght",0)
        local mfd_row3_lenght_storage = ac.storage("MFD_PRESET_"..preset_index.."_Row3Lenght",0)
        local mfd_row4_lenght_storage = ac.storage("MFD_PRESET_"..preset_index.."_Row4Lenght",0)
        local mfd_row5_lenght_storage = ac.storage("MFD_PRESET_"..preset_index.."_Row5Lenght",0)

        local mfd_row1_lenght = mfd_row1_lenght_storage:get()
        local mfd_row2_lenght = mfd_row2_lenght_storage:get()
        local mfd_row3_lenght = mfd_row3_lenght_storage:get()
        local mfd_row4_lenght = mfd_row4_lenght_storage:get()
        local mfd_row5_lenght = mfd_row5_lenght_storage:get()

        preset.car_name = car_name_storage:get()

        for i = 0, mfd_row1_lenght - 1 do
            local data = ac.storage("MFD_PRESET_"..preset_index.."_ROW1_"..i,0)
            preset.mfd_row1[i] = data:get()
        end
        for i = 0, mfd_row2_lenght - 1 do
            local data = ac.storage("MFD_PRESET_"..preset_index.."_ROW2_"..i,0)
            preset.mfd_row2[i] = data:get()
        end
        for i = 0, mfd_row3_lenght - 1 do
            local data = ac.storage("MFD_PRESET_"..preset_index.."_ROW3_"..i,0)
            preset.mfd_row3[i] = data:get()
        end
        for i = 0, mfd_row4_lenght - 1 do
            local data = ac.storage("MFD_PRESET_"..preset_index.."_ROW4_"..i,0)
            preset.mfd_row4[i] = data:get()
        end
        for i = 0, mfd_row5_lenght - 1 do
            local data = ac.storage("MFD_PRESET_"..preset_index.."_ROW5_"..i,0)
            preset.mfd_row5[i] = data:get()
        end
        MFD_PRESETS[preset_index] = preset
    end

    local preset_found = false
    for preset_index = 0, MFD_PresetCount - 1 do
        local preset = MFD_PRESETS[preset_index]
        if preset.car_name == ac.getCarName(0) then
            preset_found = true
            MFD_Row1 = table.clone(preset.mfd_row1, true)
            MFD_Row2 = table.clone(preset.mfd_row2, true)
            MFD_Row3 = table.clone(preset.mfd_row3, true)
            MFD_Row4 = table.clone(preset.mfd_row4, true)
            MFD_Row5 = table.clone(preset.mfd_row5, true)
            MFD_PresetIndex = preset_index
            MFD_Save_Preset_Car = true
            apply_preset()
        end
    end

    if preset_found == false then
        local preset = MFD_PRESETS[0]
        if preset ~= nil then
            MFD_Row1 = table.clone(preset.mfd_row1, true)
            MFD_Row2 = table.clone(preset.mfd_row2, true)
            MFD_Row3 = table.clone(preset.mfd_row3, true)
            MFD_Row4 = table.clone(preset.mfd_row4, true)
            MFD_Row5 = table.clone(preset.mfd_row5, true)
            MFD_PresetIndex = 0
            MFD_Save_Preset_Car = false
        else
            MFD_PRESETS[0] = {
                car_name = nil,
                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)
            }
            -- default settings is Abs and Tc in the first row
            MFD_PRESETS[0].mfd_row1[0] = MFD_Type.TRACTION_CONTROL
            MFD_PRESETS[0].mfd_row1[1] = MFD_Type.ABS
            MFD_PresetCount = MFD_PresetCount + 1
        end
        apply_preset()
    end

    local focused, changed = players.get_focused_car()
    local car_state = ac.getCar(focused)
    abs_display_value = car_state.absMode
end

local function draw_text_with_font(text, font_size, pos, color, font)
    ui.pushDWriteFont(font)
    ui.dwriteDrawText(text, font_size, pos, color)
    ui.popDWriteFont()
end

local function get_fuel_per_lap_string(car_state)
    local fuel_string = "- L/Lap"
    if MFDShowGal then fuel_string = '- gal/Lap' end
    if car_state.fuelPerLap ~= 0 then
        if MFDShowGal then
            fuel_string = string.format("%.1fgal/Lap", car_state.fuelPerLap / 3.785)
        else
            fuel_string = string.format("%.1fL/Lap", car_state.fuelPerLap)
        end
    elseif player_saved_fuel_estimate ~= nil then
        if MFDShowGal then
            fuel_string = string.format("%.1fgal/Lap", player_saved_fuel_estimate / 3.785)
        else
            fuel_string = string.format("%.1fL/Lap", player_saved_fuel_estimate)
        end
    end
    return fuel_string
end

local function get_pitlane_timer(car_state)
    local timer = pitlane_timers[car_state.index]
    if timer == nil then return "0.00s" end -- shouldn't happen anyway
    return string.format("%.2fs", timer)
end

local function get_racepos_string()
    local player_count = #players.get_leaderboard()
    local player_lb_index = players.get_player_leaderboard_index() -- already takes into account spectating other players
    local player_racepos = players.get_racepos(player_lb_index)
    local position_string = string.format("%d/%d", player_racepos, player_count)
    return position_string
end

local function update_animated_values()
    local focused, changed = players.get_focused_car()
    local car_state = ac.getCar(focused)
    if abs_old_value ~= car_state.absMode then
        if abs_anim_state then
            abs_display_value = car_state.absMode
        end
        abs_old_value = car_state.absMode
        abs_anim_time = Time
        abs_anim_state = true
    end

    if tractioncontrol_old_value ~= car_state.tractionControlMode then
        if tractioncontrol_anim_state then
            tractioncontrol_display_value = car_state.tractionControlMode
        end
        tractioncontrol_old_value = car_state.tractionControlMode
        tractioncontrol_anim_time = Time
        tractioncontrol_anim_state = true
    end

    if tractioncontrol2_old_value ~= car_state.tractionControl2 then
        if tractioncontrol2_anim_state then
            tractioncontrol2_display_value = car_state.tractionControl2
        end
        tractioncontrol2_old_value = car_state.tractionControl2
        tractioncontrol2_anim_time = Time
        tractioncontrol2_anim_state = true
    end

    if brakebias_old_value ~= car_state.brakeBias * 100 then
        if brakebias_anim_state then
            brakebias_display_value = car_state.brakeBias * 100
        end
        brakebias_old_value = car_state.brakeBias * 100
        brakebias_anim_time = Time
        brakebias_anim_state = true
    end
end

local function animate_mfd_text(anim_time, anim_state, offset, display_value, current_value)
    local lerp_t = settings.anim_lerp(Time - anim_time, anim_state, 0.2)
    if lerp_t == 1 then
        anim_time = Time
        anim_state = false
    end
    
    if anim_state then
        offset = math.lerp(0,2, lerp_t)
    else
        display_value = current_value
        offset = math.lerp(0,-2, lerp_t)
    end

    return lerp_t, anim_state, anim_time, display_value,  offset
end

local function draw_dot(start_pos, line_height, color, add_bloom)
    local dot_center = start_pos + vec2(0, line_height / 2)
    ui.drawCircleFilled(dot_center, dot_size, color, 16)
    if add_bloom then
        ui.drawImage(
            settings.get_asset("bloom"),
            dot_center - dot_size * 3,
            dot_center + dot_size * 3,
            color
        )
    end
end

local function bool_to_number(value)
    return value and 1 or 0
end


local function draw_mfd_app_from_type(start_pos, car_state, mfd_type)
    if mfd_type == MFD_Type.ABS then
        if (car_state.absModes > 1 or car_state.absMode > 0) then
            
            local size = (abs_text_size + vec2(abs_value_text_size.x, 0) + vec2(dot_size + temptexts_pad * 2, 0))

            if settings.is_inside(ui.mouseLocalPos(), start_pos + size / 2, size / 2) then
                abs_bloom = settings.damp(abs_bloom , 0.7, 20)
                if ui.mouseClicked(ui.MouseButton.Left) then
                    abs_bloom = 2
                    ac.setABS((car_state.absMode + 1) % car_state.absModes);
                end
                local mouseWheel_value =  ui.mouseWheel()
                if mouseWheel_value > 0 then
                    ac.setABS((car_state.absMode + 1) % car_state.absModes);
                end
                if mouseWheel_value < 0 then
                
                    ac.setABS((car_state.absMode - 1) % car_state.absModes);
                end
            else
                abs_bloom = settings.damp(abs_bloom , 0, 20)
            end


            local lerp_t, anim_state, anim_time, display_value, offset = animate_mfd_text(abs_anim_time, abs_anim_state, abs_offset, abs_display_value, car_state.absMode)
            abs_anim_state = anim_state
            abs_anim_time = anim_time
            abs_display_value = display_value
            abs_offset = offset
            local alpha = math.abs(lerp_t - 1)

            local abs_text_color = colors.TEXT_GRAY
            local dot_color = colors.GRAY
            local bloom = false
            if car_state.absInAction then
                abs_text_color = colors.YELLOW_BATTERY_CHARGE
                dot_color = colors.YELLOW_BATTERY_CHARGE
                bloom = true
            end

            ui.drawImage(
                settings.get_asset("bloom2"),
                start_pos + vec2(dot_size + temptexts_pad,0) - abs_text_size * 0.6 + vec2(5, -1) * MFDScale * 1.2,
                start_pos + vec2(dot_size + temptexts_pad,0) + abs_text_size * 1.6 + vec2(5, -1) * MFDScale * 1.2,
                (colors.WHITE) * abs_bloom
            )

            draw_dot(start_pos, abs_text_size.y, dot_color, bloom)
            start_pos.x = start_pos.x + dot_size + temptexts_pad
            draw_text_with_font("ABS: ", font_size, start_pos, abs_text_color, base_font)
            start_pos.x = start_pos.x + abs_text_size.x + temptexts_pad
            draw_text_with_font(abs_display_value, font_size, start_pos + vec2(abs_offset * 2 * MFDScale,0), colors.WHITE * alpha, value_font)
            start_pos.x = start_pos.x + abs_value_text_size.x + temptexts_pad * 4
        end
    elseif mfd_type == MFD_Type.BRAKE_BIAS then
        
        if car_state.brakesCockpitBias then
            local size = (brake_bias_text_size + vec2(brake_bias_control_value_text_size.x, 0) + vec2(temptexts_pad, 0))
            if settings.is_inside(ui.mouseLocalPos(), start_pos + size / 2, size / 2) then
                local mouseWheel_value =  ui.mouseWheel()
                if mouseWheel_value > 0 then
                    ac.setBrakeBias(car_state.brakeBias + 0.5 / 100);
                end
                if mouseWheel_value < 0 then
                
                    ac.setBrakeBias(car_state.brakeBias - 0.5 / 100);
                end
                breakbias_bloom = settings.damp(breakbias_bloom , 0.7, 20)
            else
                breakbias_bloom = settings.damp(breakbias_bloom , 0, 20)
            end

            ui.drawImage(
                settings.get_asset("bloom2"),
                start_pos - brake_bias_text_size * 0.6 + vec2(1, -1) * MFDScale * 1.2,
                start_pos + brake_bias_text_size * 1.6 + vec2(1, -1) * MFDScale * 1.2,
                (colors.WHITE) * breakbias_bloom
            )
            
            local lerp_t, anim_state, anim_time, display_value, offset = animate_mfd_text(brakebias_anim_time, brakebias_anim_state, brakebias_offset, brakebias_display_value, car_state.brakeBias * 100)
            brakebias_anim_state = anim_state
            brakebias_anim_time = anim_time
            brakebias_display_value = display_value
            brakebias_offset = offset
            local alpha = math.abs(lerp_t - 1)

            draw_text_with_font("B. BIAS: ", font_size, start_pos, colors.TEXT_GRAY, base_font)
            start_pos.x = start_pos.x + brake_bias_text_size.x + temptexts_pad
            draw_text_with_font(string.format("%.1f", brakebias_display_value) .. "%", font_size, start_pos + vec2(brakebias_offset * 2 * MFDScale, 0), colors.WHITE * alpha,
                value_font)
            start_pos.x = start_pos.x + brake_bias_control_value_text_size.x + temptexts_pad * 4
        end
    elseif mfd_type == MFD_Type.LIGHTS then
        local size = vec2(lights_size.x * 1.2, lights_size.y * 1.2)
        if settings.is_inside(ui.mouseLocalPos(), start_pos + size / 2, size / 2) then
            if ui.mouseClicked(ui.MouseButton.Left) then
                headlight_bloom = 2
                ac.setHeadlights(not car_state.headlightsActive);
            end

            headlight_bloom = settings.damp(headlight_bloom , 0.7, 20)
        else
            headlight_bloom = settings.damp(headlight_bloom , 0, 20)
        end

        ui.drawImage(
            settings.get_asset("bloom2"),
            start_pos - lights_size * 0.6 + vec2(3, 2) * MFDScale * 1.2,
            start_pos + lights_size * 1.6 + vec2(3, 2) * MFDScale * 1.2,
            (colors.WHITE) * headlight_bloom
        )

        if car_state.flashingLightsActive and car_state.hasFlashingLights then
            ui.drawImageQuad(
                settings.get_asset("flash"),
                start_pos + vec2(0, 0),
                start_pos + vec2(lights_size.x * 1.2, 0),
                start_pos + vec2(lights_size.x * 1.2, lights_size.y * 1.2),
                start_pos + vec2(0, lights_size.y * 1.2),
                colors.BLUE_BATTERY
            )
            ui.drawImage(
                settings.get_asset("bloom"),
                start_pos - arrow_light_size * 0.6 + vec2(5, -1) * MFDScale * 1.2,
                start_pos + arrow_light_size * 1.6 + vec2(5, -1) * MFDScale * 1.2,
                colors.BLUE_BATTERY
            )
        else

            if car_state.headlightsActive then
                ui.drawImageQuad(
                    settings.get_asset("head"),
                    start_pos + vec2(0, 0),
                    start_pos + vec2(lights_size.x * 1.2, 0),
                    start_pos + vec2(lights_size.x * 1.2, lights_size.y * 1.2),
                    start_pos + vec2(0, lights_size.y * 1.2),
                    colors.GREEN
                )
                ui.drawImage(
                    settings.get_asset("bloom"),
                    start_pos - arrow_light_size * 0.6 + vec2(5, -1) * MFDScale * 1.2,
                    start_pos + arrow_light_size * 1.6 + vec2(5, -1) * MFDScale * 1.2,
                    colors.GREEN
                )
            else
                ui.drawImageQuad(
                    settings.get_asset("head"),
                    start_pos + vec2(0, 0),
                    start_pos + vec2(lights_size.x * 1.2, 0),
                    start_pos + vec2(lights_size.x * 1.2, lights_size.y * 1.2),
                    start_pos + vec2(0, lights_size.y * 1.2),
                    colors.LIGHT_GRAY
                )
            end

        end
        start_pos.x = start_pos.x + lights_size.x + temptexts_pad * 4
    elseif mfd_type == MFD_Type.PIT_LIMITER then
        local pit_color = colors.TEXT_GRAY
        local dot_color = colors.GRAY
        local bloom = false
        if car_state.speedLimiter > 0 then
            pit_color = colors.BLUE_BATTERY
            if Time % 0.8 > 0.4 then
                dot_color = colors.BLUE_BATTERY
                bloom = true
            end
        end
        draw_dot(start_pos, pit_limiter_text_size.y, dot_color, bloom)
        start_pos.x = start_pos.x + dot_size + temptexts_pad
        draw_text_with_font("PIT", font_size, start_pos, pit_color, base_font)
        start_pos.x = start_pos.x + pit_limiter_text_size.x + temptexts_pad * 4
    elseif mfd_type == MFD_Type.TRACTION_CONTROL then
        if (car_state.tractionControlModes ~= 0 or car_state.tractionControlMode > 0) then
            local size = (traction_control_text_size + vec2(traction_control_value_text_size.x, 0) + vec2(dot_size + temptexts_pad * 2, 0))
            if settings.is_inside(ui.mouseLocalPos(), start_pos + size / 2, size / 2) then
                if ui.mouseClicked(ui.MouseButton.Left) then
                    tc_bloom = 2
                    ac.setTC((car_state.tractionControlMode + 1) % car_state.tractionControlModes);
                end
                local mouseWheel_value =  ui.mouseWheel()
                if mouseWheel_value > 0 then
                    ac.setTC((car_state.tractionControlMode + 1) % car_state.tractionControlModes);
                end
                if mouseWheel_value < 0 then
                    ac.setTC((car_state.tractionControlMode - 1) % car_state.tractionControlModes);
                end
                tc_bloom = settings.damp(tc_bloom , 0.7, 20)
            else
                tc_bloom = settings.damp(tc_bloom , 0, 20)
            end


            ui.drawImage(
                settings.get_asset("bloom2"),
                start_pos - traction_control_text_size * 0.6 + vec2(10, 0) * MFDScale * 1.2,
                start_pos + traction_control_text_size * 1.6 + vec2(10, 0) * MFDScale * 1.2,
                (colors.WHITE) * tc_bloom
            )

            local lerp_t, anim_state, anim_time, display_value, offset = animate_mfd_text(tractioncontrol_anim_time,
            tractioncontrol_anim_state, tractioncontrol_offset, tractioncontrol_display_value, car_state.tractionControlMode)
            tractioncontrol_anim_state = anim_state
            tractioncontrol_anim_time = anim_time
            tractioncontrol_display_value = display_value
            tractioncontrol_offset = offset
            local alpha = math.abs(lerp_t - 1)

            local traction_control_text = colors.TEXT_GRAY
            local dot_color = colors.GRAY
            local bloom = false
            if car_state.tractionControlInAction then
                traction_control_text = colors.YELLOW_BATTERY_CHARGE
                dot_color = colors.YELLOW_BATTERY_CHARGE
                bloom = true
            end
            draw_dot(start_pos, traction_control_text_size.y, dot_color, bloom)
            start_pos.x = start_pos.x + dot_size + temptexts_pad
            draw_text_with_font("TC: ", font_size, start_pos, traction_control_text, base_font)
            start_pos.x = start_pos.x + traction_control_text_size.x + temptexts_pad
            draw_text_with_font(tractioncontrol_display_value, font_size, start_pos + vec2(tractioncontrol_offset * 4 * MFDScale), colors.WHITE * alpha, value_font)
            start_pos.x = start_pos.x + traction_control_value_text_size.x + temptexts_pad * 4
        end
    elseif mfd_type == MFD_Type.TRACTION_CONTROL2 then
        local lerp_t, anim_state, anim_time, display_value, offset = animate_mfd_text(tractioncontrol2_anim_time,
        tractioncontrol2_anim_state, tractioncontrol2_offset, tractioncontrol2_display_value, car_state.tractionControl2)
        tractioncontrol2_anim_state = anim_state
        tractioncontrol2_anim_time = anim_time
        tractioncontrol2_display_value = display_value
        tractioncontrol2_offset = offset
        local alpha = math.abs(lerp_t - 1)
        if car_state.tractionControl2Modes ~= 0 then
            local traction_contro2_text = colors.TEXT_GRAY
            if car_state.tractionControlInAction then
                traction_contro2_text = colors.YELLOW_BATTERY_CHARGE
            end
            draw_text_with_font("TC2: ", font_size, start_pos, traction_contro2_text, base_font)
            start_pos.x = start_pos.x + traction_control2_text_size.x + temptexts_pad
            draw_text_with_font(tractioncontrol2_display_value, font_size, start_pos + vec2(tractioncontrol2_offset * 2 * MFDScale), colors.WHITE  * alpha, value_font)
            start_pos.x = start_pos.x + traction_control2_value_text_size.x + temptexts_pad * 4
        end
    elseif mfd_type == MFD_Type.TURNING_LIGHTS then
        if car_state.hasTurningLights then
            local size = arrow_light_size
            if settings.is_inside(ui.mouseLocalPos(), start_pos + size / 2, size / 2) then
                if ui.mouseClicked(ui.MouseButton.Left) then
                    local t_lights = 0
                    t_lights = t_lights + bool_to_number(not car_state.turningLeftLights)
                    t_lights = t_lights + bool_to_number(car_state.turningRightLights) * 2
                    ac.setTurningLights(t_lights);
                    turn_left_bloom = 2
                end
                turn_left_bloom = settings.damp(turn_left_bloom , 0.7, 20)
            else
                turn_left_bloom = settings.damp(turn_left_bloom , 0, 20)
            end

            ui.drawImage(
                settings.get_asset("bloom2"),
                start_pos - arrow_light_size * 0.6,
                start_pos + arrow_light_size * 1.6,
                (colors.WHITE) * turn_left_bloom
            )

            size = arrow_light_size
            if settings.is_inside(ui.mouseLocalPos(), start_pos + vec2(arrow_light_size.x + temptexts_pad, 0 ) + size / 2, size / 2) then
                if ui.mouseClicked(ui.MouseButton.Left) then
                    local t_lights = 0
                    turn_right_bloom = 2
                    t_lights = t_lights + bool_to_number(car_state.turningLeftLights)
                    t_lights = t_lights + bool_to_number(not car_state.turningRightLights) * 2
                    ac.setTurningLights(t_lights);
                end
                turn_right_bloom = settings.damp(turn_right_bloom , 0.7, 20)
            else
                turn_right_bloom = settings.damp(turn_right_bloom , 0, 20)
            end

            ui.drawImage(
                settings.get_asset("bloom2"),
                start_pos - arrow_light_size * 0.6 + vec2(arrow_light_size.x + temptexts_pad, 0) * 1.2,
                start_pos + arrow_light_size * 1.6 + vec2(arrow_light_size.x + temptexts_pad, 0) * 1.2,
                (colors.WHITE) * turn_right_bloom
            )
            


            if car_state.turningLeftLights then
                local lerp_t = math.clamp(math.abs(math.sin(Time * 4.5) * 1.2), 0, 1)
                local color = settings.color_lerp(colors.GRAY, colors.GREEN, lerp_t)
                ui.drawImageQuad(
                    settings.get_asset("arrow_light"),
                    start_pos + vec2(0, 0),
                    start_pos + vec2(arrow_light_size.x, 0),
                    start_pos + vec2(arrow_light_size.x, arrow_light_size.y),
                    start_pos + vec2(0, arrow_light_size.y),
                    color
                )
                ui.drawImage(
                    settings.get_asset("bloom"),
                    start_pos - arrow_light_size * 0.6,
                    start_pos + arrow_light_size * 1.6,
                    color
                )
            else
                ui.drawImageQuad(
                    settings.get_asset("arrow_light"),
                    start_pos + vec2(0, 0),
                    start_pos + vec2(arrow_light_size.x, 0),
                    start_pos + vec2(arrow_light_size.x, arrow_light_size.y),
                    start_pos + vec2(0, arrow_light_size.y),
                    colors.LIGHT_GRAY
                )
            end
            start_pos.x = start_pos.x + arrow_light_size.x + temptexts_pad
            if car_state.turningRightLights then
                local lerp_t = math.clamp(math.abs(math.sin(Time * 4.5) * 1.2), 0, 1)
                local color = settings.color_lerp(colors.GRAY, colors.GREEN, lerp_t)
    
                ui.drawImageQuad(
                    settings.get_asset("arrow_light"),
                    start_pos + vec2(arrow_light_size.x, 0),
                    start_pos + vec2(0, 0),
                    start_pos + vec2(0, arrow_light_size.y),
                    start_pos + vec2(arrow_light_size.x, arrow_light_size.y),
                    color
                )
                ui.drawImage(
                    settings.get_asset("bloom"),
                    start_pos - arrow_light_size * 0.6,
                    start_pos + arrow_light_size * 1.6,
                    color
                )
            else
                ui.drawImageQuad(
                    settings.get_asset("arrow_light"),
                    start_pos + vec2(arrow_light_size.x, 0),
                    start_pos + vec2(0, 0),
                    start_pos + vec2(0, arrow_light_size.y),
                    start_pos + vec2(arrow_light_size.x, arrow_light_size.y),
                    colors.LIGHT_GRAY
                )
            end
            start_pos.x = start_pos.x + arrow_light_size.x + temptexts_pad * 4
        end
    elseif mfd_type == MFD_Type.WIPERS then
        if car_state.wiperModes > 1 then
            local size = wipers_image_size + vec2(0, 5) * MFDScale
            if settings.is_inside(ui.mouseLocalPos(), start_pos + size / 2, size / 2) then
                if ui.mouseClicked(ui.MouseButton.Left) then
                    ac.setWiperMode((car_state.wiperMode + 1) % car_state.wiperModes);
                    wipers_bloom = 2
                end
                local mouseWheel_value =  ui.mouseWheel()
                if mouseWheel_value > 0 then
                    ac.setWiperMode((car_state.wiperMode + 1) % car_state.wiperModes);
                end
                if mouseWheel_value < 0 then
                    ac.setWiperMode((car_state.wiperMode - 1) % car_state.wiperModes);
                end
                wipers_bloom = settings.damp(wipers_bloom , 0.7, 20)
            else
                wipers_bloom = settings.damp(wipers_bloom , 0, 20)
            end

            ui.drawImage(
                settings.get_asset("bloom2"),
                start_pos - wipers_image_size * 0.6 + vec2(1, -1) * MFDScale * 1.2,
                start_pos + wipers_image_size * 1.6 + vec2(1, -1) * MFDScale * 1.2,
                (colors.WHITE) * wipers_bloom
            )

            local wiper_col = colors.LIGHT_GRAY
            if car_state.wiperMode > 0 then wiper_col = colors.BLUE_BATTERY end
            ui.drawImage(
                settings.get_asset("wipers"),
                start_pos + vec2(0, -2) * MFDScale,
                start_pos + wipers_image_size + vec2(0, -2) * MFDScale,
                wiper_col
            )
            for i=0, math.clamp(car_state.wiperModes, 0, 3) do
                local color = colors.LIGHT_GRAY
                if i < car_state.wiperMode then color = colors.BLUE_BATTERY end
                ui.drawImage(
                    settings.get_asset("speed"),
                    start_pos + vec2(0 + i * 6, 16) * MFDScale,
                    start_pos + vec2(5 + i * 6, 19) * MFDScale,
                    color
                )
            end
            if car_state.wiperMode > 0 then
                ui.drawImage(
                    settings.get_asset("bloom"),
                    start_pos - wipers_image_size * 0.4,
                    start_pos + wipers_image_size * 1.4,
                    colors.BLUE_BATTERY
                )
            end
            start_pos.x = start_pos.x + wipers_image_size.x + temptexts_pad * 4
        end
    elseif mfd_type == MFD_Type.FUEL_PER_LAP then
        draw_text_with_font("FUEL: ", font_size, start_pos, colors.TEXT_GRAY, base_font)
        start_pos.x = start_pos.x + fuel_per_lap_text_size.x + temptexts_pad
        local fuel_string = get_fuel_per_lap_string(car_state)
        draw_text_with_font(fuel_string, font_size, start_pos, colors.WHITE, value_font)
        start_pos.x = start_pos.x + fuel_per_lap_value_size.x + temptexts_pad * 4
    elseif mfd_type == MFD_Type.PLAYER_RACE_POSITION then
        draw_text_with_font("POS: ", font_size, start_pos, colors.TEXT_GRAY, value_font)
        start_pos.x = start_pos.x + racepos_text_size.x + temptexts_pad
        local position_string = get_racepos_string()
        draw_text_with_font(position_string, font_size, start_pos, colors.WHITE, value_font)
        start_pos.x = start_pos.x + racepos_value_size.x + temptexts_pad * 4
    elseif mfd_type == MFD_Type.PITLANE_TIMER then
        draw_text_with_font("PIT TIME: ", font_size, start_pos, colors.TEXT_GRAY, base_font)
        start_pos.x = start_pos.x + pitlane_timer_text_size.x + temptexts_pad
        draw_text_with_font(get_pitlane_timer(car_state), font_size, start_pos, colors.WHITE, value_font)
        start_pos.x = start_pos.x + pitlane_timer_value_size.x + temptexts_pad * 4
    elseif mfd_type == MFD_Type.FUEL_TIME_REMAINING then
        draw_text_with_font("FUEL TIME: ", font_size, start_pos, colors.TEXT_GRAY, base_font)
        start_pos.x = start_pos.x + fueltime_text_size.x + temptexts_pad
        draw_text_with_font(get_remaining_fueltime_estimate(car_state.index), font_size, start_pos, colors.WHITE, value_font)
        start_pos.x = start_pos.x + fueltime_value_size.x + temptexts_pad * 4
    elseif mfd_type == MFD_Type.FUEL_TO_COMPLETE_WHOLE_RACE then
        draw_text_with_font("RACE FUEL: ", font_size, start_pos, colors.TEXT_GRAY, base_font)
        start_pos.x = start_pos.x + fuel_to_full_race_text_size.x + temptexts_pad
        draw_text_with_font(get_full_race_fuel(), font_size, start_pos, colors.WHITE, value_font)
        start_pos.x = start_pos.x + fuel_to_full_race_value_size.x + temptexts_pad * 4
    elseif mfd_type == MFD_Type.FUEL_TO_ADD_TO_FINISH_RACE then
        draw_text_with_font("PIT FUEL: ", font_size, start_pos, colors.TEXT_GRAY, base_font)
        start_pos.x = start_pos.x + fuel_to_finish_race_text_size.x + temptexts_pad
        draw_text_with_font(get_fuel_to_add(car_state), font_size, start_pos, colors.WHITE, value_font)
        start_pos.x = start_pos.x + fuel_to_finish_race_value_size.x + temptexts_pad * 4
    end

    return start_pos
end

local function draw_mfd_row(start_pos, MFD_ROW)
    if MFD_ROW ~= nil then
        local row_len = table.nkeys(MFD_ROW)
        local focused, changed = players.get_focused_car()
        local car_state = ac.getCar(focused)
        for i = 0, row_len - 1 do
            start_pos = draw_mfd_app_from_type(start_pos, car_state, MFD_ROW[i])
        end
    end
end

local function calculate_row_size(start_pos, row_id)
    local row_size = vec2(0, 0)
    local focused, changed = players.get_focused_car()
    local car_state = ac.getCar(focused)
    if car_state == nil then return row_size end -- should never happen anyway

    if (car_state.absModes > 1 or car_state.absMode > 0) and MFDAbs == row_id then
        row_size.x = row_size.x + abs_value_text_size.x + abs_text_size.x + dot_size + temptexts_pad * 6
        row_size.y = math.max(row_size.y, start_pos.y + abs_text_size.y)
    end
    if (car_state.tractionControlModes ~= 0 or car_state.tractionControlMode > 0) and MFDTractionControl == row_id then
        row_size.x = row_size.x + traction_control_text_size.x + traction_control_value_text_size.x + dot_size + temptexts_pad * 6
        row_size.y = math.max(row_size.y, start_pos.y + traction_control_text_size.y)
    end
    if car_state.tractionControl2Modes ~= 0 and MFDTractionControl2 == row_id then
        row_size.x = row_size.x + traction_control2_text_size.x + traction_control2_value_text_size.x + temptexts_pad * 5
        row_size.y = math.max(row_size.y, traction_control2_text_size.y)
    end
    if car_state.brakesCockpitBias and MFDBrakeBias == row_id then
        row_size.x = row_size.x + brake_bias_text_size.x + brake_bias_control_value_text_size.x + temptexts_pad * 5
        row_size.y = math.max(row_size.y, start_pos.y + brake_bias_text_size.y)
    end

    if car_state.wiperModes > 1 and MFDWipers == row_id then
        row_size.x = row_size.x + wipers_image_size.x + temptexts_pad * 4
        row_size.y = math.max(row_size.y, start_pos.y + wipers_image_size.y)
    end

    if MFDPitLimiter == row_id then
        row_size.x = row_size.x + pit_limiter_text_size.x + dot_size + temptexts_pad * 5
        row_size.y = math.max(row_size.y, start_pos.y + pit_limiter_text_size.y)
    end

    if MFDLights == row_id then
        row_size.x = row_size.x + lights_size.x + temptexts_pad * 4
        row_size.y = math.max(row_size.y, start_pos.y + lights_size.y)
    end

    if car_state.hasTurningLights and MFDTurningLights == row_id then
        row_size.x = row_size.x + arrow_light_size.x * 2 + temptexts_pad * 5
        row_size.y = math.max(row_size.y, start_pos.y + arrow_light_size.y)
    end

    if MFDFuelPerLap == row_id then
        row_size.x = row_size.x + fuel_per_lap_text_size.x + fuel_per_lap_value_size.x + temptexts_pad * 5
        row_size.y = math.max(row_size.y, start_pos.y + fuel_per_lap_text_size.y)
    end

    if MFDRacePosition == row_id then
        row_size.x = row_size.x + racepos_text_size.x + racepos_value_size.x + temptexts_pad * 5
        row_size.y = math.max(row_size.y, start_pos.y + racepos_value_size.y)
    end

    if MFDPitlaneTimer == row_id then
        row_size.x = row_size.x + pitlane_timer_text_size.x + pitlane_timer_value_size.x + temptexts_pad * 5
        row_size.y = math.max(row_size.y, start_pos.y + pitlane_timer_text_size.y)
    end

    if MFDFuelTimeLeft == row_id then
        row_size.x = row_size.x + fueltime_text_size.x + fueltime_value_size.x + temptexts_pad * 5
        row_size.y = math.max(row_size.y, start_pos.y + fueltime_text_size.y)
    end

    if MFDFuelForWholeRace == row_id then
        row_size.x = row_size.x + fuel_to_full_race_text_size.x + fuel_to_full_race_value_size.x + temptexts_pad * 5
        row_size.y = math.max(row_size.y, start_pos.y + fuel_to_full_race_text_size.y)
    end

    if MFDFuelToAdd == row_id then
        row_size.x = row_size.x + fuel_to_finish_race_text_size.x + fuel_to_finish_race_value_size.x + temptexts_pad * 5
        row_size.y = math.max(row_size.y, start_pos.y + fuel_to_finish_race_text_size.y)
    end

    return row_size
end

function mod.on_session_start()
    table.clear(was_in_pitlane_list)
    table.clear(pitlane_timers)
    table.clear(drivers_surpassed_finish_once)
    table.clear(old_drivers_real_splines)
    update_fuel_estimate()
end


function mod.update()
    local leaderboard = players.get_leaderboard()
    for i=0, #leaderboard-1 do
        local car_info = leaderboard[i].car
        local car_index = car_info.index
        local is_in_pitlane = car_info.isInPitlane
        
        -- auto set values if missing
        if pitlane_timers[car_index] == nil then pitlane_timers[car_index] = 0 end
        if was_in_pitlane_list[car_index] == nil then was_in_pitlane_list[car_index] = false end
        
        -- when in pitlane the timer increases
        local was_in_pitlane = was_in_pitlane_list[car_index]
        if is_in_pitlane then
            if was_in_pitlane == false then pitlane_timers[car_index] = 0 end
            pitlane_timers[car_index] = math.clamp(pitlane_timers[car_index] + Dt, 0, 99.99)
        end

        -- average laptime stuff
        if last_laptimes_list[car_index] == nil then
            last_laptimes_list[car_index] = table.new(20, 0)
            -- maybe we have a last lap we can already use
            local last_laptime = players.get_previous_laptime(car_index)
            if last_laptime ~= nil and last_laptime > 0 then
                last_laptimes_list[car_index][0] = last_laptime
            end
        end

        if players.player_completed_lap_this_frame(car_index) then
            -- record the last laptime
            local last_laptime = players.get_previous_laptime(car_index)
            local list_len = table.nkeys(last_laptimes_list[car_index])
            if list_len < 20 then
                last_laptimes_list[car_index][list_len] = last_laptime
            else
                settings.table_remove(last_laptimes_list[car_index], 0)
                last_laptimes_list[car_index][list_len-1] = last_laptime
            end
            
        end
        
        if drivers_surpassed_finish_once[car_index] == nil then
            drivers_surpassed_finish_once[car_index] = false
        end
        
        local real_spline = get_real_spline(car_info)
        local old_spline = old_drivers_real_splines[car_index]
        if drivers_surpassed_finish_once[car_index] == false and real_spline < 0.5 and old_spline ~= nil and old_spline > 0.5 then
            drivers_surpassed_finish_once[car_index] = true
        end
        
        -- stuff that will be used next frame
        old_drivers_real_splines[car_index] = real_spline
        was_in_pitlane_list[car_index] = is_in_pitlane
    end
end

function mod.main()
    local draw_top_left = vec2(0, 22)
    local draw_size = ui.windowSize() - vec2(0, 22)
    local draw_center = draw_top_left + draw_size / 2
    font_size = settings.fontsize(10) * MFDScale

    local focused, changed = players.get_focused_car()
    local car_state = ac.getCar(focused)

    dot_size = 6 * MFDScale
    wipers_image_size = vec2(65, 42) * 0.35 * MFDScale

    update_animated_values()

    ui.pushDWriteFont(base_font)
    abs_text_size                 = ui.measureDWriteText("ABS: ", font_size)
    traction_control_text_size    = ui.measureDWriteText("TC: ", font_size)
    traction_control2_text_size   = ui.measureDWriteText("TC2: ", font_size)
    brake_bias_text_size          = ui.measureDWriteText("B. BIAS: ", font_size)
    pit_limiter_text_size         = ui.measureDWriteText("PIT", font_size)
    fuel_per_lap_text_size        = ui.measureDWriteText("FUEL: ", font_size)
    pitlane_timer_text_size       = ui.measureDWriteText("PIT TIME: ", font_size)
    racepos_text_size             = ui.measureDWriteText("POS: ", font_size)
    fueltime_text_size            = ui.measureDWriteText("FUEL TIME: ", font_size)
    fuel_to_full_race_text_size   = ui.measureDWriteText("RACE FUEL: ", font_size)
    fuel_to_finish_race_text_size = ui.measureDWriteText("PIT FUEL: ", font_size)
    ui.popDWriteFont()

    ui.pushDWriteFont(value_font)
    abs_value_text_size = ui.measureDWriteText(15, font_size)
    traction_control_value_text_size = ui.measureDWriteText(15, font_size)
    traction_control2_value_text_size = ui.measureDWriteText(15, font_size)
    brake_bias_control_value_text_size = ui.measureDWriteText(string.format("%.1f%%", 1 * 100), font_size)
    fuel_per_lap_value_size = ui.measureDWriteText(get_fuel_per_lap_string(car_state), font_size)
    racepos_value_size = ui.measureDWriteText(get_racepos_string(), font_size)
    pitlane_timer_value_size = ui.measureDWriteText("99.99s", font_size) -- so the text doesn't move the app around
    fueltime_value_size = ui.measureDWriteText("99.99s", font_size)
    fuel_to_full_race_value_size = ui.measureDWriteText(get_full_race_fuel(), font_size)
    fuel_to_finish_race_value_size = ui.measureDWriteText(get_fuel_to_add(car_state), font_size)
    ui.popDWriteFont()

    lights_size      = vec2(73, 45) * 0.3 * MFDScale
    arrow_light_size = vec2(58, 50) * 0.3 * MFDScale
    temptexts_pad = 5 * MFDScale

    local panel_final_size = vec2(50, 50)
    local start_pos = draw_top_left + vec2(20, 20) * MFDScale
    for i = 0, 4 do
        local row_size = calculate_row_size(start_pos, i + 1)
        start_pos = start_pos + vec2(0, abs_text_size.y * 2)
        panel_final_size = vec2(math.max(panel_final_size.x, row_size.x), math.max(panel_final_size.y, row_size.y))
    end

    panel_final_size = panel_final_size + vec2(20, 20) * MFDScale
    start_pos = draw_top_left + vec2(20, 20) * MFDScale


    players.play_intro_anim_setup(draw_center, panel_final_size, on_show_animation_start, is_showing)
    ui.drawRectFilled(draw_top_left, panel_final_size, colors.BG, 5)

    local start_x = start_pos.x
    draw_mfd_row(start_pos, MFD_Row1)
    start_pos.x = start_x
    start_pos.y = start_pos.y + abs_text_size.y * 2
    draw_mfd_row(start_pos, MFD_Row2)
    start_pos.x = start_x
    start_pos.y = start_pos.y + abs_text_size.y * 2
    draw_mfd_row(start_pos, MFD_Row3)
    start_pos.x = start_x
    start_pos.y = start_pos.y + abs_text_size.y * 2
    draw_mfd_row(start_pos, MFD_Row4)
    start_pos.x = start_x
    start_pos.y = start_pos.y + abs_text_size.y * 2
    draw_mfd_row(start_pos, MFD_Row5)

    players.play_intro_anim(draw_center, panel_final_size, on_show_animation_start, 1)
    settings.lock_app(draw_center, panel_final_size, APPNAMES.MFD, 1)
    settings.auto_scale_window(panel_final_size * 1.01, APPNAMES.MFD)
    settings.auto_place_once(panel_final_size, APPNAMES.MFD)
    ui.popDWriteFont()
end

return mod
