local World = Object:extend()

local Obj = require "scenes.levels.entities"

local Sti   = require "libs.sti"
local Bump  = require "libs.bump"

-- INIT FUNCTIONS
-- All functions to init the world and the map

function World:new(scene, mapfile)
  self.scene  = scene
  self.map = Sti("assets/maps/" .. mapfile .. ".lua")
  self.obj = Obj
  self.entities = Bump.newWorld(50)
  self.backcolor = self.map.backgroundcolor or {0, 0, 0}

  self.activeObjects = 0
end

function World:load()
  self:loadCollisions()
  self:loadEntities()
end

function World:loadEntities()
  for k, objectlayer in pairs(self.map.layers) do
    if (self:isEntityLayer(objectlayer.name)) then
        for k, object in pairs(objectlayer.objects) do
          self:addEntityByNameOnGrid( objectlayer.name, object.x, object.y,
                                      object.width, object.height )
        end
        self.map:removeLayer(objectlayer.name)
    end
  end
end

function World:isEntityLayer(layername)
  return (self.obj.index[layername] ~= nil)
end

function World:addEntityByNameOnGrid(name, x, y, w, h)
  local objWidth, objHeight = 16, 16
  local cellHor   = math.ceil(w / objWidth)
  local cellVert  = math.ceil(h / objHeight)
  for i=1, cellHor do
    for j=1, cellVert do
      self:addEntityByName(name, x + (i-1)*objWidth, y + (j-1)*objHeight)
    end
  end
end

function World:addEntityByName(name, x, y)
  self.obj.index[name](self.scene, x, y)
end

function World:loadCollisions()
  for k, objectlayer in pairs(self.map.layers) do
    if self:isCollisionLayer(objectlayer.name) then
        for k, object in pairs(objectlayer.objects) do
          self:addCollision(object.x,object.y,object.width,object.height, objectlayer.name)
        end
        self.map:removeLayer(objectlayer.name)
    end
  end
end

function World:getStartPosition()
  local startx, starty
  for k, objectlayer in pairs(self.map.layers) do
    if objectlayer.name == "playerstart" then
        for k, object in pairs(objectlayer.objects) do
          startx = object.x + (object.width/2)
          starty = object.y + (object.height) - 12
        end
        self.map:removeLayer("playerstart")
    end
  end
  return startx, starty
end

function World:isCollisionLayer(layername)
  return (self.obj.collisions[layername] == true)
end

function World:addCollision(x, y, w, h, name)
  -- Rajouter un block solide dans le monde physique
  if w == 0 then
    w = 1
  end
  self.obj.Collision(self.scene, x, y, w, h, name)
end

-- ENTITY MANAGEMENT FUNCTIONS
-- All BUMP2D wrappers

function World:addEntity(entity)
  return self.entities:add(entity, entity.x, entity.y, entity.w, entity.h)
end

function World:moveEntity(entity, x, y, filter)
  return self.entities:move(entity, x, y, filter)
end

function World:removeEntity(entity)
  return self.entities:remove(entity)
end

function World:queryRect(x, y, w, h)
  return self.entities:queryRect(x, y, w, h)
end

function World:countEntities()
  return self.entities:countItems()
end

function World:getEntities()
  return self.entities:getItems()
end

-- MAP FUNCTIONS
-- All map wrappers

function World:getDimensions()
  return  self.map.width  * self.map.tilewidth,
          self.map.height * self.map.tileheight
end

function World:setBackgroundColor(r, g, b)
  self.backcolor = {r, g, b}
end

function World:getBackgroundColor()
  return self.backcolor[1]/256, self.backcolor[2]/256, self.backcolor[3]/256
end

-- UPDATE FUNCTIONS
-- All update functions

function World:update(dt)
  self:updateEntities(dt)
  self:updateMap(dt)
end

function World:updateEntities(dt)
  --l,t,w,h = l or 0, t or 0, w or self.width, h or self.height
    local visibleThings, len = self.scene.camera:getVisibleEntities()
    --table.sort(visibleThings, sortByUpdateOrder)

    for i=1, len do
      visibleThings[i]:update(dt)
    end

    self.activeObjects = len
end

function World:updateMap(dt)
  self.map:update(dt)
end

-- DRAW FUNCTIONS
-- All function to draw the map, world and entities

function World:draw()
  -- Ona attache puis détache la caméra pour dessiner le monde, afin que celui
  -- reste "fixe" tandis que le jouer bouge.
  self:drawBackgroundColor()
  self.scene.camera:attach()
  self:drawMap()
  self:drawEntities()
  self.scene.camera:detach()
end

function World:drawEntities()
  --l,t,w,h = l or 0, t or 0, w or self.width, h or self.height
    local visibleThings, len = self.scene.camera:getVisibleEntities()
    --table.sort(visibleThings, sortByUpdateOrder)

    for i=1, len do
      visibleThings[i]:draw(dt)
    end
end

function World:drawMap()
  -- Du à la manière dont fonctionne STI, on est obligé de récupérer les info
  -- de position de camera pour afficher la carte par rapport à ces infos
  local tx, ty  = self.scene.camera:getCoord()
  local scale   = self.scene.camera:getScale()
  local tx = tx
	local ty = ty

	tx = math.floor(tx)
	ty = math.floor(ty)

	self.map:draw(-tx, -ty, scale, scale)
end

function World:drawBackgroundColor()
  local r, g, b = self.backcolor[1], self.backcolor[2], self.backcolor[3]
  love.graphics.setColor(r/256, g/256, b/256)
  love.graphics.rectangle("fill", 0, 0, 480, 272)
  utils.graphics.resetColor()
end

return World
