---------------------------------
-- The different types of bonuses
---------------------------------
BonusType =
{
   BOMB = 0,
   EXPLOSION = 1,
   ROCKET = 2,
   SPEED = 3,
}

------------------------------
-- Creates the grid of bonuses
------------------------------
function newBonuses()
   local o = {}
   
   
   -------------------------------------
   -- Constructor of the grid of bonuses
   -------------------------------------
   function o:construct()
   
      -- Load the sprites
      self.sprites =
      {
         [BonusType.BOMB]      = newSprite("images/sprites.png", 0,   76, 38, 38),
         [BonusType.EXPLOSION] = newSprite("images/sprites.png", 38,  76, 38, 38),
         [BonusType.ROCKET]    = newSprite("images/sprites.png", 76,  76, 38, 38),
         [BonusType.SPEED]     = newSprite("images/sprites.png", 114, 76, 38, 38),
      }
      for k, spr in pairs(self.sprites) do
         spr:setCenter(0.5, 0.5)
      end
      
      -- Load the sound
      self.bonusSound = newSound("sounds/bonus.wav")
      
      -- Build the grid of bonuses
      self.map = {}
      for i = 0, boombastic.numTilesX - 1 do
         self.map[i] = {}
         for j = 0, boombastic.numTilesY - 1 do
            self.map[i][j] = nil
         end
      end
      
      return self
   end
   
   
   -----------------------------
   -- Resets the grid of bonuses
   -----------------------------
   function o:reset()
      for i = 0, boombastic.numTilesX - 1 do
         for j = 0, boombastic.numTilesY - 1 do
            self.map[i][j] = nil
         end
      end
   end
   
   
   -----------------------------------------------------------------
   -- Adds a new bonus to the grid of bonuses, at the given position
   -----------------------------------------------------------------
   function o:addBonus(tileX, tileY, type)
      if (not self.map[tileX][tileY]) then
         local bonus = {}
         bonus.currentTime = 0.0
         bonus.scale = 1.0
         
         -- Determine the type of the bonus
         if (type == nil) then
            if (math.random() <= 0.66) then
               bonus.type = math.random(0, 1)
            else
               bonus.type = math.random(2, 3)
            end
         else
            bonus.type = type
         end
         
         self.map[tileX][tileY] = bonus
      end
   end
   
   
   ------------------------------------
   -- Adds a bonus at a random position
   ------------------------------------
   function o:addBonusAtRandomPosition(type)
      local bonusX = math.random(0, boombastic.numTilesX - 1)
      local bonusY = math.random(0, boombastic.numTilesY - 2)
      
      -- Add the bonus to the first free tile, from a random position
      for i = bonusX, boombastic.numTilesX - 1 do
         for j = bonusY, boombastic.numTilesY - 1 do
            if (not tileIsBlocking(i, j) and #getTanksAtTile(i, j) == 0) then
               self:addBonus(i, j, type)
               return
            end
         end
         bonusY = 0
      end
   end
   
   
   ----------------------------------
   -- Removes the bonus from the grid
   ----------------------------------
   function o:removeBonus(tileX, tileY)
      if (self.map[tileX][tileY]) then
         self.map[tileX][tileY] = nil
      end
   end
   
   
   -------------------------------------------
   -- Checks whether the given tile is a bonus
   -------------------------------------------
   function o:tileIsBonus(tileX, tileY)
      return (self.map[tileX][tileY] ~= nil)
   end
   
   
   ------------------------------------------------------
   -- Applies on the tank the bonus at the given position
   ------------------------------------------------------
   function o:applyBonus(tileX, tileY, tank)
      local bonus = self.map[tileX][tileY]
      if (bonus) then
         
         -- Apply the bonus on the tank
         if (bonus.type == BonusType.BOMB) then
            tank.numBombs = tank.numBombs + 1
         
         elseif (bonus.type == BonusType.EXPLOSION) then
            tank.bombPower = tank.bombPower + 1
         
         elseif (bonus.type == BonusType.ROCKET) then
            tank.numRockets = tank.numRockets + 1
         
         elseif (bonus.type == BonusType.SPEED) then
            tank.speed = tank.speed + boombastic.speedBonus
         end
         
         tank.collectedBonuses[bonus.type] = (tank.collectedBonuses[bonus.type] or 0) + 1
         self:removeBonus(tileX, tileY)
         
         -- Add the particle-explosion
         local x, y = convertTileToPixels(tileX, tileY)
         boombastic.particleSystems:addBonusExplosion(x, y)
         
         -- Play the bonus sound
         self.bonusSound:play()
      end
   end
   
   
   ----------------------
   -- Updates the bonuses
   ----------------------
   function o:update(dt)
      for i = 0, boombastic.numTilesX - 1 do
         for j = 0, boombastic.numTilesY - 1 do
            -- Animate the bonus
            if (self.map[i][j]) then
               local bonus = self.map[i][j]
               bonus.currentTime = bonus.currentTime + dt
               bonus.scale = math.abs(math.cos(2.0 * bonus.currentTime))
            end
         end
      end
   end
   
   
   ----------------------------
   -- Draws the grid of bonuses
   ----------------------------
   function o:draw()
      for i = 0, boombastic.numTilesX - 1 do
         for j = 0, boombastic.numTilesY - 1 do
            if (self.map[i][j]) then
               local bonus = self.map[i][j]
               local sprite = self.sprites[bonus.type]
               local x, y = convertTileToPixels(i, j)
               sprite:draw(boombastic.origX + x,
                           boombastic.origY + y,
                           0, bonus.scale, 1)
            end
         end
      end
   end
   
   
   return o:construct()
end
