/*global $, window, document, navigator, setTimeout */
//
// USAGE:
// document.AgeVerification.Language(en_or_es); // explicitly set the langauge
// document.AgeVerification.PassCallback(function() { alert("Passed AV!"); }); // define a function to be called when AV passes
// document.AgeVerification.FailCallback(function() { alert("Failed AV!"); }); // define a function to be called when AV fails
// document.AgeVerification.ShowCallback(function() { alert("Showing Form!"); }); // define a function to be called when AV form is being displayed
// document.AgeVerification.ContentCallback(function() { alert("Showing Content!"); }); // define a function to be called when content is being displayed (AV passed or skipped)
//
// document.AgeVerification.Validators.Add(domElement, callbackfunction, errorMessage, maxFieldLength); // Add additional validation on AV submit (eg, for a zip code field)
// document.AgeVerification.Validators.Add($('#inputElement').get(0), function(elem) { return elem.val() == 7; }, "Input must be 7", 1);
//
// Your page must include a jquery library (1.7+) before this script
// Your page must contain an element with the ID "av_container". This is where the AV form is inserted in the DOM.
//
// All elements with the class "av_content" that are immediate children of the "body" tag will be shown with the AV form. 
// All elements with the class "av_ignore" will be shown whether or not the AV form is being shown. 
// All elements with the class "av_fail_hide" will be shown with the AV form, but hidden if AV fails. They must also have (or be a child of) the av_content class.
// All other page contents will be hidden when the AV form is being shown. 
//
// All elements with the class "av_submit" can be clicked on to submit the form.
// All elements with the classes "av_lang_en" or "av_lang_es" may be clicked on to change the language.
// "av_lang_selected" is applied to elements with "av_lang_en" or "av_lang_es" classes when the corresponding language is being displayed.
//
// TODO: Make language support accessible outside of this object
//
function AgeVerification() {
    var _this = this;
    var _isContentDisplayed = false;
    var _AVContainer = "#av_container"; // AV form is inserted here
    var _isMobile = document.isMobile || (function (a) { return (/android.+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|e\-|e\/|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|xda(\-|2|g)|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))); })(navigator.userAgent || navigator.vendor || window.opera); // uses number input types, doesn't redirect to thecoolspot.gov; detection code from http://detectmobilebrowsers.com/
	document.trackStateQueue = document.trackStateQueue || new Array();

    // START PAGE-DEFINED CALLBACK FUNCTIONS
    var _passCallback = false;
    this.PassCallback = function (val) { _passCallback = val; };
    var _failCallback = false;
    this.FailCallback = function (val) { _failCallback = val; };
    var _showCallback = false;
    this.ShowCallback = function (val) { _showCallback = val; if (isFormVisible()) { _showCallback(); } };
    var _contentCallback = false;
    this.ContentCallback = function (val) { _contentCallback = val; if (_isContentDisplayed) { _contentCallback(); } };
    // END PAGE-DEFINED CALLBACK FUNCTIONS


	function avTrackPage(state) {
		if (typeof trackPage == "function") {
			trackPage(document.title + " - " + state);
		} else { 
			document.trackStateQueue.push(state); 
		}
	}

    // START 'LOGIC'
    $(function () { // on jquery document ready
        if (hasValidBypassCookie()) {
            DisplayContent();
        } else {
            startTokenCheck();
            BindEvents();
            DisplayForm();

			avTrackPage('AV Display');
            if (_showCallback) { _showCallback(); }
        }
    });

    function SubmitForm() {
        if (isFormValid()) {
            var month = $("#av_month").val();
            var day = $("#av_day").val();
            var year = $("#av_year").val();

            if (isLegalAge(month, day, year)) {
				avTrackPage('AV Pass');
                DisplayContent();
            } else {
	            avTrackPage('AV Fail');
                DisplayFail();
            }
        }
    }
    // END 'LOGIC'


    // START LANGUAGE SETUP
    var _language = function (language) {
        var languages = {};
        languages.en = {
            Prompt: 'PLEASE ENTER YOUR DATE OF BIRTH',
            FailMessage: 'You must be of legal drinking age (21 or older) to enter our site. You are being redirected to http://www.thecoolspot.gov/ - a place for teens to find info on alcohol and resisting peer pressure.',
            MobileFailMessage: 'Sorry, you must be of legal drinking age to enter our site.',
            MonthPrompt: 'MM',
            InvalidMonth: 'Please enter a valid month',
            DayPrompt: 'DD',
            InvalidDay: 'Please enter a valid day',
            YearPrompt: 'YYYY',
            InvalidYear: 'Please enter a valid year',
            Submit: 'Submit'
        };

        languages.es = {
            Prompt: 'INDICA TU FECHA DE NACIMIENTO',
            FailMessage: 'Este sitio es para mayores de 21 a–os. La p‡gina se est‡ transfiriendo a thecoolspot.gov, donde hay informaci—n para adolescentes sobre el alcohol y c—mo resistir las presiones de grupo.',
            MobileFailMessage: 'Este sitio es para mayores de 21 a–os.',
            MonthPrompt: 'MM',
            InvalidMonth: 'Ingresa un mes v‡lido',
            DayPrompt: 'DD',
            InvalidDay: 'Ingresa un d’a v‡lido',
            YearPrompt: 'AAAA',
            InvalidYear: 'Ingresa un a–o v‡lido',
            Submit: 'Enviar'
        };

        if (typeof languages[language] == "undefined") { throw new Error('Invalid language'); }
        return languages[language];
    };

    var l = new _language(getBrowserLanguage());
    _this.Language = function (val) { l = new _language(val); if (isFormVisible()) { DisplayForm(); } };
    // END LANGUAGE SETUP


    // START VALIDATION SETUP
    var _validators = function () {
        var _validator = function (element, callbackFunction, errorMessage, maxCharacters) {
            this.element = element;
            this.callbackFunction = callbackFunction;
            this.errorMessage = errorMessage;
            this.maxCharacters = maxCharacters;

            this.IsValid = function () { return this.callbackFunction($(this.element).val()); };
            this.IsMaxLength = function () { return $(this.element).val().length == this.maxCharacters; };
        };

        var _validators = [];
        this.Add = function (element, callbackFunction, errorMessage, maxCharacters) {
            _validators.push(new _validator(element, callbackFunction, errorMessage, maxCharacters));
        };

        this.IsFieldComplete = function (element) {
            var isComplete = false;
            $(_validators).each(function () {
                if (this.element === element) {
                    isComplete = this.IsValid() && this.IsMaxLength();
                }
            });

            return isComplete;
        };

        this.getFormErrors = function () {
            var failed = [];
            $(_validators).each(function () {
                if (!this.IsValid()) { failed.push(this); }
            });
            return failed;
        };
    };

    function isValidYear(year) {
        if (!isNumeric(year)) { return false; }
        return ((year > 1890) && (year < 2020));
    }

    function isValidMonth(month) {
        if (!isNumeric(month)) { return false; }
        return ((month >= 1) && (month <= 12));
    }

    function isValidDay(day) {
        var month = $("#av_month").val();
        var year = $("#av_year").val();

        if (!isNumeric(day)) { return false; }
        if (!isNumeric(year)) { year = 2000; } // most permissive case (leap year) until we know otherwise
        if (!isValidMonth(month)) { month = 1; } // most permissive case (31 days) until we know otherwise

        var testDate = new Date(year, month - 1, day);
        return ((month == (testDate.getMonth() + 1)) && (day == testDate.getDate()));
    }

    function isNumeric(str) {
        return (/^\d+$/).test(str);
    }

    _this.Validators = new _validators();
    $(function () {
        _this.Validators.Add($("#av_month").get(0), isValidMonth, l.InvalidMonth, 2);
        _this.Validators.Add($("#av_day").get(0), isValidDay, l.InvalidDay, 2);
        _this.Validators.Add($("#av_year").get(0), isValidYear, l.InvalidYear, 4);
    });
    // END VALIDATION SETUP


    // START CHANGE PAGE STATE
    function BindEvents() {
        $(".av_lang_en, .av_lang_es").live('click', function () { _this.Language($(this).hasClass("av_lang_es") ? "es" : "en"); });

        $(".av_submit").live('click', SubmitForm);
        $(".av_form input").live('keyup', AutoTab);

        $("#av_month, #av_day, #av_year").live('focus', function () { $(this).select(); });
    }

    function DisplayForm(selectedLanguage) {
        $(".av_lang_selected").removeClass("av_lang_selected");
        $(".av_lang_" + selectedLanguage).addClass("av_lang_selected");

        $(".av_content_en, .av_content_es").hide();
        $(".av_content_" + selectedLanguage).show();

        var _inputType = _isMobile ? "number" : "text";
        var _avhtml = '<div class="av_form av_content">'
		+ '<div id="av_prompt">' + l.Prompt + '</div>'
		+ '<span id="av_errors" class="av_errors"></span>'
 		+ '<table><tr>'
		+ '<td><input type="' + _inputType + '" id="av_month" placeholder="' + l.MonthPrompt + '" maxLength="2" size="2" tabindex="1" autocomplete="off" /></td>'
		+ '<td><input type="' + _inputType + '" id="av_day" placeholder="' + l.DayPrompt + '" maxLength="2" size="2" tabindex="2" autocomplete="off" /></td>'
		+ '<td><input type="' + _inputType + '" id="av_year" placeholder="' + l.YearPrompt + '" maxLength="4" size="4" tabindex="3" autocomplete="off" /></td>'
		+ '</tr></table>'
		+ '<div id="av_submit" class="av_submit" style="cursor:pointer;">' + l.Submit + '</div>'
		+ '</div>';

        $("body").children(":not(.av_content, .av_ignore, script)").wrapAll('<div style="display: none;" class="av_hidden-content" />');
        $(_AVContainer).children(".av_form").remove();
        $(_AVContainer).append(_avhtml);
        $(".av_content").show();

        placeholderHack();

        $("#av_month").focus();
    }

    function DisplayContent() {
        SetCookie();

        $(".av_content").hide();
        $(".av_hidden-content").children().unwrap();
		
		_isContentDisplayed = true;
        if (_contentCallback) { _contentCallback(); }
        if (_passCallback) { _passCallback(); }
    }

    function DisplayFail() {
        $(".av_fail_hide").hide();
        $(".av_form").html('<div id="av_fail">' + (_isMobile ? l.MobileFailMessage : l.FailMessage) + '</div>');
        if (!_isMobile) {
            setTimeout(function () { document.location.href = "http://www.thecoolspot.gov"; }, 5000);
        }

        if (_failCallback) { _failCallback(); }
    }
    // END CHANGE PAGE STATE


    // START DYNAMIC HELPER FUNCTIONS (interact with DOM)
    function placeholderHack() {
        var input = document.createElement('input');

        if (!('placeholder' in input)) {
            $("#av_month, #av_day, #av_year").unbind('blur')
	        .blur(function () { if ($(this).val() == "") { $(this).val($(this).attr("placeholder")); } })
                .each(function () { $(this).val($(this).attr("placeholder")); });
        }
    }

    function isFormVisible() {
        return $('.av_form').filter(':visible').length > 0;
    }

    function AutoTab(e) {
        if (e.keyCode == 13) {
            SubmitForm();
        } else if ((e.keyCode >= 48 && e.keyCode < 58) || (e.keyCode >= 96 && e.keyCode < 106)) { // a number or letter
            if (_this.Validators.IsFieldComplete($(this).get(0))) {
                focusNextInput($(this));
            }
        }
    }

    function focusNextInput(currentInput) {
        var inputs = $("input:visible");
        inputs.sort(function (a, b) { return ((-$(a).attr('tabindex')) < (-$(b).attr('tabindex'))) ? 1 : 0; });

        var currentIndex = $.inArray($(inputs).filter("[tabindex='" + $(currentInput).attr('tabindex') + "']").get(0), $(inputs));
        var nextElement = $(inputs).slice(currentIndex).get(1);

        if (typeof nextElement != "undefined") { $(nextElement).focus(); }
    }

    function isFormValid() {
        $("#av_errors").html("");

        var results = _this.Validators.getFormErrors();
        $(results).each(function () { $("#av_errors").append('<div class="av_error">' + this.errorMessage + '</div>'); });
        $(results).first().each(function () { $(this.element).select(); });

        return (results.length === 0);
    }
    // END DYNAMIC HELPER FUNCTIONS


    // START STATIC HELPER FUNCTIONS
    function hasValidBypassCookie() {
        return (readCookie("site") != null);
    }

    function startTokenCheck() {
        var avtoken = getParameterByName("avtoken");
        if (avtoken != null) {
            $.ajax({ dataType: "jsonp",
                url: 'http://stage.avbypass.millercoors.com/CheckToken.aspx?token=' + avtoken,
                success: function (resp) { if (resp.IsValid == true) { DisplayContent(); } }
            });
        }
    }

    function getParameterByName(name) {
        var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
        return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
    }

    function getBrowserLanguage() {
        var _browserLanguage = ((navigator.language) ? navigator.language : navigator.userLanguage);
        return (_browserLanguage.substring(0, 2) == "es") ? "es" : "en";
    }

    function SetCookie() {
        document.cookie = "site=" + document.domain.replace(/\./, "") + "av; path=/";
    }

    function readCookie(name) {
        var nameEQ = name + "=";
        var ca = document.cookie.split(';');
        for (var i = 0; i < ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0) == ' ') { c = c.substring(1, c.length); }
            if (c.indexOf(nameEQ) === 0) { return c.substring(nameEQ.length, c.length); }
        }

        return null;
    }

    function isLegalAge(month, day, year) {
        var minDate = new Date((year - -21), month - 1, day);
        var maxDate = new Date((year - -120), month - 1, day);
        var today = new Date();

        return (((today.getTime() - minDate.getTime()) >= 0) && ((today.getTime() - maxDate.getTime()) < 0));
    }
    // END STATIC HELPER FUNCTIONS
};
document.AgeVerification = document.AgeVerification || new AgeVerification();
