(function (context, $) {

  "use strict";
  context.JK = context.JK || {};
  context.JK.ChatPanel = function (app) {
    var logger = context.JK.logger;
    var rest = context.JK.Rest();
    var $panel = null;
    var $contents = null;
    var $count = null;
    var $chatMessages = null;
    var $chatMessagesScroller = null;
    var $sendChatMessageBtn = null;
    var $chatSender = null;
    var $form = null;
    var $textBox = null;
    var $sessionId = null;
    var $errorMsg = null;
    var sendingMessage = false;
    var showing = false;
    var fullyInitialized = true;
    var renderQueue = [];
    var sidebar = null;
    var user = null;
    var currentPage = 0;
    var LIMIT = 20;
    var next = null;

    function reset() {
      fullyInitialized = true;
      renderQueue = [];
      sendingMessage = false;
      //$chatMessages.empty();
      //$textBox.val('');
    }

    function buildMessage() {
      var message = {};

      message['message'] = $textBox.val();
      message['music_session'] = $sessionId;
      message['client_id'] = app.clientId;

      return message;
    }

    function sendMessage() {
      if (!context.JK.JamServer.connected) {
        return false;
      }

      var msg = $textBox.val();
      if (!msg || msg == '') {
        // don't bother the server with empty messages
        return false;
      }

      if (!sendingMessage) {
        sendingMessage = true;

        rest.createChatMessage(buildMessage())
          .done(function () {
            $textBox.val('');
            renderMessage(msg, user.id, user.name, new Date().toISOString(), true);
          })
          .fail(function (jqXHR) {
            app.notifyServerError(jqXHR, 'Unable to Send Chat Message');
          })
          .always(function () {
            sendingMessage = false;
          })

      }
      return false;
    }

    function scrollToBottom(instant) {
      $chatMessagesScroller.animate({scrollTop: $chatMessagesScroller[0].scrollHeight}, instant ? 0 : 'slow');
    }

    function renderMessage(msg, senderId, senderName, sent, append) {
      var options = {
        msg: msg,
        sender: senderId == user.id ? 'me' : senderName,
        sent: sent
      };
      var txt = $(context._.template($('#template-chat-message').html(), options, {variable: 'data'}));
      txt.find('.timeago').timeago();
      if (append) {
        $chatMessages.append(txt);
        scrollToBottom();
      }
      else {
        $chatMessages.prepend(txt);
      }
    }

    function drainQueue() {
      context._.each(renderQueue, function (msg) {
        renderMessage(msg.message, msg.user_id, msg.user_name, msg.sent, true);
      });
      renderQueue = [];
    }

    // we handled the notification, meaning the dialog showed this message as a chat message
    function handledNotification(payload) {
      return showing && payload.description == "TEXT_MESSAGE";
    }

    function pasteIntoInput(el, text) {
      el.focus();
      if (typeof el.selectionStart == "number"
        && typeof el.selectionEnd == "number") {
        var val = el.value;
        var selStart = el.selectionStart;
        el.value = val.slice(0, selStart) + text + val.slice(el.selectionEnd);
        el.selectionEnd = el.selectionStart = selStart + text.length;
      } else if (typeof document.selection != "undefined") {
        var textRange = document.selection.createRange();
        textRange.text = text;
        textRange.collapse(false);
        textRange.select();
      }
    }

    function handleEnter(evt) {
      if (evt.keyCode == 13 && evt.shiftKey) {
        evt.preventDefault();
        pasteIntoInput(this, "\n");
      }
      else if (evt.keyCode == 13 && !evt.shiftKey) {
        sendMessage();
        return false;
      }
    }

    function events(bind) {
      /**if (bind) {
        $form.submit(sendMessage);
        $textBox.keydown(handleEnter);
        $sendChatMessageBtn.click(sendMessage);
      }
       else {
        $form.submit(null);
        $textBox.keydown(null);
        $sendChatMessageBtn.click(null);
      }*/

    }

    // called from sidebar when messages come in
    function chatMessageReceived(payload) {
      if (fullyInitialized) {
        if (isChatPanelVisible()) {

        }
        else {
          highlightCount();
          incrementChatCount();
          context.jamClient.UserAttention(true);
        }
      }
    }

    function registerChatMessage(bind) {
      if (bind && bind == true) {
        context.JK.JamServer.registerMessageCallback(context.JK.MessageType.CHAT_MESSAGE, function (header, payload) {
          logger.debug("Handling CHAT_MESSAGE msg " + JSON.stringify(payload));
          chatMessageReceived(payload);
          context.ChatActions.msgReceived(payload);

          handledNotification(payload);
        });
      }
      else {
        context.JK.JamServer.registerMessageCallback(context.JK.MessageType.CHAT_MESSAGE, null);
      }
    }

    function opened() {
      lowlightCount();
      setCount(0);
      drainQueue();
    }

    function fullyOpened() {
      context.ChatActions.fullyOpened()
    }

    function sessionStarted(e, data) {
      $sessionId = data.session.id;
      var lessonId = null;
      if (data.session.lesson_session) {
        lessonId = data.session.lesson_session.id
      }
      // open chat panel
      //$chatSender.show();
      //$chatMessagesScroller.show();
      $errorMsg.hide();
      $panel.find('.panel-header').trigger('click');
      $panel.find('.btn-next-pager').attr('href', '/api/sessions/' + $sessionId + '/chats?page=1');

      reset();

      context.ChatActions.sessionStarted($sessionId, lessonId);
      showing = true
      fullyInitialized = true;
      drainQueue();

      events(true);
    }

    function sessionStopped(e, data) {
      // open chat panel
      //$chatSender.hide();
      //$chatMessagesScroller.hide();
      //$errorMsg.show();

      reset();
      events(false);
    }

    function isChatPanelVisible() {
      return $contents.is(':visible');
    }

    function incrementChatCount() {
      var count = parseInt($count.text());
      setCount(count + 1);
    }

    function setCount(count) {
      $count.text(count);
    }

    function lowlightCount() {
      $count.removeClass('highlighted');
    }

    function highlightCount() {
      $count.addClass('highlighted');
    }

    function buildQuery() {
      var query = {type: 'CHAT_MESSAGE', music_session: $sessionId, limit: LIMIT, page: currentPage};

      if (next) {
        query.start = next;
      }

      return query;
    }

    function renderChats(chats) {
      context._.each(chats, function (chatMessage) {
        renderMessage(chatMessage.message, chatMessage.user_id, chatMessage.user.name, chatMessage.created_at);
      });
    }

    function handleChatResponse(response) {
      next = response.next;

      renderChats(response.chats);

      if (response.next == null) {
        // if we less results than asked for, end searching
        $chatMessagesScroller.infinitescroll('pause');

        if (currentPage > 0) {
          // there are bugs with infinitescroll not removing the 'loading'.
          // it's most noticeable at the end of the list, so whack all such entries
          $('.infinite-scroll-loader').remove();
        }
      }
      else {
        currentPage++;
        buildQuery();
//        registerInfiniteScroll();
      }
    }

    function registerInfiniteScroll() {

      $chatMessagesScroller.infinitescroll({
        behavior: 'local',
        navSelector: '.chat-sender .btn-next-pager',
        nextSelector: '.chat-sender .btn-next-pager',
        binder: $chatMessagesScroller,
        dataType: 'json',
        appendCallback: false,
        prefill: false,
        bufferPx: 100,
        loading: {
          msg: $('<div class="infinite-scroll-loader">Loading ...</div>'),
          img: '/assets/shared/spinner-32.gif'
        },
        path: function (page) {
          return '/api/sessions/' + $sessionId + '/chats?' + $.param(buildQuery());
        }
      }, function (json, opts) {
        handleChatResponse(json);
      });
      $chatMessagesScroller.infinitescroll('resume');
    }

    function initialize(sidebarInstance) {
      sidebar = sidebarInstance;
      $panel = $('[layout-id="panelChat"]');
      $contents = $panel.find('.chatcontents');
      $chatMessagesScroller = $panel.find('.chat-list-scroller');
      $count = $panel.find('#sidebar-chat-count');

      $errorMsg = $panel.find('.chat-status');
      $errorMsg.show();

      $panel.on('open', opened);
      $panel.on('fullyOpen', fullyOpened);
      app.user()
        .done(function (userDetail) {
          user = userDetail;

          registerChatMessage(true);

        });
    }

    this.initialize = initialize;
    this.sessionStarted = sessionStarted;
    this.sessionStopped = sessionStopped;
    this.registerChatMessage = registerChatMessage;
  };

  return this;
})(window, jQuery);