$("button, input[type=button]").button();
Avatars.cached = {};
Avatars.fetching = {};
Avatars.munchQueue = function () {
    var image;
    for (var personUrl in Avatars.errors) {
        image = Avatars.errors[personUrl].pop();
        if (!image) {
            // Nothing more to munch
            break;
        }
        Avatars.onError.call(image, personUrl);
    }
};
Avatars.setImage = function (image, personUrl) {
    // Update image source and mark as done
    $(image).attr('src', Avatars.cached[personUrl]).data('avatar.fixed', true);
    Avatars.munchQueue();
};
Avatars.onError = function (personUrl) {
    var image = this;
    if ($(image).data('avatar.fixed')) {
        // Already done
        return;
    }
    if (Avatars.cached[personUrl]) {
        // Cached
        Avatars.setImage(image, personUrl);
        return;
    }
    if (Avatars.fetching[personUrl]) {
        // Already fetching, enqueue
        Avatars.queueError.call(image, personUrl);
        return;
    }
    // Fetch the new avatar from Twitter
    Avatars.fetching[personUrl] = true;
    $.ajax({
        url: personUrl,
        type: 'post',
        dataType: 'json',
        data: {
            checkAvatar: 1
        },
        success: function success (data, textStatus) {
            if (!data.error && data.avatar) {
                // Fetched hurrah!
                Avatars.cached[personUrl] = data.avatar;
                Avatars.fetching[personUrl] = false;
                Avatars.setImage(image, personUrl);
            }
        }
    });
};
Avatars.munchQueue();

