Migration to maven almost complete. At least everything builds and works
[utils] / crawler / kiss / src / main / java / org / wamblee / crawler / kiss / guide / Program.java
diff --git a/crawler/kiss/src/main/java/org/wamblee/crawler/kiss/guide/Program.java b/crawler/kiss/src/main/java/org/wamblee/crawler/kiss/guide/Program.java
new file mode 100644 (file)
index 0000000..44bdc52
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * Copyright 2005 the original author or authors.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.wamblee.crawler.kiss.guide;
+
+import java.util.Comparator;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.dom4j.DocumentFactory;
+import org.dom4j.Element;
+import org.wamblee.crawler.Action;
+import org.wamblee.crawler.Page;
+import org.wamblee.crawler.PageException;
+import org.wamblee.crawler.kiss.main.SystemProperties;
+
+/**
+ * Represents a television program.
+ */
+public class Program {
+
+    private static final String ELEM_PROGRAM = "program";
+
+    private static final String ELEM_NAME = "name";
+
+    private static final String ELEM_KEYWORDS = "keywords";
+
+    private static final String ELEM_DESCRIPTION = "description";
+
+    private static final String ELEM_CHANNEL = "channel";
+
+    private static final String ELEM_INTERVAL = "interval";
+
+    private static final String ELEM_END_TIME = "end";
+
+    private static final String ELEM_BEGIN_TIME = "begin";
+
+    /**
+     * Lexicographical comparison of programs based on (time, title, channel).
+     * 
+     */
+    public static class TimeComparator implements Comparator<Program> {
+
+        /**
+         * Lexicographical comparison based on start time, program name, and
+         * channel.
+         * 
+         * @param aProgram1
+         *            First program.
+         * @param aProgram2
+         *            Second program.
+         * @return See {@link Comparator#compare(T, T)}
+         */
+        public int compare(Program aProgram1, Program aProgram2) {
+            int value = aProgram1.getInterval().getBegin().compareTo(
+                    aProgram2.getInterval().getBegin());
+            if (value != 0) {
+                return value;
+            }
+            value = aProgram1.getName().compareTo(aProgram2.getName());
+            if (value != 0) {
+                return value;
+            }
+            return aProgram1.getChannel().compareTo(aProgram2.getChannel());
+        }
+    }
+
+    private static final Log LOG = LogFactory.getLog(Program.class);
+
+    /**
+     * Name of the record action on the program details page.
+     */
+    private static final String RECORD_ACTION = "record";
+
+    /**
+     * Result of recording a program.
+     * 
+     */
+    public enum RecordingResult {
+        /**
+         * Successfully recorded.
+         */
+        OK,
+
+        /**
+         * Already recorded program.
+         */
+        DUPLICATE,
+
+        /**
+         * Recording conflict with another program.
+         */
+        CONFLICT,
+
+        /**
+         * Program occurred in the past.
+         */
+        OLDSHOW,
+
+        /**
+         * Program could not be recorded for technical reasons.
+         */
+        ERROR;
+    };
+
+    /**
+     * Indent string to use for pretty printing.
+     */
+    private static final String INDENT = "       ";
+
+    /**
+     * Channel the program is on.
+     */
+    private String _channel;
+
+    /**
+     * Program name.
+     */
+    private String _name;
+
+    /**
+     * Program description.
+     */
+    private String _description;
+
+    /**
+     * Keywords or classification of the program.
+     */
+    private String _keywords;
+
+    /**
+     * Time interval for the program (from/to).
+     */
+    private TimeInterval _interval;
+
+    /**
+     * Action to execute to obtain program information and/or record the
+     * program.
+     */
+    private Action _programInfo;
+
+    /**
+     * Constructs the program.
+     * 
+     * @param aChannel
+     *            Channel name.
+     * @param aName
+     *            Program name.
+     * @param aDescription
+     *            Description.
+     * @param aKeywords
+     *            Keywords/classification.
+     * @param aInterval
+     *            Time interval.
+     * @param aProgramInfo
+     *            Action to execute for detailed program information or for
+     *            recording the page.
+     */
+    public Program(String aChannel, String aName, String aDescription,
+            String aKeywords, TimeInterval aInterval, Action aProgramInfo) {
+        _channel = aChannel;
+        _name = aName;
+        _description = aDescription;
+        _keywords = aKeywords;
+        _interval = aInterval;
+        _programInfo = aProgramInfo;
+    }
+
+    /**
+     * Gets the channel.
+     * 
+     * @return Channel.
+     */
+    public String getChannel() {
+        return _channel;
+    }
+
+    /**
+     * Gets the program name.
+     * 
+     * @return Name.
+     */
+    public String getName() {
+        return _name;
+    }
+
+    /**
+     * Gets the description.
+     * 
+     * @return Description.
+     */
+    public String getDescription() {
+        return _description;
+    }
+
+    /**
+     * Gets the keywords/classification.
+     * 
+     * @return Keywords/classification
+     */
+    public String getKeywords() {
+        return _keywords;
+    }
+
+    /**
+     * Gets the time interval.
+     * 
+     * @return Time interval.
+     */
+    public TimeInterval getInterval() {
+        return _interval;
+    }
+
+    /**
+     * Checks if recording is possible.
+     * 
+     * @return True iff recording is possible.
+     */
+    public boolean isRecordingPossible() {
+        try {
+            return _programInfo.execute().getAction(RECORD_ACTION) != null;
+        } catch (PageException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Records the show.
+     * 
+     * @return Status describing the result of recording.
+     */
+    public RecordingResult record() {
+        LOG.info("Recording " + this);
+        if (SystemProperties.isRecordDisabled()) {
+            return RecordingResult.OK;
+        }
+        try {
+            Action record = _programInfo.execute().getAction(RECORD_ACTION);
+            if (record == null) {
+                LOG.info("  result: " + RecordingResult.OLDSHOW);
+                return RecordingResult.OLDSHOW;
+            }
+            Page result = record.execute();
+            RecordingResult recordingResult = RecordingResult.valueOf(result
+                    .getContent().getText());
+            LOG.info("  result: " + recordingResult);
+            return recordingResult;
+        } catch (PageException e) {
+            LOG.warn("Technical problem recording program: '" + this + "'", e);
+            LOG.info("  result: " + RecordingResult.ERROR);
+            return RecordingResult.ERROR;
+        }
+    }
+
+    /**
+     * Accepts the visitor.
+     * 
+     * @param aVisitor
+     *            Visitor.
+     */
+    public void accept(Visitor aVisitor) {
+        aVisitor.visitProgram(this);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return _interval + " - " + _name + " (" + _channel + "/" + _keywords
+                + ")" + "\n"
+                + (INDENT + _description).replaceAll("\n", "\n" + INDENT);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object aObject) {
+        if (!(aObject instanceof Program)) {
+            return false;
+        }
+        Program program = (Program) aObject;
+        return getName().equals(program.getName())
+                && _programInfo.equals(program._programInfo);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        return getName().hashCode();
+    }
+
+    /**
+     * Converts program information to XML.
+     * 
+     * @return XML representation of program information.
+     */
+    public Element asXml() {
+        DocumentFactory factory = DocumentFactory.getInstance();
+        Element program = factory.createElement(ELEM_PROGRAM);
+        program.addElement(ELEM_NAME).setText(getName());
+        program.addElement(ELEM_DESCRIPTION).setText(getDescription());
+        program.addElement(ELEM_KEYWORDS).setText(getKeywords());
+        program.addElement(ELEM_CHANNEL).setText(getChannel());
+        Element interval = program.addElement(ELEM_INTERVAL);
+        interval.addElement(ELEM_BEGIN_TIME).setText(
+                getInterval().getBegin().toString());
+        interval.addElement(ELEM_END_TIME).setText(
+                getInterval().getEnd().toString());
+        return program;
+    }
+}