// Archibald Haddock (123456789)
// COMP 202-A, Section 0 (Fall 2007)
// Instructor: Cuthbert Calculus
// Assignment 3, Question 2

import java.text.DecimalFormat;

public class Word {
	public static void main(String[] args) {
		DecimalFormat formatter;
		String candidate;
		boolean previousIsWhitespace;
		boolean currentIsWhitespace;

		double sumOfLengths;
		double sumOfSquaredLengths;
		int wordLength;
		int wordCount;

		double average;
		double standardDeviation;

		formatter = new DecimalFormat("0.00000000");

		// Repeat 5 times
		for (int i = 1; i <= 5; i++) {
			candidate = "";

			// Assign a String object from class SomeString to
			// candidate depending on the number of times the outer
			// loop has already been executed.
			if (i == 1) {
				candidate = SomeStrings.s1;
			}
			if (i == 2) {
				candidate = SomeStrings.s2;
			}
			if (i == 3) {
				candidate = SomeStrings.s3;
			}
			if (i == 4) {
				candidate = SomeStrings.s4;
			}
			if (i == 5) {
				candidate = SomeStrings.s5;
			}

			sumOfLengths = 0.0;
			sumOfSquaredLengths = 0.0;
			wordCount = 0;
			wordLength = 1;

			// General idea
			// We isolate words based on transitions from a
			// whitespace character to a non-whitespace character
			// and vice-versa by keeping track of what the previous
			// character was in addition to determining what the
			// current character is.
			// * If the previous character was a whitespace
			//   character, and the current is not, a new word is
			//   starting
			// * If the previous character was a non-whitespace
			//   character and the current is whitespace, then the
			//   word has just ended.

			// For the first character, we consider that the
			// previous character is whitespace so that it correctly
			// detects a word that starts with the first character.
			previousIsWhitespace = true;

			// Note that this loop is *not* off-by-one; if j ==
			// candidate.length(), we do not call charAt() on
			// candidate at position j. The purpose of this is to
			// "fake" the existence of a whitespace character at the
			// end of a String to correctly handle a String ending
			// with a non-whitespace character.
			for (int j = 0; j <= candidate.length(); j++) {
				// "Fake" the existence of a whitespace
				// character at non-existent position
				// candidate.length() so that a word ending the
				// String gets detected.
				// If j is a valid position, then the nature of
				// the character is given normally by
				// isWhiteSpace().
				if (j == candidate.length()) {
					currentIsWhitespace = true;
				} else {
					currentIsWhitespace =
						Character.isWhitespace(
							candidate.charAt(j));
				}
				
				// Previous is whitespace and current is not
				// This is the start of a new word, we set
				// its length to 1
				if (previousIsWhitespace &&
					!currentIsWhitespace) {
					wordLength = 1;
				}

				// Neither previous nor current is whitespace.
				// Increment the current length of the word.
				if (!previousIsWhitespace &&
					!currentIsWhitespace) {
					wordLength++;
				}

				// Previous is not whitespace, but current is.
				// This is the end of the word.
				// Increment the word count.
				// wordLength contains the length of the whole
				// word, so we can add that to the sum of the
				// lengths (and its square to the sum of squared
				// lengths).
				if (!previousIsWhitespace &&
					currentIsWhitespace) {
					wordCount++;
					sumOfLengths += wordLength;
					sumOfSquaredLengths +=
						(wordLength * wordLength);
				}

				// On the next iteration, the current character
				// becomes the previous. Not need to verify
				// whether it's whitespace, we know it already.
				previousIsWhitespace = currentIsWhitespace;
			}

			// Handle the special case for a String with no words.
			if (wordCount == 0) {
				average = 0.0;
				standardDeviation = 0.0;
			} else {
				// Compute the average normally...
				average = sumOfLengths / wordCount;
				
				// The equation for standard deviation is can be
				// unrolled so that using the average is not
				// necessary each time you find a new word.
				// See README.txt for details.
				standardDeviation = Math.sqrt(
					(sumOfSquaredLengths - wordCount
					* average * average) / wordCount);
			}

			// Display the relevant information for the candidate
			// String
			System.out.println("String: s" + i);
			System.out.println("Average: " +
				formatter.format(average));
			System.out.println("Standard deviation: " +
				formatter.format(standardDeviation));
			System.out.println();
		}
	}
}
