local cwd   = (...):gsub('%.sti$', '') .. "."

local Parent  = require(cwd .. "parent")
local STI     = require(cwd .. "libs.sti")

local StiMap  = Parent:extend()

function StiMap:new(world, mapfile)
  self.sti = STI(mapfile)
  StiMap.super.new(self, world)
  self:setBackgroundColorFromTable(self.sti.backgroundcolor)
end

function StiMap:getDimensions()
  return  self.sti.width  * self.sti.tilewidth,
          self.sti.height * self.sti.tileheight
end

-- UPDATE FUNCTION
-- Update or modify the map

function StiMap:resize(w, h)
  self.sti:resize(w, h)
end

function StiMap:update(dt)
  self.sti:update(dt)
end

-- LOADING FUNCTION
-- Load actors directly into the world

function StiMap:loadCollisions()
  for k, objectlayer in pairs(self.sti.layers) do
    if self.world:isCollisionIndexed(objectlayer.name) then
      local debugstring = "loading " .. #objectlayer.objects .. " objects in " .. objectlayer.name .. " collision layer"
      core.debug:print("map/sti", debugstring)
        for k, object in pairs(objectlayer.objects) do
          self:newCollision(objectlayer, object)
        end
        self.sti:removeLayer(objectlayer.name)
    end
  end
end

function StiMap:loadActors()
  for k, objectlayer in pairs(self.sti.layers) do
    if self.world:isActorIndexed(objectlayer.name) then
      local debugstring = "loading " .. #objectlayer.objects .. " objects in " .. objectlayer.name .. " actor layer"
      core.debug:print("map/sti", debugstring)
        for k, object in pairs(objectlayer.objects) do
          if (object.properties.batchActor) then
            self:batchActor(objectlayer, object)
          else
            self:newActor(objectlayer, object)
          end
        end
        self.sti:removeLayer(objectlayer.name)
    end
  end
end

function StiMap:loadPlayers()
  for k, objectlayer in pairs(self.sti.layers) do
    if (objectlayer.name == "player") then
      local debugstring = "loading at most " .. #objectlayer.objects .. " actors in " .. objectlayer.name .. " actor layer"
      core.debug:print("map/sti", debugstring)
      local i = 1
        for k, object in pairs(objectlayer.objects) do
          self:newPlayer(object, i)
          i = i + 1
        end
        self.sti:removeLayer(objectlayer.name)
    end
  end
end

function StiMap:batchActor(objectlayer, object)
  local name     = objectlayer.name
  local gwidth   = object.properties.gwidth  or self.sti.tilewidth
  local gheight  = object.properties.gheight or self.sti.tileheight
  local x = object.x
  local y = object.y
  local z = object.properties.z or 0
  local w = object.width
  local h = object.height

  local cellHor   = math.ceil(w / gwidth)
  local cellVert  = math.ceil(h / gheight)

  for i=1, cellHor do
    for j=1, cellVert do
      self.world:newActor(name, x + (i-1)*gwidth, y + (j-1)*gheight, z)
    end
  end
end

function StiMap:newActor(objectlayer, object)
  local z = object.properties.z or 0
  local adaptPosition = object.properties.adaptPosition or false

  local y = object.y
  if (adaptPosition) then
    y = y + z
  end

  self.world:newActor(objectlayer.name, object.x, y, z)
end

function StiMap:newCollision(objectlayer, object)
  local z = object.properties.z or 0
  local d = object.properties.d or 16
  local fromTop = object.properties.fromTop or false

  local y = object.y
  if (fromTop) then
    local poschange = z .. ";" .. y .. " => " .. z-d .. ";" .. y+z
    core.debug:print("map/sti", "create from top, set z and y: " .. poschange)
    y = y + z
    z = z - d
  end

  self.world:newCollision(objectlayer.name, object.x, y, z, object.width, object.height, d)
end

function StiMap:newPlayer(object, i)
  local z = object.properties.z or 0
  local adaptPosition = object.properties.adaptPosition or false

  local y = object.y
  if (adaptPosition) then
    core.debug:print("map/sti", "adapting position, set y: " .. y .. " => ", y+z)
    y = y + z
  end

  self.world:addPlayer(object.x, y, z, i)
end

-- DRAW FUNCTIONS
-- Draw the map

function StiMap:draw()
  for _, layer in ipairs(self.sti.layers) do
    if layer.visible and layer.opacity > 0 and (layer.type == "tilelayer") then
      self.sti:drawLayer(layer)
    end
  end
end

return StiMap
