
passwordCharsets = [
	[1, 'digits', '0123456789'],
	[2, 'lower-letters', 'abcdefghijklmnopqrstuvwxyz'],
	[4, 'upper-letters', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'],
	[8, 'special-chars', '`~!@#$%^&*()-+\\=|[]{};\':",./<>?'],
	[16, 'lower-polish-letters', 'ąćęłńóśźż'],
	[32, 'upper-polish-letters', 'ĄĆĘŁŃÓŚŹŻ'],
	[64, 'lower-hex-digits', '0123456789abcdef'],
	[128, 'upper-hex-digits', '0123456789ABCDEF'],		
	[256, 'space', ' '],
	[512, 'binary-digits', '01']
];


entropy = new Entropy();

String.prototype.trim = function () {
    return this.replace(/^\s*/, "").replace(/\s*$/, "");
}

String.prototype.uniqueChars = function () {
	var us = "";
	for(var i=0; i<this.length; i++) {
		var c = this.charAt(i);
		if (us.indexOf(c) < 0)
			us += c;
	}
	return us;
}

//kodowanie znakow specjalnych html
String.prototype.htmlEncode  = function () {
        var str = new String(this);
        str = str.replace(/&/g, "&amp;");
        str = str.replace(/</g, "&lt;");
        str = str.replace(/>/g, "&gt;");
        str = str.replace(/"/g, "&quot;");
        return str;
} 



function fraction(x) {
	x = Math.abs(x);
	return x - Math.floor(x);
}

//generowanie losowej liczby calkowitej w zakresie od 0 do m-1
function randomInt(m) {
	var x = entropy.readByte() + 1;	
	result = Math.random() * x;
	result = fraction(result);	
	result = Math.floor(result * m);
	return result;
}

//wybranie losowego znaku z lancucha chars
function randomChar(chars) {
	if (chars.length>0) {
		var p = randomInt(chars.length);
		return chars.charAt(p);
	}
	else
		return null;
}

//wybranie i sklejenie l losowych znakow z lancucha chars
function randomString(chars, l) {
	var s = "";
	for(var	i=0; i<l; i++) {
		var c = randomChar(chars);
		s = s + c;
	}
	return s;
}

//pobranie lancucha dozwolonych znakow
function getAllowedChars(allowFlags, additionalChars) {
	var chars="";
	for(var i=0; i<passwordCharsets.length; i++) {
		if ((passwordCharsets[i][0] & allowFlags)>0) {
			chars += passwordCharsets[i][2];
		}
	}
	chars += additionalChars;	
	chars = chars.uniqueChars();			
	return chars;
}


//przeliczenie dni na tekst
function sec2Text(d) {
	if (d < 60)
		return d+" " + L_TIME_NAMES[0];		
	d = d / 60;
	
	if (d < 60)
		return Math.round(d)+" " + L_TIME_NAMES[1];
	d = d / 60;
	
	if (d < 24)
		return Math.round(d)+" " + L_TIME_NAMES[2];	
	d = d / 24;
	
	if (d < 30.4375)
		return Math.round(d)+" " + L_TIME_NAMES[3];
	d = d / 30.4375;
	
	if (d < 12)
		return Math.round(d)+" " + L_TIME_NAMES[4];
	d = d / 12;
	
	if (d < 1000)
		return Math.round(d)+" " + L_TIME_NAMES[5];
	d = d / 1000;
	
	if (d < 1000)
		return Math.round(d)+" " + L_TIME_NAMES[6];
	d = d / 1000;
	
	if (d < 1000)
		return Math.round(d)+" " + L_TIME_NAMES[7];
	d = d / 1000;
	
	if (d < 1000)
		return Math.round(d)+" " + L_TIME_NAMES[8];
	d = d / 1000;
	 
	if (d < 1000)
		return Math.round(d)+" " + L_TIME_NAMES[9];
	d = d / 1000;

	if (d < 1000)
		return Math.round(d)+" " + L_TIME_NAMES[10];
	d = d / 1000;

	if (d < 1000)
		return Math.round(d)+" " + L_TIME_NAMES[11];
	d = d / 1000;
	
	return Math.round(d) +" " + L_TIME_NAMES[12];
}

function getElement(id) {
	return document.getElementById(id);
}

function getInputParams() {
	var inputParams = [];	
	inputParams[0] = parseInt(getElement('rpg-count').value);
	inputParams[1] = 0;
	for(var i=0; i<passwordCharsets.length; i++) {
		var e = getElement('rpg-allow-'+passwordCharsets[i][1]);
		if (e != undefined) {
			if (e.checked) {
				inputParams[1] = inputParams[1] | passwordCharsets[i][0];
			}
		}
	}
	inputParams[2] = getElement('rpg-additional-chars').value;
	inputParams[3] = parseInt(getElement('rpg-length').value);	
	return inputParams;
}



function showHide(elementName, v) {
	var e = getElement(elementName);	
	if (v)
		e.style.display = "block";
	else
		e.style.display = "none";
}

function generatePassword(inputParams) {
	var allowedChars = getAllowedChars(inputParams[1], inputParams[2]);
	var passwordLength = inputParams[3];
	var passwordCount = inputParams[0];
	var passwordList = "";
	for(var i=0; i<passwordCount; i++) {
		var password = randomString(allowedChars, passwordLength);
		passwordList += password
		if (i!=(passwordCount-1))
			passwordList += "\n";
	}
	
	
	getElement('rpg-password').value = passwordList;	
}

function clearResults() {
	getElement('rpg-allowed-chars').innerHTML = "";
	getElement('rpg-allowed-chars-count').innerHTML = "";
	getElement('rpg-num-bits').innerHTML = "";
	getElement('rpg-how-long').innerHTML = "";
	getElement('rpg-num-combinations').innerHTML = "";
	getElement('rpg-password').value = "";
}

function clearErrors() {
	showHide("rpg-allow-error", false);
	showHide("rpg-count-error", false);
	showHide("rpg-length-error", false);
}

function displayErrors(errors) {
	for(var i=0; i<errors.length; i++) {
		showHide(errors[i], true);
	}
}

function checkLimit(v, minv, maxv) {
	var ok_min = false;
	var ok_max = false;
	
	if (minv!=undefined) {
		ok_min = (v!=NaN) && (v!=undefined) && (v >= minv);
	} else
		ok_min = true;

	if (minv!=undefined) {
		ok_max = (v!=NaN) && (v!=undefined) && (v <= maxv);
	} else
		ok_max = true;
	
	return ok_min && ok_max;
}

function onInputParamsChange(inputParams) {
	if (inputParams == undefined)
		inputParams = getInputParams();
	
	var allowedChars = getAllowedChars(inputParams[1], inputParams[2]);	
	var errors = [];
	
	clearErrors();
	
	if (!checkLimit(allowedChars.length, 1, 256)) {
		errors.push('rpg-allow-error');
	}
			
	var passwordCount = inputParams[0];
	if (!checkLimit(passwordCount, 1, 100)) {
		errors.push('rpg-count-error');
	}
			
	var passwordLength = inputParams[3];
	if (!checkLimit(passwordLength, 1, 256)) {
		errors.push('rpg-length-error');
	}
	
	if (errors.length > 0) {
		displayErrors(errors);
		clearResults();
		return;
	}
	
	//obliczenie dlugosci bitowej pojedynczego znaku
	var bitsPerChar = Math.log(allowedChars.length) / Math.LN2;	
	//obliczenie dlugosci bitowej calego hasla
	var numBits = passwordLength * bitsPerChar;	
	var numBitsRound = Math.round(numBits);	
	var perSec = Math.log(1000000)/Math.LN2;	
	//obliczenie ilosci sekund potrzebnych na zlamanie hasla
	var howLong = Math.round(Math.pow(2, numBits - perSec));
	var numCombinations = Math.pow(allowedChars.length, passwordLength);
	
	getElement('rpg-allowed-chars').innerHTML = allowedChars.htmlEncode();
	getElement('rpg-allowed-chars-count').innerHTML = allowedChars.length.toString();
	getElement('rpg-num-bits').innerHTML = Math.round(numBits).toString();
	getElement('rpg-how-long').innerHTML = sec2Text(howLong);	
	getElement('rpg-num-combinations').innerHTML = numCombinations.toString();
	
	generatePassword(inputParams);
}

function generatePasswordClick() {
	var inputParams = getInputParams();
	if (inputParams != null) {
		//generatePassword(inputParams);
		onInputParamsChange(inputParams);
	}
}

function onProfileUpdate() {
	var e = getElement('rpg-profile');
	if (e.selectedIndex >= 0) {
		var pi = parseInt(e.options[e.selectedIndex].value);
		setProfile(pi);
	}
}

function setProfile(pi) {
	var profile = profiles[pi];
	
	getElement('rpg-profile-description').innerHTML = profile[1].htmlEncode();
	var af = profile[2];
	
	for(var i=0; i<passwordCharsets.length; i++) {
		var e = getElement('rpg-allow-'+passwordCharsets[i][1]);
		if (e != undefined) {
			e.checked = ((af & passwordCharsets[i][0]) > 0);
		}
	}	
	getElement('rpg-length').value = profile[3];
	getElement('rpg-additional-chars').value = '';
	
	onInputParamsChange();	
}

function fillProfiles() {
	var e = getElement('rpg-profile');
	e.options.length = 0;
	
	for(var i=0; i<profiles.length; i++) {
		e.options[i] = new Option(profiles[i][0], i, false, false);
	}
	e.options[0].selected = true;
	onProfileUpdate();
}

function selectAll() {
	var e = getElement('rpg-password');
	e.focus();
	e.select();
}

function onUpdateEntropy() {
	var resultsElement = getElement('rpg-results');
	var rdcElement = getElement('rpg-random-data-collect');
	
	var ready = entropy.isReady();
	
	if (ready) {
		resultsElement.style.display = "block";
		rdcElement.style.display = "none";
	} else {
		var ff = Math.round(entropy.fillFactor()*100);		 
		resultsElement.style.display = "none";
		rdcElement.style.display = "block";
		rdcElement.innerHTML = "<p class=\"error\">"+L_COLLECTING_DATA_TEXT+"<br/>"+
			ff.toString()+" %</p>";
	}
	
	if (ready && !firstPassGen) {
		generatePasswordClick();
		firstPassGen = true;
	}
	
	isEntropyOk = ready;
		
	var e = getElement('rpg-entropy');	
	e.innerHTML = entropy.getNumBits().toString() + " " + L_BITS;
}

window.onload = function() {
	entropy.addTimeEvent();
	onUpdateEntropy();
	fillProfiles();
}

var firstPassGen = false;

// Detect if the browser is IE or not.
// If it is not IE, we assume that the browser is NS.
var IE = document.all?true:false

// If NS -- that is, !IE -- then set up for mouse capture
if (!IE) document.captureEvents(Event.MOUSEMOVE)

// Set-up to use getMouseXY function onMouseMove
document.onmousemove = function(e) { 
	if ((e==undefined) && (event!=undefined))
		e = event;		
	entropy.addMouseEvent(e); 
	onUpdateEntropy();
}



