/*
 * pwdmkr 1.0 by marcos@marumushi.com
 * http://marumushi.com/code/pwdmkr/
 * 
 * Configurable variables.
 */

//BEFORE YOU BEGIN: CUSTOMIZE THIS:
var salt                        = 'lkjaBcal9l'; // <-- make sure to customize this to a random string of your choice!
var numchars                    = 10;           // how long will the generated password be.
var charsets			= [             // feel free to add or customize your own charsets. the more irregular, the safer.
	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~!$*_-+={}[]:;",
	"abcdefghijklmnopqrstuvwxyz0123456789"
];

//YOU SHOULDN'T NEED TO CUSTOMIZE THIS:
var hideCharsetChooser  = charsets.length < 2; 	//if there's only one charset, don't bother displaing the chooser
var hidePaswordMasker	= false;                //raise this flag if you rather not see the password masking option.

/*
* Convert a raw string to an arbitrary string encoding
* borrowed from:
* http://pajhome.org.uk/crypt/md5/ripemd160.html
*/
function rstr2any (input, encoding) {
  var divisor = encoding.length;
  var remainders = Array();
  var i, q, x, quotient;

  /* Convert to an array of 16-bit big-endian values, forming the dividend */
  var dividend 	= Array(input.length / 2);
  var inp 		= new String(input);
  for(i = 0; i < dividend.length; i++) {
    dividend[i] = (inp.charCodeAt(i * 2) << 8) | inp.charCodeAt(i * 2 + 1);
  }

  /*
   * Repeatedly perform a long division. The binary array forms the dividend,
   * the length of the encoding is the divisor. Once computed, the quotient
   * forms the dividend for the next step. We stop when the dividend is zero.
   * All remainders are stored for later use.
   */
  while(dividend.length > 0) {
    quotient = Array();
    x = 0;
    for(i = 0; i < dividend.length; i++) {
      x = (x << 16) + dividend[i];
      q = Math.floor(x / divisor);
      x -= q * divisor;
      if(quotient.length > 0 || q > 0)
        quotient[quotient.length] = q;
    }
    remainders[remainders.length] = x;
    dividend = quotient;
  }

  /* Convert the remainders to the output string */
  var output = "";
  for(i = remainders.length - 1; i >= 0; i--)
    output += encoding.charAt(remainders[i]);

  return output;
}

function updateCase(){
	var jurl		= $('#url');
	var jusr		= $('#username');
	jurl.val(jurl.val().toLowerCase());
	jusr.val(jusr.val().toLowerCase());
}

function updatePwd(){
	// make sure url and username are lowercase, 
	// for some reason iphone capitalizes first
	updateCase();
	//now grab all values
	var url 		= $('#url').val();
	var master 		= $('#masterpassword').val();
	var username 	= $('#username').val();
	var charset		= $('#charset').val();
	var pwd			= '';
	//only display value once we have all components.
	if(url!=''){
		pwd = salt + 
			$.md5(url) + 
			$.md5(master) + 
			$.md5(username);
		pwd = $.md5(pwd);
		pwd = rstr2any(pwd,charset);
		pwd = pwd.substr(0,numchars);
	}
	$('#generatedpassword_clear').val(pwd);
	$('#generatedpassword_masked').val(pwd);
}

function togglePwdVisibility(){
	$('#generatedpassword_clear').toggle();
	$('#generatedpassword_masked').toggle();
}

function toggleMoreVisibility(){
	$('#more').toggle();
	var msg = $('#more').css('display') == 'none' ? 'more &gt;' : '&lt; less';
	$('#morelink').html(msg);
	return false;
}

function init(){
	if(salt!=''){
		$('#morelink').click( function (e){toggleMoreVisibility();});
		var input = $( ":input" );
		input.change( 	function( e ){ updatePwd (); 	});
		input.keyup( 	function( e ){ updatePwd (); 	});
		input.keydown( 	function( e ){ updateCase (); 	});
		input.focus( 	function( e ){ if(this.select)this.select(); });
		$('#hidepassword').change ( function ( e ){ togglePwdVisibility(); });
		if(hidePaswordMasker){$('#passwordmasker').hide()};
		if(hideCharsetChooser){$('#charsetchooser').hide()};
		//update value based on checked state set by browser history.
		if($('#hidepassword:checked').val()){togglePwdVisibility();};
		//populate with defined charsets
		var el =  $('#charset').get(0);;
		$.each(charsets, function () { el.options[el.options.length] = new Option(this, this);});
		updatePwd();
		$('#url').focus();
	}else{
		$('#main').html("<h1>pwdmkr!</h1><h2>ERROR: Application has not been configured yet.</h2><h3>Make sure to set the <b>salt</b> variable to a random string of your choice in <a href='js/application.js'>application.js</a></h3>")
	}
}

$( init );
