class = require 'engine/libs/30log'

local HC = require 'engine/libs/hardoncollider'
-- has to come before the sti initialization so I can add the collision tiles
collider = HC(100)

local sti = require "engine/libs/sti"
local object = require "engine/object"
local ui = require "engine/ui"
local story = require 'story'

Engine = class()

Engine.objects = {}

function Engine:__init()
  self.windowWidth = love.graphics.getWidth()
  self.windowHeight = love.graphics.getHeight()
  
  story:start(self)
end

function Engine:checkObjectAnimation(key)
  for _, object in ipairs(self.objects) do
    if object.relevantKeys then
      for _, relevantKey in ipairs(object.relevantKeys) do
        if key == relevantKey then
          object.controller:stopAnimation()
        end
      end
    end
  end
end

function Engine:checkObjectKeys(dt)
  if not ui.active then
    for _, object in ipairs(self.objects) do
      object.controller.animation:update(dt)

      if object.relevantKeys then
        for _, relevantKey in ipairs(object.relevantKeys) do
          if love.keyboard.isDown(relevantKey) then
            object.controller:sendKey(relevantKey)
          end
        end
      end
    end
  else
    for _, relevantKey in ipairs(ui.relevantKeys) do
      if love.keyboard.isDown(relevantKey) then
        ui:sendKey(relevantKey)
      end
    end
  end
end

function Engine:update(dt)
  self:checkObjectKeys(dt)
  collider:update(dt)
  self.map:update(dt)
end

function Engine:draw()
  local translateX = 0
  local translateY = 0

  -- Draw Range culls unnecessary tiles
  self.map:setDrawRange(translateX, translateY, self.windowWidth, self.windowHeight)

  self.map:draw()
  ui:draw()

  --self:debugDrawing()
end

function Engine:initObjects()
  self.objects = {}
  
  self.map:addCustomLayer("object layer", 4)

  local objectLayer = self.map.layers["object layer"]
  objectLayer.sprites = {}

  for _, obj in pairs(self.map.layers["objects"].objects) do
    local filename = "objects/" .. obj.name .. ".lua"
    local objectinfo = love.filesystem.load(filename)()
    objectinfo.x = obj.x - object.width / 4
    objectinfo.y = obj.y

    objectinfo.controller.objectinfo = objectinfo

    objectinfo.image = love.graphics.newImage(objectinfo.spritesheet)
    objectinfo.controller:init()

    table.insert(objectLayer.sprites, {info = objectinfo})
    table.insert(self.objects, objectinfo)
  end

  -- Draw callback for Custom Layer
  function objectLayer:draw()
    table.sort(self.sprites, object.sortNorthSouth)

    for _, sprite in pairs(self.sprites) do
      local x = math.floor(sprite.info.x)
      local y = math.floor(sprite.info.y)

      sprite.info.controller.animation:draw(sprite.info.image, x, y)
    end
  end

  self.map.layers["objects"].visible = false
end

function Engine:debugDrawing()
  -- draw collision shapes for debugging
  for shape in pairs(collider:shapesInRange(0, 0, self.windowWidth, self.windowHeight)) do
    shape:draw()
  end

  -- Draw Collision Map (useful for debugging)
  self.map:drawCollisionMap(collision)
end

function Engine:loadLevel(name)
  local mapName = 'levels/' .. name
  
  self.map = sti.new(mapName)
  self.collision = self.map:getCollisionMap("collision")
  
  self:initObjects()
end

function Engine:showMessage(message)
  ui:showMessage(message)
end
