if (
    $('topic') && $('topic').get('id') == 'topic' ||
    $(document.body).hasClass('home')
) {
    var Topic = new Class({
        Implements: [Options, Events],

        options: {
            degree: [0, 0],
            commented: false,
            elements: {
                bar: null,
                plus: null,
                minus: null,
                status: null
            },
            fx: {
                unit: '%',
                duration: 'short',
                transition: Fx.Transitions.Cubic.easeIn,
                link: 'cancel'
            },
            onExpress: $empty,
            onSuccess: $empty
        },

        prefers: ['plus', 'minus'],

        initialize: function(context, options) {
            this.context = context;
            this.setOptions(options);
            this.expressed = null;
            this.degree = this.options.degree;

            this.prefers.each(function(prefer) {
                var el = $(this.options.elements[prefer]);
                this.options.elements[prefer] = el;

                if (el.get('tag') == 'a') {
                    el.addEvent('click', (function(e) {
                        if (e) (new Event(e)).stop();
                        this[this.expressed == prefer ? 'cancel' : prefer]();
                    }).bind(this));
                } else if (el.get('tag') == 'input') {
                    el.addEvent('click', (function(e) {
                        if (e) (new Event(e)).stop();
                        if (!this.context) return false;
                        this.submit(prefer);
                    }).bind(this));
                }

                if (el.hasClass('selected')) {
                    this.expressed = prefer;
                }
            }, this);

            if (this.options.elements.bar) {
                this.options.elements.bar = $(this.options.elements.bar);
                (function() {
                    var matches = this.get('class').match(/percent-([0-9]+)/);
                    this.setStyle('width', matches[1] + '%');
                    this.removeClass(matches[0]);
                }).run(null, this.options.elements.bar);

                this.fx = new Fx.Tween(
                    this.options.elements.bar,
                    this.options.fx
                );
            }
        },

        submit: function(prefer) {
            if (this.options.commented && !confirm(vlaah.lang['topic.9']))
                return;

            //alert([form.toQueryString(), action, method]);

            this.options.commented = false;
            this.onExpress(this.expressed == prefer ? 'cancel' : prefer);

            var expr = this.options.elements[prefer];
            var form = expr.getParent('form');
            var action = form.get('action');
            var method = form._method || form.get('method');

            var update_form = function(result, json) {
                var topic_base = vlaah.topic_base.replace(/\/$/, '');
                if (result.expressed) {
                    var other = form.getParent().getChildren('.express').filter(
                        function(el) { return el != form; }
                    );
                    var url = '{base}/{context}'.substitute({
                        base: topic_base,
                        context: window.encodeURIComponent(result.comment)
                    });
                    form.set('method', 'delete');
                    form._method = 'delete';
                    other.set({
                        action: form.get('action'),
                        method: 'post'
                    });
                    other._method = 'post';
                } else {
                    var url = '{base}/{context}'.substitute({
                        base: topic_base,
                        context: window.encodeURIComponent(this.context)
                    });
                    form.set('method', 'post');
                    form._method = 'post';
                }
                form.set('action', url);
            }

            var onSuccess = function() {
                //console.dir(arguments[0]);
                update_form.run(arguments, this);
                this.onSuccess.run(arguments, this);
            }

            //console && console.log(form.toQueryString());
            new Request.JSON({
                url: action,
                method: method,
                headers: { Accept: 'application/json' },
                onSuccess: onSuccess.bind(this),
                onFailure: $empty
            }).send('_method=' + method + '&' + form.toQueryString());
            //console.log(action + ' | _method=' + method + '&' +
            //form.toQueryString());

            return false;
        },

        express: function(prefer) {
            if (this.options.commented && !confirm(vlaah.lang['topic.9']))
                return;

            this.options.commented = false;
            this.onExpress(prefer);

            //console && console.dir(this);

            var url = '{base}{context}'.substitute({
                base: vlaah.topic_base,
                context: window.encodeURIComponent(this.context),
                prefer: prefer
            });
            new Request.JSON({
                url: url,
                method: 'post',
                headers: { Accept: 'application/json' },
                onSuccess: this.onSuccess.bind(this),
                onFailure: $empty
            }).send($H({prefer: prefer, body: '', tags: ''}).toQueryString());
        },

        update: function(result) {
            ['degree', 'count', 'percent'].each(function(attr) {
                var el = this.options.elements
                             .status.getElement('dd.'+attr);
                if (el.getFirst().get('tag') == 'a') {
                    el.getElement('em').set('text', result[attr].total);
                } else {
                    ['total', 'plus', 'minus'].each(function(prefer) {
                        el.getElement('.'+prefer+' em').set(
                            'text',
                            Math.round(result[attr][prefer] * 10) / 10
                        );
                    }, this);
                }
            }, this);
        },

        onExpress: function(prefer) {
            //console && console.log(prefer);
            var percent = (function(p) {
                var plus = this.degree[0].toInt();
                var sum = this.degree[1].toInt() + plus;
                var expressed = this.expressed;

                if (prefer == 'cancel') sum -= p;
                else if (expressed == null) sum += p;

                if (expressed == 'plus') plus -= p;
                else if (prefer == 'plus'
                     && (expressed == 'minus' || expressed == null)) plus += p;

                var percent = plus / sum;

                if (isNaN(percent)) return 0.5;
                else return percent.limit(0, 1);
            }).run(10, this);

            this.fx && this.fx.start('width', percent * 100);

            var elements = this.options.elements;
            if (prefer != 'cancel') {
                var other = this.prefers[1 - this.prefers.indexOf(prefer)];

                elements[prefer].removeClass('public').addClass('selected');
                elements[other].addClass('public').removeClass('selected');
            } else {
                this.prefers.each(function(prefer) {
                    elements[prefer].addClass('public').removeClass('selected');
                }, this);
            }

            return this.fireEvent('express', arguments);
        },

        onSuccess: function(result, json) {
            //alert(json);
            //console && console.log(json);

            this.expressed = result.expressed;

            this.degree = [result.degree.plus, result.degree.minus];
            var percent = this.degree[0].toInt() /
                         (this.degree[0].toInt() + this.degree[1].toInt());
            if (isNaN(percent)) percent = 0.5;

            this.fx && this.fx.start('width', percent * 100);
            try {
                this.update(result);
            } catch (e) {
            //    this.options.elements
            //        .topic.getElement('em').set('text', result.count.total);
            }

            return this.fireEvent('success', arguments);
        },

        onFailure: function() {
            alert('error');
        },

        plus: function() { return this.express('plus');  },
        minus: function() { return this.express('minus'); },
        cancel: function() {
            alert('Not implemented yet!');
            return;
            var url = '{base}{context}'.substitute({
                base: vlaah.topic_base,
                context: window.encodeURIComponent(this.context),
                prefer: prefer
            });
            new Request.JSON({
                url: url,
                method: 'post',
                headers: { Accept: 'application/json' },
                onSuccess: this.onSuccess.bind(this),
                onFailure: $empty
            }).send($H({prefer: prefer, body: '', tags: ''}).toQueryString());
        },

        toString: function() {
            return '[[{context}]]'.substitute({context: this.context});
        }
    });
}

