Now using dependency injection for the XslTransformer instead of
[utils] / crawler / kiss / src / org / wamblee / crawler / kiss / main / ProgramActionExecutor.java
index 44132b5f5e88d42f93ee2d82f9f64f4bf2331aa8..51aef60f1a2148f58300f1c085b642e4028a322f 100644 (file)
@@ -17,6 +17,7 @@
 package org.wamblee.crawler.kiss.main;
 
 import java.util.EnumMap;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
@@ -27,6 +28,7 @@ import org.apache.commons.logging.LogFactory;
 import org.dom4j.DocumentFactory;
 import org.dom4j.Element;
 import org.wamblee.crawler.kiss.guide.Program;
+import org.wamblee.crawler.kiss.guide.TimeInterval;
 import org.wamblee.crawler.kiss.guide.Program.RecordingResult;
 
 /**
@@ -35,8 +37,9 @@ import org.wamblee.crawler.kiss.guide.Program.RecordingResult;
  * in what order and makes decisions in case of conflicts.
  */
 public class ProgramActionExecutor {
-    
-    private static final Log LOG = LogFactory.getLog(ProgramActionExecutor.class);
+
+    private static final Log LOG = LogFactory
+            .getLog(ProgramActionExecutor.class);
 
     /**
      * A map of category name to a set of program. Useful for displaying the
@@ -45,9 +48,9 @@ public class ProgramActionExecutor {
     private Map<String, Set<Program>> _interestingShows;
 
     /**
-     * Set of programs to record.
+     * Map of priority to set of programs.
      */
-    private Set<Program> _showsToRecord;
+    private Map<Integer, Set<Program>> _showsToRecord;
 
     /**
      * Map or recording result to a set of programs.
@@ -60,7 +63,7 @@ public class ProgramActionExecutor {
      */
     public ProgramActionExecutor() {
         _interestingShows = new TreeMap<String, Set<Program>>();
-        _showsToRecord = new TreeSet<Program>(new Program.TimeSorter());
+        _showsToRecord = new TreeMap<Integer, Set<Program>>();
         _recordings = new EnumMap<RecordingResult, Set<Program>>(
                 RecordingResult.class);
         for (RecordingResult result : RecordingResult.values()) {
@@ -79,7 +82,14 @@ public class ProgramActionExecutor {
      */
     public void recordProgram(int aPriority, Program aProgram) {
         LOG.info("priority = " + aPriority + ", program: " + aProgram);
-        _showsToRecord.add(aProgram);
+        // Putting -priority into the set makes sure that iteration order 
+        // over the priorities will go from higher priority to lower priority. 
+        Set<Program> programs = _showsToRecord.get(-aPriority);
+        if (programs == null) {
+            programs = new TreeSet<Program>(new Program.TimeSorter());
+            _showsToRecord.put(-aPriority, programs); 
+        }
+        programs.add(aProgram);
     }
 
     /**
@@ -102,13 +112,36 @@ public class ProgramActionExecutor {
 
     /**
      * Makes sure that the actions are performed.
-     * 
      */
     public void commit() {
-        for (Program program : _showsToRecord) {
-            RecordingResult result = program.record();
-            _recordings.get(result).add(program);
+        Set<TimeInterval> previouslyRecorded = new HashSet<TimeInterval>();
+        for (Integer priority : _showsToRecord.keySet()) {
+            for (Program program : _showsToRecord.get(priority)) {
+                TimeInterval interval = program.getInterval(); 
+                if ( recordingConflictExists(previouslyRecorded, interval)) { 
+                    _recordings.get(RecordingResult.CONFLICT).add(program);
+                } else {
+                    RecordingResult result = program.record();
+                    _recordings.get(result).add(program);
+                    previouslyRecorded.add(interval);
+                }
+            }
+        }
+    }
+    
+    /**
+     * Checks an interval for overlap with a previously recorded program. 
+     * @param aPreviouslyRecorded Previously recorded programs. 
+     * @param interval Interval. 
+     * @return True iff there is a recording conflict.
+     */
+    private boolean recordingConflictExists(Set<TimeInterval> aPreviouslyRecorded, TimeInterval interval) { 
+        for (TimeInterval recordedInterval: aPreviouslyRecorded ) { 
+            if ( interval.overlap(recordedInterval)) {
+                return true; 
+            }
         }
+        return false; 
     }
 
     /**
@@ -119,6 +152,8 @@ public class ProgramActionExecutor {
     public Element getReport() {
         DocumentFactory factory = DocumentFactory.getInstance();
         Element report = factory.createElement("report");
+        
+        Set<Program> reportedPrograms = new HashSet<Program>();
 
         for (RecordingResult result : RecordingResult.values()) {
             if (_recordings.get(result).size() > 0) {
@@ -127,6 +162,7 @@ public class ProgramActionExecutor {
 
                 for (Program program : _recordings.get(result)) {
                     recordingResult.add(program.asXml());
+                    reportedPrograms.add(program);
                 }
             }
         }
@@ -140,7 +176,16 @@ public class ProgramActionExecutor {
                     categoryElem.addAttribute("name", category);
                 }
                 for (Program program : _interestingShows.get(category)) {
-                    categoryElem.add(program.asXml());
+                    if ( !reportedPrograms.contains(program)) {
+                        categoryElem.add(program.asXml());
+                    } else { 
+                        LOG.info("Category '" + category + "', program " + program + " already reported");
+                    }
+                }
+                if ( categoryElem.elements().size() == 0 ) {
+                    // Remove empty category element. 
+                    LOG.info("Removing element for category '" + category + "'");
+                    interesting.remove(categoryElem);
                 }
             }