package com.google.sps.utilities;

import com.google.common.collect.Sets;
import com.google.sps.data.Event;
import com.google.sps.data.User;
import com.google.sps.data.VolunteeringOpportunity;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.javatuples.Pair;

public class EventRanker {
  private static Double SIMILAR_WEIGHT = 0.7;

  /**
   * Sorts events based on each event's score. Breaks ties with the event's date; the more recent
   * event will be ranked higher. Makes the assumption that all events are NOT in the past.
   *
   * @param user The user for whom the events are ranked
   * @param directMatches A {@link Set} of events that need to be ranked; direct event maches
   * @param similarMatches A {@link Set} of events that need to be ranked; similar event matches
   * @return A {@link List} of events that is ranked according to each element's score
   */
  public static List<Event> rankEvents(User user, Set<Event> events) {
    Map<Event, Double> eventScoreMap = getEventScoreMap(user, events);
    List<Event> rankedEvents = new ArrayList<>(eventScoreMap.keySet());
    Collections.sort(
        rankedEvents,
        (Event event1, Event event2) -> {
          int comparison = eventScoreMap.get(event1).compareTo(eventScoreMap.get(event2));
          if (comparison == 0) {
            comparison = event2.getDate().compareTo(event1.getDate());
          }
          return comparison;
        });
    Collections.reverse(rankedEvents);
    return rankedEvents;
  }

  private static Map<Event, Double> getEventScoreMap(User user, Set<Event> events) {
    Pair<Set<Pair<Event, Integer>>, Set<Pair<Event, Integer>>> allEvents =
        new GetLabelCategories().getEventRelevancy(events, user);
    Set<Pair<Event, Integer>> directEventPairs = allEvents.getValue0();
    Set<Pair<Event, Integer>> similarEventPairs = allEvents.getValue1();

    Map<Event, Double> eventScoreMap = new HashMap<>();
    for (Pair<Event, Integer> eventRelevancyPair : directEventPairs) {
      eventScoreMap.put(eventRelevancyPair.getValue0(), new Double(eventRelevancyPair.getValue1()));
    }
    for (Pair<Event, Integer> eventRelevancyPair : similarEventPairs) {
      eventScoreMap.put(eventRelevancyPair.getValue0(), SIMILAR_WEIGHT * eventRelevancyPair.getValue1());
    }
    return eventScoreMap;
  }
}

@@ -508,16 +508,22 @@
  static 
+final 
 Double S
@@ -542,16 +542,69 @@
 T = 0.7;
+%0A  private static final Double NO_MATCH_WEIGHT = 0.0;
 %0A%0A  /**%0A
@@ -2128,16 +2128,166 @@
 ue1();%0A%0A
+    Set%3CEvent%3E directEvents = new HashSet%3C%3E();%0A    Set%3CEvent%3E similarEvents = new HashSet%3C%3E();%0A    Set%3CEvent%3E noMatchEvents = new HashSet%3C%3E(events);%0A%0A
     Map%3C
@@ -2411,34 +2411,36 @@
 %7B%0A      
-e
+E
 vent
-ScoreMap.put(
+ directEvent = 
 eventRel
@@ -2461,16 +2461,53 @@
 Value0()
+;%0A      eventScoreMap.put(directEvent
 , new Do
@@ -2541,24 +2541,61 @@
 Value1()));%0A
+      directEvents.add(directEvent);%0A
     %7D%0A    fo
@@ -2656,24 +2656,83 @@
 entPairs) %7B%0A
+      Event similarEvent = eventRelevancyPair.getValue0();%0A
       eventS
@@ -2821,24 +2821,245 @@
 tValue1());%0A
+      similarEvents.add(similarEvent);%0A    %7D%0A    noMatchEvents.removeAll(directEvents);%0A    noMatchEvents.removeAll(similarEvents);%0A    for (Event event : noMatchEvents) %7B%0A      eventScoreMap.put(event, NO_MATCH_WEIGHT);%0A
     %7D%0A    re

Change EventRanker to accept noMatchEvents