
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * Test a randomly generated array of arbitrary length and values to see if the
 * two numbers in that array sum a passed in number.
 * <p>
 * Syntax:
 * <p>
 * TestArray <array_length><max_range_for_numbers><number_to_find_sum> <stop_at_first_match(boolean)>
 * <p>
 * Example: TestArray 1000 200 175 true
 * <p>
 * Creates an array 1000 numbers large with random values between 0 and 199.
 * Looks for two numbers in that array that sum to 175 and stops at the first
 * match.
 * 
 * @author Chris Van Vlack
 * @since Apr 19, 2008
 *  
 */
public class TestArray {

	private static int[] randomArray;

	public TestArray(int arrMaxLength, int maxRange) {
		generateRandomArray(arrMaxLength, maxRange);
	}

	public static void main(String[] args) {

		int arrLen = 0;
		int maxRange = 0;
		int sumToFind = 0;
		boolean endAtFirst = false;

		try {
			arrLen = Integer.parseInt(args[0]);
			maxRange = Integer.parseInt(args[1]);
			sumToFind = Integer.parseInt(args[2]);
			endAtFirst = Boolean.valueOf(args[3]).booleanValue();
		} catch (Exception e) {
			System.err.println("Exception when trying to convert your args!\n"
					+ e);
		}

		TestArray t = new TestArray(arrLen, maxRange);
		t.findNumberSum(randomArray, sumToFind, endAtFirst);
	}

	private static void generateRandomArray(int arrMaxLength, int maxRange) {
		// initalize array with max length passed.
		randomArray = new int[arrMaxLength];

		Random r = new Random();

		for (int i = 0; i < randomArray.length; i++) {
			randomArray[i] = r.nextInt(maxRange);
		}

	}

	/**
	 * So we have this issue. We have arbitrary length arrays filled with
	 * numbers, and need to find if two numbers in this array sum to the passed
	 * in number
	 * 
	 * @param numberArray
	 *            The arbitrary length array of numbers
	 * @param sumToFind
	 *            The sum we are looking for
	 * @param stopAtFirst
	 *            boolean value to stop at first match or get all matches
	 */
	public void findNumberSum(int[] numberArray, int sumToFind,
			boolean stopAtFirst) {

		Map foundNumbers = new HashMap();

		// Loop through the array, but we'll only need to do it once, due to
		// using a HashMap - O(n) rather than O(n^2)
		int i = 0;
		while (i < numberArray.length) {
			int arrVal = numberArray[i];

			int diff = sumToFind - arrVal;
			//System.out.println("sumToFind[" + sumToFind + "] - arrVal[" +
			// arrVal + "] = diff[" + diff + "]");

			foundNumbers.put(String.valueOf(diff), String.valueOf(arrVal));

			// If the map contains either of the values, in this case the
			// difference of the sumToFind and the number from the array or the
			// actual number from the array, then we've found a match, check
			// stopAtFirst to break and return the first match back or continue
			// on your way listing all matches.
			if (foundNumbers.containsKey(String.valueOf(diff))
					&& foundNumbers.containsValue(String.valueOf(diff))) {
				System.out.println("Found a set! [" + arrVal + ", " + diff
						+ "]");

				if (stopAtFirst)
					return;
			}

			i++;
		}
	}

}