/**
 * Determines the strength of a given password based on
 * frequency of of occurrence of lowercase, uppercase,
 * numbers and the special characters passed via the spc_chars
 * argument.  The more even the spread of occurrences, the
 * stronger the password.
 *
 * This class contains the following public parameters:
 *   'lcase_count'    : lowercase occurrence count.
 *   'ucase_count'    : uppercase occurrence count.
 *   'num_count'      : number occurrence count.
 *   'schar_count'    : special character occurrence count.
 *   'length'         : length of password string.
 *   'strength'       : strength value of password.
 *   'verdict'        : textual strength indication
 *                      ['weak', 'medium', 'strong'].
 *
 * @param string arg_password  The password
 * @param string arg_spc_chars A string of special characters
 *     to search for in the password. By making this an
 *     argument, the range of special characters can be
 *     controlled  externally.
 * @return string The verdict as 'Weak'|'Medium'|'Strong'
 */
function Password(arg_password, arg_spc_chars)
{
    var password = arg_password;
    var spc_chars = arg_spc_chars;
    this.lcase_count = 0;
    this.ucase_count = 0;
    this.num_count = 0;
    this.schar_count = 0;
    this.length = 0;
    this.strength = 0;
    this.runs_score = 0;
    this.verdict = '';

    // These numbers are just guesses on my part (and not
    // all that educated, either ;) Adjust accordingly.
    var verdict_conv = {'weak':2.7, 'medium':40, 'strong':100};

    // These are weighting factors.  I figure that adding
    // numbers is a little better than adding uppercase
    // because numbers probably are not vulnerable to
    // dictionary searches, and adding special chars is
    // even better.  These factors provide yet another
    // dimension.  Again, there are only guesses.
    var flc = 1.0;  // lowercase factor
    var fuc = 1.5;  // uppercase factor
    var fnm = 1.5;  // number factor
    var fsc = 1.8;  // special char factor

    this.getStrength = function()
    {
    	
        if (this.detectRuns() <= 1)
        {
            return "25";
        }
        
        var regex_sc = new RegExp('['+spc_chars+']', 'g');

        this.lcase_count = password.match(/[a-z]/g);
        this.lcase_count = (this.lcase_count) ? this.lcase_count.length : 0;
        this.ucase_count = password.match(/[A-Z]/g);
        this.ucase_count = (this.ucase_count) ? this.ucase_count.length : 0;
        this.num_count   = password.match(/[0-9]/g);
        this.num_count   = (this.num_count) ? this.num_count.length : 0;
        this.schar_count = password.match(regex_sc);
        this.schar_count = (this.schar_count) ? this.schar_count.length : 0;
        this.length = password.length;

        var avg = this.length / 4;

        // I'm dividing by (avg + 1) to linearize the strength a bit.
        // To get a result that ranges from 0 to 1, divide 
        // by Math.pow(avg + 1, 4)
        this.strength = ((this.lcase_count * flc + 1) * 
                         (this.ucase_count * fuc + 1) *
                         (this.num_count * fnm + 1) * 
                         (this.schar_count * fsc + 1)) / (avg + 1);

        //alert(this.strength);
        if (this.strength > verdict_conv.strong)
            this.verdict = '100';
        else if (this.strength > verdict_conv.medium)
            this.verdict = '75';
        else if (this.strength > verdict_conv.weak)
            this.verdict = '50';
        else
            this.verdict = "25";

        return this.verdict;
    }

    // 
    // absolute zero) result.  The difference of adjacent equivalent 
    // char values is zero.  The greater the difference, the higher
    // the result.  'aaaaa' sums to 0. 'abcde' sums to 1.  'acegi'
    // sums to 2, etc.  'aaazz', which has a sharp edge, sums to  
    // 6.25.  Any thing 1 or below is a run, and should be considered
    // weak.
    this.detectRuns = function()
    {
        var parts = password.split('');
        var ords = new Array();
                
        for (var i=0; i < parts.length; i++)
        {        	
            ords[i] = parts[i].charCodeAt(0);
        }
        
        var accum = 0;
        var lasti = ords.length-1

        for (var i=0; i < lasti; ++i)
        {
            accum += Math.abs(ords[i] - ords[i+1]);
        }

        return accum/lasti;
    }
}


function checkPassword(val)
{	
    var special_chars = "~!@#$%&*";
		

    if(val != null && val.length > 0)
    {
	    var pw = new Password(val,special_chars);
				    
	    var verdict = pw.getStrength();		
	         
	    if(verdict == 25)  setPwdSecurityBar('52px','52px');   
	    if(verdict == 50)  setPwdSecurityBar('162px','162px');
	    if(verdict == 75)  setPwdSecurityBar('262px','262px');
	    if(verdict == 100) setPwdSecurityBar('392px','352px');    
    }
    else
    {		
    	setPwdSecurityBar('0px','0px');
    }
}

function setPwdSecurityBar(w,l)
{		
	document.getElementById("passwort_sicher_bar").style.width = w;	
	document.getElementById("passwort_sicher_sign").style.left = l;		
}
