"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var validation_nls_1 = require("./validation.nls");
var vdom_1 = require("@dojo/framework/core/vdom");
var i18n_1 = require("@dojo/framework/core/middleware/i18n");
var upperCaseRegEx = /[A-Z]/;
var numbersRegEx = /\d/;
/* OWASP Special Characters: https://www.owasp.org/index.php/Password_special_characters */
var specialCharactersRegEx = new RegExp([
    ' ',
    '!',
    '"',
    '#',
    '\\$',
    '%',
    '&',
    "'",
    '\\(',
    '\\)',
    '\\*',
    '\\+',
    ',',
    '-',
    '\\.',
    '/',
    ':',
    ';',
    '<',
    '=',
    '>',
    '\\?',
    '@',
    '\\[',
    '\\\\',
    '\\]',
    '\\^',
    '_',
    '`',
    '{',
    '\\|',
    '}',
    '~'
].join('|'));
var validationFactory = vdom_1.create({ i18n: i18n_1.default });
var validation = validationFactory(function validation(_a) {
    var i18n = _a.middleware.i18n;
    var format = i18n.localize(validation_nls_1.default).format;
    function formatList(atLeast, list) {
        var fixedList = tslib_1.__spread(list);
        if (list.length > 1) {
            if (atLeast) {
                fixedList[fixedList.length - 1] = format('or', {
                    rule: fixedList[fixedList.length - 1]
                });
            }
            else {
                fixedList[fixedList.length - 1] = format('and', {
                    rule: fixedList[fixedList.length - 1]
                });
            }
        }
        if (fixedList.length === 1 && !atLeast) {
            return format('mustContain', { rules: fixedList[0] });
        }
        return format('mustContain', {
            rules: format(atLeast ? 'atLeastOf' : 'allOf', {
                count: atLeast,
                rules: fixedList.join(', ')
            })
        });
    }
    var validators = {
        length: {
            validate: function (_a, value) {
                var min = _a.min, max = _a.max;
                if (min !== undefined) {
                    if (value.length < min) {
                        return {
                            valid: false,
                            message: format('minimumLength', { length: min })
                        };
                    }
                }
                if (max !== undefined) {
                    if (value.length > max) {
                        return {
                            valid: false,
                            message: format('maximumLength', { length: max })
                        };
                    }
                }
            },
            describe: function (_a) {
                var min = _a.min, max = _a.max;
                var limits = [];
                if (min !== undefined) {
                    limits.push(format('minimumLength', { length: min }));
                }
                if (max !== undefined) {
                    limits.push(format('maximumLength', { length: max }));
                }
                return limits;
            }
        },
        contains: {
            validate: function (_a, value) {
                var atLeast = _a.atLeast, _b = _a.uppercase, uppercase = _b === void 0 ? 0 : _b, _c = _a.numbers, numbers = _c === void 0 ? 0 : _c, _d = _a.specialCharacters, specialCharacters = _d === void 0 ? 0 : _d;
                var failures = [];
                var uppercaseTotal = 0;
                var numberTotal = 0;
                var specialTotal = 0;
                var containsAtLeast = atLeast || 0;
                var successes = 0;
                if (atLeast === undefined) {
                    containsAtLeast =
                        (uppercase ? 1 : 0) + (numbers ? 1 : 0) + (specialCharacters ? 1 : 0);
                }
                for (var i = 0; i < value.length; i++) {
                    var c = value.charAt(i);
                    uppercaseTotal += uppercase && upperCaseRegEx.test(c) ? 1 : 0;
                    numberTotal += numbers && numbersRegEx.test(c) ? 1 : 0;
                    specialTotal += specialCharacters && specialCharactersRegEx.test(value) ? 1 : 0;
                }
                if (uppercaseTotal < uppercase) {
                    failures.push(format('uppercase', {
                        count: uppercase
                    }));
                }
                else if (uppercase) {
                    successes++;
                }
                if (numberTotal < numbers) {
                    failures.push(format('numbers', {
                        count: numbers
                    }));
                }
                else if (numbers) {
                    successes++;
                }
                if (specialTotal < specialCharacters) {
                    failures.push(format('specialCharacters', {
                        count: specialCharacters
                    }));
                }
                else if (specialCharacters) {
                    successes++;
                }
                if (successes < containsAtLeast) {
                    return {
                        valid: false,
                        message: formatList(atLeast ? containsAtLeast - successes : undefined, failures)
                    };
                }
            },
            describe: function (_a) {
                var atLeast = _a.atLeast, uppercase = _a.uppercase, numbers = _a.numbers, specialCharacters = _a.specialCharacters;
                var types = [];
                if (uppercase) {
                    types.push(format('uppercase', {
                        count: uppercase
                    }));
                }
                if (numbers) {
                    types.push(format('numbers', {
                        count: numbers
                    }));
                }
                if (specialCharacters) {
                    types.push(format('specialCharacters', {
                        count: specialCharacters
                    }));
                }
                return [formatList(atLeast, types)];
            }
        }
    };
    return function (rules) {
        function validator(value) {
            var failedResults = Object.keys(rules)
                .map(function (rule) {
                return validators[rule] && validators[rule].validate(rules[rule], value);
            })
                .filter(function (result) { return result && !result.valid; });
            if (failedResults.length) {
                return {
                    valid: false,
                    message: failedResults.map(function (result) { return (result ? result.message : ''); }).join(' ')
                };
            }
        }
        validator.describe = function () {
            return Object.keys(rules).reduce(function (prev, rule) { return tslib_1.__spread(prev, validators[rule].describe(rules[rule])); }, []);
        };
        return validator;
    };
});
exports.default = validation;

/*# sourceMappingURL=validation.js.map*/