--- /dev/null
+/*
+ * 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;
+ }
+}