<!-- Paste this code into an external JavaScript file named: wordComb.js  -->

/* This script and many more are available free online at
The JavaScript Source :: http://javascript.internet.com
Created by: Brett McLean :: http://www.brettbits.com/ */

// calculateCombinations takes inputText as a parameter, which is a string containing all
// user-provided characters. It calculates how many combinations exist for these characters,
// prints them in the outputField, as well as returning the number to the calling function.
function calculateCombinations(inputText) {
 	inputCopy = inputText;
 	numerator = factorial(inputText.length);
 	denominator = 1;
 	while(inputCopy != "") {
  		denominator *= factorial(howManyOccurances(inputCopy, inputCopy.charAt(0)));
  		inputCopy = stripCharactersFromString(inputCopy, inputCopy.charAt(0));
 	}
 	document.combform.outputField.value = (numerator/denominator);	
 	return numerator/denominator;
}

// HowManyOccurances returns how many times characterToFind appears in stringToSearch.
// Example: howManyOccurances("abcabcabca", "a") returns 4.
function howManyOccurances(stringToSearch, characterToFind) {
 	count = 0;
 	for(i = 0; i < stringToSearch.length; i++) {
 		if(stringToSearch.charAt(i) == characterToFind)
  			count++;
 	}
 	return count;
}

// stripCharactersFromString returns stringToStripFrom, with all occurances
// of characterToStrip removed.
// Example: stripCharactersFromString("abcabcabca", "a") returns "bcbcbc".
function stripCharactersFromString(stringToStripFrom, characterToStrip) {
 	outputString = "";
 	for(i = 0; i < stringToStripFrom.length; i++)
  		if(stringToStripFrom.charAt(i) != characterToStrip)
  			outputString += stringToStripFrom.charAt(i);
 	return outputString;
}

// factorial returns the factorial of inputNumber, also written as (inputNumber)!.
// Definition of factorial: inputNumber! = (inputNumber) * (inputNumber-1) * ... * 2 * 1
// Example: factorial(4) = 4! = 4 * 3 * 2 * 1 = 24
function factorial(inputNumber) {
 	outputNumber = 1;
 	for(i = inputNumber; i > 0; i--)
  		outputNumber *= i;
 	return outputNumber;
}

// createWordList recursively generates an array containing all possible combinations of
// a given string of letters. It solves this problem by taking each letter in the word,
// and then appending to it all possible combinations of the remaining letters.
// Initially, wordArray should be empty, strbase should equal "", and remainingchars
// should contain the user's input string.
function createWordList(wordArray, strbase, remainingchars) {
	if(remainingchars.length == 1) { // base case: only one character remains, and can be arranged only one way
 		wordArray[wordArray.length] = strbase + remainingchars.charAt(0); // append one remaining character to string base
	} else {
 		for(var j = 0; j < remainingchars.length; j++) {
  			currchar = remainingchars.charAt(j); // first character of remaining characters
  			if(remainingchars.indexOf(currchar) == j) // ensures repeat letters do not cause combination redundancy
   				wordArray = createWordList(wordArray, strbase + remainingchars.charAt(j), remainingchars.substring(0, j) + remainingchars.substring(j+1, remainingchars.length)); //recursive call
		 }
	}
 	return wordArray; //returns the wordArray containing stbase plus all possible combinations of remainingchars
}

// printWordList accepts an array, and prints each string contained within, separated by commas.
// It then places this output into the textarea named "combinationlist".
function printWordList(wordArray) {
 	output = "";
 	for(i = 0; i < wordArray.length-1; i++)
  		output += wordArray[i] + ", ";
 	output += wordArray[wordArray.length-1];
 	document.combform.combinationlist.value = output;
}

// showCombinations receives the user's input characters as a parameter, calculates how many combinations exist from these
// characters, and then displays every one of these combinations. This function has a safeguard in which it warns
// the user if a calculation will take a long time to process.
function showCombinations(inputText) {
 	numCombinations = calculateCombinations(inputText);
 	confirmMessage = "The following calculation will involve finding " + numCombinations + " different combinations of the letters";
 	confirmMessage += "\nyou have provided. Depending on the speed of your computer, it may take a while to";
 	confirmMessage += "\nprocess this request, or in a worst-case scenario, your web browser may crash.";
 	confirmMessage += "\nThis will do no damage to your computer that a restart will not solve.";
 	confirmMessage += "\nAre you sure you want to continue?";
 	if(numCombinations < 5000 || confirm(confirmMessage)) // only do it if the number of combinations to calculate is low, or the user agrees to the warning
  		printWordList(createWordList(new Array(), "", inputText)); // calculate and then print all combinations of the letters provided
}
