this.App =
  debug: (msg) ->
    console.log msg

  stripJid: (jid) ->
    r = new RegExp('(^.*)\/.*$')
    match = r.exec(jid)
    if match and (match.length > 0)
      return match[1]
    else
      return jid

  UI:
    setAutoHeight: ->
      App.debug 'resizing'
      App.UI.resizeRoster()
      App.UI.resizeMessages()

    resizeRoster: ->
      if (windowHeight < $('.roster').css('min-height').replace(/[^-\d\.]/g, ''))
        return

      windowHeight = $(window).height()
      toolboxHeight = $("#height-setter-1 .toolbox").height()
      $(".friends").css({height: windowHeight - toolboxHeight - $('#js-me').height() - 40})
      $("#height-setter-1").css({height: windowHeight - toolboxHeight - $('#js-active-friends').height() - 120})

    resizeMessages: ->
      windowHeight = $(window).height()
      $("#height-setter-2").css({height: windowHeight - $('#tabbar').outerHeight() - $('#msg-writer').outerHeight() - 62})
      messagesContainer = $('.messages')
      messagesContainer.animate(scrollTop: messagesContainer.height(), 'fast')

    filterContacts: (searchTerm) ->
      App.Collections.contacts.filter(searchTerm)

  Com:
    connect: (callback) ->
      App._dispatcher = new WebSocketRails('www.xmpp.dev:3000/websocket')
      App._dispatcher.on_open = =>
        @_setupBackboneComponents()
        @_bindListeners(callback)

    trigger: (options) ->
      _.defaults(options, {data: {} })
      App._dispatcher.trigger(options.event, options.data, options.success, options.error)

    initRoster: (callback) ->
      App.Com.trigger(
        event: 'app.roster.initRoster'
        success: (data) ->
          _.each(data.contacts, (contact) ->
            newContact = new Xmpp.Models.Contact(
              id: contact.jid
              jid: contact.jid
              belongsTo: [contact.belongsTo]
            )
            App.Collections.contacts.add(newContact, merge: true)
          )

          callback?()
      )

    startFetchingVcards: ->
      App.Com.trigger(event: 'app.roster.startFetchingVcards')

    startPollingRoster: ->
      App.Com.trigger(event: 'app.roster.startPolling')

    startPollingMessages: ->
      App.Com.trigger(event: 'app.chat.startPollingMessages')

    setPresence: ->
      App.Com.trigger(event: 'app.roster.setPresence')

    getMe: ->
      App.Com.trigger(event: 'app.roster.myself', success: (response) ->
        App.Models.me = new Xmpp.Models.Me(
          jid: response.jid
          name: response.vcard.name
          status: response.status
          avatar: response.vcard.avatar
        )
      )

    sendMessage: (message, to, from, callbackOk, callbackFail) ->
      App.Com.trigger(event: 'app.chat.sendMessage', data: {message: message, to: to, from: from}, success: callbackOk, error: callbackFail)

    sendMultiMessage: (message, chatId, from, callbackOk, callbackFail) ->
      App.Com.trigger(event: 'app.chat.sendMessage', data: {message: message, chatId: chatId, from: from}, success: callbackOk, error: callbackFail)

    openNewMultiChat: (chatOwner, attendant, chat) ->
      @trigger(event: 'app.chat.newMultiChat', data: {chatOwner: chatOwner.get('jid')}, success: (response) =>
        chat.setChatId(response.id)
        chat.appendWithWhom(attendant)
        @trigger(event: 'app.chat.addToMultiChat', data: {chatOwner: chatOwner.get('jid'), chatId: response.id, jid: attendant.get('jid')}, success: ->
          Backbone.Events.trigger('openChat', chat)
        )
      )

    inviteToChat: (chat, toAdd, me) ->
      @trigger(event: 'app.chat.addToMultiChat', data: {chatOwner: me, chatId: chat.get('chatId'), jid: toAdd.get('jid')}, success: ->
        chat.appendWithWhom(toAdd)
        Backbone.Events.trigger('openChat', chat)
      )

    iClosedMultichat: (chatId, jid) ->
      @trigger(event: 'app.chat.iClosedMultichat', data: {chatId: chatId, me: jid})

    kickFromMultichat: (chatId, me, jidToKick) ->
      @trigger(event: 'app.chat.kickFromMultichat', data: {chatId: chatId, me: me, kick: jidToKick})

    switchMultiChatOwner: (me, newOwner, chatId) ->
      @trigger(event: 'app.chat.switchOwnership', data: {chatId: chatId, me: me, newOwner: newOwner})

    syncMultiChatContacts: (me, chatId) ->
      @trigger(event: 'app.chat.syncMultiChatContacts', data: {me: me, chatId: chatId})

    syncedContacts: () ->


    updateMyStatus: (message, state)->
      App.Com.trigger(event: 'app.roster.updateMyStatus', data: {message: message, state: state})

    updateMyVcardName: (name) ->
      App.Com.trigger(event: 'app.roster.updateMyVcard', data: {name: name})

    updateMyVcardAvatar: (imageBase64) ->
      App.Com.trigger(event: 'app.roster.updateMyVcard', data: {avatar: imageBase64})

    removeContactRemote: (contact, client) ->
      App.Com.trigger(event: 'app.roster.removeContact', data: {jid: contact, client: client})

    addContact: (jid) ->
      App.Com.trigger(event: 'app.roster.addContact', data: {jid: jid})

    answerFriendRequest: (jid, answer) ->
      App.Com.trigger(event: 'app.roster.answerFriendRequest', data: { jid: jid, answer: answer})

    checkSavingHistory: (me, chatId, attendant, onSuccess) ->
      App.Com.trigger(event: 'app.chat.canSaveHistory', data: {me: me, chatId: chatId, attendant: attendant}, success: onSuccess)

    setHistory: (me, chatId, attendant, state, onSuccess) ->
      App.Com.trigger(event: 'app.chat.setHistorySaving', data: {me: me, chatId: chatId, attendant: attendant, enable: state}, success: onSuccess)

    loadHistory: (me, chatId, attendant, step, onSuccess) ->
      App.Com.trigger(event: 'app.chat.loadHistory', data: {me: me, chatId: chatId, attendant: attendant, step: step}, success: onSuccess)

    _setupBackboneComponents: ->
      App.Collections.contacts = new Xmpp.Collections.ContactsCollection()
      App.Collections.chats = new Xmpp.Collections.ChatsCollection()

      App.Views.tabbar = new Xmpp.Views.Tabbar.TabbarView()

    _bindListeners: (callback) ->
      App._dispatcher.bind('connection_closed', ->
        window.location.reload()
      )

      App._dispatcher.bind('app.client.connected', (jid) ->
        callback?(jid)
      )

      App._dispatcher.bind('app.client.cannot_connect', (jid) ->
        alert('cannot connect to ' + jid)
      )

      App._dispatcher.bind('app.roster.statusChanged', (result) ->
        App.debug 'change contact state'
        App.Collections.contacts.updateStatus(result)
      )

      App._dispatcher.bind('app.roster.vcard', (result) ->
        App.debug 'got vcard'
        App.Collections.contacts.udpateVcard(result)
      )

      App._dispatcher.bind('app.roster.subscriptionChanged', (subscription) ->
        App.debug 'subscription changed'
        App.Collections.contacts.subscriptionChanged(subscription)
      )

      App._dispatcher.bind('app.roster.using_this_app', (person) ->
        App.debug ['is using this app', person.jid]
        contact = App.Collections.contacts.get(person.jid)
        if (contact)
          contact.setUsingMyApp()
      )

      App._dispatcher.bind('app.chat.destroyMultichat', (data) ->
        chatId = data.chat_id
        chat = App.Collections.chats.findById(chatId)
        if chat
          App.debug 'destroying multicat from outside'
          Backbone.Events.trigger('closeChat', chat, true)
      )

      App._dispatcher.bind('app.chat.makeMeNewOwner', (chatData) ->
        App.debug 'Makeing me new chat owner'
        chat = App.Collections.chats.findById(chatData.chat_id)
        if chat
          attendants = chat.get('withWhom')
          attendants = _.without(attendants, App.Models.me) #TODO zamenit .me za model zo serveru

          chat.set('who', App.Models.me)
          chat.set('withWhom', attendants)
      )

      App._dispatcher.bind('app.roster.friendRequest', (request) ->
        App.debug ['receiving friend request', request]
        popup = new Xmpp.Views.Popup.FriendRequestView(jid: request.jid, name: request.name)
        popup.render()
      )

      App._dispatcher.bind('app.chat.importChat', (chatData) ->
        chatId = chatData.chat_id
        chat = App.Collections.chats.findById(chatId)

        if not chat
          chat = new Xmpp.Models.Chat(
            chatId: chatId,
            isMultiChat: true
          )

          App.Collections.chats.add(chat);

        chat.syncContacts(chatData.contacts, chatData.owner)
        Backbone.Events.trigger('openChat', chat)
      )

      App._dispatcher.bind('app.chat.updateSyncedContacts', (syncData) ->
        App.debug ['new multichat contacts arrived', syncData.contacts]

        chat = App.Collections.chats.findById(syncData.chat_id)
        if chat
          chat.syncContacts(syncData.contacts, syncData.owner)
          Backbone.Events.trigger('openChat', chat)
      )

      App._dispatcher.bind('app.chat.messageReceived', (result) ->
        App.debug ['message received', result]

        if (result.chat_id)
          chat = App.Collections.chats.findById(result.chat_id)

          Backbone.Events.trigger('openChat', chat)

          tab = _.find(App.Views.tabbar.tabs, (tab) ->
            tab.getChatId() == result.chat_id
          )

          tab.showChat()
          contact = App.Collections.contacts.findByJid(App.stripJid(result.from))
          tab.chatWindow.appendMessage(contact, new Date(), result.message)
        else
          #TODO: prepisat tuto hrozu

          contact = App.Collections.contacts.findByJid(App.stripJid(result.from))

          if contact
            contactView = App.Collections.contacts.friendsList.hasContact(contact) ||
              App.Collections.contacts.activeList.hasContact(contact)
          else
            contact = new Xmpp.Models.Contact(
              id: App.stripJid(result.from)
              jid: App.stripJid(result.from)
              belongsTo: [result.to]
            )
            App.Collections.contacts.add(contact, merge: true)
            contactView = App.Collections.contacts.friendsList.hasContact(contact)

          contact.setPreferredResource(result.from)
          contactView.startChat()

          tab = _.find(App.Views.tabbar.tabs, (tab) ->
            tab.hasParticipants(App.Models.me, contact)
          )

          tab.chatWindow.appendMessage(contact, new Date(), result.message)
      )

  Models:
    me: null

  Collections:
    contacts: null
    chats: null

  Views:
    tabbar: null
    chat: null