(function () {
    require(["errorAggregationService"], passwordValidationService);

    function passwordValidationService(errorAggregationService) {
        var passwordInput,
            passwordConfirmationInput,
            submitButton,
            revealPasswordButton,
            errorKey = "passwordErrors",
            alertClass = "alert-danger",
            feedbackClass = "glyphicon-ok",
            passwordMismatchError = "Your password doesn’t match.",
            passwordRequiredError = "Please enter your password.",
            passwordStrengthTester,
            shortPassword = { type: "short", message: "Please try again with a longer password.", hint: "Password is too short." },
            longPassword = { type: "long", message: "Please try again with a shorter password.", hint: "Password is too long." },
            weakPassword = { type: "weak", message: "Enter a password with upper and lower case letters, and numbers.", hint: "Weak Password." },
            okPassword = { type: "ok", message: "", hint: "" },
            strongPassword = { type: "strong", message: "", hint: "" };

        $(initialize);

        function initialize() {
            passwordInput = $("input#password");
            passwordConfirmationInput = $("input#confirm-password");
            submitButton = $("button[type='submit']");
            if (passwordInput.length != 1 || passwordConfirmationInput.length != 1 || submitButton.length != 1) {
                // console.log("Password validation logic can't be initialized for this view.");
                return;
            }
            bindTextInput(passwordInput, true);
            bindTextInput(passwordConfirmationInput);
            passwordStrengthTester = new PasswordStrengthTest();
            showStrongPasswordFeedback(passwordInput, false);
            showStrongPasswordFeedback(passwordConfirmationInput, false);
            revealPasswordButton = $("#show-hide-password");
            revealPasswordButton.unbind("click").bind("click", showHidePassword);
            passwordInput.unbind("blur").bind("blur", validateAndSetPasswordErrors);
            submitButton.bind("click", validateForm);
        }

        function bindTextInput(input, chain) {
            if (chain) {
                input.bind("keyup", validateAndClear);
                input.bind("paste", validateAndClear);
                input.bind("input", validateAndClear);
            } else {
                input.unbind("keyup").bind("keyup", validateAndClear);
                input.unbind("paste").bind("paste", validateAndClear);
                input.unbind("input").bind("input", validateAndClear);
            }
        }

        function enableSubmitButton(enable) {
            submitButton.prop("disabled", !enable);
        }

        function setErrors(errorsSummary, hasPasswordErrors, hasPasswordConfirmationErrors) {
            if (hasPasswordErrors) {
                passwordInput.addClass(alertClass);
            } else {
                passwordInput.removeClass(alertClass);
            }
            if (hasPasswordConfirmationErrors) {
                passwordConfirmationInput.addClass(alertClass);
            }else {
                passwordConfirmationInput.removeClass(alertClass);
            }
            if (errorsSummary) {
                errorAggregationService.addError(errorKey, errorsSummary);
            }else {
                errorAggregationService.deleteError(errorKey);
            }
        }

        function showStrongPasswordFeedback(input, isStrong) {
            var feedbackInput = input.parent().find("." + feedbackClass);
            if (isStrong) {
                feedbackInput.show();
            } else {
                feedbackInput.hide();
            }
        }

        function updatePasswordErrors(errors) {
            $("#password-errors").text(errors);
        }

        function validateAndClear() {
            validate(true);
        }

        function validateAndSetPasswordErrors() {
            validate(true, true);
        }

        function validateForm(event) {
            function stopProcessing() {
                if (!event) {
                    event = window.event;
                }
                if (!event) {
                    return;
                }
                if (typeof event.stopPropagation == "function") {
                    event.stopPropagation();
                } else {
                    event.cancelBubble = true;
                }
                if (typeof event.preventDefault == "function") {
                    event.preventDefault();
                } else {
                    event.returnValue = false;
                }
            }

            if (!validate(true, true, true)) {
                stopProcessing();
                return false;
            }
        }

        function validate(clearErrors, setPasswordErrors, validateForm) {
            var passwordVal = passwordInput.val(),
                passwordConfirmVal = passwordConfirmationInput.val(),
                hasPasswordErrors = false,
                hasPasswordConfirmationErrors = false,
                errors = "",
                strength,
                isStrongPassword;

            if (!passwordVal) {
                showStrongPasswordFeedback(passwordInput, false);
                showStrongPasswordFeedback(passwordConfirmationInput, false);
                hasPasswordErrors = false;
                updatePasswordErrors("");
                if (passwordConfirmVal) {
                    if (validateForm) {
                        hasPasswordConfirmationErrors = true;
                        errors = passwordMismatchError;
                    }
                }else {
                    if (validateForm) {
                        hasPasswordErrors = true;
                        errors = passwordRequiredError;
                    }
                    hasPasswordConfirmationErrors = false;
                }
            }else {
                strength = passwordStrengthTester.test(passwordVal);
                if (strength != okPassword.type && strength != strongPassword.type) {
                    isStrongPassword = false;
                    if (setPasswordErrors) {
                        updatePasswordErrors(passwordStrengthTester.hint);
                    }
                    if (validateForm) {
                        hasPasswordErrors = true;
                        errors = passwordStrengthTester.message;
                    }
                } else {
                    updatePasswordErrors("");
                    isStrongPassword = (strength == strongPassword.type);
                }
                showStrongPasswordFeedback(passwordInput, isStrongPassword);
                if (!passwordConfirmVal) {
                    hasPasswordConfirmationErrors = !!validateForm;
                    showStrongPasswordFeedback(passwordConfirmationInput, false);
                    if (validateForm) {
                        hasPasswordConfirmationErrors = true;
                        errors = passwordMismatchError;
                    }
                } else {
                    if (passwordConfirmVal !== passwordVal) {
                        if (validateForm) {
                            hasPasswordConfirmationErrors = true;
                            errors = passwordMismatchError;
                        }
                        showStrongPasswordFeedback(passwordConfirmationInput, false);
                    }else {
                        showStrongPasswordFeedback(passwordConfirmationInput, isStrongPassword);
                    }
                }
            }
            if (clearErrors && !errors || setPasswordErrors || setConfirmPasswordErrors) {
                setErrors(errors, hasPasswordErrors, hasPasswordConfirmationErrors);
            }
            return !hasPasswordErrors && !hasPasswordConfirmationErrors;
        }

        function showHidePassword() {
            var currentTitle = revealPasswordButton.text(),
                showPrompt = "Show Characters",
                hidePrompt = "Hide Characters";

            if (!currentTitle) {
                return;
            }
            if (currentTitle == showPrompt) {
                passwordConfirmationInput[0].type = "text";
                passwordInput[0].type = "text";
                revealPasswordButton.text(hidePrompt);
            } else {
                passwordConfirmationInput[0].type = "password";
                passwordInput[0].type = "password";
                revealPasswordButton.text(showPrompt);
            }
        }

        function PasswordStrengthTest() {
            var self = this,
                minChars = 8,
                maxChars = 25;

            self.score = null;

            function testUpperLetters(inputValue) {
                var regexp = /[A-Z]/g,
                    letters = inputValue.match(regexp);

                if (letters) {
                    if (letters.length === 1) {
                        self.score += 15;
                    } else {
                        self.score += 25;
                    }
                    return true;
                } else {
                    return false;
                }
            }

            function testLowLetters(inputValue) {
                var regexp = /[a-z]/g,
                    letters = inputValue.match(regexp);

                if (letters) {
                    if (letters.length === 1) {
                        self.score += 15;
                    } else {
                        self.score += 25;
                    }
                    return true;
                } else {
                    return false;
                }
            }

            function testNumbers(inputValue) {
                var regexp = /[0-9]/g,
                    numbers = inputValue.match(regexp);

                if (numbers) {
                    if (numbers.length === 1) {
                        self.score += 15;
                    } else {
                        self.score += 25;
                    }
                    return true;
                } else {
                    return false;
                }
            }

            // Test for non alpha-numeric chars.

            function testSpecialChars(inputValue) {
                var characters = inputValue.match(/[^\w]/g) || [];

                if (characters.length === 0) {
                    self.score += 0;
                } else if (characters.length === 1) {
                    self.score += 15;
                } else {

                    self.score += 25;
                }
            }

            this.getScore = function () {
                return self.score;
            }

            this.test = function (inputValue) {
                var strengthClass;

                if (inputValue.length < minChars) {
                    this.message = shortPassword.message;
                    this.hint = shortPassword.hint;
                    strengthClass = shortPassword.type;
                } else if (inputValue.length >= maxChars) {
                    this.message = longPassword.message;
                    this.hint = longPassword.hint;
                    strengthClass = longPassword.type;
                } else {
                    containsNumbers = testNumbers(inputValue);
                    containsUpperLetters = testUpperLetters(inputValue);
                    containsLowLetters = testLowLetters(inputValue);
                    testSpecialChars(inputValue);

                    if (!containsNumbers || !containsUpperLetters || !containsLowLetters) {
                        this.message = weakPassword.message;
                        this.hint = weakPassword.hint;
                        strengthClass = weakPassword.type;
                    } else if (this.getScore() <= 65) {
                        this.message = okPassword.message;
                        strengthClass = okPassword.type;
                    } else {
                        this.message = strongPassword.message;
                        strengthClass = strongPassword.type;
                    }
                }
                return strengthClass;
            }
        }
    }
})();

