﻿(function($) {
    //Polling functionality

    $.mmsGenericPoll = {
        speed: 1000, //The speed at which transitions happen
        baseCookieDomain: '', //Domain to use for cookies
        services: { poll: '', answer: '' }
    };


    //Templates for generating pieces of the poll
    $.mmsGenericPoll.templates = {
        poll: '<div id="genericPoll1" class="genericPoll genericPollOpen">' +
        '<h2><span></span></h2>' +
        '<div class="content"><p class="vote"><span>Vote</span></p>' +
        '<p class="thanks">Thank you for voting!</p><p class="status"></p>' +
        '<p class="responses">(<span class="totalVotes"></span> total responses)</p></div></div>',

        question: '<div class="question"><p></p><ul></ul></div>',

        answer: '<li><input name="aName" id="anId" type="radio"></input><label></label>' +
        '<div class="resultBar"><div class="bar"></div>' +
        '<div class="pct"></div></div></li>'
    };


    //Regular expressions used in the polling app
    $.mmsGenericPoll.regex = {
        //Matches pollAnswer query param value
        pollVote: /pollVote=(\d+)/i
    };


    //Show a single poll based on a service call
    $.mmsGenericPoll.singlePoll = function(id, settings) {
        $.extend($.mmsGenericPoll, settings);
        $.ajax({ dataType: 'jsonp', url: $.mmsGenericPoll.services.poll + '?id=' + id,
            success: function(data) { $.mmsGenericPoll.processPollData(data); }
        });
    };


    //Process poll data and create the poll
    $.mmsGenericPoll.processPollData = function(data) {
        if (data.questions) {
            var poll = $($.mmsGenericPoll.templates.poll); //Make the poll from its template
            poll.data = data;

            //Fill in the title with the name of the poll
            //poll.find('h2 span').text('Anonymous Reader Poll');

            //Add each poll question to the poll
            $.each(data.questions,
            function(i) { $.mmsGenericPoll.buildQuestion(i, this, poll); });

            poll.find('.question:last').addClass('last');

            $('#genericPoll').replaceWith(poll); //Add the poll to the DOM

            //Determine if this poll is open, answered, and which date to display
            //in the status (i.e. 'Poll opened x/y/z')
            var open = !data.closeDate || $.mmsJsonDate(data.closeDate) > new Date(),
            answered = $.cookie('genericPoll' + poll.data.id) == 'voted',
            date = $.mmsJsonDate(!open ? data.closeDate : data.openDate);

            $.mmsGenericPoll.displayPoll(poll, open, answered, date); //Display the poll

            //If a pollVote query parameter is specified, vote for that option
            window.location.href.replace($.mmsGenericPoll.regex.pollVote, function(m, id) {
                poll.find('input:eq(' + id + ')').attr('checked', 'checked').end()
                .find('.vote').trigger('click', poll).end();
            });
        }
    };


    //Display a poll according to its state
    $.mmsGenericPoll.displayPoll = function(poll, open, answered, date) {
        //Build up the poll status string
        var formattedDate = $.dateFormat(date, 'mmm. d, yyyy'),
        status = 'Poll ' + (open ? 'Opened ' : 'Closed ') + formattedDate;

        if (!open)
            poll.find('.status').text(status).end();

        //Don't display thanks for voting once the poll is closed
        if (!open) poll.find('.thanks').remove().end();

        //Set up a new user link
        if (open)
            poll.find('.newUser').click(function() {
                $.cookie('genericPoll' + poll.data.id, null,
                { domain: $.mmsGenericPoll.baseCookieDomain });
                $('#genericPoll1').replaceWith('<div id="genericPoll"></div>');
                $.mmsGenericPoll.processPollData(poll.data);
                ntptEventTag('ev=pollNewUser');
            });
        else
            poll.remove('.newUser');

        //The poll is open and unanswered
        if (open && !answered) {
            poll.find('.thanks, .responses, .resultBar, .newUser').hide().end()
            .find('.vote').bind('click', poll, $.mmsGenericPoll.vote).end();
        }
        //The poll is either closed or answered
        else {
            poll.find('.vote').hide().end()
            .find('input').attr('disabled', 'disabled').end();

            $.mmsGenericPoll.showResults(poll);
        }
    };


    //Build a poll question and it's answers out of its template
    $.mmsGenericPoll.buildQuestion = function(qIndex, question, poll) {
        var el = $($.mmsGenericPoll.templates.question),
        ul = el.find('ul'),
        name = 'genericPoll1q' + qIndex;

        //Add answers to this question
        $.each(question.answers,
        function(i) { ul.append($.mmsGenericPoll.buildAnswers(name, i, this)); });

        //Add each question right before the vote button
        poll.find('.vote').before(el.find('p').text(question.question).end());
    };


    //Create each answer out of its template
    $.mmsGenericPoll.buildAnswers = function(name, aIndex, answer) {
        var id = name + 'a' + aIndex;

        //Modify the template to fill it in and make the label match the input
        return $($.mmsGenericPoll.templates.answer.replace('aName', name))
        .find('input').attr('id', id).end()
        .find('label').text(answer.text).attr('for', id).end();
    };


    //Handle a click of the vote button
    $.mmsGenericPoll.vote = function(e) {
        var questions = e.data.find('.question');
        //Get a mapping of questions answered to answers selected
        var votes = $.mmsGenericPoll.mapVotes(e.data.find('input:checked'));

        //Register the vote if all question have been answered
        if ($.mmsPropertyCount(votes) == questions.length) {
            $.mmsGenericPoll.registerVote(e.data, votes);
            ntptEventTag('ev=submitPoll');
        }
        else
            $.mmsGenericPoll.alertUnanswered(questions, votes);
    };


    //Alert the user that they haven't answered all questions
    $.mmsGenericPoll.alertUnanswered = function(questions, votes) {
        questions.each(function(i) {
            if (!votes[i])
                $(this).css('background-color', '#fdfd80').animate({ 'backgroundColor': '#FFFFFF' }, $.mmsGenericPoll.speed);
        });
    };


    //Register the vote and show results
    $.mmsGenericPoll.registerVote = function(poll, votes) {
        //Write a cookie to indicate that this poll has been answered
        $.cookie('genericPoll' + poll.data.id, 'voted',
        { domain: $.mmsGenericPoll.baseCookieDomain, expires: 365 });

        //Build up the answer URL
        var params = 'id=' + poll.data.id, q = poll.data.questions;
        for (x in votes) params += '&q' + q[x].id + '=' + q[x].answers[votes[x]].id;

        //Register the answers
        $.mmsGenericPoll.sendVote($.mmsGenericPoll.services.answer + '?' + params);

        //Add the votes to the existing vote counts. We do this rather than getting
        //new vote counts from the server since it allows for immediate feedback
        $.mmsGenericPoll.eachAnswer(poll, function(i, j) { votes[i] == j && this.votes++; });

        //Disable the radio buttons, hide the vote button, and show results
        poll.find('input').attr('disabled', 'disabled').end()
        .find('.vote').mmsFadeHide($.mmsGenericPoll.speed / 2,
            function() { $.showResultsDelayed(poll); });
    };


    //Send the vote (separate function so it can be disabled)
    $.mmsGenericPoll.sendVote = function(url) { $.ajax({ dataType: 'jsonp', url: url }); };


    //Create an object whose keys and values match up with the selected options.
    $.mmsGenericPoll.mapVotes = function(selectedOptions) {
        var votes = {};
        selectedOptions.each(function() {
            //IDs are formatted like 'genericPoll1q1a3'
            var vote = this.id.match(/q(\d*)a(\d*)$/);
            //Turn them into key: value, e.g. { 1: 3 }
            votes[new Number(vote[1])] = new Number(vote[2]);
        });

        return votes;
    };


    //Show the results after a delay
    $.showResultsDelayed = function(poll) {
        setTimeout(function() { $.mmsGenericPoll.showResults(poll); }, $.mmsGenericPoll.speed / 2);
    };


    //Show results - bars, percentages, etc
    $.mmsGenericPoll.showResults = function(poll) {
        //Find the inital width of the bars
        var bars = poll.find('.bar');
        poll.find('.resultBar').show();
        var startWidth = bars.width();
        poll.find('.resultBar').hide();

        //Get the total # of votes by summing the votes to the first question
        var totalVotes = 0, q = poll.data.questions[0];
        $.each(q.answers, function() { totalVotes += new Number(this.votes); });

        //Find the final width of each bar
        $.mmsGenericPoll.calcResults(poll, totalVotes, startWidth);
        poll.find('.totalVotes').text(totalVotes);

        //Start the bars at 0 pixels and fade them in
        bars.width(0);
        poll.find('.resultBar').mmsFadeShow($.mmsGenericPoll.speed).end()
	    .find('.pct').add(bars).fadeIn($.mmsGenericPoll.speed);

        //Animate each bar to its full width 
        bars.each(function(i) {
            $(this).animate({ width: $(this).attr('barWidth') }, $.mmsGenericPoll.speed);
        });

        //Show thanks and # of responses
        poll.find('.thanks, .responses').mmsFadeShow($.mmsGenericPoll.speed);
    };


    //Calculate bar widths and percentages
    $.mmsGenericPoll.calcResults = function(poll, totalVotes, startWidth) {
        var bars = poll.find('.bar'), pcts = poll.find('.pct');

        //Loop through each answer
        var i = 0;
        $.mmsGenericPoll.eachAnswer(poll, function() {
            //Calculate the width of each bar and it's percentage
            var ratio, width = 1, pct = 0;
            if (totalVotes > 0) {
                ratio = this.votes / totalVotes;
                width = Math.max(Math.round(ratio * startWidth), 1);
                pct = Math.round(ratio * 100);
            }

            //Set custom attributes and the percentage text
            bars.eq(i).attr('barWidth', width).attr('votePct', pct);
            pcts.eq(i).text(pct + '%');
            i++;
        });
    };


    //Loop through each answer in each question
    $.mmsGenericPoll.eachAnswer = function(poll, fn) {
        $.each(poll.data.questions, function(i) {
            $.each(this.answers, function(j) { fn.apply(this, [i, j]); });
        });
    };


})(jQuery);