/*
//jQuizMe 1.0 First release 
//Documenation at www.bateru.com/jquery/jquizme/
//Please give me feedback at blarry@bateru.com
//Copyright (c) 2009 Larry Battle 3/6/2009
//Dual licensed under the MIT and GPL licenses.
//http://www.opensource.org/licenses/mit-license.php
//http://www.gnu.org/licenses/gpl.html
// quizData =[ { ques: "", ans : ""},  {ques: "", ans : ""}, etc ];
// quiz( quizData, options ) # wordsList is an arrary of objects with the following format, 
*/
// Sees if an array1 and array2 are the same.
Array.prototype.compare = function(testArr) {
    if (this.length != testArr.length) { return false; }
    var i = this.length;
    while (i--) {
        if (this[i].compare) {
            if (!this[i].compare(testArr[i])) { return false; }
        }
        if (this[i] !== testArr[i]) { return false; }
    }
    return true;
};

(function($) {
    $.fn.jQuizMeDefaultLayOut = $("<div/>").attr("class", "quiz-el").append(
		$("<div/>").attr("class", "q-header").append(
				$("<div/>").attr("class", "q-title"),
				$("<div/>").attr("class", "q-counter")
			),
		$("<div/>").attr("class", "q-help").append(
				$("<div/>").attr("class", "q-help-menu").append(
						$("<input type='button'/>").attr({ "class": "help-btn", "title": " Click to open & close", "value": "Help" }),
						$("<input type = 'button' />").attr({ "class": "quit-btn", "title": "End quit", "value": "Quit" }),
						$("<div/>").attr("class", "q-help-info").hide()
				)
		),
		$("<div/>").attr("class", "q-intro").hide(),
		$("<div/>").attr("class", "q-prob").append(
			$("<div/>").attr("class", "q-ques"),
			$("<div/>").attr("class", "q-ans"),
			$("<div/>").attr("class", "q-result").hide()
		),
		$("<div/>").attr("class", "q-gameOver").append(
			$("<div/>").attr("class", "stat"),
			$("<div/>").attr("class", "options").append(
				$("<input type='button'/>").attr({ "class": "restartBtn", "value": "Restart" }),
				$("<input type='button'/>").attr({ "class": "deleteBtn", "value": "Delete" })
			)
		).hide()
	);
    /*Everything is defined then called. So the starting functions are at the end.*/
    $.fn.jQuizMe = function(wordList, options) {

        var settings = jQuery.extend({}, {
            addToEnding: " = ?",
            activeClass: "q-ol-active",
            numOfQuizQues: 0,
            help: 'None',
            hoverClass: "q-ol-hover",
            intro: '',
            multiplyChoiceLength: 3,
            showWrongAns: false,
            random: true,
            right: 'Great Job. Right!',
            quizType: 'fillInTheBlank',
            title: 'jQuizMe'
        }, options);
        var isMSIE = $.browser.msie;

        return this.each(function() {
            /* currQuiz is the output file.(this is what the user sees)*/
            var currQuiz = 0, currIndex = 0, stickyEl = this, quit = false, userAns = '';
            var wList = wordList || 0;
            var wListLen = wList.length;
            var numOfQQ = settings.numOfQuizQues;
            if (settings.multiplyChoiceLength > wListLen) { settings.multiplyChoiceLength = wListLen; }
            if (!numOfQQ || numOfQQ > wListLen) { numOfQQ = wListLen; }
            /*The q object is where the quiz data is stored. Everything is made before the quiz starts.*/
            var q = {
                ans: [], ansSel: [], ques: [], helpAns: []
            };
            var stats = {
                numOfQues: numOfQQ,
                quesTried: 0,
                /* rightAns[] and wrongAns[] keeps an index of the q's questions and answer index. So at the end the user can review their choses. */
                rightAns: [],
                wrongAns: [],
                perc: function() {
                    var x = Math.round(this.rightAns.length / this.numOfQues * 10000);
                    return (x / 100);
                },
                reset: function() {
                    this.numOfQues = numOfQQ;
                    this.quesTried = 0;
                    this.rightAns = [];
                    this.wrongAns = [];
                }
            };
            /* Just for no confusion: r is for random. */
            var rNum = function(len) {
                return Math.floor(Math.random() * len);
            };
            var rBool = function() {
                return (rNum(100) % 2 !== 0);
            };
            var rAns = function(len) {
                return wList[rNum(len || wListLen)].ans;
            };
            var makeArrayRandom = function(arr) {
                var j, x, i = arr.length;
                while (i) {
                    j = parseInt(Math.random() * i);
                    x = arr[--i];
                    arr[i] = arr[j];
                    arr[j] = x;
                }
                return arr;
            };
            var createQuizEl = function() {
                /* Rememeber currQuiz is shown to the user, so hide until ready*/
                currQuiz = $.fn.jQuizMeDefaultLayOut.clone(true).hide();
                $(".help-btn", currQuiz).toggle(
				function() { $(".q-help-info", currQuiz).fadeIn("slow"); }
				, function() { $(".q-help-info", currQuiz).fadeOut("slow"); }
			);
                $(".quit-btn", currQuiz).click(function() { quitQuiz(); });
                $(stickyEl).append(currQuiz);
            };
            var cont = function() {
                return (!quit && (currIndex < numOfQQ));
            };
            var display = function() {
                $(currQuiz).show();
            };
            var gameOver = function() {
                $(".stat", currQuiz).text(
				(stats.perc() + '% confident in your business.')
			);
                $(".restartBtn", currQuiz).one("click", function() {
                    reStartQuiz();
                });
                $(".deleteBtn", currQuiz).one("click", function() {
                    deleteQuiz();
                });
                $(".q-prob, .q-intro", currQuiz).hide();
                $(".q-gameOver", currQuiz).show();
            };
            var changeProb = function() {
                $(".q-counter", currQuiz).text((currIndex + 1) + '/' + numOfQQ);
                $(".q-ques", currQuiz).html(q.ques[currIndex]);
                $(".q-ans", currQuiz).html(
                /* Checks to see if one answer selection (ansSel) element was created. This was done to save space and time in making quizTypes. */
				(q.ansSel[currIndex]) ? q.ansSel[currIndex].clone(true) : q.ansSel[0].eq(0).clone(true)
			);
                $(".q-result", currQuiz).hide();
                $(".focusThis", currQuiz).focus();
            };
            var changeQuizInfo = function() {
                $(".q-title", currQuiz).text(settings.title);
                $(".q-help-info", currQuiz).html(settings.help);
                if (settings.intro) {
                    $(".q-prob", currQuiz).hide();
                    $(".q-intro", currQuiz).html(settings.intro).show()
				.append($("<br/>"))
				.append($('<input type="button"/>').attr("value", "Begin Quiz")
					.click(function() {
					    $(".q-intro", currQuiz).hide();
					    $(".q-prob", currQuiz).show();
					})
				);
                }
            };
            var nextMove = function() {
                currIndex++;
                cont() ? changeProb() : gameOver();
            };
            var cAns = function(i) {
                return q.ans[i || currIndex];
            };
            var cHelpAns = function(i) {
                return q.helpAns[i || currIndex];
            };

            var checkAns = function() {

                var ans = cAns(), isAnsCorr = false;
                if (typeof ans == "object") {
                    var i = ans.length;
                    while (i--) {
                        if (userAns == ans[i]) {
                            isAnsCorr = true;
                        }
                    }
                    if (userAns == ans.toString()) { isAnsCorr = true; }
                }
                else {
                    isAnsCorr = (userAns == ans || userAns.toString().toLowerCase() == ans.toString().toLowerCase());
                }
                stats.quesTried++;
                (isAnsCorr) ? stats.rightAns.push(currIndex) : stats.wrongAns.push(currIndex);
                return isAnsCorr;
            };
            var ansResult = function() {
                var currAns = cAns();
                var currHelp = cHelpAns();
                var isUserAnsCorr = checkAns();
                var isLongArr = (typeof currAns == "object") && (currAns.length != 1);
                var show = (isUserAnsCorr) ? (settings.right) :
							('Correct answer(s)<br/>' + ((isLongArr) ? currAns.join('<br/>') : currAns));
			    //Display the helpAns message
                if (!isUserAnsCorr && settings.showWrongAns) {
                    show = currHelp + "<br/><a href='/contactus'>Contact us</a>";
                 }

                $(".q-result", currQuiz).html(show).fadeIn("slow");
            };
            var hasAnsSel = function(i) {
                return (!!wList[i || currIndex].ansSel);
            };
            /*The quizes are made this way. The q object is filled with the questions, answers and answer selections(what the user can choose from). 
            The user's input gets assigned to userAns ( global inside quizMe ). 
            Then nextMove() is called. Which checks to see if the user's Input is contained in the answer, or is the array.*/
            var quizTypes = {
                'fillInTheBlank': function(fCVer) {
                    /* fillInTheBlank Quiz:	ques = ques,	ansSel = Input text[ ans ].*/
                    var makeQuesAndAns = function() {
                        var d;
                        if (fCVer) {
                            d = $('<div><input type="button" class="check-btn focusThis" value="Check"/></div>');
                            $(".check-btn", d).one("click", function() {
                                userAns = "";
                                stats.rightAns.push(currIndex); // The user is review. So they get points.
                                $(this).attr("value", "Next").one("click", function() {
                                    nextMove();
                                });
                                ansResult();
                            });
                        }
                        else {
                            d = $('<div><input type="text" class="q-quesInput focusThis"/><br/><input type="button" class="check-btn" value="Check"/></div>');
                            $(".check-btn", d).one("click", function() {
                                userAns = $(".q-quesInput", currQuiz).attr("disabled", "true").val();
                                userAns = jQuery.trim(userAns);
                                $(this).attr("value", "Next").one("click", function() {
                                    nextMove();
                                });
                                ansResult();
                            });
                        }
                        q.ansSel[0] = d.clone(true); /* If you only set one ansSel, it will be used through the quiz.*/
                        var i = numOfQQ;
                        while (i--) {
                            q.helpAns[i] = wList[i].helpAns;
                            q.ans[i] = wList[i].ans;
                            q.ques[i] = (wList[i].ques + settings.addToEnding);
                        }
                    };
                    makeQuesAndAns();
                },
                'flashCard': function() {
                    /*flashCard Quiz:  ques = ques, ansSel =null .*/
                    this.fillInTheBlank(true);
                },
                'trueOrFalse': function() {
                    /* trueOrFalse Quiz:
                    ques  = (typeof ans != bool) ? (real or fake ans)  : ques;
                    ansSel =  T / F ( radio );
                    If the answer is a bool, then there is no creation of a question, 
                    by combining a right or wrong answers, to make a true or false statement.
                    */
                    var makeQuesAndAns = function() {
                        var d = $('<div><input type="radio" value="1" class="true-radio"/><label>True</label><input type="radio" value="0" class="false-radio"/><label>False</label><br/><input class="check-btn" type="button" value="Check"/></div>');
                        $(".true-radio, .false-radio, label", d).click(function() {
                            $(".check-btn", currQuiz).attr("disabled", false);
                        });
                        $("label:eq(0), .true-radio", d).click(function() {
                            $(".true-radio", currQuiz).attr("checked", true);
                            $(".false-radio", currQuiz).attr("checked", false);
                            userAns = true;
                        });
                        $("label:eq(1), .false-radio", d).click(function() {
                            $(".true-radio", currQuiz).attr("checked", false);
                            $(".false-radio", currQuiz).attr("checked", true);
                            userAns = false;
                        });
                        $(".check-btn", d).attr("disabled", true).one("click", function() {
                            $(this).attr("value", "Next").one("click", function() {
                                nextMove();
                            });
                            ansResult();
                        });
                        q.ansSel[0] = d.clone(true); /* If you only set one ansSel, it will be reused through the quiz.*/

                        var i = numOfQQ;
                        while (i--) {
                            var currAns = wList[i].ans;
                            q.ques[i] = wList[i].ques;

                            if (typeof currAns != "boolean") {
                                q.ans[i] = rBool();
                                var result = (q.ans[i]) ? currAns : rAns();
                                var a = (typeof currAns != "object" || typeof result != "object") ? result == currAns : result.compare(currAns);
                                if (a) {
                                    q.ans[i] = true;
                                }
                                q.ques[i] += " <br/>=<br/> " + result;
                            }
                            else {
                                q.ans[i] = currAns;
                            }
                        }
                    };
                    makeQuesAndAns();
                },
                'multiplyChoice': function(olVer) {
                    /* multiplyChoice Quiz: 
                    ques = ques;
                    ansSel = <select>[ <option> is the answer + <option> * settings.multiplyChoiceLength]*/
                    var makeQuesAndAns = function() {
                        //var oV = olVer; // faster. Because
                        var d;
                        if (olVer) {
                            d = $('<div><ol class="q-ol"></ol><input type="button" class="check-btn" value="Check"/></div>');
                            $(".q-ol-li", d)
							.live("click", function(e) {
							    $(".check-btn", currQuiz).attr("disabled", false);
							    var val = parseInt($(e.target).attr("val"), 10);
							    /* If the user's answer(userAns) is array, only one of the elements is needed for checkAns to return true.*/
							    userAns = (isNaN(val)) ? $(e.target).text() :
											(typeof wList[val].ans == "object") ? wList[val].ans[0] :
												wList[val].ans;
							    $("." + settings.activeClass, currQuiz).removeClass(settings.activeClass);
							    $(e.target).addClass(settings.activeClass);
							})
							.live("mouseover", function(e) {
							    $(e.target).addClass(settings.hoverClass);
							})
							.live("mouseout", function(e) {
							    $(e.target).removeClass(settings.hoverClass);
							});
                        }
                        else {
                            d = $('<div><select class="q-select"></select><input type="button" class="check-btn" value="Check"/></div>');
                            $(".q-select", d).bind("click keypress", function(e) {
                                $(".check-btn", currQuiz).attr("disabled", false);
                                var val = parseInt($(e.target).val(), 10);
                                /* If the user's answer(userAns) is array, only one of the elements is needed for checkAns to return true.*/
                                userAns = (isNaN(val)) ? $("option:selected", this).text() :
										(typeof wList[val].ans == "object") ? wList[val].ans[0] :
											wList[val].ans;
                            });
                        }
                        $(".check-btn", d).attr("disabled", true).one("click", function() {
                            $(this).attr("value", "Next").one("click", function() {
                                nextMove();
                            });
                            ansResult();
                        });
                        var setLen = settings.multiplyChoiceLength;
                        var i = numOfQQ;
                        var ansPos, optHtml, val, len;
                        var wListRange = [], j = wListLen;
                        while (j--) {
                            wListRange[j] = j;
                        }

                        while (i--) {
                            optHtml = "";
                            if (hasAnsSel(i)) {
                                val = [];
                                if (typeof wList[i].ansSel == "object") {
                                    val = wList[i].ansSel.concat();
                                    len = val.length + 1;
                                }
                                else {
                                    val[0] = wList[i].ansSel;
                                    len = 2;
                                }
                                val[val.length] = wList[i].ans;
                                makeArrayRandom(val);

                                while (len--) {
                                    optHtml += (olVer) ? ["<li class = 'q-ol-li' >", val[len], "</li> "].join("") :
												["<option value='n", i, "'>", val[len], "</option> "].join("");
                                }
                            }
                            else {
                                var randAns = wListRange.concat();
                                randAns.splice(i, 1); // From the answer Index from randAns. 
                                len = setLen;
                                ansPos = rNum(len);
                                while (len--) {
                                    var randIndex = rNum(randAns.length);
                                    val = (len == ansPos) ? i : randAns.splice(randIndex, 1) || 0;
                                    optHtml += (olVer) ? ["<li class = 'q-ol-li' val ='", val, "'>", wList[val].ans, "</li> "].join("") :
												["<option value =' ", val, " '>", wList[val].ans, "</option> "].join("");
                                }
                            }
                            /*below: innerHTML is 2x faster than $.html() but IE generates corrrupt option html*/
                            (olVer) ? $(".q-ol", d)[0].innerHTML = optHtml :
						(isMSIE) ? $("select", d).html(optHtml) : $("select", d)[0].innerHTML = optHtml;
                            q.ansSel[i] = d.clone(true);
                            q.ques[i] = wList[i].ques;
                            q.ans[i] = wList[i].ans;
                            q.helpAns[i] = wList[i].helpAns;
                        }
                    };
                    makeQuesAndAns();
                },
                'multiplyChoiceOl': function() {
                    /* multiplyChoiceOlQuiz: ques = ques, ansSel = ol [ <list> real ans + <list> * settings.multipleChooseLength] */
                    this.multiplyChoice(true);
                }
            };
            var makeQuizType = function() {
                (quizTypes[settings.quizType]) ? quizTypes[settings.quizType]() : quizTypes.fillInTheBlank();
            };
            var quitQuiz = function() {
                quit = true;
                nextMove();
            };
            var createNewQuiz = function() {
                if (settings.random) { makeArrayRandom(wList); }
                stats.reset();
                makeQuizType();
                changeQuizInfo();
                changeProb();
                display();
            };
            var deleteQuiz = function() {
                $(currQuiz).remove();
                q = {};
            };
            var reStartQuiz = function() {
                $(currQuiz).hide();
                $(".q-gameOver", currQuiz).hide();
                $(".q-prob", currQuiz).show();
                quit = false;
                currIndex = 0;
                createNewQuiz();
            };
            var start = function(el) {
                if (!el) { return false; }
                stickyEl = el;
                if (!wListLen) {
                    currQuiz = $("<p/>").text("Error: Empty word list.");
                    display();
                    return currQuiz;
                }
                createQuizEl();
                createNewQuiz();
                return currQuiz;
            };
            start(this); //This is where it all starts.
        });
    };
})(jQuery);
