conditions = require '../conditions'
{_} = require 'underscore'

# Abstracts out sending messages from player to battle.
# Makes the Battle smoothly go into the next turn
# Necessary to separate out making commands and executing commands.
class @BattleController
  constructor: (@battle) ->
    conditions.attach(this)
    @battle.emit('initialize')

  BATTLE_DELEGATES = 'getPlayer isOver sendRequestTo
              add remove'.trim().split(/\s+/)

  for method in BATTLE_DELEGATES
    do (method) =>
      this::[method] = ->
        @battle[method].apply(@battle, arguments)

  # Returns all the player ids participating in this battle.
  getPlayerIds: ->
    @battle.playerIds

  # Returns all the names of players participating in this battle.
  # These names may be masked by alts
  getPlayerNames: ->
    @battle.playerNames

  # Tells the player to execute a certain move by name. The move is added
  # to the list of player actions, which are executed once the turn continues.
  makeMove: (playerId, moveName, forSlot = 0, forTurn = @battle.turn, options = {}) ->
    return false  if @battle.isOver()
    return false  if forTurn != @battle.turn
    return false  if playerId not in @battle.playerIds
    pokemon = @battle.getTeam(playerId).at(forSlot)
    return false  if !pokemon
    request = @battle.requestFor(pokemon)
    return false  if !request
    return false  if moveName not in (request.moves || [])
    move = @battle.getMove(moveName)
    @battle.recordMove(playerId, move, forSlot, options)
    @transitionToNextState()
    return true

  # Tells the player to switch with a certain pokemon specified by position.
  # The switch is added to the list of player actions, which are executed
  # once the turn continues.
  makeSwitch: (playerId, toPosition, forSlot = 0, forTurn = @battle.turn) ->
    return false  if @battle.isOver()
    return false  if forTurn != @battle.turn
    return false  if playerId not in @battle.playerIds
    pokemon = @battle.getTeam(playerId).at(forSlot)
    return false  if !pokemon
    request = @battle.requestFor(pokemon)
    return false  if !request
    return false  if toPosition not in (request.switches || [])
    @battle.recordSwitch(playerId, toPosition, forSlot)
    @transitionToNextState()
    return true

  # Tells the player to cancel their latest completed request.
  undoCompletedRequest: (playerId, forTurn = @battle.turn) ->
    return false  if forTurn != @battle.turn
    @battle.undoCompletedRequest(playerId)
    @sendUpdates()
    return true

  # Makes a player forfeit.
  forfeit: (playerId) ->
    return  if @battle.isOver()
    @battle.forfeit(playerId)
    @sendUpdates()

  messageSpectators: (user, message) ->
    # In case the user is an alt.
    userName = @battle.getPlayerName(user.name)
    for spectator in @battle.spectators
      spectator.send('updateBattleChat', @battle.id, userName, message)

  rawMessage: (message) ->
    for spectator in @battle.spectators
      spectator.send('rawBattleMessage', @battle.id, message)

  # Continue or begin a new turn if each player has made an action.
  transitionToNextState: ->
    return  if not @battle.areAllRequestsCompleted()
    if @battle.replacing
      @battle.performReplacements()
      @sendUpdates()
    else
      @continueTurn()

  # Officially starts the battle.
  beginBattle: ->
    @battle.begin()
    @sendUpdates()

  beginTurn: ->
    @battle.beginTurn()
    @sendUpdates()

  # Continues the turn. This is called once all requests
  # have been submitted and the battle is ready to continue.
  #
  # If there are no more requests, the engine progresses to endTurn. Otherwise,
  # it waits for continueTurn to be called again.
  continueTurn: ->
    @battle.continueTurn()

    # If all requests have been completed, then end the turn.
    # Otherwise, wait for further requests to be completed before ending.
    if @battle.areAllRequestsCompleted() then @endTurn()
    @sendUpdates()

  # Calls Battle#endTurn. If all pokemon are fainted, then it
  # ends the battle. Otherwise, it will request for new pokemon and wait if
  # any replacements are needed, or begins the next turn.
  endTurn: ->
    @battle.endTurn()
    @sendUpdates()

  endBattle: ->
    @battle.endBattle()
    @sendUpdates()

  # Sends battle updates to spectators.
  sendUpdates: ->
    @battle.sendUpdates()