(function () {
    define("errorAggregationService", errorAggregationService);

    function errorAggregationService() {
        var errors = {},
            callbacks = [];

        function addError(key, error) {
            errors[key] = error;
            notifyAll();
            return;
        }

        function deleteError(key) {
            delete errors[key];
            notifyAll();
        }

        function registerCallback(callback) {
            if (typeof callback == "function") {
                callbacks.push(callback);
            }
        }

        function getErrors() {
            var error,
                errorKey,
                aggregatedErrors = "";

            for (errorKey in errors) {
                if (errors.hasOwnProperty(errorKey) &&
                    (error = errors[errorKey]) != null && error.length
                ) {
                    if (aggregatedErrors) {
                        aggregatedErrors += "<br />";
                    }
                    aggregatedErrors += error;
                }
            }
            return aggregatedErrors;
        }

        function notifyAll() {
            callbacks.forEach(function (callback) {
                callback(getErrors());
            });
        }

        return {
            addError: addError,
            deleteError: deleteError,
            getErrors: getErrors,
            registerCallback: registerCallback
        };
    }
})();

(function () {
    define("browserValidationService", browserValidationService);

    function browserValidationService() {
        var modal;

        function isCurrentBrowserSupported() {
            try {
                return Modernizr.mq("only all");
            }catch (ex) {
                console.log(ex.message);
            }
            return false;
        }

        function validateBrowser(modalSelector) {
            var dataUrl = "/Home/BrowserUpdateModal",
                modalId = "browser-validation-modal";

            function doValidation() {
                // initialize modal in the specified container in case current browser is not supported
                $.ajax({
                    url: dataUrl,
                    method: "GET"
                }).done(function (data) {
                    if (!data) {
                        return;
                    }
                    $(modalSelector).append('<div id="' + modalId + '"></div>');
                    modal = $("#" + modalId);
                    modal.append(data);
                    showCurtain();
                    hookCloseButton();
                    hookBrowserLinks();
                    modal.css("display", "block");
                });
            }

            function checkjQuery(callback) {
                var script = document.createElement("script");

                function checkReady() {
                    if (window.jQuery) {
                        if (typeof callback == "function") {
                            callback();
                        }
                    } else {
                        setTimeout(checkReady, 100);
                    }
                }

                script.src = "/resources/javascript/jquery-1.7.1.min.js";
                script.type = "text/javascript";
                document.getElementsByTagName("head")[0].appendChild(script);
                checkReady();
            }

            if (!modalSelector || isCurrentBrowserSupported()) {
                return;
            }
            checkjQuery(doValidation);
        }

        function showCurtain() {
            var curtain;

            if (!$(".curtain").length) {
                curtain = '<div class="curtain">&nbsp;</div>';
                $("body").append(curtain);
            }
        }

        function hideCurtain() {
            var curtain = $("body .curtain");

            curtain.fadeOut("fast", function () {
                $(this).remove();
            })
        }

        function hookCloseButton() {
            $("a.browser-validation-modal-close").click(function (event) {
                hideCurtain();
                if (modal && modal.length) {
                    modal.hide();
                }
            });
        }

        function hookBrowserLinks() {
            var downloadMap = {
                "browser-chrome": "https://www.google.com/chrome/browser/desktop/",
                "browser-firefox": "https://www.mozilla.org/en-US/firefox/new/",
                "browser-explorer": "http://windows.microsoft.com/en-us/internet-explorer/download-ie",
                "browser-safari": "http://www.apple.com/safari/"
            };

            $(".browser-link").click(function (event) {
                if (!this.id || !downloadMap.hasOwnProperty(this.id)) {
                    return;
                }
                window.open(downloadMap[this.id], "_blank");
            });
        }

        return {
            isCurrentBrowserSupported: isCurrentBrowserSupported,
            validateBrowser: validateBrowser
        };
    }
})();