Bleepie = {
    getUserSetting: function (key, onSuccess, onError) {
        $.ajax({
            url: '/settings',
            type: 'GET',
            dataType: 'json',
            data: {
                key: key
            },
            success: function success (data, textStatus) {
                Settings[data.key] = data.value;
                if (onSuccess) {
                    onSuccess(data.key, data.value);
                }
            },
            error: function error () {
                if (onError) {
                    onError();
                }
            }
        });
    },
    setUserSetting: function (key, value, onSuccess, onError) {
        $.ajax({
            url: '/settings',
            type: 'POST',
            dataType: 'json',
            data: {
                accessToken: Session.accessToken,
                setting: JSON.stringify({
                    key: key,
                    value: value
                })
            },
            success: function success (data, textStatus) {
                Settings[data.key] = data.value;
                if (onSuccess) {
                    onSuccess(data.key, data.value);
                }
            },
            error: function error () {
                if (onError) {
                    onError();
                }
            }
        });
    },
    autocomplete: function (input, onSelect) {
        $(input).addClass('autocomplete');
        $(input).suggest({
            type_strict: 'all',
            // soft: true,
            flyout: true,
            type:'/cvg/computer_videogame',
            suggest_new: 'Add a new game'
        })
        .bind("fb-select", function (e, data) {
            onSelect(data);
        })
        .bind("fb-select-new", function (e, data) {
            $('#newGameName').val(data);
            Bleepie.showDialog({
                'id': 'newGame',
                'afterShow': function afterShow () {
                    $('#newGameName').focus();
                    $('#newGameForm').submit(function (e) {
                        $('#newGameLoading').show();
                        var game = Model.Game.newFromForm(this);
                        game.create(function success (data) {
                            $('#newGameError').hide();
                            $('#newGameLoading').hide();
                            $(document).click();
                            onSelect(data);
                        }, function failure () {
                            $('#newGameLoading').hide();
                            $('#newGameError').show();
                        });
                        return false;
                    });
                },
                'afterHide': function afterHide () {
                    $('#newGameForm').unbind('submit');
                    $('#newGameName').val('');
                    $('#newGameDateData').val('');
                }
            });
        })
        .focus(function (e) {
            $(this).select();
        });
    },
    // callback is a function that takes two arguments
    // 1. connected (whether the user has a facebook connect session
    // 2. granted (whether the user granted the permission)
    // 3. prompted (whether the user was shown a prompt)
    checkFacebookPermission: function (permission, callback, recursed) {
        if (Session.facebook_id) {
            FB.Connect.requireSession(function onConnect () {
                // http://wiki.developers.facebook.com/index.php/Users.hasAppPermission
                FB.Facebook.apiClient.users_hasAppPermission(permission, function onPermissionCheck (perm, response) {
                    if (perm === null || (response instanceof Error && (response.userData == 102 || response.userData.error_code == 102))) {
                        // Session error, refresh session and wait for facebook.notconnected before trying once more
                        FB.Connect.forceSessionRefresh();
                        if (!recursed) {
                            $(document).bind('facebook.notconnected', function onSessionRefresh (e) {
                                // Unbind the handler immediately, this event can fire again later
                                $(this).unbind(e);
                                Bleepie.checkFacebookPermission(permission, callback, true);
                            });
                        }
                    } else if (perm) {
                        // Permission already granted, carry on
                        callback(true, true, false);
                    } else {
                        // No permission yet, prompt for it
                        FB.Connect.showPermissionDialog(permission, function onPermissionPrompt (perm) {
                            // perm is a comma separated string listing allowed permissions.
                            // indexof might not be safe if permissions can be substrings of each other
                            // TODO split and loop through instead
                            var granted = perm.indexOf(permission) !== -1;
                            callback(true, granted, true);
                        });
                    }
                });
            }, function onCancelConnect () {
                // Cancelled connect, carry on
                callback(false, false, false);
            });
        } else {
            // No facebook_id in session, carry on
            callback(false, false, false);
        }
    },
    facebookStreamPublish: function (post, auto_publish, onSuccess, onFailure) {
        // http://developers.facebook.com/docs/?u=facebook.jslib.FB.Connect.streamPublish
        FB.Connect.streamPublish(
            post.message,
            post.attachment,
            post.action_links,
            null, // target_id
            'Game review', // user_message_prompt
            function callback (post_id, exception) {
                if (post_id && post_id !== 'null') {
                    // Successfully published
                    if (!Settings.facebook_publish_stream) {
                        // No decision made yet, prompt for automatic publishing permission
                        Bleepie.checkFacebookPermission('publish_stream', function onPermissionCheck (connected, granted, prompted) {
                            if (prompted) {
                                // If they got this far and revoked the permission then don't disable stream posting,
                                // just revert it to feed form behaviour
                                var setting = granted ? 'yes' : 'prompt';
                                Bleepie.setUserSetting('facebook_publish_stream', setting);
                            }
                        });
                    }
                    if (onSuccess) {
                        onSuccess(post_id);
                    }
                } else {
                    // This can also happen if the Facebook session expired. Force a refresh for next time
                    // so they get a session prompt.
                    FB.Connect.forceSessionRefresh();
                    if (onFailure) {
                        onFailure(exception);
                    }
                }
            },
            auto_publish
        );
    },
    more: function (linkContainer, trackingLabel, identifier, onLoad) {
        // Load from more button
        $('a', linkContainer).click(function (e) {
            e.preventDefault();
            loadCursor($(this).attr('href'), function (data) {
                _gaq.push(['_trackEvent', 'Paginate', trackingLabel, Session.name]);
            });
        });
        // Load from hash
        var regex = new RegExp('^#?' + identifier + '(\\d+)');
        var matches = window.location.hash.match(regex);
        if (matches) {
            var cursor = (matches[1] - 0) + 1;
            loadCursor('?' + $.param({
                cursor: cursor
            }));
        }
        // Load cursor from a querystring e.g. ?cursor=138&lastCursor=158
        function loadCursor(querystring, onSuccess) {
            $.ajax({
                url: querystring,
                type: 'GET',
                dataType: 'json',
                data: {
                    more: 1
                },
                success: function success(data, textStatus) {
                    if (data.count) {
                        onLoad(data);
                        window.location.hash = '';
                        window.location.hash = identifier + data.first;
                    }
                    if (!data.count || data.count != data.limit) {
                        $(linkContainer).fadeOut('fast');
                    } else {
                        $('a', linkContainer).attr('href', '?' + $.param({
                            lastCursor: data.lastCursor,
                            cursor: data.cursor
                        }));
                    }
                    if (onSuccess) {
                        onSuccess(data);
                    }
                }
            });
        }
    },
    showDialog: function (options) {
        options = options || {};
        var fullId = '#' + options['id'] + 'Dialog';
        var dialog = $(fullId);
        if (options.css) {
            dialog.css(options.css);
        }
        var mask = dialog.prev('.modalMask');
        mask.fadeIn('fast');
        dialog.fadeIn('fast', options.afterShow);
        var keyHandler = function(e) {
            if (e.keyCode == 27) { // ESC
                mask.fadeOut('fast');
                dialog.fadeOut('fast', options.afterHide);
                $(this).unbind(e);
                $(document).unbind('click', clickHandler);
            }
        };
        var clickHandler = function (e) {
            var target = $(e.target);
            if (!target.is(fullId) && !target.parents(fullId).size()) {
                mask.fadeOut('fast');
                dialog.fadeOut('fast', options.afterHide);
                $(this).unbind(e);
                $(window).unbind('keydown', keyHandler);
            }
        };
        $(window).keydown(keyHandler);
        $(document).click(clickHandler);
    },
    addToList: function (addLink) {
        var gameListItem = Model.GameListItem.newFromForm('#addToGameListForm');
        gameListItem.create(function (data) {
            _gaq.push(['_trackEvent', 'Lists', 'Add from dialog', Session.name]);
            if (!$('#addToGameList-l' + data.list.id).size()) {
                var linkItem = $(data.list.html);
                $('#addToGameListLists').prepend(linkItem);
                linkItem.effect('highlight');
            }
            $('#addToGameListId').val(0);
            $('#addToGameListTitle').hide().val('');
            $('#addToGameListSubmit').hide();
            var gameLink = $('<a>')
                .attr('href', data.list.url)
                .attr('title', data.list.title)
                .text('added to list')
                .wrapInner('<strong>');
            // Update the add link
            gameLink.insertAfter(addLink);
            addLink.hide();
            setTimeout(function () {
                $(document).click();
            }, 1000);
        }, function () {
            // TODO error display
        });
    },
    showSignIn: function () {
        Bleepie.showDialog({
            'id': 'signin',
            'afterShow': function afterShow () {
                $('#signinUsername').focus();
            }
        });
    },
    resetAddReview: function () {
        // Reset image
        $('a#chosenGame').attr('href', '#');
        $('a#chosenGame img').attr('src', Bleepie.buildFreebaseImage('empty'));
        // Reset form elements
        $('input#gameGuid').val('');
        $('input#gameName').val('');
        $('input#gameRateYes').attr('checked', true).removeAttr('checked');
        $('textarea#gameReviewBody').val('');
        // Focus input
        $("input#gameSearchInput").focus();
    },
    buildFreebaseImage: function (guid, width, height) {
        width = width || 48;
        height = height || 60;
        var imageUrl = 'http://www.freebase.com/api/trans/image_thumb/guid/' + guid + '?' + $.param({
            maxwidth: width,
            maxheight: height,
            mode: 'fillcropmid'
        });
        return imageUrl;
    },
    serializeForm: function (formElements) {
        var params = {};
        $.each($(formElements).serializeArray(), function (i, item) {
            params[item.name] = item.value;
        });
        return params;
    },
    // Cookie helpers
    setCookie: function (name, value, days) {
        var expires;
        if (days) {
            var date = new Date();
            date.setTime(date.getTime() + (days*24*60*60*1000));
            expires = "; expires=" + date.toGMTString();
        } else {
            expires = "";
        }
        document.cookie = name + "=" + value + expires + "; path=/";
    },
    getCookie: function (name) {
        var namekey = name + "=";
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length;i++) {
            var c = cookies[i];
            while (c.charAt(0) == ' ') {
                c = c.substring(1, c.length);
            }
            if (c.indexOf(namekey) === 0) {
                return c.substring(namekey.length, c.length);
            }
        }
        return null;
    },
    deleteCookie: function (name) {
        Bleepie.setCookie(name, "", -1);
    }
};

