|
/* |
|
* Copyright (C) 2018 easyaspi314 |
|
* MIT license |
|
*/ |
|
|
|
import java.util.Scanner; |
|
|
|
// Filename must be ShowNumClient.java |
|
public class ShowNumClient { |
|
|
|
private Scanner mScanner; |
|
private Reader<Integer> mRowsReader; |
|
private Reader<Integer> mColsReader; |
|
private ShowNum mShowNum; |
|
|
|
/** |
|
* Creates a ShowNumClient instance. |
|
*/ |
|
public ShowNumClient() { |
|
mScanner = new Scanner(System.in); |
|
mRowsReader = createIntReader("How many rows (-1 to exit): "); |
|
mColsReader = createIntReader("How many columns (-1 to exit): "); |
|
mShowNum = null; |
|
} // end ShowNumClient ctor |
|
|
|
/** |
|
* A callback for Reader<T>. |
|
* |
|
* @param T: The type to return |
|
*/ |
|
private static interface ReaderCallback<T> { |
|
|
|
/** |
|
* Displays a prompt message. |
|
*/ |
|
public void prompt(); |
|
|
|
/** |
|
* Validates an input. Return null on an error, or the valid input on |
|
* success. |
|
* |
|
* @param value The value to parse. |
|
* @return T The parsed value, or null to indicate failure. |
|
*/ |
|
public T validateInput(String value); |
|
|
|
/** |
|
* Displays an invalid input message. |
|
* |
|
* @param input The input given, or an empty string for empty input. |
|
*/ |
|
public void invalidInput(String input); |
|
} // end ReaderCallback interface |
|
|
|
/** |
|
* A callback to read input from the reader, using ReaderCallback to |
|
* validate. |
|
* |
|
* @param <T> The type to return |
|
*/ |
|
private static class Reader<T> { |
|
|
|
private Scanner mScanner; |
|
private ReaderCallback<T> mCallback; |
|
|
|
/** |
|
* Don't use this |
|
*/ |
|
private Reader() { |
|
throw new UnsupportedOperationException("Use Reader(ReaderCallback<T>) instead."); |
|
} // end Reader ctor () |
|
|
|
/** |
|
* Constructs a new Reader object. |
|
* |
|
* @param callback A { |
|
* @see ReaderCallback} to handle the input |
|
*/ |
|
public Reader(Scanner scanner, ReaderCallback<T> callback) { |
|
mScanner = scanner; |
|
mCallback = callback; |
|
} // end Reader ctor (ReaderCallback<T>) |
|
|
|
/** |
|
* Reads a value and validates it, using mCallback to validate and |
|
* prompt. |
|
* |
|
* This will repeat itself until a correct input is found, calling |
|
* invalidInput. |
|
* |
|
* @return T, a non-null value. |
|
*/ |
|
public T read() { |
|
String input; |
|
T ret = null; |
|
// Loop until validateInput sets ret to a non-null value |
|
while (ret == null) { |
|
// Prompt the user |
|
mCallback.prompt(); |
|
// Read a line of input |
|
input = mScanner.nextLine(); |
|
|
|
// Empty input calls invalidInput with an empty String. |
|
if (input == null || input.isEmpty()) { |
|
mCallback.invalidInput(""); |
|
} |
|
// Validate the input. |
|
ret = mCallback.validateInput(input); |
|
// Call invalidInput if ret failed. |
|
if (ret == null) { |
|
mCallback.invalidInput(input); |
|
} |
|
} |
|
return ret; |
|
} // end read method |
|
} // end class Reader |
|
|
|
/** |
|
* Creates a new Reader<Integer> which validates input for ShowNum and |
|
* exits on -1. |
|
* |
|
* @param prompt The prompt message to show. |
|
* @return A Reader with the correct prompt. |
|
*/ |
|
final Reader<Integer> createIntReader(final String prompt) { |
|
return new Reader<>(mScanner, new ReaderCallback<Integer>() { |
|
/** |
|
* Prompts the user to enter a number with the message prompt. |
|
*/ |
|
@Override |
|
public void prompt() { |
|
System.out.print(prompt); |
|
} // end prompt method |
|
|
|
/** |
|
* Validates an input from 1 to 30, or -1. |
|
* |
|
* @param value The String to parse. |
|
* @return The correct value, or null |
|
*/ |
|
@Override |
|
public Integer validateInput(String value) { |
|
if (value.isEmpty()) { |
|
return null; |
|
} |
|
try { |
|
// Parse the integer |
|
Integer i = Integer.parseInt(value); |
|
// -1 exits but is still valid |
|
if (i != -1 && (i < 1 || i > 30)) { |
|
return null; |
|
} |
|
return i; |
|
|
|
} catch (NumberFormatException unused) { |
|
// from Integer.parseInt if value isn't a number. |
|
// We don't care about the exception itself. |
|
return null; |
|
} |
|
} // end validateInput method |
|
|
|
/** |
|
* Prints an invalid message. |
|
* |
|
* @param input Unused. |
|
*/ |
|
@Override |
|
public void invalidInput(String input) { |
|
System.out.println("Please enter a number between 1 and 30, or -1 to exit."); |
|
} // end invalidInput method |
|
}); // end ReaderCallback implementation |
|
}// end createReader method |
|
|
|
/** |
|
* Runs the loop, prompting the user and displaying. |
|
* |
|
* @return true, or false if the user wants to exit. |
|
*/ |
|
public boolean run() { |
|
int rows = mRowsReader.read(); |
|
if (rows == -1) { |
|
return false; |
|
} |
|
|
|
int cols = mColsReader.read(); |
|
if (cols == -1) { |
|
return false; |
|
} |
|
|
|
// Note: We already checked for ShowNum's bounds so we don't need to catch anything. |
|
if (mShowNum == null) { |
|
// If mShowNum is null, create it once with rows, cols. |
|
mShowNum = new ShowNum(rows, cols); |
|
} else { |
|
// Otherwise, set the rows on an existing instance |
|
mShowNum.setRows(rows); |
|
mShowNum.setCols(cols); |
|
} |
|
// Display the asterisks. |
|
mShowNum.display(); |
|
return true; |
|
} // end run method |
|
|
|
/** |
|
* The main method. Loops run() until it returns false, in which it exits. |
|
* |
|
* @param args the command line arguments |
|
*/ |
|
public static void main(String[] args) { |
|
ShowNumClient client = new ShowNumClient(); |
|
while (client.run()) { |
|
// loop forever |
|
} |
|
} // end main method |
|
} // end class ShowNumClient |