local active = true
local voicePre = 1
local names = {"None", "Female", "Male", "Sinister", "Vasudan", "Vasudan Translated"}

local function setActive(a)
  active = a
end

local function setVoice(a)
  if a < 0 or a > #names then
    ba.warning("Cannot set alarm voice to index " .. a .. "!")
	return
  end
  voicePre = a .. '_'
end

local function getVoiceIndex(name)
  for i, v in ipairs(names) do
	if string.lower(v) == string.lower(name) then
	  return i - 1
	end
  end
  ba.warning("Invalid alarm voice! Using default!")
  return 1
end

local utils = require('utils')
local config = utils.loadConfig('alarms.cfg')
for _, v in pairs(config) do
  if type(v.show) == 'string' then
    v.show = {gauge = v.show}
  end
  if v.show and v.show.always then
    v.alwaysShow = true
  end
end

local function isSecondaryBankLow(bankIndex, threshold)
  local bank = hv.Player.SecondaryBanks[bankIndex]
  if bank:isValid() then
    local percent = (bank.AmmoLeft / bank.AmmoMax) * 100
    return percent < (threshold or 25)
  else
    return false
  end
end

local function isSecondaryBankEmpty(bankIndex)
  local bank = hv.Player.SecondaryBanks[bankIndex]
  return bank:isValid() and bank.AmmoLeft == 0
end

local alarms = {
  ['Hull Critical'] = function()
    local percent = hv.Player.HitpointsLeft / hv.Player.Class.HitpointsMax
    local threshold = config['Hull Critical'].threshold or 30
    return (percent * 100) <= threshold
  end,
  ['Shields Breached'] = function()
    if mn.evaluateSEXP('( are-ship-flags-set !' .. tostring(hv.Player) .. '! !no-shields! )') then
      return false
    else
      local threshold = config['Shields Breached'].threshold or 15
      local shield = hv.Player.Shields
      local count = #shield
      for i = 1, count do
        if shield[i] < threshold then
          return true
        end
      end
      return false
    end
  end,
  ['Communications Destroyed'] = function()
    if hv.Player.Communication:isValid() and hv.Player.Communication.HitpointsLeft == 0 then
      return true
    elseif hv.Player.Communications:isValid() and hv.Player.Communications.HitpointsLeft == 0 then
      return true
    else
      return false
    end
  end,
  ['Engines Destroyed'] = function()
    if hv.Player.Engine:isValid() and hv.Player.Engine.HitpointsLeft == 0 then
      return true
    elseif hv.Player.Engines:isValid() and hv.Player.Engines.HitpointsLeft == 0 then
      return true
    else
      return false
    end
  end,
  ['Navigation Destroyed'] = function()
    return hv.Player.Navigation:isValid() and hv.Player.Navigation.HitpointsLeft == 0
  end,
  ['Sensors Destroyed'] = function()
    return hv.Player.Sensors:isValid() and hv.Player.Sensors.HitpointsLeft == 0 
  end,
  ['Weapons Destroyed'] = function()
    return hv.Player.Weapons:isValid() and hv.Player.Weapons.HitpointsLeft == 0
  end,
  ['Secondary 1 Low'] = function() return isSecondaryBankLow(1, config['Secondary 1 Low'].threshold) end,
  ['Secondary 2 Low'] = function() return isSecondaryBankLow(2, config['Secondary 2 Low'].threshold) end,
  ['Secondary 3 Low'] = function() return isSecondaryBankLow(3, config['Secondary 3 Low'].threshold) end,
  ['Secondary 1 Empty'] = function() return isSecondaryBankEmpty(1) end,
  ['Secondary 2 Empty'] = function() return isSecondaryBankEmpty(2) end,
  ['Secondary 3 Empty'] = function() return isSecondaryBankEmpty(3) end,
  ['Weapon Energy Low'] = function()
    local threshold = config['Weapon Energy Low'].threshold or 15
    local percent = (hv.Player.WeaponEnergyLeft / hv.Player.WeaponEnergyMax) * 100
    return percent <= threshold
  end,
  ['Countermeasures Low'] = function()
    local threshold = config['Countermeasures Low'].threshold or 7
    local count = hv.Player.CountermeasuresLeft
    return count <= threshold
  end,
  ['Countermeasures Empty'] = function()
    return hv.Player.CountermeasuresLeft == 0
  end,
  ['Departure Authorized'] = function()
    return not mn.evaluateSEXP('( are-ship-flags-set !' .. tostring(hv.Player) .. '! !no-subspace-drive! )')
  end,
  ['Cheater Cheater'] = function()
    return mn.evaluateSEXP('( player-is-cheating )')
  end
}

local lit = {}

local function reset(name, cfg)
  lit[name] = alarms[name]()
  if cfg.show then
    mn.runSEXP('( hud-set-custom-gauge-active ( false ) !' .. cfg.show.gauge .. '! )')
  end
end

local function check(name, cfg)
  if cfg and (active or cfg.alwaysShow) then
    local currentState = alarms[name]()
    local lastState = lit[name]
    if currentState and not lastState then
      lit[name] = true
      local show = cfg.show
      if show then
        local gauge = show.gauge
        mn.runSEXP('( hud-set-custom-gauge-active ( true ) !' .. gauge .. '! )')
        if show.text then
          local text = show.text
          text = ba.XSTR(text[1], text[2])
          text = ba.replaceTokens(text)
          text = ba.replaceVariables(text)
          text = string.sub(text, 1, 31) -- SEXP string limit
          mn.runSEXP('( hud-set-text !' .. gauge .. '! !' .. text.. '!)')
        end
        local ms = show.ms
        if ms then
          mn.waitAsync(ms / 1000):continueWith(function()
                mn.runSEXP('( hud-set-custom-gauge-active ( false ) !' .. gauge .. '! )')
          end)
        end
      end
      local play = cfg.play
      if play and active then
	    local soundFile = voicePre .. play
		local ScriptedAudio = require("soundhandler")
	    local handle = ScriptedAudio:playSound(soundFile, false)
      end
    elseif not currentState and lastState then
      lit[name] = false
      local show = cfg.show
      if show then
        mn.runSEXP('( hud-set-custom-gauge-active ( false ) !' .. show.gauge .. '! )')
      end
    end
  end
end

local function onFrame()
  local now = mn.getMissionTime()
  for k, v in pairs(config) do
    if now > 2 then
      check(k, v)
    else
      reset(k, v)
    end
  end
end

return { onFrame = onFrame, setActive = setActive, setVoice = setVoice, getVoiceIndex = getVoiceIndex }

