
(function () {
    var init = function () {
        var that = this;
        $.ajax({
            url: this.url(),
            async: false,
            cache: that.cache,
            contentType: this.contentType,
            data: { methodName: that.methodNames.Init },
            success: function (result) {
                that.isActvieSecurity = result.IsActvieSecurity;
                that.passwordParam = result.PasswordParam;
            },
            error: function () {
            }
        });
    }

    var eosEncode = function (val) {
        
        var inputString = val;
        var result = "";
        //for (var i = 0; i < inputString.length ; i++) {
        //    var encodedChar = windows1256.encode(inputString[i]);
        //    var newwEncodedChar = String.fromCharCode(encodedChar.charCodeAt(0) ^ (0x1F * (i + 1)));

        //    if (!(newwEncodedChar.charCodeAt(0) === 10 || newwEncodedChar.charCodeAt(0) === 13)) {
        //        result += newwEncodedChar;
        //    }
        //    //result += newwEncodedChar;
        //}

        for (var i = 0; i < inputString.length ; i++) {
            var encodedChar = windows1256.encode(inputString.charAt(i));
            var bbb = encodedChar.charCodeAt(0);

            var newwEncodedChar = String.fromCharCode(bbb ^ (0x1F * (i + 1)));

            var aaa = newwEncodedChar.charCodeAt(0);

            if (!(aaa === 10 || aaa === 13)) {
                result += newwEncodedChar;
            }
            //result += newwEncodedChar;
        }

        //var bytes = new TextEncoder('windows-1256', { NONSTANDARD_allowLegacyEncoding: true }).encode(inputString);
        //for (var i = 0; i < bytes.length ; i++) {
        //    result += String.fromCharCode(bytes[i] ^ (0x1F * (i + 1)));
        //}
        
        var test = result.toString();

        return result;
    }

    var eosHash = function (val) {
        var result = sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash(val)).toUpperCase();
        return result;
    }
    var isDigit = function (val) { return /^\d$/.test(val); }
    var isSymbolOrPunctuation = function (val) { return /[!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~]/.test(val); }
    var isUpper = function (val) { return val === val.toUpperCase() && !isDigit(val) && !isSymbolOrPunctuation(val); }
    var isLower = function (val) { return val === val.toLowerCase() && !isDigit(val) && !isSymbolOrPunctuation(val); };
    var isLetter = function (val) { return (/^[a-z]/i.test(val)) || (/^[آ-ی]/i.test(val)); }

    var strReverse = function (val) { return val.split("").reverse().join(""); }

    var securityManager = function () {
        init.call(this);
    };

    securityManager.prototype = {
        //url: "Handlers/SecurityManager.ashx",
        url: function () {
             return "Handlers/SecurityManager.ashx";
            //return $("#systemSecurityUrl").val() + "Handlers/SecurityManager.ashx";
        },
        contentType: "application/json; charset=utf-8",
        cache: false,
        EncryptionType: { OldEncoding: 0, Sha256: 1 },
        SystemEncriptionType: 0,
        methodNames: {
            Init: "Init",
            GetSystemEncryptionType: "GetSystemEncryptionType",
            GetUserEncryptionType: "GetUserEncryptionType",
            GetValidationData: "GetValidationData"
        },
        passwordParam: {
            UserPassMinLength: 0,
            UserPassCharTypeCount: 0,
            AdminPassMinLength: 0,
            AdminPassCharTypeCount: 0,
            HasRepeatChar: false,
            MaxRepeatPassCount: 0,
            HasPersonalityInformation: false,
            MaxPassChangePerDay: 0
        }
    };

    var scanPassword = function (password, groupCountRequired, checkRepeatChar, setting) {
        var iUpperCase = 0;
        var iLowerCase = 0;
        var iDigit = 0;
        var iSymbol = 0;
        var consecutiveMode = 0;
        var iConsecutiveUpper = 0;
        var iConsecutiveLower = 0;
        var iConsecutiveDigit = 0;
        var iRepeated = 1;
        var isDuplicateChar = false;
        var sAlphas = "abcdefghijklmnopqrstuvwxyz";
        var sNumerics = "01234567890";
        var nSeqAlpha = 0;
        var nSeqChar = 0;
        var nSeqNumber = 0;
        var htRepeated = [];
        var sFwd = "";
        var sRev = "";


        var groupCount = 0;


        for (var i = 0; i < password.length; i++) {
            var ch = password.charAt(i);

            // Count digits
            if (isDigit(ch)) {
                iDigit++;
                if (consecutiveMode === 3)
                    iConsecutiveDigit++;

                consecutiveMode = 3;
                for (var k = 0; k < htRepeated.length; k++) {
                    if (htRepeated[k] === ch) {
                        iRepeated++;
                        isDuplicateChar = true;
                    }
                }

                if (!isDuplicateChar) {
                    isDuplicateChar = false;
                    htRepeated.push(ch);
                }

                //if (htRepeated.filter(function (t) { return t == ch; }).length > 0) {
                //    iRepeated++;
                //}
                //else {
                //    htRepeated.push(ch);
                //}
            }

            // Count uppercase characters
            if (isUpper(ch)) {
                iUpperCase++;
                if (consecutiveMode === 1)
                    iConsecutiveUpper++;
                consecutiveMode = 1;
            }

            // Count lowercase characters
            if (isLower(ch)) {
                iLowerCase++;
                if (consecutiveMode === 2)
                    iConsecutiveLower++;
                consecutiveMode = 2;
            }

            if (isLetter(ch)) {
                for (var kk = 0; kk < htRepeated.length; kk++) {
                    if (htRepeated[kk] === ch) {
                        iRepeated++;
                        isDuplicateChar = true;
                        break;
                    }
                }

                if (!isDuplicateChar) {
                    isDuplicateChar = false;
                    htRepeated.push(ch);
                }

                //if (htRepeated.filter(function (t) { return t == ch; }).length > 0) {
                //    iRepeated++;
                //} else {
                //    htRepeated.push(ch);
                //}
            }

            // Count symbols
            if (isSymbolOrPunctuation(ch)) {
                iSymbol++;
                consecutiveMode = 0;
                for (var kkk = 0; kkk < htRepeated.length; kkk++) {
                    if (htRepeated[kkk] === ch) {
                        iRepeated++;
                        isDuplicateChar = true;
                        break;
                    }
                }

                if (!isDuplicateChar) {
                    isDuplicateChar = false;
                    htRepeated.push(ch);
                }

                //if (htRepeated.filter(function (t) { return t == ch; }).lenght > 0) {
                //    iRepeated++;
                //} else {
                //    htRepeated.push(ch);
                //}
            }

        }

        // Check for sequential alpha string patterns (forward and reverse)
        for (var s = 0; s < 26; s++) {
            sFwd = sAlphas.substring(s, s + 3);
            sRev = strReverse(sFwd);
            if (password.toLowerCase().indexOf(sFwd) !== -1 ||
                password.toLowerCase().indexOf(sRev) !== -1) {
                nSeqAlpha++;
                nSeqChar++;
            }
        }

        // Check for sequential numeric string patterns (forward and reverse)
        for (var j = 0; j < 8; j++) {
            sFwd = sNumerics.substring(j, j + 3);
            sRev = strReverse(sFwd);
            if (password.toLowerCase().indexOf(sFwd) !== -1 ||
                password.toLowerCase().indexOf(sRev) !== -1) {
                nSeqNumber++;
                nSeqChar++;
            }
        }

        if (iDigit > 0)
            groupCount++;

        if (iUpperCase > 0)
            groupCount++;

        if (iLowerCase > 0)
            groupCount++;

        if (iSymbol > 0)
            groupCount++;

        if (groupCount < groupCountRequired)
            return "رمزعبور باید شامل حداقل " + setting.UserPassCharTypeCount + " گروه از حروف انگلیسی بزرگ و کوچک، اعداد و علائم باشد ";

        if (setting.HasRepeatChar) {
            if (iRepeated > 1)
                return "رمز عبور نمی تواند شامل کاراکترهای تکراری باشد";

            if (nSeqAlpha > 0) {
                return "رمز عبور نمی تواند شامل کاراکترهای متوالی باشد";
            }

            if (nSeqNumber > 0) {
                return "رمز عبور نمی تواند شامل کاراکترهای متوالی باشد";
            }
        }


        return true;
    }

    securityManager.prototype.validate = function (userName, password) {
        var that = this;
        var personInfo = {};
        var passwordList = [];
        var exceededMaxPassChangePerDay = false;
        var setting = that.passwordParam;
        if (!that.isActvieSecurity) return !that.isActvieSecurity;

        $.ajax({
            url: that.url(),
            async: false,
            cache: that.cache,
            contentType: that.contentType,
            data: { methodName: that.methodNames.GetValidationData, UserName: userName, MaxPassChangePerDay: setting.MaxPassChangePerDay },
            success: function (result) {
                personInfo = result.personInfo;
                passwordList = result.passwordList;
                exceededMaxPassChangePerDay = result.exceededMaxPassChangePerDay;
            }
        });

        if (personInfo.PerNo == null) {
            return "شماره پرسنلی نامعتبر است ";
        }

        var oldEncryptedPass = "";
        var hashedPass = "";
        try {
            oldEncryptedPass = eosEncode(password);
            hashedPass = eosHash(password);
        } catch (e) {
            return "خطا در رمز نگاری کلمه عبور";
        }

        //if (setting.MaxRepeatPassCount > 0 && passwordList.filter(function (t) { return t == oldEncryptedPass || t == hashedPass }).length > 0)
        //{
        //    return "رمزعبور جدید نمی تواند یکی از " + setting.MaxRepeatPassCount + " رمزعبور قبلی شما باشد";
        //}

        if (setting.MaxRepeatPassCount > 0) {
            for (var k = 0; k < passwordList.length; k++) {
                if (passwordList[k] === oldEncryptedPass || passwordList[k] === hashedPass) {
                    return "رمزعبور جدید نمی تواند یکی از " + setting.MaxRepeatPassCount + " رمزعبور قبلی شما باشد";
                }
            }
        }


        if (!exceededMaxPassChangePerDay) {
            return " تغییر رمز عبور در یک روز بیشتر از " + setting.MaxPassChangePerDay + " مرتبه امکانپذیر نیست.";
        }


        if (userName.trim() !== "Admin") {
            if (password.trim().length < setting.UserPassMinLength) {
                return "حداقل طول رمز عبور " + setting.UserPassMinLength + " کاراکتر می باشد";
            }

            if (setting.HasPersonalityInformation) {

                if (personInfo.ShenasNo != null && personInfo.ShenasNo !== "" && password.trim().toLowerCase().indexOf(personInfo.ShenasNo.toLowerCase()) !== -1) {
                    return "شماره شناسنامه نمی تواند به عنوان رمز عبور انتخاب شود";
                }


                if (personInfo.FatherName != null && personInfo.FatherName && windows1256.encode(password).match(new RegExp(windows1256.encode(personInfo.FatherName), "g")) != null) {
                    return "نام پدر نمی تواند به عنوان رمز عبور انتخاب شود";
                }

                if (personInfo.FirstName != null && personInfo.FirstName && windows1256.encode(password).match(new RegExp(windows1256.encode(personInfo.FirstName), "g")) != null) {
                    return "نام  نمی تواند به عنوان رمز عبور انتخاب شود";
                }

                if (personInfo.LastName != null && personInfo.LastName && windows1256.encode(password).match(new RegExp(windows1256.encode(personInfo.LastName), "g")) != null) {
                    return "نام خانوادگی نمی تواند به عنوان رمز عبور انتخاب شود";
                }


                if (personInfo.BirthDate != null && personInfo.BirthDate.trim() !== "") {
                    if (password.trim().toLowerCase().indexOf(personInfo.BirthDate.substring(0, 4)) !== -1 ||
                        password.trim().toLowerCase().indexOf( personInfo.BirthDate.substring(0, 4)) !== -1) {
                        return "سال تولد نمی تواند به عنوان رمز عبور انتخاب شود";
                    }

                    if (password.trim().toLowerCase().indexOf(personInfo.BirthDate) !== -1) {
                        return "تاریخ تولد نمی تواند به عنوان رمز عبور انتخاب شود";
                    }


                    if (password.trim().toLowerCase().indexOf(personInfo.BirthDate.substring(5)) !== -1
                        || password.trim().toLowerCase().replace(/\//g, "").indexOf(personInfo.BirthDate.replace(/\//g, "").substring(2)) !== -1) {
                        return "ماه تولد نمی تواند به عنوان رمز عبور انتخاب شود";
                    }


                }

            }

            return scanPassword(password, setting.UserPassCharTypeCount, setting.HasRepeatChar, setting);
        }

        if (password.trim().length < setting.AdminPassMinLength)
            return "حداقل طول رمز عبور " + setting.AdminPassCharTypeCount + " کاراکتر می باشد";

        return scanPassword(password, setting.AdminPassCharTypeCount, setting.HasRepeatChar, setting);
    };

    securityManager.EncryptLoginPass = function (userName, plainPassword, isChangingDb, serverName, dbName, dbUserName, dbPassword) {
        plainPassword = String(plainPassword);
        var that = this.prototype;
        var data = { methodName: that.methodNames.GetUserEncryptionType, userName: userName, isChangingDb: false };
        var loginResult = { success: false, result: "", message: "" };
        if (isChangingDb) {
            data.isChangingDb = true;
            data.serverName = serverName;
            data.dbName = dbName;
            data.dbUserName = dbUserName;
            data.dbPassword = dbPassword;
        }


        $.ajax({
            url: that.url(),
            contentType: that.contentType,
            async: false,
            cache: that.cache,
            data: data,
            success: function (result) {
            if (result.Success) {
                    try {
                        if (that.EncryptionType.OldEncoding === result.Result) {

                            loginResult.result = eosEncode(plainPassword);

                        }
                        else {
                            loginResult.result = eosHash(plainPassword);
                        }
                        loginResult.success = true;
                        return;
                    } catch (e) {
                        loginResult.message = e.message;
                        return;
                    }
                } else {
                    loginResult.message = result.Message;
                    return;
                }
            },
            error: function () {
                loginResult.message = "عملیات ورود به سیستم با خطا مواجه شد";
            }
        });
        return loginResult;
    }

    securityManager.EncryptNewPass = function (plainPassword) {
        plainPassword = String(plainPassword);
        var that = this.prototype;
        var encryptResult = { success: false, result: "", message: "" };
        $.ajax({
            url: that.url(),
            async: false,
            cache: that.cache,
            contentType: that.contentType,
            data: { methodName: that.methodNames.GetSystemEncryptionType },
            success: function (result) {
                try {
                    if (that.EncryptionType.OldEncoding === result) {
                        encryptResult.result = eosEncode(plainPassword);
                    } else {
                        encryptResult.result = eosHash(plainPassword);
                    }
                    encryptResult.success = true;
                    return;
                } catch (e) {
                    encryptResult.message = e.message;
                    return;
                }
            },
            error: function () {
                encryptResult.message = "عملیات ورود به سیستم با خطا مواجه شد";
            }
        });

        return encryptResult;
    }

    securityManager.eosEncode = function (val) {
        return eosEncode(val);
    }

    securityManager.eosHash = function (val) {
        return eosHash(val);
    }
    window.SecurityManager = securityManager;
})()