// Load Amazon offers on game and review pages
if ($('#amazonOffers').size()) {
    $.ajax({
        url: Page.gameUrl,
        type: 'GET',
        dataType: 'json',
        data: {
            amazon: true
        },
        success: function success(data, textStatus) {
            if (data.offers.length) {
                $('#amazonOffers')
                    .hide()
                    .html(data.html)
                    .fadeIn('fast');
            } else {
                $('#amazonOffers').hide();
            }
            $('#amazonButton').fadeIn('fast');
        },
        error: function error() {
            $('#amazonOffers').hide();
            $('#amazonButton').fadeIn('fast');
        }
    });
}

(function () {
    // Add review form
    new Views.AddReview($('tbody.addTarget'), null, function (data) {
        $('div#reviews').fadeIn('fast');
        var review = Views.Reviews[data.review.freebase_guid];
        if (!data.created && review) {
            review.updateDom(data).startEditing();
        } else {
            review = Views.Review.createFromData(data, this.collection);
            review.addToDom();
            if (data.created) {
                this.editor.slideUp('fast', function () {
                    Bleepie.resetAddReview();
                });
            } else {
                review.startEditing();
            }
        }
        return review;
    });
    // Rankings/recs
    $.each($('ol.rankings li.ranking'), function (i, ranking) {
        var reviews = $('ol.reviews', $(ranking));
        $.each($('li.review', reviews), function (i, review) {
            new Views.Review($(review), reviews);
        });
        new Views.AddReview(reviews, $(ranking));
        new Views.IgnoredGame($(ranking));
        new Views.GameList($(ranking));
    });
    // Add to game list
    $('#addToGameListCreate').click(function (e) {
        $('#addToGameListTitle').show().focus().select();
        $('#addToGameListSubmit').show();
        return false;
    });
    $('#addToGameListLists').delegate('a.addToGameListList', 'click', function (e) {
        var listId = $(this).attr('id');
        $('#addToGameListId').val(listId.replace('addToGameList-l', ''));
        $('#addToGameListForm').submit();
        return false;
    });
    // Ignored games
    $.each($('ul.ignored li'), function (i, ignored) {
        new Views.IgnoredGame($(ignored));
    });
    // Suggested friends
    $.each($('ul.suggested li'), function (i, suggested) {
        new Views.SuggestedFriend($(suggested));
    });
    // Follow actions
    $.each($('ul.suggested li, table.userInfo'), function (i, follower) {
        new Views.Follower($(follower));
    });
    // Reviews and friend reviews
    $.each($('table.reviews tbody, table.friendreviews tbody'), function (i, tbody) {
        $.each($('tr', tbody), function (i, review) {
            if ($(review).hasClass('new')) {
                new Views.AddReview($(tbody), $(review), function (data) {
                    var review = Views.Reviews[data.review.freebase_guid];
                    if (data.created) {
                        var container = $(data.review.html);
                        review = new Views.Review(container, this.collection);
                        this.container.slideUp('fast', function () {
                            review.addToDom();
                        });
                    }
                    return review;
                });
            } else {
                new Views.Review($(review), $(tbody));
            }
        });
    });
    // Review page
    new Views.Review($('.singleReview'), $('.gameReview'));
    // Resend email confirmation
    $('#resend').click(function (e) {
        e.preventDefault();
        $('form#resendForm').slideDown('fast');
    });
    // Signin links
    $('a.signin').click(function (e) {
        Bleepie.showSignIn();
        return false;
    });
    // Facebook connect
    $('a.facebookSignin').click(function (e) {
        e.preventDefault();
        var self = this;
        FB.Connect.requireSession(function () {
            window.location = $(self).attr('href');
        });
    });
    // Reset account link
    $('#resetFormLink').click(function (e) {
        e.preventDefault();
        $('#signinForgottenUsername').val($('#signinUsername').val());
        $('#resetForm').slideDown('fast', function () {
            $('#signinForgottenUsername').focus();
        });
    });
    // Add game form
    $('#newGameDate').suggestdate().bind("fb-select", function (e, data) {
        $('#newGameDateData').val(data.value);
    });
    // Initialise Facebook Connect
    try {
        FB.init(Session.FacebookKey, '/xd_receiver.html', {
            // debugLogLevel: 5,
            ifUserConnected: function (uid) {
                $(document).trigger('facebook.connected', [uid]);
            },
            ifUserNotConnected: function (uid) {
                $(document).trigger('facebook.notconnected', [uid]);
            }
        });
    } catch (e) {
        // pass
    }
})();
// Doesn't mean we're not smart
(function () {
    var code = "38,38,40,40,37,39,37,39,66,65";
    var kkeys = [];
    $(window).keydown(function(e) {
        kkeys.push(e.keyCode);
        if (kkeys.toString().indexOf(code) > -1) {
            $(window).unbind('keydown', arguments.callee);
            _gaq.push(['_trackEvent', 'Easter Egg', 'Konami']);
            window.location = "/freebase/9202a8c04000641f8000000000276013";
        }
    });
})();

$('body').removeClass('loading');
