var Views = {
    Reviews: {},
    AddReviews: []
};
Views.Review = function (container, collection) {
    this.container = container;
    this.collection = collection;
    this.review = $('div.review', this.container);
    // Comments
    this.reaction = $('span.reaction', this.review);
    this.comments = $('div.comments', this.container);
    if (this.reaction.size() && this.comments.size()) {
        this.commentDummy = $('input.commentDummy', this.container);
        this.commentForm = $('form.commentForm', this.container);
        this.commentBody = $('textarea[name=body]', this.commentForm);
        this.commentSubmit = $('button', this.commentForm);
        // Set up comment events
        this.commentEvents();
    }
    // Editor
    this.editor = $('form.editReview', this.container);
    if (this.collection.size() && this.editor.size()) {
        this.fields = $('.hidden', this.container);
        this.ratingSelector = $('p.rating', this.editor);
        this.ratingInput = $('input[name=rating]', this.editor);
        this.reviewLoading = $('img.loading', this.review);
        this.editorLoading = $('p.submit img.loading', this.editor);
        // Set up events
        this.events();
        var review = this.getReview();
        Views.Reviews[review.data.guid] = this;
    }
};
Views.Review.classToRating = function (className) {
    var rating = null;
    switch (className) {
    case 'yes':
        rating = '2';
        break;
    case 'maybe':
        rating = '1';
        break;
    case 'no':
        rating = '0';
        break;
    }
    return rating;
};
Views.Review.createFromData = function (data, collection) {
    var container = $(data.review.html);
    return new Views.Review(container, collection);
};
Views.Review.prototype = {
    setRating: function (className) {
        var rating = Views.Review.classToRating(className);
        if (rating) {
            this.ratingInput.val(rating);
            $('a.rating', this.ratingSelector).removeClass('selected');
            $('a.rating:has(img.' + className + ')', this.ratingSelector).addClass('selected');
            this.startEditing();
        }
        return this;
    },
    startEditing: function () {
        this.review.hide();
        this.fields.show();
        $('textarea', this.fields).focus();
        return this;
    },
    cancelEditing: function () {
        this.fields.hide();
        this.review.show();
        return this;
    },
    markAsDeleted: function (data) {
        this.reviewLoading.hide();
        this.container.addClass('deleted');
        return this;
    },
    markAsRestored: function (data) {
        this.reviewLoading.hide();
        this.container.removeClass('deleted');
        return this;
    },
    updateDom: function (data) {
        var newReview = Views.Review.createFromData(data, this.collection);
        this.container.replaceWith(newReview.container);
        var target = newReview.container;
        if (target.is('tr')) {
            target = $('td', target);
        }
        target.effect('highlight');
        return newReview;
    },
    addToDom: function () {
        var target = this.container;
        if (target.is('tr')) {
            target = $('td', target);
        }
        target.hide();
        this.collection.prepend(this.container);
        // TODO - reinstate Bleepie.highlight once you figure out buggy behaviour
        target.fadeIn('fast');
        return this;
    },
    getReview: function () {
        return Model.Review.newFromForm(this.editor);
    },
    getComment: function () {
        return Model.Comment.newFromForm(this.commentForm);
    },
    showCommentForm: function () {
        this.commentDummy.hide();
        this.commentForm.show();
        this.commentBody.focus();
    },
    hideCommentForm: function () {
        this.commentForm.hide();
        this.commentDummy.show();
    },
    commentEvents: function () {
        // Comments
        var self = this;
        this.commentSubmit.button('option', 'icons', {
            primary: 'ui-icon-comment'
        });
        this.commentDummy.focus(function (e) {
            self.showCommentForm();
        });
        this.commentBody.blur(function (e) {
            if (!$(this).val()) {
                self.hideCommentForm();
            }
        });
        
        this.reaction.delegate('a.comment', 'click', function (e) {
            if (Session.isLoggedIn) {
                self.showCommentForm();
            } else {
                Bleepie.showSignIn();
            }
            return false;
        });
        this.commentForm.submit(function (e) {
            e.preventDefault();
            self.commentSubmit.button('disable');
            var loading = $('img.loading', this);
            loading.show();
            var comment = self.getComment();
            comment.create(function (data) {
                self.commentBody.val('');
                self.hideCommentForm();
                var commentHtml = $(data.comment.html);
                $('ul.commentList', self.comments).append(commentHtml);
                commentHtml.effect('highlight');
                self.reaction.html(data.comment.reactionHtml);
                loading.hide();
                self.commentSubmit.button('enable');
            }, function () {
                loading.hide();
                self.commentSubmit.button('enable');
            });
        });
    },
    onFacebookPublishSuccess: function (post_id) {
        // TODO log the post id somewhere so we can keep these highlighted
        this.review.find('a.facebookPost').addClass('facebookPosted');
    },
    onFacebookPublishFailure: function (exception) {
        // This mostly happens if they've skipped the feed form
        // … assuming that auto_published posts never fail silently
        if (exception) {
            // exception never seems to be populated really, even when invalid session
            // TODO try again if publish call fails?
        } else {
            this.review.find('div.facebookNeverPrompt').show();
        }
    },
    facebookPublish: function (data) {
        if (!Session.facebook_id) {
            // Not a facebook user, abort
            return null;
        }
        var onFacebookPublishFailure = $.proxy(this.onFacebookPublishFailure, this);
        var onFacebookPublishSuccess = $.proxy(this.onFacebookPublishSuccess, this);
        var post = data.facebookPost;
        Bleepie.getUserSetting('facebook_publish_stream', function onSuccess (setting, facebook_publish_stream) {
            switch (facebook_publish_stream) {
            case 'never':
                // They've explicitly chosen not to publish to their stream
                return false;
                break;
            case 'yes':
                // Double check the auto publish permission is still granted
                Bleepie.checkFacebookPermission('publish_stream', function onPermissionCheck (connected, granted, prompted) {
                    if (granted) {
                        // Yep still granted, publish away
                        Bleepie.facebookStreamPublish(post, true, onFacebookPublishSuccess);
                    } else if (prompted) {
                        // They've revoked it, fallback to feed form behaviour
                        Bleepie.setUserSetting('facebook_publish_stream', 'prompt', function onSuccess (setting, value) {
                            Bleepie.facebookStreamPublish(post, false, onFacebookPublishSuccess, onFacebookPublishFailure);
                        });
                    } else {
                        // Not connected, do nothing
                    }
                });
                break;
            case 'prompt':
            default:
                // They've chosen to be prompted or haven't decided on feed publishing yet, show a feed form
                Bleepie.facebookStreamPublish(post, false, onFacebookPublishSuccess, onFacebookPublishFailure);
            }
        });
    },
    events: function () {
        var self = this;
        this.ratingSelector.delegate('a.rating', 'click', function (e) {
            self.setRating($(this).find('img').attr('className'));
            return false;
        });
        this.review.delegate('a.edit', 'click', function (e) {
            self.startEditing();
            return false;
        });
        this.review.delegate('a.delete', 'click', function (e) {
            var review = self.getReview();
            self.reviewLoading.show();
            review.remove(function (data) {
                self.markAsDeleted(data);
                _gaq.push(['_trackEvent', 'Review', 'Remove', data.deleted.slug, data.deleted.score]);
            }, function () {
                // TODO error display
                self.reviewLoading.hide();
            });
            return false;
        });
        this.review.delegate('a.undo', 'click', function (e) {
            var review = self.getReview();
            self.reviewLoading.show();
            review.create(function (data) {
                self.markAsRestored(data);
                _gaq.push(['_trackEvent', 'Review', 'Restore', data.review.slug, data.review.score]);
            }, function () {
                // TODO error display
                self.reviewLoading.hide();
            });
            return false;
        });
        this.review.delegate('a.facebookPost', 'click', function (e) {
            var review = self.getReview();
            review.data = {
                id: review.data.id,
                type: review.data.type
            };
            self.reviewLoading.show();
            review.get(function (data) {
                self.reviewLoading.hide();
                Bleepie.facebookStreamPublish(data.facebookPost, false, $.proxy(self.onFacebookPublishSuccess, self));
            }, function () {
                // TODO error display
                self.reviewLoading.hide();
            });
            return false;
        });
        this.review.delegate('a.facebookNeverPromptLink', 'click', function (e) {
            var prompt = $(this);
            Bleepie.setUserSetting('facebook_publish_stream', 'never', function onSuccess (setting, value) {
                self.review.find('div.facebookNeverPrompt span.updated').show();
            });
            return false;
        });
        this.editor.delegate('a.cancel', 'click', function (e) {
            self.cancelEditing();
            return false;
        });
        this.editor.submit(function (e) {
            e.preventDefault();
            var review = self.getReview();
            self.editorLoading.show();
            review.update(function (data) {
                self.updateDom(data);
                _gaq.push(['_trackEvent', 'Review', 'Edit', data.review.slug, data.review.score]);
            }, function () {
                // TODO error display
                self.editorLoading.hide();
            });
        });
    }
};

