(function(context,$) {

    "use strict";

    context.JK = context.JK || {};
    context.JK.Sidebar = function(app) {
      var EVENTS = context.JK.EVENTS;
      var logger = context.JK.logger;
      var friends = [];
      var rest = context.JK.Rest();
      var invitationDialog = null;
      var textMessageDialog = null;
      var notificationPanel = null;
      var chatPanel = null;
      var me = null;
      var $sidebar = null;

      function initializeSearchPanel() {
        $('#search_text_type').change(function() {
          searchForInput();
          context.JK.SearchResultScreen.searchTypeSelection($('#search_text_type').val());
        });
      }

      context.JK.Sidebar.searchTypeSelection = function(typeSelection) {
        $('#search_text_type').val(typeSelection);
        emptySearchResults();
      }

      function refreshFriends() {
        rest.getFriends().
          done(function(response) {
            friends = response;
            updateFriendList(response);
            // set friend count
            $('#sidebar-friend-count').html(response.length);
          })
      }

      function initializeFriendsPanel() {

          $('#sidebar-search-header').hide();
          app.user().done(function() {
            refreshFriends();
          })
          $('#friend-help-howto').click(function() {
              context.JK.popExternalLink("https://forum.jamkazam.com/showthread.php?tid=117")
              return false;
          })
          return false;
      }

      function updateFriendList(response) {
          $('#sidebar-friend-list li:not(.invite-friend-row)').remove();

          // show online friends first (sort by first name within online/offline groups)
          response.sort(function(a, b) {

              var a_online = a.online;
              var b_online = b.online;

              var a_firstname = a.first_name.toLowerCase();
              var b_firstname = b.first_name.toLowerCase();

              if (b_online != a_online) {
                  if (b_online < a_online) return -1;
                  if (b_online > a_online) return 1;
                  return 0;
              }

              if (a_firstname < b_firstname) return -1;
              if (a_firstname > b_firstname) return 1;
              return 0;
          });

          context.FriendActions.updateFriends.trigger(response)


          $.each(response, function(index, val) {

              var css = val.online ? '' : 'offline';

              friends[val.id] = val;

              // fill in template for Connect pre-click
              var template = $('#template-friend-panel').html();
              var searchResultHtml = context.JK.fillTemplate(template, {
                  userId: val.id,
                  cssClass: css,
                  avatar_url: context.JK.resolveAvatarUrl(val.photo_url),
                  userName: val.name.length > 20 ? val.name.substring(0,20) + "..." : val.name,
                  status: val.online ? 'Available' : 'Offline',
                  extra_info: '',
                  hoverAction: val.musician ? "musician" : "fan",
                  info_image_url: ''
              });

              $('#sidebar-friend-list li.invite-friend-row').before(searchResultHtml);
          });

          context.JK.bindHoverEvents();
      }

      function initializeNotificationsPanel() {
        notificationPanel = new context.JK.NotificationPanel(app);
        notificationPanel.initialize(me, textMessageDialog);
      }

      // session events for chat
      function registerSessionEvents() {
        $(document).on(EVENTS.SESSION_STARTED, function(e, data){
          chatPanel.sessionStarted(e, data);
          return false;
        });

        $(document).on(EVENTS.SESSION_ENDED, function(e, data) {
          chatPanel.sessionStopped(e, data);
          return false;
        });
      }

      function initializeChatPanel() {
        chatPanel = new context.JK.ChatPanel(app);
        chatPanel.initialize(me);

        registerSessionEvents();
      }

      function search(query) {
          logger.debug('query=' + query);
          if (query !== '') {
              context.JK.search(query, app, context.JK.SearchResultScreen.onSearchSuccess);
          }
      }

      function hideSearchResults() {
          emptySearchResults();
          $('#search-input').val('');
          $('#sidebar-search-header').hide();
      }

      function emptySearchResults() {
          $('#sidebar-search-results').empty();
      }

      var delay = (function(){
          var timer = 0;
          return function(callback, ms) {
              clearTimeout(timer);
              timer = setTimeout(callback, ms);
          };
      })();


      function inviteHoverIn() {
        $('.invitation-button-holder').slideDown();
      }

      function inviteHoverOut() {
        $('.invitation-button-holder').slideUp();
      }

      function searchForInput() {
        var query = $('#search-input').val();
        // logger.debug("query=" + query);
        if (query === '') {
          return hideSearchResults();
        }
        
        if (query.length > 2) {
          // FIXME:  this is in searchResults
          $('#query').html(query);
          query += '&search_text_type='+$('#search_text_type').val();
          emptySearchResults();
          search(query);
        }
      }

      function events() {
          $('#search-input').keyup(function(evt) {
              delay(function() {
                  // ENTER KEY
                  if (evt.which === 13) {
                      return hideSearchResults();
                  }
                  // ESCAPE KEY
                  if (evt.which === 27) {
                      return hideSearchResults();
                  }
                  searchForInput();
              }, 500);
          });

          $('#sidebar-search-expand').click(function(evt) {
              $('#searchForm').submit();
              hideSearchResults();
          });

          //$('.sidebar .invite-friend-row').hoverIntent(inviteHoverIn, inviteHoverOut);

          // friend notifications
          registerFriendUpdate();

          // session invitations
          registerSessionJoin();
          registerSessionDepart();

          // recording notifications
          registerRecordingStarted();
          registerRecordingEnded();

          // broadcast notifications
          registerSourceUpRequested();
          registerSourceDownRequested();
          registerSourceUp();
          registerSourceDown();

          // watch for Invite More Users events
          $('#sidebar-div .email-invitation-holder').click(function() {
              invitationDialog.showEmailDialog();
              return false;
          });

          $('#sidebar-div .gmail-invitation-holder').click(function() {
              invitationDialog.showGoogleDialog();
              return false;
          });

          $('#sidebar-div .facebook-invitation-holder').click(function(evt) {
              invitationDialog.showFacebookDialog(evt);
              return false;
          });
      }

      function registerFriendUpdate() {
          context.JK.JamServer.registerMessageCallback(context.JK.MessageType.FRIEND_UPDATE, function(header, payload) {
              logger.debug("Handling FRIEND_UPDATE msg " + JSON.stringify(payload));

              var friend = friends[payload.user_id];
              if(friend) {
                friend.online = payload.online;
                updateFriendList(friends);

                var online_text = payload.online ? "online" : "offline";
                app.notify({
                  "title": "Friend is now " + online_text,
                  "text": payload.msg,
                  "icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
                });
              }
          });
      }

      function registerSessionJoin() {
          context.JK.JamServer.registerMessageCallback(context.JK.MessageType.SESSION_JOIN, function(header, payload) {
              logger.debug("Handling SESSION_JOIN msg " + JSON.stringify(payload));

              if (app.clientId != payload.client_id) {
                // display notification
                app.notify({
                  "title": "New Session Participant",
                  "text": payload.msg,
                  "icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
                });

                // tell session store that this happened
                context.SessionActions.sessionJoinedByOther(payload)
              }

            if (context.jamClient.ClientJoinedSession) {
              context.jamClient.ClientJoinedSession(payload["source_user_id"], payload["client_id"], payload["session_id"])
            }
          });
      }

      function registerSessionDepart() {
          context.JK.JamServer.registerMessageCallback(context.JK.MessageType.SESSION_DEPART, function(header, payload) {
              logger.debug("Handling SESSION_DEPART msg " + JSON.stringify(payload));

               if (app.clientId != payload.client_id) {
                 var recordingId = payload.recording_id;

                 if (recordingId && context.RecordingStore.recordingModel.isRecording(recordingId)) {
                   context.RecordingStore.recordingModel.onServerStopRecording(recordingId);
                 }
                 else {
                   app.notify({
                     "title": "Musician Left Session",
                     "text": payload.msg,
                     "icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
                   });
                 }
               }
              if (context.jamClient.ClientLeftSession) {
                context.jamClient.ClientLeftSession(payload["source_user_id"], payload["client_id"], payload["session_id"])
              }
          });
      }

      function registerRecordingStarted() {
          context.JK.JamServer.registerMessageCallback(context.JK.MessageType.RECORDING_STARTED, function(header, payload) {
              logger.debug("Handling RECORDING_STARTED msg " + JSON.stringify(payload));

              app.notify({
                  "title": "Recording Started",
                  "text": payload.msg,
                  "icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
                });
          });
      }

      function registerRecordingEnded() {
          context.JK.JamServer.registerMessageCallback(context.JK.MessageType.RECORDING_ENDED, function(header, payload) {
              logger.debug("Handling RECORDING_ENDED msg " + JSON.stringify(payload));

              app.notify({
                  "title": "Recording Ended",
                  "text": payload.msg,
                  "icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
                });
          });
      }

      function registerSourceUpRequested() {
        context.JK.JamServer.registerMessageCallback(context.JK.MessageType.SOURCE_UP_REQUESTED, function(header, payload) {

            logger.debug("Handling SOURCE_UP_REQUESTED msg " + JSON.stringify(payload));

            var current_session_id = context.SessionStore.id();

            if (!current_session_id) {
                // we are not in a session
                var last_session = context.SessionStore.getCurrentOrLastSession();
                if(last_session && last_session.id == payload.music_session) {
                    // the last session we were in was responsible for this message. not that odd at all
                    logger.debug("SOURCE_UP_REQUESTED came in for session_id" + payload.music_session + ", but was dropped because we have left that session")
                }
                else {
                    // this means we aren't in a session, and, what's worse,
                    // the last session we were in does not match the specified music_session id
                    throw "SOURCE_UP_REQUESTED came in for session_id:" + payload.music_session + ", but we are not in a session and the last session ID did not match the one specified";
                }
            }
            else {
                // we are in a session
                if(current_session_id == payload.music_session) {
                    context.jamClient.SessionLiveBroadcastStart(payload.host, payload.port, payload.mount,
                        payload.source_user, payload.source_pass,
                        '', payload.bitrate)
                }
                else {
                    var last_session = context.SessionStore.getCurrentOrLastSession();
                    if(last_session && last_session.id == payload.music_session) {
                        // the last session we were in was responsible for this message. not that odd at all
                        logger.debug("SOURCE_UP_REQUESTED came in for session_id" + payload.music_session + ", but was dropped because we have left that session and are in a new one")
                    }
                    else {
                        // this means we aren't in a session, and, what's worse,
                        // the last session we were in does not match the specified music_session id
                        throw "SOURCE_UP_REQUESTED came in for session_id:" + payload.music_session + ", but we are in a session and the last session ID did not match the one specified";
                    }
                }
            }
        });
      }

      function registerSourceDownRequested() {
        context.JK.JamServer.registerMessageCallback(context.JK.MessageType.SOURCE_DOWN_REQUESTED, function(header, payload) {
            logger.debug("Handling SOURCE_DOWN_REQUESTED msg " + JSON.stringify(payload));
            var current_session_id = context.SessionStore.id();

            if (!current_session_id) {
                // we are not in a session
                var last_session = context.SessionStore.getCurrentOrLastSession();
                if(last_session && last_session.id == payload.music_session) {
                    // the last session we were in was responsible for this message. not that odd at all
                    logger.debug("SOURCE_DOWN_REQUESTED came in for session_id" + payload.music_session + ", but was dropped because we have left that session")
                }
                else {
                    // this means we aren't in a session, and, what's worse,
                    // the last session we were in does not match the specified music_session id
                    throw "SOURCE_DOWN_REQUESTED came in for session_id:" + payload.music_session + ", but we are not in a session and the last session ID did not match the one specified";
                }
            }
            else {
                // we are in a session
                if(current_session_id == payload.music_session) {
                    context.jamClient.SessionLiveBroadcastStop();
                }
                else {
                    var last_session = context.SessionStore.getCurrentOrLastSession();
                    if(last_session && last_session.id == payload.music_session) {
                        // the last session we were in was responsible for this message. not that odd at all
                        logger.debug("SOURCE_DOWN_REQUESTED came in for session_id" + payload.music_session + ", but was dropped because we have left that session and are in a new one")
                    }
                    else {
                        // this means we aren't in a session, and, what's worse,
                        // the last session we were in does not match the specified music_session id
                        throw "SOURCE_DOWN_REQUESTED came in for session_id:" + payload.music_session + ", but we are in a session and the last session ID did not match the one specified";
                    }
                }
            }
        });
      }

      function registerSourceUp() {
        context.JK.JamServer.registerMessageCallback(context.JK.MessageType.SOURCE_UP, function(header, payload) {
          logger.debug("Handling SOURCE_UP msg " + JSON.stringify(payload));

          logger.debug("session %o is now being broadcasted", payload.music_session);
          app.notify({
              "title": "Now Broadcasting",
              "text": "This session is now being broadcasted."
          });
        });
      }

      function registerSourceDown() {
        context.JK.JamServer.registerMessageCallback(context.JK.MessageType.SOURCE_DOWN, function(header, payload) {
          logger.debug("Handling SOURCE_DOWN msg " + JSON.stringify(payload));
          logger.debug("session %o is no longer being broadcasted", payload.music_session);
          app.notify({
              "title": "No Longer Broadcasting",
              "text": "This session is no longer being broadcasted."
          });
        });
      }

      this.initialize = function(invitationDialogInstance, textMessageDialogInstance) {
        me = this;
        invitationDialog = invitationDialogInstance;
        textMessageDialog = textMessageDialogInstance;
        $sidebar = $('#sidebar-div')
        app.user()
          .done(function() {
            events();
            initializeSearchPanel();
            initializeFriendsPanel();
            initializeChatPanel();
            initializeNotificationsPanel();
          })
          .fail(function(arg1) {
            if(arg1 == "not_logged_in") {
              $('#search-input').attr('disabled', 'disabled')
              $('.sidebar .invite-friend-row').click(function() {
                app.layout.showDialog('login-required-dialog')
              });
              $sidebar.addClass('not-logged-in')
            }
          })
      };

      this.refreshFriends = refreshFriends;
  }
})(window,jQuery);