--══════════════════════════════════════════════════════════════════════════════
-- rpm_bar_5_manual_boxes.lua
-- 5 manually positioned RPM boxes, automatic fill, optional reversed order
-- each box has its own real outline
--══════════════════════════════════════════════════════════════════════════════

----------------------------------------- USER SETTINGS -----------------------
local START_RPM = 4500
local END_RPM   = 6500

-- true  = last box in BOXES lights first
-- false = first box in BOXES lights first
local REVERSE_FILL = true

local COL_EDGE1 = rgb(1.00, 0.25, 0.00)
local COL_EDGE2 = rgb(1.00, 0.25, 0.00)
local COL_MID   = rgb(1.00, 0.25, 0.00)

local SPLIT1 = 0.50
local SPLIT2 = 0.50

local RED_RPM   = 6750
local RED_MODE  = "blink_hide"   -- "off" | "solid" | "blink" | "blink_hide"
local RED_COLOR = rgb(1.00, 0.05, 0.00)
local BLINK_HZ  = 4

local DRAW_OUTLINE = true
local OUTLINE_COL  = rgb(1, 1, 1)
local OUTLINE_SIZE = 1

local DEBUG_MODE = false
local DEBUG_RPM  = 6750

-- Each box has its own position and size here
local BOXES = {
  { x =   17, y = 145, w = 180, h = 100 }, -- box 1
  { x = 205, y = 145, w = 180, h = 100 }, -- box 2
  { x = 410, y = 145, w = 180, h = 100 }, -- box 3
  { x = 590, y = 145, w = 180, h = 100 }, -- box 4
  { x = 780, y = 145, w = 180, h = 100 }, -- box 5
}

----------------------------------------- HELPERS -----------------------------
local function clamp(v, a, b)
  return (v < a) and a or ((v > b) and b or v)
end

local function rect(x, y, w, h, c)
  if w <= 0 or h <= 0 then return end
  display.rect({
    pos = vec2(x, y),
    size = vec2(w, h),
    color = c
  })
end

local function drawBoxOutline(b, c)
  local s = OUTLINE_SIZE
  rect(b.x,         b.y,         b.w, s,   c) -- top
  rect(b.x,         b.y + b.h-s, b.w, s,   c) -- bottom
  rect(b.x,         b.y,         s,   b.h, c) -- left
  rect(b.x + b.w-s, b.y,         s,   b.h, c) -- right
end

local function drawBoxFill(b, c)
  local s = DRAW_OUTLINE and OUTLINE_SIZE or 0
  rect(b.x + s, b.y + s, b.w - s * 2, b.h - s * 2, c)
end

local function colorAtFrac(frac)
  if frac <= SPLIT1 then
    return COL_EDGE1
  elseif frac <= SPLIT2 then
    return COL_EDGE2
  else
    return COL_MID
  end
end

local function getBoxCount()
  return #BOXES
end

local function getDrawIndex(i, count)
  if REVERSE_FILL then
    return count - i + 1
  end
  return i
end

local function drawBoxes(litCount, useRed)
  local count = getBoxCount()
  litCount = clamp(math.floor(litCount or 0), 0, count)

  for i = 1, count do
    local drawIndex = getDrawIndex(i, count)
    local b = BOXES[i]

    if drawIndex <= litCount then
      local c = useRed and RED_COLOR or colorAtFrac((drawIndex - 0.5) / math.max(count, 1))
      drawBoxFill(b, c)
    end

    if DRAW_OUTLINE then
      drawBoxOutline(b, OUTLINE_COL)
    end
  end
end

----------------------------------------- RUNTIME -----------------------------
local car = ac.getCar(0)
local blinkTimer = 0

function script.update(dt)
  if not car then return end
  blinkTimer = blinkTimer + (type(dt) == "number" and dt or 0)

  local rpm = DEBUG_MODE and DEBUG_RPM or (car.rpm or 0)
  local count = getBoxCount()

  if rpm >= RED_RPM and RED_MODE ~= "off" then
    if RED_MODE == "solid" then
      drawBoxes(count, true)
      return

    elseif RED_MODE == "blink" then
      local period = 1 / math.max(0.1, BLINK_HZ)
      local on = (blinkTimer % period) < (period * 0.5)
      if on then
        drawBoxes(count, true)
        return
      end

    elseif RED_MODE == "blink_hide" then
      local period = 1 / math.max(0.1, BLINK_HZ)
      local on = (blinkTimer % period) < (period * 0.5)
      if on then
        drawBoxes(count, true)
      else
        drawBoxes(0, false)
      end
      return
    end
  end

  local lo = math.min(START_RPM, END_RPM)
  local hi = math.max(START_RPM, END_RPM)
  local progress = clamp((rpm - lo) / math.max(hi - lo, 1), 0, 1)

  local litCount = math.floor(progress * count + 1e-6)
  drawBoxes(litCount, false)
end