Annotate Filter interface with @NotNull
[rhynodge.git] / src / main / java / net / pterodactylus / rhynodge / filters / EpisodeFilter.java
index 9318d84..6aa3e1f 100644 (file)
@@ -19,10 +19,9 @@ package net.pterodactylus.rhynodge.filters;
 
 import static com.google.common.base.Optional.absent;
 import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.FluentIterable.from;
 import static java.util.Arrays.asList;
 
-import java.util.HashMap;
-import java.util.Map;
 import java.util.Collection;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -35,7 +34,12 @@ import net.pterodactylus.rhynodge.states.FailedState;
 import net.pterodactylus.rhynodge.states.TorrentState;
 import net.pterodactylus.rhynodge.states.TorrentState.TorrentFile;
 
+import com.google.common.base.Function;
 import com.google.common.base.Optional;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+import org.apache.log4j.Logger;
+import org.jetbrains.annotations.NotNull;
 
 /**
  * {@link Filter} implementation that extracts {@link Episode} information from
@@ -45,6 +49,8 @@ import com.google.common.base.Optional;
  */
 public class EpisodeFilter implements Filter {
 
+       private static final Logger logger = Logger.getLogger(EpisodeFilter.class);
+
        /** The pattern to parse episode information from the filename. */
        private static final Collection<Pattern> episodePatterns = asList(Pattern.compile("[Ss](\\d{2})[Ee](\\d{2})"), Pattern.compile("[^\\d](\\d{1,2})x(\\d{2})[^\\d]"));
 
@@ -55,27 +61,25 @@ public class EpisodeFilter implements Filter {
        /**
         * {@inheritDoc}
         */
+       @NotNull
        @Override
-       public State filter(State state) {
+       public State filter(@NotNull State state) {
                if (!state.success()) {
                        return FailedState.from(state);
                }
                checkState(state instanceof TorrentState, "state is not a TorrentState but a %s!", state.getClass());
 
                TorrentState torrentState = (TorrentState) state;
-               Map<Episode, Episode> episodes = new HashMap<Episode, Episode>();
+               final Multimap<Episode, TorrentFile> episodes = HashMultimap.create();
                for (TorrentFile torrentFile : torrentState) {
                        Optional<Episode> episode = extractEpisode(torrentFile);
                        if (!episode.isPresent()) {
                                continue;
                        }
-                       if (!episodes.containsKey(episode.get())) {
-                               episodes.put(episode.get(), episode.get());
-                       }
-                       episodes.get(episode.get()).addTorrentFile(torrentFile);
+                       episodes.put(episode.get(), torrentFile);
                }
 
-               return new EpisodeState(episodes.values());
+               return new EpisodeState(from(episodes.keySet()).transform(episodeFiller(episodes)).toSet());
        }
 
        //
@@ -83,6 +87,27 @@ public class EpisodeFilter implements Filter {
        //
 
        /**
+        * Returns a function that creates an {@link Episode} that contains all {@link
+        * TorrentFile}s.
+        *
+        * @param episodeTorrents
+        *              A multimap mapping episodes to torrent files.
+        * @return The function that performs the extraction of torrent files
+        */
+       private static Function<Episode, Episode> episodeFiller(final Multimap<Episode, TorrentFile> episodeTorrents) {
+               return new Function<Episode, Episode>() {
+                       @Override
+                       public Episode apply(Episode episode) {
+                               Episode completeEpisode = new Episode(episode.season(), episode.episode());
+                               for (TorrentFile torrentFile : episodeTorrents.get(episode)) {
+                                       completeEpisode.addTorrentFile(torrentFile);
+                               }
+                               return completeEpisode;
+                       }
+               };
+       }
+
+       /**
         * Extracts episode information from the given torrent file.
         *
         * @param torrentFile
@@ -91,6 +116,7 @@ public class EpisodeFilter implements Filter {
         *         no episode information could be found
         */
        private static Optional<Episode> extractEpisode(TorrentFile torrentFile) {
+               logger.debug(String.format("Extracting episode from %s...", torrentFile));
                for (Pattern episodePattern : episodePatterns) {
                        Matcher matcher = episodePattern.matcher(torrentFile.name());
                        if (!matcher.find() || matcher.groupCount() < 2) {
@@ -98,6 +124,7 @@ public class EpisodeFilter implements Filter {
                        }
                        String seasonString = matcher.group(1);
                        String episodeString = matcher.group(2);
+                       logger.debug(String.format("Parsing %s and %s as season and episode...", seasonString, episodeString));
                        int season = Integer.valueOf(seasonString);
                        int episode = Integer.valueOf(episodeString);
                        return Optional.of(new Episode(season, episode));