001package edu.pdx.cs410J.grader.poa;
002
003import com.google.common.annotations.VisibleForTesting;
004import com.google.common.eventbus.EventBus;
005import com.google.common.eventbus.Subscribe;
006import com.google.inject.Inject;
007import com.google.inject.Singleton;
008import edu.pdx.cs410J.grader.gradebook.Assignment;
009import edu.pdx.cs410J.grader.gradebook.GradeBook;
010
011import java.time.LocalDateTime;
012import java.time.format.DateTimeFormatter;
013import java.util.ArrayList;
014import java.util.Collections;
015import java.util.List;
016import java.util.Optional;
017import java.util.regex.Matcher;
018import java.util.regex.Pattern;
019import java.util.stream.Collectors;
020
021@Singleton
022public class POAAssignmentsPresenter {
023  private final EventBus bus;
024  private final POAAssignmentsView view;
025  private List<Assignment> poaAssignments = Collections.emptyList();
026
027  @Inject
028  public POAAssignmentsPresenter(EventBus bus, POAAssignmentsView view) {
029    this.bus = bus;
030    this.view = view;
031    this.view.addAssignmentSelectedHandler(this::fireAssignmentSelectedForAssignment);
032
033    this.bus.register(this);
034  }
035
036  private void fireAssignmentSelectedForAssignment(int index) {
037    Assignment assignment = this.poaAssignments.get(index);
038    this.view.setSelectedAssignmentDueDate(formatDueDate(assignment));
039    fireAssignmentSelectedEvent(assignment);
040  }
041
042  private void fireAssignmentSelectedEvent(Assignment assignment) {
043    this.bus.post(new AssignmentSelectedEvent(assignment));
044  }
045
046  @Subscribe
047  public void populateAssignmentNamesInView(GradeBookLoaded event) {
048    GradeBook book = event.getGradeBook();
049
050    poaAssignments = book.assignmentsStream().filter(this::isAssignmentPOA).collect(Collectors.toList());
051
052    if (!poaAssignments.isEmpty()) {
053      List<String> poaNames = poaAssignments.stream().map(Assignment::getName).collect(Collectors.toList());
054      this.view.setAssignments(poaNames);
055
056      selectAssignmentWithMostRecentlyPastDueDate();
057    }
058  }
059
060  private void selectAssignmentWithMostRecentlyPastDueDate() {
061    Optional<Assignment> mostRecentlyDueAssignment = this.poaAssignments.stream().
062      filter(a -> a.getDueDate() != null).
063      filter(a -> a.getDueDate().isBefore(LocalDateTime.now())).
064      sorted((a1, a2) -> a1.getDueDate().compareTo(a2.getDueDate()) * -1).
065      findFirst();
066
067    int index;
068    if (mostRecentlyDueAssignment.isPresent()) {
069      index = poaAssignments.indexOf(mostRecentlyDueAssignment.get());
070
071    } else {
072      index = 0;
073    }
074
075    setSelectedAssignmentInView(index);
076  }
077
078  private void setSelectedAssignmentInView(int index) {
079    this.view.setSelectedAssignment(index);
080    this.view.setSelectedAssignmentDueDate(formatDueDate(this.poaAssignments.get(index)));
081  }
082
083  private boolean isAssignmentPOA(Assignment assignment) {
084    return assignment.getType() == Assignment.AssignmentType.POA;
085  }
086
087  @Subscribe
088  public void selectAssignmentThatMatchesSubmissionSubject(POASubmissionSelected submission) {
089    List<String> numbersInSubject = findNumbersInString(submission.getSubmission().getSubject());
090    for (int i = 0; i < this.poaAssignments.size(); i++) {
091      Assignment assignment = this.poaAssignments.get(i);
092      for (String numberInSubject : numbersInSubject) {
093        if (assignment.getName().contains(numberInSubject)) {
094          setSelectedAssignmentInView(i);
095          fireAssignmentSelectedEvent(assignment);
096        }
097      }
098    }
099  }
100
101  @VisibleForTesting
102  static List<String> findNumbersInString(String string) {
103    Pattern pattern = Pattern.compile(".*?(\\d+).*?");
104    Matcher matcher = pattern.matcher(string);
105    List<String> numbers = new ArrayList<>();
106    while (matcher.find()) {
107      numbers.add(matcher.group(1));
108    }
109
110    return numbers;
111  }
112
113  @VisibleForTesting
114  static String formatDueDate(Assignment assignment) {
115    LocalDateTime dueDate = assignment.getDueDate();
116    if (dueDate == null) {
117      return "";
118    } else {
119      return dueDate.format(DateTimeFormatter.ofPattern("M/d/yyyy h:mm a"));
120    }
121  }
122}
123