local CameraSystem  = Object:extend()
local Camera        = require "libs.hump.camera"

-- INIT FUNCTIONS
-- Initialize the camera system

function CameraSystem:new(scene, x, y)
  self.scene = scene
  self.world = scene.world
  self.view = Camera(x, y, 1, 0, true)

  local width, height, flags = love.window.getMode( )
  self.screenWidth = width
  self.screenHeight = height
  self.viewWidth, self.viewHeight = core.screen:getDimensions()

  self.resolution = self.screenWidth / self.viewWidth
  self:limit()
end

-- WRAPPER and UTILS
-- Access data from the camera

function CameraSystem:floorCoord()
  self.view.x, self.view.y = utils.math.floorCoord(self.view.x, self.view.y)
end

function CameraSystem:getCoord()
  local camx, camy, camh, camw
  camx = self.view.x - (self.viewWidth/2)
  camy = self.view.y - (self.viewHeight/2)

  camw = self.viewWidth
  camh = self.viewHeight
  return camx, camy, camw, camh
end

function CameraSystem:getScale()
  return self.view.scale
end

function CameraSystem:getScreenCoord()
  local camx, camy, camh, camw
  camx = self.view.x - (self.screenWidth/2)
  camy = self.view.y - (self.screenHeight/2)

  camw = self.screenWidth
  camh = self.screenHeight
  return camx, camy, camw, camh
end

function CameraSystem:worldCoord(x, y, ox, oy, w, h)
  ox, oy = ox or 0, oy or 0
	w,h = w or love.graphics.getWidth(), h or love.graphics.getHeight()
  return self.view:worldCoords(x, y, ox, oy, w, h)
end

function CameraSystem:cameraCoords(x, y)
  return self.view:cameraCoords(x, y, ox, oy, w, h)
end

function CameraSystem:getVisibleEntities()
  local camx, camy, camw, camh = self:getScreenCoord()
  local visibleThings, len = self.world:queryRect(camx-64, camy-64, camw+128, camh+128)
  return visibleThings, len
end

function CameraSystem:isInsideView(x, y, w, h, border)
  local camx, camy, camw, camh = self:getCoord()
  local border = border or 0
  if      (x + w + border >= camx) and (x < camx + camw + border)
      and (y + h + border >= camy) and (y < camy + camh + border) then
    return true
  else
    return false
  end
end

function CameraSystem:attach()
  self.view:attach()
end

function CameraSystem:detach()
  self.view:detach()
end

-- UPDATE and MOVE functions
-- Move and update the camera system

function CameraSystem:update(dt)
  self:followPlayer(self.scene.playermanager.activePlayer)
  self:limit()
  self:floorCoord()
end

function CameraSystem:followPlayer(id)
  local player = self.scene.playermanager:getPlayerByID(id)

  if (player ~= nil) then
    local playx, playy = utils.math.floorCoord(player.center.x,
                                               player.center.y)

    local camx, camy   =  self.view.x + (self.viewWidth/2),
                          self.view.y + (self.viewHeight/2)


    playx, playy = self:cameraCoords(playx, playy)
    playx = playx - (self.viewWidth/2)
    playy = playy - (self.viewHeight/2)

    if (math.abs(playx) > 8) then
      camx = camx + (playx - (8*utils.math.sign(playx)))
    end

    if (playy > 16)  then
      camy = camy + (playy - 16)
    elseif (playy < -64) then
      camy = camy + (playy + 64)
    end

    self.view.x, self.view.y =  camx - (self.viewWidth/2),
                                    camy - (self.viewHeight/2)
  end
end

function CameraSystem:move(x, y)
  self.view.x = x
  self.view.y = y

  self:limit()
end

function CameraSystem:limit()
  local camx, camy        = self.view.x, self.view.y
  local camMinX, camMinY  = (self.screenWidth/2), (self.screenHeight/2)

  local camMaxX, camMaxY  = self.world:getDimensions()

  if (self.resolution == 1) then
    camMaxX, camMaxY = camMaxX - camMinX, camMaxY - camMinY
  end


  camx = math.max(camx, camMinX)
  camx = math.min(camx, camMaxX)

  camy = math.max(camy, camMinY)
  camy = math.min(camy, camMaxY)

  self.view.x, self.view.y = camx, camy
end

return CameraSystem
