-- based on
-- https://healeycodes.com/virtual-ants
-- https://github.com/healeYcodes/virtual-ants/blob/main/index.html

require("util")

local function rotate(direction, clockwise)
  local match
  if clockwise then
    match = {
      u = "r",
      r = "d",
      d = "l",
      l = "u",
    }
  else
    match = {
      u = "l",
      l = "d",
      d = "r",
      r = "u"
    }
  end
  return match[direction]
end

local function initColors(rules)
  rules = rules:lower()
  local colorbrewer = require("colorbrewer")
  local scheme = colorbrewer.random(#rules)
  COLORS = {}
  for i, color in pairs(scheme) do
    COLORS[i] = {
      clockwise = rules:sub(i, i) == "r",
      rgba = color
    }
  end
end

local function initScreen()
  local width, height = love.graphics.getDimensions()
  WIDTH, HEIGHT = round2even(width), round2even(height)
  CANVAS = love.graphics.newCanvas(WIDTH, HEIGHT)
  CANVAS:renderTo(function()
    local c = COLORS[1].rgba
    love.graphics.setColor({ c[1], c[2], c[3], 0.9 })
    love.graphics.rectangle("fill", 0, 0, WIDTH, HEIGHT)
  end)
end

local function initFont()
  FONT = love.graphics.newFont(16)
  love.graphics.setFont(FONT)
  FPS_WIDTH = FONT:getWidth("120 FPS")
  FPS_HEIGHT = FONT:getHeight()
end

local function spawnAnt(x, y)
  table.insert(ANTS, {
    x = x,
    y = y,
    direction = "u"
  })
end

local function spawnAntCentered()
  spawnAnt(
    (WIDTH / 2) - ((WIDTH / 2) % UNITS),
    (HEIGHT / 2) - ((HEIGHT / 2) % UNITS)
  )
end

local function initAnts()
  ANTS = {}
  spawnAntCentered()
end

local function initGrid()
  GRID = {}
  GRID.mt = {}
  setmetatable(GRID, GRID.mt)
  GRID.mt.__index = function(table, key)
    table[key] = {}
    table[key].mt = {}
    setmetatable(table[key], table[key].mt)
    table[key].mt.__index = function(innerTable, innerKey)
      innerTable[innerKey] = 1
      return innerTable[innerKey]
    end
    return table[key]
  end
end

function love.load(args)
  local rules = args[1] or "RL"
  UNITS = args[2] or 4
  STEPS_PER_FRAME = args[3] or 5
  initColors(rules)
  initScreen()
  initFont()
  initAnts()
  initGrid()
end

local function antColor(ant)
  return GRID[ant.x][ant.y]
end

local function setColor(ant, color)
  GRID[ant.x][ant.y] = color
end

local function updateColor(ant)
  local val = antColor(ant)
  if val == #COLORS then
    val = 1
  else
    val = val + 1
  end
  setColor(ant, val)
end

local function nextColor(ant)
  local c = COLORS[antColor(ant)]
  updateColor(ant)
  return c
end

function love.mousepressed(x, y)
  spawnAnt(x, y)
end

function love.update()
  pcall(function()
    require("lurker").update()
  end)
  for _ = 1, STEPS_PER_FRAME do
    for i, ant in pairs(ANTS) do
      local c = nextColor(ant)
      ant.direction = rotate(ant.direction, c.clockwise)
      CANVAS:renderTo(function()
        love.graphics.setBlendMode("alpha")
        love.graphics.setColor(c.rgba)
        love.graphics.rectangle("fill", ant.x, ant.y, UNITS, UNITS)
      end)
      if ant.direction == "u" then
        ant.y = ant.y - UNITS
      elseif ant.direction == "r" then
        ant.x = ant.x + UNITS
      elseif ant.direction == "d" then
        ant.y = ant.y + UNITS
      else
        ant.x = ant.x - UNITS
      end

      if ant.x >= WIDTH then
        ant.x = 0
      elseif ant.x < 0 then
        ant.x = (WIDTH - 1) - ((WIDTH - 1) % UNITS)
      end
      if ant.y >= HEIGHT then
        ant.y = 0
      elseif ant.y < 0 then
        ant.y = (HEIGHT - 1) - ((HEIGHT - 1) % UNITS)
      end
      ANTS[i] = ant
    end
  end
end

local function paintFPS()
  love.graphics.setBlendMode("alpha")
  local fps = tostring(love.timer.getFPS()) .. " FPS"
  love.graphics.setColor(COLORS[1].rgba)
  love.graphics.rectangle("fill", WIDTH - FPS_WIDTH - 10, HEIGHT - FPS_HEIGHT - 20, FPS_WIDTH + 30, FPS_HEIGHT + 10, 5, 5)
  love.graphics.setColor(COLORS[#COLORS].rgba)
  love.graphics.print(fps, WIDTH - FPS_WIDTH - 5, HEIGHT - FPS_HEIGHT - 15)
end

function love.draw()
  love.graphics.setBlendMode("alpha", "premultiplied")
  love.graphics.setColor(COLORS[1].rgba)
  love.graphics.draw(CANVAS, 0, 0)
  paintFPS()
end
