﻿function VotingStars(voteContainerElement, challengeId, entryId, loggedIn, askForLogin, messager, updateNumberOfVotes, enableShortcut)
{
    var VOTING_SCHEME_ID = 2;

    var voted = false;
    var magnitude = 0.0;

    var initAnimationTimeoutId;
    var initAnimationCurrStep = 0;

    // This should not be hardcoded. It should be generated by
    // Challenge.aspx in the initialization JavaScript for each
    // voting style separately. OK for now.
    var opts = {
        spriteBlankOffset: 0,
        spriteStarsOffset: 20,
        spriteHoverBlankOffset: 220,
        spriteHoverStarsOffset: 240,
        spriteRowHeight: 20,
        spriteStepWidth: 9,
        magnituges: [0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0] };
        
    var DEFAULT_ERROR_MESSAGE =
        "We encountered an error when recording your vote. The chance you see " +
        "this error message is very low, and most likely it is a result of a bug " +
        "in or momentary technical problem in our system. We apologize for the " +
        "inconvenience.";

	// init code
    var $container = $(voteContainerElement);
    var $retract = $container.find("div[class='retract']");
    var $stars = $container.find("div[class='stars']");
    $stars.mouseover(initWidget);
    if (enableShortcut) initShortcut();
    
    // private
    function initWidget()
    {
        $stars.unbind("mouseover", initWidget);
        cancelInitAnimation();
    
        $retract.
            data("step", -1).
            attr("title", "Retract vote, shortcut: r").
            hover(stepMouseOver, stepMouseOut).
            click(stepClick);

	    for (var i = 0; i < opts.magnituges.length; i++)
	    {
	        $("<div/>").
	            addClass("stepOverlay").
	            attr("title", getMagnitudeForStep(i) + ", shortcut: " + ((i + 1) % 10)).
	            css("top", "0px").
	            css("left", (i * opts.spriteStepWidth) + "px").
	            data("step", i).
	            hover(stepMouseOver, stepMouseOut).
	            click(stepClick).
	            appendTo($stars);
	    }
	}

	//private
	function initShortcut()
	{
	    Utils.keyboardShortcut("r", function () { stepClickInternal(-1, false); });
	    for (var i = 0; i < opts.magnituges.length; i++)
	    {
	        (function (i) {
	            Utils.keyboardShortcut(((i + 1) % 10) + '', function () { stepClickInternal(i, false);});
	        })(i);
        }

        
    }

	// public
    this.setMagnitude = function(newVotedState, newMagnitudeState)
    {
        voted = newVotedState;
        magnitude = newMagnitudeState;
        if (voted) startInitAnimation();
    }

	// private
	function startInitAnimation()
	{
	    initAnimationCurrStep = 0;
	    initAnimationDoStep();
	}

	// private
	function initAnimationDoStep()
	{
	    redrawStars(false, true, initAnimationCurrStep);
	    if (getMagnitudeForStep(initAnimationCurrStep) < magnitude)
	    {
	        initAnimationCurrStep++;
	        scheduleInitAnimationNextStep();
	    }
	}

	// private
	function scheduleInitAnimationNextStep()
	{
	    initAnimationTimeoutId = window.setTimeout(initAnimationDoStep, 50);
	}

	// private
	function cancelInitAnimation()
	{
	    window.clearTimeout(initAnimationTimeoutId);
	}

	// private
	function stepMouseOver()
	{
	    var step = $(this).data("step");
	    redrawStars(true, false, step);
	}

	// private
	function stepMouseOut()
	{
	    var step = $(this).data("step");
        redrawStars(false, voted, voted ? getStepForMagnitude(magnitude) : 0);
	}

	// private
	function stepClick()
	{
	    var step = $(this).data("step");
	    stepClickInternal(step, true);
	}

	// private
	function stepClickInternal(step, useMouse)
	{
	    if (step == -1)
	    {
	        if (voted)
	        {
	            retractVote();
	            redrawStars(useMouse, false, -1);
	        }
	        else
	        {
	            redrawStars(false, false, 0);
	        }
	    }
	    else
	    {
	        placeVote(getMagnitudeForStep(step));
	        redrawStars(useMouse, true, step);
	    } 
	}

	// private
	function getStepForMagnitude(magnituge)
	{
	    for (var step = 0; step < opts.magnituges.length; step++)
	    {
	        if (opts.magnituges[step] == magnituge)
            {
                return step;
            }
        }
        return 0;
    }

	// private
    function getMagnitudeForStep(step)
    {
        return opts.magnituges[step];
    }
    
	// private
	function redrawStars(hover, voted, step)
	{
	
	    var top = 0;
	    var left = 0;
	    
	    if (hover && step == -1)
	    {
            top = opts.spriteHoverBlankOffset;
	    }
	    else if (hover && step != -1)
	    {
            top = opts.spriteHoverStarsOffset + step * opts.spriteRowHeight;
	    }
	    else if (voted)
	    {
	        top = opts.spriteStarsOffset + step * opts.spriteRowHeight;
	    }
	    else
	    {
	        top = opts.spriteBlankOffset;
	    }
	    
	    if (hover)
	    {
	        $retract.show();
	    }
	    else
	    {
	        $retract.hide();
	    }
	    
	    $stars.css("background-position", left + "px " + (-top) + "px");

	}

	// private
	function placeVote(newMagnitude)
	{
	    voteRequest(
	        newMagnitude,
	        false,
	        voted ?
	            "Your vote has been changed." :
	            "Thank you, your vote has been submitted.");
	}
	
	// private
	function retractVote()
	{
	    voteRequest(0.0, true, "You vote has been retracted.");
	}
	
	// private
	function voteRequest(newMagnitude, retract, message)
	{
	
	    if (!loggedIn)
	    {
	        askForLogin();
	        return;
	    }
	    
	    var oldMagnitude = magnitude;
	    var oldVotedStatus = voted;
        magnitude = newMagnitude;
        voted = !retract;
	    
	    messager.displayMessage(message);
	    
	    var requestData = {
	        EntryID: entryId,
	        ChallengeID: challengeId,
	        SchemeID: VOTING_SCHEME_ID,
	        Magnitude: newMagnitude,
	        ResponseType: "JSON",
	        Retract: retract ? "true" : "false" };
	        
	    var request = {
	        url: "EndPoints/PlaceVote.ashx",
	        type: "GET",
	        data: requestData,
	        dataType: "json",
	        error: errorResponse,
	        success: successResponse };
	        
        $.ajax(request);
	        
        function successResponse(json)
        {
            if (json.result != "success")
            {
                magnitude = oldMagnitude;
                voted = oldVotedStatus;
                redrawStars(false, voted, voted ? getStepForMagnitude(magnitude) : 0);
                processError(json);
            }
            if (updateNumberOfVotes) updateNumberOfVotes(json.votesCount, json.votesCountFormatted);
            messager.hideCurrent();
            gotoAutoNext();
        }
        
        function errorResponse()
        {
            alert(DEFAULT_ERROR_MESSAGE)
            messager.hideCurrent();
        }

	}
	
	// private
	function gotoAutoNext()
	{
        var $autoNext = $('#autoNext');
        if ($autoNext.length != 0 &&
            $autoNext.find('input[type="checkbox"]').attr("checked") ||
            $.cookie("challenges.autonext") == "true")
        {
        	var $a = $autoNext.find("a");
        	if ($a.length > 0)
        	{
        		window.location = $a.attr("href");
        	}
        }
	}
	
	// private
	function processError(json)
	{
        // These errors are unusual conditions, and should not happen
        // very likely. The application should not get to this point
        // normally. TODO: To be improved later.
	    if (json.result == "logged-out")
	    {
	        askForLogin();
	    }
	    else if (json.result == "voting-closed")
	    {
	        alert("There was a problem while recording your vote: the challenge already " +
                  "closed for voting at the moment. Most likely the GTM midnight has passed " +
                  "during your voting session.");
	    }
	    else if (json.result == "user-banned")
	    {
	        alert("There was a problem while recording your vote(s): you are banned from voting.");
	    }
	    else if (json.result == "own-entry")
	    {
	        alert("Sorry, you cannot vote for your entry.");
	    }
	    else
	    {
	        alert(DEFAULT_ERROR_MESSAGE);
	    }
	}
}
