vanilla.votes = {
    _vote_class           : 'vote',
    _can_vote_class       : 'can_vote',
    _voting_class         : 'voting',
    _voted_class          : 'voted',
    _voted_up_class       : 'voted_up',
    _voted_down_class     : 'voted_down',
    _vote_count_class     : 'vote_count',
    _message_container_id : 'vote_messages',
    // *_count_tmpl's can contain: count, up_count and down_count
    _count_tmpl           : '#{total} people liked this story', 
    _zero_count_tmpl      : '',
    _one_count_tmpl       : '1 person liked this story', 
    _preview              : false,
    _up_and_down          : false,
    _on_error             : function(error, key) { alert(error); },
    _votes                : {},
    _personal_votes       : {},
    _initted              : false,
    _msgs                 : {
        require_login : 'We\'re sorry, but you must be logged in to vote.',
        ajax_error    : 'We\'re sorry. There was a problem submitting your vote. Please come back and try again later.',
        not_available : 'We\'re sorry. Voting is temporarily unavailable. Please come back and try again later.'
    },

    // class methods
    init : function(args) {
        if(vanilla.votes._initted) return; // only run once

        if(!args) args = {};
        for(var arg in args) {
            // msgs is a hash that should only have to override the msgs it wants to
            if( arg == 'msgs' ) {
                for(var key in args['msgs'] ) {
                    vanilla.votes['_msgs'][key] = args['msgs'][key];
                }
            } else {
                vanilla.votes['_' + arg] = args[arg];
            }
        }
        
        jQuery(document).ready(function() {
            var story_uuids = [];
            var extra_ids = [];

            // get all the story_ids and extra_ids that we care about
            jQuery('.' + vanilla.votes._vote_count_class).each(function(i, el) {
                if( el.className.match(/story_uuid_(\S+)/) ) {

                    story_uuids.push(RegExp.$1);
                }

                if( el.className.match(/extra_id_(\S+)/) ) {
                    extra_ids.push(RegExp.$1);
                }
            });

            var has_extra_ids = extra_ids.length != 0;
            var up_and_down = vanilla.votes._up_and_down;
            var params = { story_uuid: story_uuids, extra_id: extra_ids };
            if( up_and_down ) {
                params.direction = 1;
            }

            // get the vote counts from the server
            jQuery.ajaxSetup({ traditional: true }); // avoid PHP param bracket nonsense
            jQuery.getJSON('/api/v/counts', params, function(results) {
                vanilla.votes._votes = results;
                for(story_uuid in results) {
                    if( has_extra_ids ) {
                        for(extra_id in results[story_uuid]) {
                            vanilla.votes._update_vote_count(story_uuid, extra_id);
                        }
                    } else {
                        vanilla.votes._update_vote_count(story_uuid);
                    }
                }

                // if this person is logged in then mark what they've voted for
                if(vanilla.is_logged_in()) {
                    params.personal = 1;
                    jQuery.getJSON('/api/v/counts', params, function(results) { 
                        vanilla.votes._personal_votes = results;
                        for(story_uuid in results) {
                            if( has_extra_ids ) {
                                for(extra_id in results[story_uuid]) {
                                    vanilla.votes._update_personal_vote(story_uuid, extra_id);
                                }
                            } else {
                                vanilla.votes._update_personal_vote(story_uuid);
                            }
                        }
                    });
                }
            });
        });
        vanilla.votes._initted = true;
    },

    reinit : function(args) {
        vanilla.votes._initted = false;
        vanilla.votes.init(args);
    },

    post : function(el, story_uuid, extra_id, direction) {
        if(!vanilla.is_logged_in()) {
            vanilla.votes._handle_error('require_login');
            return;
        }

        var params = {};
        if( direction == 'down' ) {
            params.direction = 'down';
        }
        if( extra_id ) {
            params.extra_id = extra_id;
        }

        var orig_el = el;
        el = jQuery(el);
        el.addClass(vanilla.votes._voting_class);

        jQuery.post('/api/v/' + story_uuid, params, function(results) { 
            if(results.success) {
                el.removeClass(vanilla.votes._voting_class);
                if( direction == 'down' ) {
                    el.addClass(vanilla.votes._voted_down_class);
                } else {
                    el.addClass(vanilla.votes._voted_up_class);
                }

                // now increase the vote count
                if(!results.duplicate) {
                    var votes = vanilla.votes._votes;
                    var personal_votes = vanilla.votes._personal_votes;
                    if( direction == 'down' ) {
                        if( extra_id ) {
                            votes[story_uuid][extra_id].down++;
                            personal_votes[story_uuid][extra_id].down++;
                        } else {
                            votes[story_uuid][extra_id].down++;
                            personal_votes[story_uuid][extra_id].down++;
                        }
                    } else {
                        if( extra_id ) {
                            if( vanilla.votes._up_and_down ) {
                                votes[story_uuid][extra_id].up++;
                                personal_votes[story_uuid][extra_id].up++;
                            } else {
                                votes[story_uuid][extra_id]++;
                                personal_votes[story_uuid][extra_id]++;
                            }
                        } else {
                            if( vanilla.votes._up_and_down ) {
                                votes[story_uuid].up++;
                                personal_votes[story_uuid].up++;
                            } else {
                                votes[story_uuid]++;
                                personal_votes[story_uuid]++;
                            }
                        }
                    }

                    vanilla.votes._update_vote_count(story_uuid, extra_id);
                    vanilla.votes._update_personal_vote(story_uuid, extra_id);
                }

                // remove the ability to vote on this link again
                orig_el.onclick = function() { };
            } else {
                vanilla.votes._handle_error(results.error);
            }
        }, "json");
    },
    _handle_error : function(key) {
        vanilla.votes._on_error(vanilla.votes._msgs[key], key);
    },
    _update_vote_count : function(story_uuid, extra_id) {
        var votes = vanilla.votes._votes;
        var selector = '.vote_count.story_uuid_' + story_uuid;
        var up, down, total;
        
        if( extra_id ) {
            up       = vanilla.votes._up_and_down ? votes[story_uuid][extra_id].up : votes[story_uuid][extra_id];
            down     = vanilla.votes._up_and_down ? votes[story_uuid][extra_id].down : 0;
            selector = selector + '.extra_id_' + extra_id;
        } else {
            up   = vanilla.votes._up_and_down ? votes[story_uuid].up : votes[story_uuid];
            down = vanilla.votes._up_and_down ? votes[story_uuid].down : 0;
        }
        var total = up - down;
        var count_tmpl;
        
        if( total == 0 ) {
            count_tmpl = vanilla.votes._zero_count_tmpl;
        } else if( total == 1 ) {
            count_tmpl = vanilla.votes._one_count_tmpl;
        } else {
            count_tmpl = vanilla.votes._count_tmpl;
        }
        jQuery(selector).html(
            vanilla.template(
                count_tmpl,
                { up : vanilla.format_number(up), down: vanilla.format_number(down), total: vanilla.format_number(total) }
            )
        );
    },
    _update_personal_vote : function(story_uuid, extra_id) {
        var votes = vanilla.votes._personal_votes;
        var selector = '.vote.story_uuid_' + story_uuid;
        var up, down;
        
        if( extra_id ) {
            up       = vanilla.votes._up_and_down ? votes[story_uuid][extra_id].up : votes[story_uuid][extra_id];
            down     = vanilla.votes._up_and_down ? votes[story_uuid][extra_id].down : 0;
            selector = selector + '.extra_id_' + extra_id;
        } else {
            up   = vanilla.votes._up_and_down ? votes[story_uuid].up : votes[story_uuid];
            down = vanilla.votes._up_and_down ? votes[story_uuid].down : 0;
        }


        jQuery(selector).each(function(i, el) {
            el = jQuery(el);
            if( up < 1 && down < 1 ) {
                el.addClass(vanilla.votes._can_vote_class);
            } else {
                el.removeClass(vanilla.votes._can_vote_class);
                el.addClass(vanilla.votes._voted_class);
                if( up > 0 ) {
                    el.addClass(vanilla.votes._voted_up_class);
                } else if ( down > 0 ) {
                    el.addClass(vanilla.votes._voted_down_class);
                }
            }
        });
    }
};