Views.AddReview = function (collection, container, onCreate) {
    this.collection = collection;
    this.container = container;
    this.onCreate = onCreate;
    this.editor = $('form.addReview', this.container);
    if (this.collection.size() && this.editor.size()) {
        this.fields = $('.hidden', this.editor);
        this.ratingSelector = $('p.rating', this.editor);
        this.ratingInput = $('input[name=rating]', this.editor);
        this.editorLoading = $('p.submit img.loading', this.editor);
        // Setup
        this.events();
        Views.AddReviews.push(this);
    }
};
Views.AddReview.prototype = {
    setRatingFromUrlParam: function () {
        var self = this;
        var urlParts = window.location.search.replace(/^\??/, '').split('&');
        var kv;
        $.each(urlParts, function (i, part) {
            kv = (part.split('='));
            if (kv[0] == 'rating') {
                self.setRating(kv[1]);
            }
        });
    },
    setRating: function (className) {
        var rating = Views.Review.classToRating(className);
        if (rating) {
            this.ratingInput.val(rating);
            $('a.rating', this.ratingSelector).removeClass('selected');
            $('a.rating:has(img.' + className + ')', this.ratingSelector).addClass('selected');
            this.start();
        }
        return this;
    },
    start: function () {
        var editor = this.editor;
        if (this.fields.size()) {
            this.fields.fadeIn('fast', function () {
                $('textarea', editor).focus();
            });
        } else {
            $('textarea', editor).focus();
        }
        return this;
    },
    cancel: function () {
        this.fields.fadeOut('fast');
        this.setRating();
        return this;
    },
    promptRating: function () {
        $('.ratingRequired', this.editor).fadeIn('fast');
        return this;
    },
    afterCreate: function (data) {
        var self = this;
        // You know what you doing?
        if (data.review.freebase_guid == '9202a8c04000641f800000000005e239') {
            $.fancybox('/images/cats.gif', {
                'type'          : 'image',
                'padding'       : 5,
                'transitionIn'  : 'elastic',
                'transitionOut' : 'elastic',
                'easingIn'      : 'easeInOutBack',
                'easingOut'     : 'easeInOutBack'
            });
            _gaq.push(['_trackEvent', 'Easter Egg', 'Cats']);
        }
        var review;
        if (this.onCreate) {
            review = this.onCreate.call(this, data);
        } else {
            review = Views.Reviews[data.review.freebase_guid];
            if (data.created) {
                review = Views.Review.createFromData(data, this.collection);
                this.editor.slideUp('fast', function () {
                    review.addToDom();
                });
            }
        }
        // Facebook stream publish
        review.facebookPublish(data);
        // Track events
        if (data.created) {
            _gaq.push(['_trackEvent', 'Review', 'Create', data.review.slug, data.review.score]);
        } else {
            _gaq.push(['_trackEvent', 'Review', 'CreateEdit', data.review.slug, data.review.score]);
        }
        return this;
    },
    getReview: function () {
        return Model.Review.newFromForm(this.editor);
    },
    events: function () {
        var self = this;
        $(document).ready(function (e) {
            self.setRatingFromUrlParam();
        });
        this.ratingSelector.delegate('a.rating', 'click', function (e) {
            self.setRating($(this).find('img').attr('className'));
            return false;
        });
        this.editor.delegate('a.cancel', 'click', function (e) {
            self.cancel();
            return false;
        });
        this.editor.submit(function (e) {
            e.preventDefault();
            var review = self.getReview();
            if (!review.data.rating) {
                self.promptRating();
            } else {
                self.editorLoading.show();
                review.create(function (data) {
                    self.editorLoading.hide();
                    self.afterCreate(data);
                }, function () {
                    // TODO error display
                    self.editorLoading.hide();
                });
            }
        });
    }
};
Views.IgnoredGame = function (container) {
    this.container = container;
    this.linkContainer = $('.ignoreGame', this.container);
    if (this.linkContainer.size()) {
        this.ignoredGame = new Model.IgnoredGame({
            game: container.attr('id').substr(1)
        });
        this.loading = $('img.loading', this.linkContainer);
        // Setup
        this.events();
    }
};
Views.IgnoredGame.prototype = {
    events: function () {
        var self = this;
        this.linkContainer.delegate('a.ignore', 'click', function (e) {
            self.loading.show();
            self.ignoredGame.create(function (data) {
                self.loading.hide();
                if (data.ignored) {
                    self.container.addClass('ignored');
                    _gaq.push(['_trackEvent', 'Ignored Game', 'Create', data.game.slug]);
                }
            }, function () {
                self.loading.hide();
                // TODO error display
            });
            return false;
        });
        this.linkContainer.delegate('a.unignore', 'click', function (e) {
            self.loading.show();
            self.ignoredGame.remove(function (data) {
                self.loading.hide();
                if (data.unignored) {
                    self.container.removeClass('ignored');
                    _gaq.push(['_trackEvent', 'Ignored Game', 'Remove', data.game.slug]);
                }
            }, function () {
                self.loading.hide();
                // TODO error display
            });
            return false;
        });
    }
};
Views.Follower = function (container) {
    this.container = container;
    this.linkContainer = $('.followFriend', this.container);
    this.actionContainer = $('.following', this.linkContainer);
    if (this.linkContainer.size() && this.actionContainer.size()) {
        this.follower = new Model.Follower({
            id: this.container.attr('id').substr(1)
        });
        this.loading = $('img.loading', this.linkContainer);
        // Setup
        this.events();
    }
};
Views.Follower.prototype = {
    events: function () {
        var self = this;
        this.linkContainer.delegate('a.addFriend', 'click', function (e) {
            self.loading.show();
            self.follower.create(function (data) {
                self.loading.hide();
                self.actionContainer.html(data.html).effect('highlight');
                self.container.addClass('friend');
                _gaq.push(['_trackEvent', 'Social', 'Follow', Session.name]);
            }, function () {
                self.loading.hide();
                // TODO error display
            });
            return false;
        });
        this.linkContainer.delegate('a.removeFriend', 'click', function (e) {
            self.loading.show();
            self.follower.remove(function (data) {
                self.loading.hide();
                self.actionContainer.html(data.html).effect('highlight');
                self.container.removeClass('friend');
                _gaq.push(['_trackEvent', 'Social', 'Unfollow', Session.name]);
            }, function () {
                self.loading.hide();
                // TODO error display
            });
            return false;
        });
    }
};
Views.SuggestedFriend = function (container) {
    this.container = container;
    this.linkContainer = $('.suggestedFriend', this.container);
    if (this.linkContainer.size()) {
        this.suggestedFriend = new Model.SuggestedFriend({
            person: this.container.attr('id').substr(1)
        });
        this.loading = $('img.loading', this.linkContainer);
        // Setup
        this.events();
    }
};
Views.SuggestedFriend.prototype = {
    events: function () {
        var self = this;
        this.linkContainer.delegate('a.unignore', 'click', function (e) {
            self.loading.show();
            self.suggestedFriend.create(function (data) {
                self.loading.hide();
                if (data.unfiltered) {
                    self.container.addClass('suggested');
                    _gaq.push(['_trackEvent', 'Suggested Friend', 'Create', data.unfiltered]);
                }
            }, function () {
                self.loading.hide();
                // TODO error display
            });
            return false;
        });
        this.linkContainer.delegate('a.ignore', 'click', function (e) {
            self.loading.show();
            self.suggestedFriend.remove(function (data) {
                self.loading.hide();
                if (data.filtered) {
                    self.container.removeClass('suggested');
                    _gaq.push(['_trackEvent', 'Suggested Friend', 'Remove', data.filtered]);
                }
            }, function () {
                self.loading.hide();
                // TODO error display
            });
            return false;
        });
    }
};
Views.GameList = function (container) {
    this.container = container;
    this.linkContainer = $('.gameList', this.container);
    this.game = this.container.attr('id').substr(1);
    if (this.linkContainer.size()) {
        // Setup
        this.events();
    }
};
Views.GameList.prototype = {
    events: function () {
        var self = this;
        this.linkContainer.delegate('a.addToGameList', 'click', function (e) {
            var addLink = $(this);
            if (Session.isLoggedIn) {
                var offset = addLink.offset();
                Bleepie.showDialog({
                    id: 'gameList',
                    css: offset,
                    afterShow: function () {
                        _gaq.push(['_trackEvent', 'Lists', 'Open add dialog', Session.name]);
                        $('#addToGameListGame').val(self.game);
                        if (!$('#addToGameListTitle').val()) {
                            $('#addToGameListTitle').val('Untitled');
                        }
                        $('#addToGameListForm').submit(function (e) {
                            Bleepie.addToList(addLink);
                            return false;
                        });
                    },
                    afterHide: function () {
                        $('#addToGameListForm').unbind('submit');
                    }
                });
            } else {
                Bleepie.showSignIn();
            }
            return false;
        });
    }
};
