-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathStatsScreen.java
More file actions
239 lines (227 loc) · 8.7 KB
/
StatsScreen.java
File metadata and controls
239 lines (227 loc) · 8.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
import java.util.ArrayList;
import java.time.*;
import java.time.temporal.ChronoUnit;
import java.util.ListIterator;
public class StatsScreen {
private static final String cancelKey = "C";
private static final String homeKey = "H";
public static void startStats() {
// 1. Clear the screen
Printer.clearScreen();
// 2. Get the data we need
long daysBetween = getDaysBetween();
// 2. Display the message
Printer.displayStatsStart(daysBetween);
// 3. Get user input
getUserInput(daysBetween);
}
private static long getDaysBetween() {
Day firstDay = Main.listOfEntries.getFirst().getData();
Day lastDay = Main.listOfEntries.getLast().getData();
long daysBetween = ChronoUnit.DAYS.between(firstDay.getLabel(),
lastDay.getLabel());
// Add 1 because between method is exclusive of lastDay
daysBetween += 1;
return daysBetween;
}
private static void getUserInput(long daysBetween) {
while(true) {
String userSelection = UserInput.getRegularInput();
// If user selects to cancel
if(userSelection.equals(cancelKey)) {
HomeScreen.startHome();
break;
}
// If user enters a number
try {
int userSelectionInt = Integer.parseInt(userSelection);
// If user enters an appropriate number
if(userSelectionInt >= 2 && userSelectionInt <= daysBetween) {
displayStats(userSelectionInt);
break;
}
Printer.displayBadSelection();
// If user doesn't enter a number
} catch(NumberFormatException exc) {
Printer.displayNotAnInteger();
}
}
}
private static void displayStats(int numberOfDaysChosen) {
// Clear the screen
Printer.clearScreen();
// Get the data we need
ArrayList<Day> daysToConsider = new ArrayList<Day>();
LinkedList<Day>.Node currentNode = Main.listOfEntries.getLast();
LocalDate lastDay = currentNode.getData().getLabel();
// Iterate through the list backwards
while(currentNode != null) {
LocalDate nextDay = currentNode.getData().getLabel();
// Compare the next day with the last day
long daysBetween = ChronoUnit.DAYS.between(nextDay, lastDay);
// Add 1 because the between method is exclusive of the last day
daysBetween += 1;
/* If the days between is still less than the number of days to be
looked at, add this day as a day to be considered in the stats */
if(daysBetween <= numberOfDaysChosen) {
daysToConsider.add(currentNode.getData());
/* If the days between has exceeded the number of days to be
looked at, break */
} else {
break;
}
currentNode = currentNode.getPrevious();
}
// Get our stats
getStats(daysToConsider);
// Wait for the user to specify they'd like to return home
while(true) {
String userSelection = UserInput.getRegularInput();
if(userSelection.equals(homeKey)) {
HomeScreen.startHome();
break;
}
Printer.displayBadSelection();
}
}
public static void getStats(ArrayList<Day> daysToConsider) {
ListIterator<Day> iterator = daysToConsider.listIterator(0);
// Set totals to default values
long minutesForStartTimeTotal = 0;
long minutesForEndTimeTotal = 0;
double durationTotal = 0;
// Set minimums & maximums to default values
Day firstDay = daysToConsider.getFirst();
Sleep[] firstDaySleeps = firstDay.getSleeps();
Sleep firstDayFirstSleep = firstDaySleeps[0];
Sleep firstDayLastSleep = firstDaySleeps[firstDaySleeps.length - 1];
int minimumStartTime = timeToMinutes(firstDayFirstSleep.getStartTime());
int maximumStartTime = minimumStartTime;
int minimumEndTime = timeToMinutes(firstDayLastSleep.getEndTime());
int maximumEndTime = minimumEndTime;
double minimumDuration = firstDay.getTotalDuration();
double maximumDuration = minimumDuration;
// Iterate through the list to check each day
while(iterator.hasNext()) {
Day nextDay = iterator.next();
Sleep[] sleepsList = nextDay.getSleeps();
Sleep firstSleep = sleepsList[0];
Sleep lastSleep = sleepsList[sleepsList.length - 1];
// Add to totals
minutesForStartTimeTotal += timeToMinutes(firstSleep.getStartTime());
minutesForEndTimeTotal += timeToMinutes(lastSleep.getEndTime());
double currentDuration = nextDay.getTotalDuration();
durationTotal += currentDuration;
// Compare minimums & maximums
int minutesForStartTime = timeToMinutes(firstSleep.getStartTime());
if(minutesForStartTime < minimumStartTime) {
minimumStartTime = minutesForStartTime;
} else if(minutesForStartTime > maximumStartTime) {
maximumStartTime = minutesForStartTime;
}
int minutesForEndTime = timeToMinutes(lastSleep.getEndTime());
if(minutesForEndTime < minimumEndTime) {
minimumEndTime = minutesForEndTime;
} else if(minutesForEndTime > maximumEndTime) {
maximumEndTime = minutesForEndTime;
}
if(currentDuration < minimumDuration) {
minimumDuration = currentDuration;
} else if(currentDuration > maximumDuration) {
maximumDuration = currentDuration;
}
}
// Calculate averages
String startAvgString = minutesToHoursFormatted(minutesForStartTimeTotal
/ daysToConsider.size());
String endAvgString = minutesToHoursFormatted(minutesForEndTimeTotal
/ daysToConsider.size());
// Display averages
Printer.displayOperation("Average", startAvgString, endAvgString);
Printer.displayOperationDuration("Average", (durationTotal
/ daysToConsider.size()));
// Calculate & display medians
getMedians(daysToConsider);
// Display minimums & maximums
Printer.displayOperation("Earliest",
minutesToHoursFormatted(minimumStartTime),
minutesToHoursFormatted(minimumEndTime));
Printer.displayOperationDuration("Shortest", minimumDuration);
Printer.displayOperation("Latest",
minutesToHoursFormatted(maximumStartTime),
minutesToHoursFormatted(maximumEndTime));
Printer.displayOperationDuration("Longest", maximumDuration);
}
private static void getMedians(ArrayList<Day> daysToConsider) {
int medianIndex = (daysToConsider.size() / 2) - 1;
// Minus 1 because list starts at 0
/* If the list is divisible by 2, we need to get totals of the two
medians then divide by 2 */
if(daysToConsider.size() % 2 == 0) {
Day day1 = daysToConsider.get(medianIndex);
Day day2 = daysToConsider.get(medianIndex + 1);
Sleep[] day1Sleeps = day1.getSleeps();
Sleep[] day2Sleeps = day2.getSleeps();
// Start time total
int startMinutesTotal = timeToMinutes(day1Sleeps[0].getStartTime());
startMinutesTotal += timeToMinutes(day2Sleeps[0].getStartTime());
// End time total
int endMinutesTotal = timeToMinutes(
day1Sleeps[day1Sleeps.length - 1].getEndTime());
endMinutesTotal += timeToMinutes(
day2Sleeps[day2Sleeps.length - 1].getEndTime());
// Duration total
double durationTotal = day1.getTotalDuration();
durationTotal += day2.getTotalDuration();
// Print it out
Printer.displayOperation("Median",
minutesToHoursFormatted(startMinutesTotal / 2),
minutesToHoursFormatted(endMinutesTotal / 2));
Printer.displayOperationDuration("Median", (durationTotal / 2));
// If the list is not divisible by 2, just get the middle item
} else {
Day medianDay = daysToConsider.get(medianIndex + 1);
// Plus 1 due to rounding
Sleep[] medianDaySleeps = medianDay.getSleeps();
Printer.displayOperation("Median",
minutesToHoursFormatted(timeToMinutes(
medianDaySleeps[0].getStartTime())),
minutesToHoursFormatted(timeToMinutes(
medianDaySleeps[medianDaySleeps.length - 1].getEndTime())));
Printer.displayOperationDuration("Median",
medianDay.getTotalDuration());
}
}
// Takes total minutes and converts it into a formatted timestamp string
private static String minutesToHoursFormatted(long minutesTotal) {
long hour = minutesTotal / 60;
long minute = minutesTotal % 60;
boolean isPM = hour > 12;
boolean isMidnightOrNoon = hour % 12 == 0;
String timeStamp = "";
if(isMidnightOrNoon) {
timeStamp += "12";
} else {
timeStamp += hour % 12;
}
timeStamp += ":" + String.format("%02d", minute);
if(isPM) {
timeStamp += " PM";
} else {
timeStamp += " AM";
}
return timeStamp;
}
// Converts a LocalDateTime to minutes
private static int timeToMinutes(LocalDateTime time) {
int minutesTotal = time.getHour() * 60;
minutesTotal += time.getMinute();
return minutesTotal;
}
public static String getCancelKey() {
return cancelKey;
}
public static String getHomeKey() {
return homeKey;
}
}