class @PrivateMessagesView extends Backbone.View
  messageTemplate: JST['private_message']

  events:
    "keypress .chat_input"  : "keyPressEvent"
    "keyup .chat_input"  : "keyUpEvent"
    "click .challenge_button, .cancel_challenge" : "toggleChallengeEvent"
    "click .popup_messages" : "focusChatEvent"
    "click .title_minimize" : "minimizePopupEvent"
    "click .title_close" : "closePopupEvent"
    "challenge .popup" : "sendChallengeEvent"
    "cancelChallenge .popup" : "challengeCanceledEvent"
    "focus .popup" : "focusPopupEvent"

  initialize: =>
    @listenTo(@collection, 'open', @createPopup)
    @listenTo(@collection, 'focus', @focusPopup)
    @listenTo(@collection, 'receive', @receiveMessage)
    @listenTo(@collection, 'close', @closePopup)
    @listenTo(@collection, 'minimize', @minimizePopup)
    @listenTo(@collection, 'show', @showPopup)
    @listenTo(@collection, 'openChallenge', @openChallenge)
    @listenTo(@collection, 'cancelChallenge', @cancelChallenge)
    @listenTo(@collection, 'closeChallenge', @closeChallenge)
    @listenTo(@collection, 'focus show', @resetNotifications)

    # @listenTo(PokeBattle.userList, 'add', @notifyJoin)
    # @listenTo(PokeBattle.userList, 'remove', @notifyLeave)

  createPopup: (message) =>
    title = id = message.id
    $html = @$findPopup(id)
    if @$findPopup(id).length == 0
      $html = $(@messageTemplate({window, id, title}))

      @$el.append($html)
      @positionPopup($html, @$(".popup:visible").length - 1)
      @addLogMessages($html, message.getLog())
    $html

  focusPopup: (message) =>
    id = message.id
    $popup = @$findPopup(id)
    $popup.find('.chat_input').focus()

  closePopup: (message) =>
    username = message.id
    @$findPopup(username).remove()
    @repositionPopups()

  minimizePopup: (message) =>
    username = message.id
    $popup = @$findPopup(username)
    $popup.addClass('hidden')
    @repositionPopups()

  showPopup: (message) =>
    username = message.id
    $popup = @$findPopup(username)
    @$el.append($popup)
    $popup.removeClass('hidden')
    @scrollToBottom($popup)
    @repositionPopups()

  addMessage: ($popup, message) =>
    $messages = $popup.find('.popup_messages')
    $messages.append(message)

  # todo: make this and receiveMessage construct messages from a common source
  addLogMessages: ($popup, log) =>
    messageHtml = ""
    for {username, message, opts} in log
      message = _.escape(message)
      username = "Me"  if username == PokeBattle.username
      if opts.type in [ 'error', 'alert' ]
        messageHtml += "<p class='grey'>#{message}</p>"
      else
        messageHtml += "<p class='grey'><strong>#{username}:</strong> #{message}</p>"

    @addMessage($popup, messageHtml)
    @scrollToBottom($popup)

  # todo: make this and addLogMessages construct messages from a common source
  receiveMessage: (messageModel, messageId, username, message, options) =>
    message = _.escape(message)
    $popup = @$findOrCreatePopup(messageId)
    wasAtBottom = @isAtBottom($popup)
    username = "Me"  if username == PokeBattle.username
    if options.type == 'error'
      @addMessage($popup, "<p class='red italic'>#{message}</p>")
    else if options.type == 'alert'
      @addMessage($popup, "<p class='yellow italic'>#{message}</p>")
    else
      if username != "Me" && !$popup.find('.chat_input').is(":focus")
        $popup.addClass('new_message')
        PokeBattle.notifyUser(PokeBattle.NotificationTypes.PRIVATE_MESSAGE, username)
      else
        @resetNotifications(messageModel)
      @addMessage($popup, "<p><strong>#{username}:</strong> #{message}</p>")
    if wasAtBottom then @scrollToBottom($popup)

  openChallenge: (messageId, generation, conditions) =>
    $popup = @$findOrCreatePopup(messageId)
    $challenge = @createChallenge($popup, generation, conditions)
    if generation
      $challenge.find('.is_not_challenger').addClass('hidden')
      $challenge.find('.is_challenger').removeClass('hidden')

  cancelChallenge: (messageId) =>
    $popup = @$findOrCreatePopup(messageId)
    $challenge = $popup.find('.challenge')
    $challenge.find('.icon-spinner').addClass('hidden')
    $challenge.find('.send_challenge, .select').removeClass('disabled')
    $challenge.find('.challenge_text').text("Challenge")
    $challenge.find(".cancel_challenge").text('Close')

  closeChallenge: (messageId) =>
    $popup = @$findOrCreatePopup(messageId)
    $challenge = $popup.find('.challenge')
    $challenge.addClass('hidden')
    $popup.find('.popup_messages').removeClass('small')

  resetNotifications: (message) =>
    message.set('notifications', 0)

  notifyJoin: (user) =>
    message = @collection.get(user.id)
    return  unless @isOpen(message)
    message?.add(user.id, "#{user.id} is now online!", type: "alert")

  notifyLeave: (user) =>
    message = @collection.get(user.id)
    return  unless @isOpen(message)
    message?.add(user.id, "#{user.id} is now offline.", type: "alert")

  isOpen: (message) =>
    message && @$findPopup(message.id).length > 0

  # Returns true if the chat is scrolled to the bottom of the screen.
  # This also returns true if the messages are hidden.
  isAtBottom: ($popup) =>
    $el = $popup.find('.popup_messages')
    ($el[0].scrollHeight - $el.scrollTop() <= $el.outerHeight())

  scrollToBottom: ($popup) =>
    messages = $popup.find('.popup_messages')[0]
    return  unless messages
    messages.scrollTop = messages.scrollHeight
    false

  positionPopup: ($popup, index) =>
    leftOffset = $('#content').position().left
    $popup.css(left: leftOffset + index * $popup.outerWidth(true))

  repositionPopups: =>
    @$(".popup:visible").each (index, self) =>
      @positionPopup($(self), index)

  $findPopup: (id) =>
    @$(".popup[data-user-id='#{id}']")

  $findOrCreatePopup: (messageId) =>
    $popup = @$findPopup(messageId)
    $popup = @createPopup(@collection.get(messageId))  if $popup.length == 0
    $popup

  $closestPopup: (target) =>
    $target = $(target)
    return $target  if $target.hasClass("popup")
    return $target.closest(".popup")

  messageFromPopup: (target) =>
    $popup = @$closestPopup(target)
    message = @collection.get($popup.data('user-id'))
    return message

  createChallenge: ($popup, generation, conditions) =>
    $challenge = $popup.find('.challenge')
    $challenge.html(JST['challenge']())
    createChallengePane
      eventName: "challenge"
      button: $popup.find('.send_challenge')
      acceptButton: $popup.find('.accept_challenge')
      rejectButton: $popup.find('.reject_challenge')
      populate: $popup.find(".challenge_data")
      generation: generation
      personId: $popup.data('user-id')
      defaultClauses: conditions || [
        Conditions.TEAM_PREVIEW
        Conditions.PBV_1000
        Conditions.SLEEP_CLAUSE
        Conditions.EVASION_CLAUSE
        Conditions.SPECIES_CLAUSE
        Conditions.OHKO_CLAUSE
        Conditions.PRANKSTER_SWAGGER_CLAUSE
        Conditions.UNRELEASED_BAN
      ]
      blockedClauses: conditions? || [Conditions.RATED_BATTLE]
    $popup.find('.popup_messages').addClass('small')
    $challenge.removeClass('hidden')
    $challenge

  ##########
  # EVENTS #
  ##########

  keyPressEvent: (e) =>
    switch e.which
      when 13 # [ Enter ]
        $input = $(e.currentTarget)
        message = @messageFromPopup(e.currentTarget)
        text = $input.val()
        return  if text.length == 0
        PokeBattle.primus.send('privateMessage', message.id, text)
        $input.val('')

  keyUpEvent: (e) =>
    switch e.which
      when 27 # [ Esc ]
        @closePopupEvent(e)

  minimizePopupEvent: (e) =>
    message = @messageFromPopup(e.currentTarget)
    message.trigger('minimize', message)

  closePopupEvent: (e) =>
    message = @messageFromPopup(e.currentTarget)
    message.trigger('close', message)

  focusChatEvent: (e) =>
    @$closestPopup(e.currentTarget).find('input').focus()

  toggleChallengeEvent: (e) =>
    $popup = @$closestPopup(e.currentTarget)
    $challenge = $popup.find('.challenge')
    wasAtBottom = @isAtBottom($popup)
    if $challenge.hasClass("hidden")
      @createChallenge($popup)
    else if $challenge.find('.cancel_challenge').text() == 'Cancel'
      $popup.find('.send_challenge').click()
    else
      @closeChallenge(@messageFromPopup($popup))
    if wasAtBottom then @scrollToBottom($popup)

  sendChallengeEvent: (e) =>
    $popup = @$closestPopup(e.currentTarget)
    $challenge = $popup.find('.challenge')
    $challenge.find(".icon-spinner").removeClass('hidden')
    $challenge.find(".challenge_text").text('Challenging...')
    $challenge.find(".cancel_challenge").text('Cancel')

  challengeCanceledEvent: (e) =>
    message = @messageFromPopup(e.currentTarget)
    message.trigger('cancelChallenge', message.id)

  focusPopupEvent: (e) =>
    $popup = @$closestPopup(e.currentTarget)
    $popup.removeClass('new_message')
    @resetNotifications(@collection.get($popup.data('user-id')))
