001package edu.pdx.cs410J.grader.poa; 002 003import com.google.common.annotations.VisibleForTesting; 004import com.google.common.base.Strings; 005import com.google.common.eventbus.EventBus; 006import com.google.common.eventbus.Subscribe; 007import com.google.inject.Inject; 008import com.google.inject.Singleton; 009import edu.pdx.cs410J.grader.gradebook.Assignment; 010import edu.pdx.cs410J.grader.gradebook.Grade; 011import edu.pdx.cs410J.grader.gradebook.Student; 012 013import java.util.Optional; 014 015@Singleton 016public class POAGradePresenter { 017 private final EventBus bus; 018 private final POAGradeView view; 019 020 private POASubmission submission; 021 private Assignment assignment; 022 private Student student; 023 private boolean isLate; 024 private Double score; 025 private CurrentGradeCalculator currentGradeCalculator; 026 027 @Inject 028 public POAGradePresenter(EventBus bus, POAGradeView view) { 029 this.bus = bus; 030 this.view = view; 031 032 this.bus.register(this); 033 034 this.view.addIsLateHandler(POAGradePresenter.this::setIsLate); 035 this.view.addScoreValueHandler(this::setScoreValue); 036 this.view.addRecordGradeHandler(this::publishScoreToMessageBusAndDisplayNextPOA); 037 } 038 039 private void publishScoreToMessageBusAndDisplayNextPOA() { 040 if (this.score == null) { 041 throw new IllegalStateException("No score specified"); 042 } 043 044 RecordGradeEvent recordGrade = new RecordGradeEvent(this.score, this.student, this.assignment, this.isLate); 045 this.bus.post(recordGrade); 046 this.view.setScoreHasBeenRecorded(true); 047 048 SelectNextPOAEvent displayNextPOA = new SelectNextPOAEvent(); 049 this.bus.post(displayNextPOA); 050 } 051 052 @Subscribe 053 public void determineIfSubmissionIsLate(POASubmissionSelected event) { 054 this.submission = event.getSubmission(); 055 056 clearScore(); 057 determineIfPOAIsLate(); 058 } 059 060 private void clearScore() { 061 this.score = null; 062 this.view.setErrorInScore(false); 063 this.view.setScore(""); 064 this.view.setScoreHasBeenRecorded(false); 065 } 066 067 @Subscribe 068 public void determineIfStudentsPOAIsLate(StudentSelectedEvent event) { 069 this.student = event.getSelectedStudent(); 070 071 updateViewBasedOnCurrentState(); 072 } 073 074 @Subscribe 075 public void determineIfAssignmentIsLate(AssignmentSelectedEvent event) { 076 this.assignment = event.getAssignment(); 077 078 updateViewBasedOnCurrentState(); 079 } 080 081 private void updateViewBasedOnCurrentState() { 082 clearScore(); 083 determineIfPOAIsLate(); 084 setTotalPointsValue(); 085 setDefaultValueOfScore(); 086 } 087 088 private void setTotalPointsValue() { 089 String totalPoints; 090 if (this.assignment == null) { 091 totalPoints = "??"; 092 093 } else { 094 totalPoints = formatTotalPoints(this.assignment.getPoints()); 095 } 096 this.view.setTotalPoints(totalPoints); 097 } 098 099 private void setDefaultValueOfScore() { 100 if (this.currentGradeCalculator == null) { 101 this.score = null; 102 this.view.setScore(""); 103 this.view.setScoreHasBeenRecorded(false); 104 return; 105 } 106 107 Optional<Double> currentGrade = this.currentGradeCalculator.getCurrentGradeFor(this.assignment, this.student); 108 if (currentGrade.isPresent()) { 109 this.score = currentGrade.get(); 110 this.view.setScore(formatTotalPoints(this.score)); 111 this.view.setScoreHasBeenRecorded(true); 112 113 } else if (this.assignment == null) { 114 this.score = null; 115 this.view.setScore(""); 116 this.view.setScoreHasBeenRecorded(false); 117 118 } else { 119 this.score = this.assignment.getPoints(); 120 this.view.setScore(formatTotalPoints(this.score)); 121 this.view.setScoreHasBeenRecorded(false); 122 } 123 124 this.view.setErrorInScore(false); 125 } 126 127 @Subscribe 128 public void createCurrentGradeCalculator(GradeBookLoaded event) { 129 this.currentGradeCalculator = new CurrentGradeCalculator(); 130 } 131 132 private void determineIfPOAIsLate() { 133 if (this.submission != null && this.assignment != null && this.student != null) { 134 enableView(); 135 136 if (this.assignment.isSubmissionLate(this.submission.getSubmitTime())) { 137 setIsLate(true); 138 139 } else { 140 setIsLate(false); 141 } 142 143 } else { 144 disableView(); 145 } 146 } 147 148 private void setIsLate(boolean isLate) { 149 this.isLate = isLate; 150 this.view.setIsLate(isLate); 151 } 152 153 private void enableView() { 154 this.view.setIsEnabled(true); 155 } 156 157 private void disableView() { 158 setIsLate(false); 159 this.view.setIsEnabled(false); 160 } 161 162 @VisibleForTesting 163 boolean isLate() { 164 return this.isLate; 165 } 166 167 @VisibleForTesting 168 static String formatTotalPoints(double points) { 169 return String.format("%.2f", points); 170 } 171 172 public void setScoreValue(String scoreValue) { 173 if (Strings.isNullOrEmpty(scoreValue)) { 174 this.score = null; 175 this.view.setErrorInScore(false); 176 return; 177 } 178 179 try { 180 double score = Double.parseDouble(scoreValue); 181 182 validateScoreIsBetweenZeroAndAssignmentsTotalPoints(score); 183 184 } catch (NumberFormatException ex) { 185 this.score = null; 186 this.view.setErrorInScore(true); 187 } 188 } 189 190 private void validateScoreIsBetweenZeroAndAssignmentsTotalPoints(double score) { 191 if (score < 0.0) { 192 this.score = null; 193 this.view.setErrorInScore(true); 194 195 } else if (score > this.assignment.getPoints()) { 196 this.score = null; 197 this.view.setErrorInScore(true); 198 199 } else { 200 this.score = score; 201 this.view.setErrorInScore(false); 202 } 203 } 204 205 public Double getScore() { 206 return score; 207 } 208 209 private class CurrentGradeCalculator { 210 211 public CurrentGradeCalculator() { 212 } 213 214 public Optional<Double> getCurrentGradeFor(Assignment assignment, Student student) { 215 if (student == null || assignment == null) { 216 return Optional.empty(); 217 } 218 219 Grade grade = student.getGrade(assignment); 220 if (grade != null) { 221 return Optional.of(grade.getScore()); 222 } else { 223 return Optional.empty(); 224 } 225 } 226 } 227}