/**
 * 
 * @param {Object} local_conf
 */
jQuery.fn.passwordStrengthCheck = function(local_conf) {
	//
    var conf = {};

	conf.levels = {
		'tooShort': true,
		'invalid': true,
		'weak': true,
		'fair': true,
		'strong': true};

	conf.tests = {
		'minimumLength': true,
		'minimumLength': true,
		'mediumLength': true,
		'superLength': true,
		'numbers': true,
		'specialChars': true,
		'capitalLetters': true};

	//
	var inputJQ = this;
	var indicatorJQ = jQuery([]);

	var indicatorClasses = '';

	//
	var standard = {};

	standard.levels = {
		'tooShort': {
			minimumStrength: 0,
			indicatorText: '',
			indicatorClass: 'indicator-tooShort'},
		'weak': {
			minimumStrength: 0.16,
			indicatorText: '',
			indicatorClass: 'indicator-weak'},
		'fair': {
			minimumStrength: 0.48,
			indicatorText: '',
			indicatorClass: 'indicator-fair'},
		'strong': {
			minimumStrength: 0.80,
			indicatorText: '',
			indicatorClass: 'indicator-strong'}};

	standard.tests = {
		minimumLength: {
			type: 'length',
			params: [5],
			obligatory: true,
			strength: 1},
		mediumLength: {
			type: 'length',
			params: [7],
			obligatory: false,
			strength: 1},
		superLength: {
			type: 'length',
			params: [10],
			obligatory: false,
			strength: 1},
		numbers: {
			type: 'regexp',
			params: ['[0-9]+'],
			obligatory: false,
			strength: 1},
		specialChars: {
			type: 'regexp',
			params: ['[!@#$^&*()]+'],
			obligatory: false,
			strength: 1},
		capitalLetters: {
			type: 'regexp',
			params: ['[A-Z]+'],
			obligatory: false,
			strength: 1}};

	/**
	 * 
	 */
	var init = function (local_conf) {
		conf = jQuery.extend(conf, local_conf);

		//
		indicatorJQ = jQuery('<div>').addClass('passwordStrengthIndicator');
		indicatorJQ.insertAfter(inputJQ);

		indicatorJQ.append(indicatorJQ = jQuery('<div>').addClass('indicator'));

		//	
		inputJQ.bind(
			'keyup',
			function(){
				check();
			});

		//
		for(var level in conf.levels) {
			if(typeof(standard.levels[level]) !== 'undefined') {
				if(typeof(conf.levels[level]) === 'object' || conf.levels[level] === true) {
					conf.levels[level] = jQuery.extend(true, standard.levels[level], conf.levels[level]);
				}
				else {
					delete conf.levels[level];
				}
			}
			
			indicatorClasses += indicatorClasses.length ? ' ' : '';
			indicatorClasses += conf.levels[level].indicatorClass;
		}

		//
		for(var test in conf.tests) {
			if(typeof(standard.tests[test]) !== 'undefined') {
				if(typeof(conf.tests[test]) === 'object' || conf.tests[test] === true) {
					conf.tests[test] = jQuery.extend(true, standard.tests[test], conf.tests[test]);
				}
				else {
					delete conf.tests[test];
				}
			}
		}
	}
	
	/**
	 * 
	 */
	var check = function () { 
		var password = inputJQ.val();

		//
		var strength = 0;
		var maxStrength = 0;

		var allObligatoryPassed = true;

		for(var test in conf.tests) {
			if(allObligatoryPassed === false) {
				break;
			}
			
			var passed = false;
			
			switch(conf.tests[test].type) {
				case 'length':
					if(typeof(conf.tests[test].params) !== 'undefined' && password.length >= conf.tests[test].params[0]) {
						passed = true;
					} 

					break;

				case 'regexp':
					if(typeof(conf.tests[test].params) !== 'undefined' && (new RegExp(conf.tests[test].params[0])).exec(password) !== null) {
						passed = true;
					} 

					break;
			}

			if(typeof(conf.tests[test].strength) !== 'undefined' && conf.tests[test].strength > 0) {
				maxStrength += conf.tests[test].strength;
	
				if(passed === true) {
					strength += conf.tests[test].strength;
				}
			}
	
			if(typeof(conf.tests[test].obligatory) !== 'undefined' && conf.tests[test].obligatory === true && passed === false) {
				allObligatoryPassed = false;
			}
		}

		if(maxStrength !== 0) {
			strength = strength / maxStrength;
		}

		//
		var applicableLevel = null;
		var applicableLevelMinimumStrength = 0;
		
		for(var level in conf.levels) {
			if(strength >= conf.levels[level].minimumStrength && conf.levels[level].minimumStrength >= applicableLevelMinimumStrength) {
				applicableLevel = level;
				applicableLevelMinimumStrength = conf.levels[level].minimumStrength;
			}
		}

		if(applicableLevel !== null) {
			indicatorJQ
				.removeClass(indicatorClasses)
				.addClass(conf.levels[applicableLevel].indicatorClass)
				.html(conf.levels[applicableLevel].indicatorText);
		}
	}
	
	//
	jQuery(document).ready(
    	function () {
        	init(local_conf);
    	}
    );			
}

