local component = require("component")
local computer = require("computer")
local term = require("term")

if not term.isAvailable() then
  computer.beep()
  os.exit()
end
if component.gpu.getDepth() < 4 then
  print("A tier 2 or higher GPU is required")
  os.exit()
end

local function showError(message)
  component.gpu.setBackground(0x000000)
  component.gpu.setForeground(0xFF0000)
  local xt, yt = term.getCursor()
  component.gpu.set(xt, yt, message)
  component.gpu.setBackground(0x000000)
  component.gpu.setForeground(0xFFFFFF)
  print()
end

local function showErrorAndExit(message)
  showError(message)
  os.exit()
end

if not component.isAvailable("warpdriveRadar") then
  computer.beep()
  showErrorAndExit("No radar detected")
end
local radar = component.warpdriveRadar

local argv = { ... }
if #argv ~= 1 then
  showErrorAndExit("Usage: scan <scanRadius>")
end

local radius = tonumber(argv[1])

local w, h = component.gpu.getResolution()
local scale = math.min(w, h) / 2
local _, _, radarX, radarY, radarZ = radar.getGlobalPosition()

term.clear()

local function textOut(x, y, text, fg, bg)
  if term.isAvailable() then
    local w, _ = component.gpu.getResolution()
    if w then
      component.gpu.setBackground(bg)
      component.gpu.setForeground(fg)
      component.gpu.set(x, y, text)
      component.gpu.setBackground(0x000000)
    end
  end
end

local function drawBox(x, y, width, height, color)
  if term.isAvailable() then
    local w, _ = component.gpu.getResolution()
    if w then
      component.gpu.setBackground(color)
      component.gpu.fill(x, y, width, height, " ")
      component.gpu.setBackground(0x000000)
    end
  end
end

local function translateXZ(oldX, oldZ)
  local x = radarX - oldX
  local z = radarZ - oldZ
  
  x = x / (radius / scale)
  z = z / (radius / scale)
  
  x = x + (w / 2)
  z = z + (h / 2)
  
  x = math.floor(x)
  z = math.floor(z)
  
  return x, z
end

local function drawContact(x, _, z, name, color)
  local newX, newZ = translateXZ(x, z)
  
  textOut(newX, newZ, " ", 0x000000, color)
  textOut(newX - 3, newZ + 1, "[" .. name .. "]", 0xFFFFFF, 0x000000)
end

local function scanAndDraw()
  local energyStored, energyMax, _ = radar.getEnergyStatus()
  if energyStored == nil then energyStored = 0 end
  if energyMax == nil or energyMax == 0 then energyMax = 1 end
  
  radar.radius(radius)
  local success, result = radar.getEnergyRequired()
  if not success then
    showErrorAndExit(result)
  end
  local energyRequired = result
  
  if energyRequired <= 0 or energyStored < energyRequired then
    textOut((w / 2) - 8, 1, " /!\\  LOW POWER ", 0xFFFFFF, 0xFF0000)
    os.sleep(1)
    
    return 0
  end
  
  radar.start()
  local scanDuration = radar.getScanDuration()
  textOut((w / 2) - 8, 1, "   ping sent    ", 0x808080, 0x000000)
  os.sleep(scanDuration)
  
  local delay = 0
  local numResults
  repeat
    numResults = radar.getResultsCount()
    os.sleep(0.05)
    delay = delay + 1
  until (numResults ~= nil and numResults ~= -1) or delay > 10
  
  redraw()
  
  drawContact(radarX, radarY, radarZ, "RAD", 0xFFFF00)
  
  if numResults ~= nil and numResults > 0 then
    for i = 0, numResults-1 do
      local success, _, name, cx, cy, cz = radar.getResult(i)
      if success then
        drawContact(cx, cy, cz, name, 0xFF0000)
      end
    end
  end
  
  os.sleep(scanDuration)
end

function redraw()
  drawBox(2, 1, w - 2, h - 1, 0x00FF00)
  
  drawBox(1, 1, w, 1, 0x000000)
  drawBox(1, 1, 1, h, 0x000000)
  drawBox(1, h, w, 1, 0x000000)
  drawBox(w, 1, w, h, 0x000000)
  
  textOut((w / 2) - 8, 1, "= Q-Radar v0.4 =", 0xFFFFFF, 0x000000)
  
  local energyStored, _, energyUnits = radar.getEnergyStatus()
  if energyStored == nil then energyStored = 0 end
  textOut(4, h, "Energy: " .. energyStored .. " " .. energyUnits .. " | Scan radius: " .. radius, 0xFFFFFF, 0x000000)
end

local continue = true
while component.isAvailable("warpdriveRadar") and continue do
  scanAndDraw()
  os.sleep(0)
end

term.clear()
