(function(context,$) {

    "use strict";

    context.JK = context.JK || {};
    context.JK.Sidebar = function(app) {
        var logger = context.JK.logger;
        var friends = [];
        var notifications = [];
        var invitationDialog = new context.JK.InvitationDialog(app);
        var rest = context.JK.Rest();

        function initializeFriendsPanel() {

            /////////////////////////////////////////////////////////////
            // THIS IS TEST CODE TO GENERATE BACK TO BACK NOTIFICATIONS
            // app.notify({
            //   "title": "TEST 1",
            //   "text": "Test 1",
            //   "icon_url": context.JK.resolveAvatarUrl("")
            // });

            // app.notify({
            //   "title": "TEST 2",
            //   "text": "Test 2",
            //   "icon_url": context.JK.resolveAvatarUrl("")
            // });

            // app.notify({
            //   "title": "TEST 3",
            //   "text": "Test 3",
            //   "icon_url": context.JK.resolveAvatarUrl("")
            // });
            /////////////////////////////////////////////////////////////

            $('#sidebar-search-header').hide();

            var url = "/api/users/" + context.JK.currentUserId + "/friends"
            $.ajax({
                type: "GET",
                dataType: "json",
                contentType: 'application/json',
                url: url,
                processData: false,
                success: function(response) {

                    friends = response;
                    updateFriendList(response);

                    // set friend count
                    $('#sidebar-friend-count').html(response.length);
                },
                error: app.ajaxError
            });

            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;
            });

            $.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,
                    status: val.online ? 'Available' : 'Offline',
                    extra_info: '',
                    info_image_url: ''
                });

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

        function initializeNotificationsPanel() {
            // retrieve pending notifications for this user
            var url = "/api/users/" + context.JK.currentUserId + "/notifications"
            $.ajax({
                type: "GET",
                dataType: "json",
                contentType: 'application/json',
                url: url,
                processData: false,
                success: function(response) {

                    notifications = response;
                    updateNotificationList(response);

                    // set notification count
                    $('#sidebar-notification-count').html(response.length);
                },
                error: app.ajaxError
            });
        }

        function updateNotificationList(response) {
            $('#sidebar-notification-list').empty();

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

                notifications[val.notification_id] = val;

                // fill in template for Connect pre-click
                var template = $('#template-notification-panel').html();
                var notificationHtml = context.JK.fillTemplate(template, {
                    notificationId: val.notification_id,
                    avatar_url: context.JK.resolveAvatarUrl(val.photo_url),
                    text: val.formatted_msg,
                    date: context.JK.formatDate(val.created_at)
                });

                $('#sidebar-notification-list').append(notificationHtml);

                initializeActions(val, val.description);
            });
        }

        function initializeActions(notification, type) {
            // wire up "x" button to delete notification
            $('li[notification-id=' + notification.notification_id + ']').find('#img-delete-notification').click(deleteNotificationHandler);

            if (type === context.JK.MessageType.FRIEND_REQUEST) {
                var $action_btn = $('li[notification-id=' + notification.notification_id + ']').find('#btn-notification-action');
                $action_btn.text('ACCEPT');
                $action_btn.click(function() {
                    acceptFriendRequest({ "friend_request_id": notification.friend_request_id, "notification_id": notification.notification_id });
                });
            }
            else if (type === context.JK.MessageType.FRIEND_REQUEST_ACCEPTED) {
                $('li[notification-id=' + notification.notification_id + ']').find('#div-actions').hide();
            }
        }

        function deleteNotificationHandler(evt) {
            evt.stopPropagation();
            var notificationId = $(this).attr('notification-id');
            deleteNotification(notificationId);   
        }

        function deleteNotification(notificationId) {
            var url = "/api/users/" + context.JK.currentUserId + "/notifications/" + notificationId;
            $.ajax({
                type: "DELETE",
                dataType: "json",
                contentType: 'application/json',
                url: url,
                processData: false,
                success: function(response) {
                    delete notifications[notificationId];
                    $('li[notification-id=' + notificationId + ']').hide();
                    decrementNotificationCount();
                },
                error: app.ajaxError
            });
        }

        function initializeChatPanel() {
        }

        function search(query) {

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

        function onSearchSuccess(response) {

            // TODO: generalize this for each search result type (band, musician, recordings, et. al.)
            $.each(response.musicians, function(index, val) {
                // fill in template for Connect pre-click
                var template = $('#template-sidebar-search-result').html();
                var searchResultHtml = context.JK.fillTemplate(template, {
                    userId: val.id, 
                    avatar_url: context.JK.resolveAvatarUrl(val.photo_url),
                    profile_url: "/#/profile/" + val.id,
                    userName: val.name,
                    location: val.location
                });

                $('#sidebar-search-results').append(searchResultHtml);

                // fill in template for Connect post-click
                template = $('#template-sidebar-invitation-sent').html();
                var invitationSentHtml = context.JK.fillTemplate(template, {
                    userId: val.id,
                    first_name: val.first_name,
                    profile_url: "/#/profile/" + val.id
                });

                $('#sidebar-search-results').append(invitationSentHtml);

                // initialize visibility of the divs
                $('div[layout=sidebar] div[user-id=' + val.id + '].sidebar-search-connected').hide();
                $('div[layout=sidebar] div[user-id=' + val.id + '].sidebar-search-result').show();

                // wire up button click handler if search result is not a friend or the current user
                if (!val.is_friend && val.id !== context.JK.currentUserId) {
                    $('div[layout=sidebar] div[user-id=' + val.id + ']').find('.btn-connect-friend').click(sendFriendRequest);
                }
                // hide the button if the search result is already a friend
                else {
                    $('div[layout=sidebar] div[user-id=' + val.id + ']').find('.btn-connect-friend').hide();
                }
            });

            // show header
            $('#sidebar-search-header').show();

            // hide panels
            $('[layout-panel="contents"]').hide();
            $('[layout-panel="contents"]').css({"height": "1px"});

            // resize search results area
            $('#sidebar-search-results').height(getHeight() + 'px');
        }

        function getHeight() {
            // TODO: refactor this - copied from layout.js
            var sidebarHeight = $(context).height() - 75 - 2 * 60 + $('[layout-sidebar-expander]').height();
            var combinedHeaderHeight = $('[layout-panel="contents"]').length * 36;
            var searchHeight = $('.sidebar .search').first().height();
            var expanderHeight = $('[layout-sidebar-expander]').height();
            var expandedPanelHeight = sidebarHeight - (combinedHeaderHeight + expanderHeight + searchHeight);
            return expandedPanelHeight;
        }

        function showFriendsPanel() {

            var $expandedPanelContents = $('[layout-id="panelFriends"] [layout-panel="contents"]');
            var expandedPanelHeight = getHeight();

            // hide all other contents
            $('[layout-panel="contents"]').hide();
            $('[layout-panel="contents"]').css({"height": "1px"});

            // show the appropriate contens
            $expandedPanelContents.show();
            $expandedPanelContents.animate({"height": expandedPanelHeight + "px"}, 400);
        }

        function friendRequestCallback(userId) {
            // toggle the pre-click and post-click divs
            $('div[layout=sidebar] div[user-id=' + userId + '].sidebar-search-connected').show();
            $('div[layout=sidebar] div[user-id=' + userId + '].sidebar-search-result').hide();
        }

        function sendFriendRequest(evt) {
            evt.stopPropagation();
            var userId = $(this).parent().attr('user-id');
            context.JK.sendFriendRequest(app, userId, friendRequestCallback);
        }

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

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

        function incrementNotificationCount() {
            var count = parseInt($('#sidebar-notification-count').html());
            $('#sidebar-notification-count').html(count + 1);
        }

        function decrementNotificationCount() {
            var count = parseInt($('#sidebar-notification-count').html());
            $('#sidebar-notification-count').html(count - 1);
        }

        function acceptFriendRequest(args) {

            rest.acceptFriendRequest({
                status : 'accept',
                friend_request_id : args.friend_request_id
            }).done(function(response) {
                    deleteNotification(args.notification_id);  // delete notification corresponding to this friend request
                    initializeFriendsPanel();  // refresh friends panel when request is accepted
            }).error(app.ajaxError);
        }

        // default handler for incoming notification
        function handleNotification(payload, type) {
            // update notifications panel in sidebar
            notifications[payload.notification_id] = {
                "id": payload.notification_id,
                "photo_url": payload.photo_url,
                "formatted_msg": payload.msg,
                "created_at": context.JK.formatDate(payload.created_at)
            };

            incrementNotificationCount();

            var template = $("#template-notification-panel").html();
            var notificationHtml = context.JK.fillTemplate(template, {
                notificationId: payload.notification_id,
                avatar_url: context.JK.resolveAvatarUrl(payload.photo_url),
                text: payload.msg,
                date: context.JK.formatDate(payload.created_at)
            });

            $('#sidebar-notification-list').prepend(notificationHtml);

            initializeActions(payload, type);
        }

        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 events() {
            $('#search-input').keyup(function(evt) {
                delay(function() {
                    // ENTER KEY
                    if (evt.which === 13) {
                        return hideSearchResults();
                    }

                    // ESCAPE KEY
                    if (evt.which === 27) {
                        return hideSearchResults();
                    }

                    var query = $('#search-input').val();
                    logger.debug("query=" + query);

                    if (query === '') {
                        return hideSearchResults();
                    }

                    if (query.length > 2) {
                        emptySearchResults();
                        search(query);
                    }
                }, 1000);
            });

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

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

            // $('#sidebar-div').mouseleave(function(evt) {
            //     hideSearchResults();
            // });

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

                // update friends panel in sidebar
                friends[payload.user_id].online = payload.online;
                updateFriendList(friends);

                // display notification
                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)
                });
            });
            //////////////////////////////////////////////////////////////

            // wire up FRIEND_REQUEST handler
            context.JK.JamServer.registerMessageCallback(context.JK.MessageType.FRIEND_REQUEST, function(header, payload) {
                logger.debug("Handling FRIEND_REQUEST msg " + JSON.stringify(payload));

                handleNotification(payload, header.type);

                // display notification
                app.notify({
                  "title": "New Friend Request",
                  "text": payload.msg,
                  "icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
                  },
                  {
                    "ok_text": "ACCEPT",
                    "ok_callback": acceptFriendRequest,
                    "ok_callback_args": { "friend_request_id": payload.friend_request_id, "notification_id": payload.notification_id }
                  }
                );
            });
            //////////////////////////////////////////////////////////////

            // wire up FRIEND_REQUEST_ACCEPTED handler
            context.JK.JamServer.registerMessageCallback(context.JK.MessageType.FRIEND_REQUEST_ACCEPTED, function(header, payload) {
                logger.debug("Handling FRIEND_REQUEST_ACCEPTED msg " + JSON.stringify(payload));

                handleNotification(payload, header.type);

                // refresh friends panel
                initializeFriendsPanel();

                // display notification
                app.notify({
                  "title": "Friend Request Accepted",
                  "text": payload.msg,
                  "icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
                });
            });
            //////////////////////////////////////////////////////////////

            // wire up MUSICIAN_SESSION_JOIN handler
            context.JK.JamServer.registerMessageCallback(context.JK.MessageType.MUSICIAN_SESSION_JOIN, function(header, payload) {
                logger.debug("Handling MUSICIAN_SESSION_JOIN msg " + JSON.stringify(payload));

                // display notification
                app.notify({
                  "title": "Musician Joined Session",
                  "text": payload.username + " has joined the session.",
                  "icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
                });
            });
            //////////////////////////////////////////////////////////////

            // wire up MUSICIAN_SESSION_DEPART handler
            context.JK.JamServer.registerMessageCallback(context.JK.MessageType.MUSICIAN_SESSION_DEPART, function(header, payload) {
                logger.debug("Handling MUSICIAN_SESSION_DEPART msg " + JSON.stringify(payload));

                // display notification
                app.notify({
                  "title": "Musician Left Session",
                  "text": payload.username + " has left the session.",
                  "icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
                });
            });
            //////////////////////////////////////////////////////////////

            // wire up MUSICIAN_SESSION_DEPART handler
            context.JK.JamServer.registerMessageCallback(context.JK.MessageType.FRIEND_SESSION_JOIN, function(header, payload) {
                logger.debug("Handling FRIEND_SESSION_JOIN msg " + JSON.stringify(payload));

                // display notification
                app.notify({
                  "title": "Friend Joined Session",
                  "text": payload.username + " has joined a session.",
                  "icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
                });
            });
            //////////////////////////////////////////////////////////////
        }

        this.initialize = function() {
            events();
            initializeFriendsPanel();
            initializeChatPanel();
            initializeNotificationsPanel();
        };
    };
})(window,jQuery);