Ext.namespace("Ext.ux.form");
Ext.ux.form.SecurePass = function(config) {
    Ext.ux.form.SecurePass.superclass.constructor.call(this, config);
    this.markInvalid = this.markInvalid.createSequence(function() {
        this.el.addClass("invalid");
        this.el.removeClass("valid");
    });
};
Ext.extend(Ext.ux.form.SecurePass, Ext.form.TextField, {
    /**
     * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to { PwdEmpty: "Please type a
     * password, and then retype it to confirm.", PwdShort: "Your password must be at least 6 characters long. Please
     * type a different password.", PwdLong: "Your password can't contain more than 16 characters. Please type a
     * different password.", PwdBadChar: "The password contains characters that aren't allowed. Please type a different
     * password.", IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
     * FNInPwd: "Your password can't contain your first name. Please type a different password.", LNInPwd: "Your
     * password can't contain your last name. Please type a different password." })
     */
    // private
    maxlength : 255,
    errors : {
        PwdEmpty : translate("Das Passwort darf nicht leer sein."),
        PwdShort : translate("Das Passwort mu&szlig; mindestens 6 Zeichen enthalten."),
        PwdLong : translate("Das Passwort darf maximal " + this.maxlength + " Zeichen enthalten."),
        PwdBadChar : translate("Das Passwort enth&auml;t ung&uuml;ltige Zeichen."),
        IDInPwd : translate("Das Passwort ist Teil des Logins."),
        FNInPwd : translate("Ihr Vorname darf nicht im Passwort vorkommen."),
        LNInPwd : translate("Ihr Nachname darf nicht im Passwort vorkommen.")
    },
    /**
     * @cfg {String/Object} Label for the strength meter (defaults to 'Password strength:')
     */
    // private
    meterLabel : translate('Passwort Sicherheit'),
    /**
     * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to ['Weak', 'Medium',
     * 'Strong'])
     */
    // private
    pwdStrengths : [
        translate('Schwach'), translate('Mittel'), translate('Ok')
    ],
    /**
     * @cfg {String/Object} fieldsFilter A fieldsFilter spec, as [['field_name', 'error_id'], ...]
     */
    // private
    fieldsFilter : null,
    // private
    strength : 0,
    // private
    _lastPwd : null,
    // private
    kCapitalLetter : 0,
    kSmallLetter : 1,
    kDigit : 2,
    kPunctuation : 3,
    // private
    initEvents : function() {
        Ext.ux.form.SecurePass.superclass.initEvents.call(this);
        this.el.on('keyup', this.checkStrength, this, {
            buffer : 50
        });
        this._lastPwd = this.el.getValue();
    },
    // private
    onRender : function(ct, position) {
        Ext.ux.form.SecurePass.superclass.onRender.call(this, ct, position);
        this.wrap = this.el.wrap({
            cls : "x-form-field-wrap"
        });
        this.trigger = this.wrap.createChild({
            tag : "div",
            cls : "StrengthMeter"
        });
        if (this.meterLabel != '') {
            this.trigger.createChild({
                tag : "label",
                html : this.meterLabel
            });
        };
        this.trigger.createChild({
            tag : "div",
            cls : "PwdMeterBase",
            html : '<div class="PwdBack"><div class="PwdMeter" id="PwdMeter"></div></div>'
        });
        if (this.hideTrigger) {
            this.trigger.setDisplayed(false);
        };
        this.setSize(this.width || '', this.height || '');
    },
    // private
    onDestroy : function() {
        if (this.trigger) {
            this.trigger.removeAllListeners();
            this.trigger.remove();
        };
        if (this.wrap) {
            this.wrap.remove();
        };
        Ext.form.TriggerField.superclass.onDestroy.call(this);
    },
    // private
    checkStrength : function() {
        var pwd = this.el.getValue();
        if (pwd == this._lastPwd) {
            return;
        };
        this.trigger.setDisplayed(true);
        var strength;
        if (this.ClientSideStrongPassword(pwd)) {
            strength = 3;
        } else if (this.ClientSideMediumPassword(pwd)) {
            strength = 2;
        } else if (this.ClientSideWeakPassword(pwd)) {
            strength = 1;
        } else {
            strength = 0;
        };
        document.getElementById('PwdMeter').style.width = 82 * strength + 'px';
        if (this.pwdStrengths != null && strength > 0) {
            document.getElementById('PwdMeter').innerHTML = '&nbsp;' + this.pwdStrengths[strength - 1];
        } else {
            document.getElementById('PwdMeter').innerHTML = '';
        };
        this._lastPwd = pwd;
    },
    // private
    validateValue : function(value) {
        var pwOpts = recon.getPwOpts();
        if (!Ext.form.TextField.superclass.validateValue.call(this, value)) {
            return false;
        };
        if (value.length == 0) {
            this.markInvalid(this.errors.PwdEmpty);
            return false;
        };
        if ("[\x21-\x7e]*".match(value)) {
            this.markInvalid(this.errors.PwdBadChar);
            return false;
        };
        if (value.length < pwOpts.length || 6) {
            this.markInvalid(this.errors.PwdShort);
            return false;
        };
        if (value.length > this.maxlength) {
            this.markInvalid(this.errors.PwdLong);
            return false;
        };
        for ( var index = 0; index < this.fieldsFilter.length; ++index) {
            var f = Ext.getDom(this.fieldsFilter[index][0]);
            if (f && f.value != '') {
                var reg = new RegExp(value, 'gi');
                if (f.value.match(reg)) {
                    this.markInvalid(eval('this.errors.' + this.fieldsFilter[index][1]));
                    return false;
                }
            }
        };
        return true;
    },
    // private
    CharacterSetChecks : function(type) {
        this.type = type;
        this.fResult = false;
    },
    // private
    isctype : function(character, type) {
        switch (type) { // why needed break after return in js ? very odd bug
            case this.kCapitalLetter :
                if (character >= 'A' && character <= 'Z') {
                    return true;
                }
                ;
                break;
            case this.kSmallLetter :
                if (character >= 'a' && character <= 'z') {
                    return true;
                }
                ;
                break;
            case this.kDigit :
                if (character >= '0' && character <= '9') {
                    return true;
                }
                ;
                break;
            case this.kPunctuation :
                if ("!@#$%^&*()_+-='\";:[{]}|.>,</?`~".indexOf(character) >= 0) {
                    return true;
                }
                ;
                break;
            default :
                return false;
                break;
        }
    },
    // private
    IsLongEnough : function(pwd, size) {
        return !(pwd == null || isNaN(size) || pwd.length < size);
    },
    // private
    SpansEnoughCharacterSets : function(word, nb) {
        if (!this.IsLongEnough(word, nb)) {
            return false;
        };
        var characterSetChecks = new Array(new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter), new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation));
        for ( var index = 0; index < word.length; ++index) {
            for ( var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
                if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
                    characterSetChecks[nCharSet].fResult = true;
                    break;
                }
            }
        };
        var nCharSets = 0;
        for ( var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
            if (characterSetChecks[nCharSet].fResult) {
                ++nCharSets;
            }
        };
        if (nCharSets < nb) {
            return false;
        };
        return true;
    },
    // private
    ClientSideStrongPassword : function(pwd) {
        return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
    },
    // private
    ClientSideMediumPassword : function(pwd) {
        return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
    },
    // private
    ClientSideWeakPassword : function(pwd) {
        return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
    }
})
