diff --git a/src/CustomTimer.java b/src/CustomTimer.java
new file mode 100644
index 0000000..7825877
--- /dev/null
+++ b/src/CustomTimer.java
@@ -0,0 +1,203 @@
+import java.io.*;
+import java.util.NoSuchElementException;
+import java.util.Scanner;
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * Singleton timer class.
+ * Warning: gets confusing with all the uses of timer as a word, vs the actual JDK Timer class.
+ */
+public class CustomTimer {
+
+ private static CustomTimer singleton = new CustomTimer();
+ private Timer currentTimer;
+ protected boolean isTimerRunning = false;
+
+ public Timer getCurrentTimer() {
+ return currentTimer;
+ }
+
+ private CustomTimer() {}
+
+ /* Static 'instance' method */
+ public static CustomTimer getInstance() {
+ return singleton;
+ }
+
+ //File paths
+ String timerLength = Main.inputPath + "TimerLength.txt";
+ String timerTXT = Main.outputPath + "Timer.txt";
+
+
+ /*--- Methods ---*/
+
+ /**
+ * Sets the value the timer will go to on initial start, or after a restart or stop
+ *
+ * @param seconds a positive integer
+ * @see #getInitialTimerLength()
+ */
+ public void setInitialTimerLength(int seconds) throws IOException {
+ if (seconds <= 0) throw new IllegalArgumentException("Cannot set initial timer value to 0");
+ //open TimerLength file and set a new value
+ Writer fileWriter = new FileWriter(timerLength);
+ fileWriter.write(String.valueOf(seconds));
+ fileWriter.close();
+ }
+
+ /**
+ * Resets the timer back to beginning value and starts it again
+ * @see #start()
+ * @see #stop()
+ * @see #pause()
+ */
+ public void restart() throws IOException, InvalidDataException {
+ //stop timer
+ if (currentTimer != null) {
+ currentTimer.cancel();
+ isTimerRunning = false;
+ }
+
+ //write initial timer length to Timer.txt
+ set(getInitialTimerLength());
+
+ //start
+ start();
+ }
+
+ /**
+ * Gets the total length of the timer. Not to be confused with the current length,
+ * this value is where the timer will go to when restarting or starting after a stop.
+ *
+ * @return timer length in seconds
+ * @throws IOException
+ * @throws NoSuchElementException TimerLength.txt contains an unexpected character.
+ * @see #setInitialTimerLength(int)
+ */
+ public int getInitialTimerLength() throws IOException, NoSuchElementException, InvalidDataException {
+ //open TimerLength file and gets the current value
+ File timerSettings = new File(timerLength);
+ Scanner scanner = new Scanner(timerSettings);
+ int value = scanner.nextInt();
+ if (value <= 0) throw new InvalidDataException("TimerLength.txt cannot contain a non-postive value");
+ return value;
+ }
+
+ /**
+ * Start the timer (initial or after a pause)
+ * @throws IOException
+ * @throws NoSuchElementException
+ * @see #stop()
+ * @see #pause()
+ * @see #restart()
+ */
+ public void start() throws IOException, NoSuchElementException, InvalidDataException {
+ if (!isTimerRunning) { //prevent starting when there is already a timer. no doubling up!
+ if (get() <= 0) { //if timer is currently at 0, restart
+ restart();
+ } else { //otherwise, resume from last position by starting CountdownTimer task
+ isTimerRunning = true;
+ currentTimer = new Timer();
+ TimerTask task = new CountdownTimer();
+ currentTimer.schedule(task,0, 1000);
+ }
+ } else System.err.println("Timer already running!");
+ }
+
+ /**
+ * Completely stops and cancels the timer. NOT EQUIVALENT TO A PAUSE.
+ * Starting after this state will restart the timer.
+ *
+ * @throws NullPointerException there is no current timer or {@link TimerTask} running
+ * @throws IOException if I/O error is encountered when writing to Timer.txt
+ * @see #start()
+ * @see #pause()
+ * @see #restart()
+ */
+ public void stop() throws NullPointerException, IOException {
+ //stop the current TimerTask
+ if (currentTimer != null) {
+ currentTimer.cancel();
+ isTimerRunning = false;
+ }
+ //set Timer.txt to nothing [will cause start() to restart timer if called next]
+ set(0);
+ }
+
+ /**
+ * Pauses the current timer state. Starting from this after this state will
+ * continue the timer from where the timer left off.
+ * Does nothing if there is no active timer
+ *
+ * @see #start()
+ * @see #stop()
+ * @see #restart()
+ */
+ public void pause() {
+ //cancel TimerTask to stop countdown. Keeps value, so start() can resume from it
+ if (currentTimer != null) {
+ currentTimer.cancel();
+ isTimerRunning = false;
+ }
+ }
+
+ /**
+ * Set the current value of the timer
+ *
+ * @param seconds a second value (non-negative)
+ * @throws IOException if any I/O error occurs when accessing Timer.txt
+ */
+ public void set(int seconds) throws IOException {
+ if (seconds < 0) {
+ throw new IllegalArgumentException("Cannot set a timer for negative seconds!");
+ }
+ Writer fileWriter = new FileWriter(timerTXT);
+ fileWriter.write(String.valueOf(seconds));
+ fileWriter.close();
+ }
+
+ /**
+ * Gets the current value of the timer.
+ * @return time left in seconds.
+ * @throws FileNotFoundException timer.txt cannot be found
+ * @throws NoSuchElementException timer.txt contains an unexpected character
+ */
+ public int get() throws FileNotFoundException, NoSuchElementException {
+ //open Timer.txt and scan first integer
+ File timerSettings = new File(timerTXT);
+ Scanner scanner = new Scanner(timerSettings);
+ return scanner.nextInt();
+ }
+}
+
+/**
+ * Begins countdown from current value in the Timer.txt
file. {@link TimerTask} to be scheduled in {@link Timer#schedule(TimerTask, long, long)} for the countdown timer system.
+ * @implNote Be careful with scheduling this function too fast/often, it doesn't implement any
+ * file locks and is not atomic as of the current version.
+ * @implNote Does not use system clock (or at least efficiently. Timer will start to lag behind if more system resources are used or application is active with other tasks
+ */
+class CountdownTimer extends TimerTask {
+
+ public void run() {
+
+ /*todo, implement lock*/
+
+ CustomTimer timer = CustomTimer.getInstance();
+
+ try {
+ int currentTime = timer.get();
+ if (currentTime <= 0) {
+ System.out.println("Timer Finished!\n>");
+ CustomTimer.getInstance().isTimerRunning = false;
+ timer.getCurrentTimer().cancel();
+ } else {
+ timer.set(currentTime - 1);
+ }
+ } catch (FileNotFoundException exception) {
+ exception.printStackTrace();
+ } catch (IOException exception) {
+ exception.printStackTrace();
+ }
+ }
+}
diff --git a/src/InvalidDataException.java b/src/InvalidDataException.java
new file mode 100644
index 0000000..0a47611
--- /dev/null
+++ b/src/InvalidDataException.java
@@ -0,0 +1,8 @@
+/**
+ * A file read in by the application contains invalid data, typically due to outside tampering.
+ */
+public class InvalidDataException extends Exception {
+ public InvalidDataException(String message) {
+ super(message);
+ }
+}
diff --git a/src/Main.java b/src/Main.java
index bfd2b9d..42d00b4 100644
--- a/src/Main.java
+++ b/src/Main.java
@@ -2,9 +2,7 @@
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.*;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.Scanner;
+import java.util.*;
import java.util.stream.Stream;
public class Main {
@@ -37,6 +35,13 @@ private static void CLIParse(String input) {
System.out.println("TOURNAMENT NUMBER");
System.out.println(" 'number set', update current tourney number");
+ System.out.println("TIMER");
+ System.out.println(" 'timer set', determine timer length");
+ System.out.println(" 'timer start', start the timer");
+ System.out.println(" 'timer pause', pause the timer");
+ System.out.println(" 'timer stop', ends the timer early");
+ System.out.println(" 'timer restart', restarts the timer");
+
System.out.println("TEAMS");
System.out.println(" 'team add', add a team");
System.out.println(" 'team add-noimg', add a team (no image)");
@@ -122,6 +127,58 @@ private static void CLIParse(String input) {
}
break;
+ case "timer set":
+ CustomTimer timer = CustomTimer.getInstance();
+ try {
+ System.out.println("How many seconds would you like to set the timer for");
+ int setTime = scanner.nextInt();
+ timer.pause(); //pause timer to prevent ticking
+ timer.setInitialTimerLength(setTime); //set new initial
+ timer.set(setTime); //set currently displayed timer to not confuse user
+ } catch (IOException exception) {
+ exception.printStackTrace();
+ } catch (InputMismatchException exception) {
+ exception.printStackTrace(); //thrown by scanner
+ } catch (NoSuchElementException exception) {
+ exception.printStackTrace();
+ } catch (IllegalArgumentException exception) {
+ System.out.println("Cannot set initial timer value to 0!");
+ }
+ break;
+
+ case "timer start":
+ try {
+ CustomTimer.getInstance().start();
+ } catch (IOException exception) {
+ exception.printStackTrace();
+ } catch (NoSuchElementException exception) {
+ exception.printStackTrace();
+ } catch (InvalidDataException e) {
+ e.printStackTrace();
+ }
+ break;
+
+ case "timer stop":
+ try {
+ CustomTimer.getInstance().stop();
+ System.out.println("Stopped!");
+ } catch (IOException exception) {
+ exception.printStackTrace();
+ }
+ break;
+
+ case "timer pause":
+ CustomTimer.getInstance().pause();
+ break;
+
+ case "timer restart": case "timer reset":
+ try {
+ CustomTimer.getInstance().restart();
+ } catch (IOException | InvalidDataException exception) {
+ exception.printStackTrace();
+ }
+ break;
+
default:
System.out.println("Unknown Input. Type 'help' for commands");
}
@@ -207,6 +264,10 @@ public static void verifyContent() throws IOException {
//check teams.txt
File teams = new File(inputPath + "teams.txt");
teams.createNewFile(); // if file already exists will do nothing
+
+ //check TimerLength.txt
+ File timerLength = new File(inputPath + "TimerLength.txt");
+ teams.createNewFile(); // if file already exists will do nothing
}
/**