(no commit message)
[utils] / crawler / kiss / src / main / java / org / wamblee / crawler / kiss / guide / Program.java
1 /*
2  * Copyright 2005 the original author or authors.
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  * 
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  * 
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.wamblee.crawler.kiss.guide;
18
19 import java.util.Comparator;
20
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23 import org.dom4j.DocumentFactory;
24 import org.dom4j.Element;
25 import org.wamblee.crawler.Action;
26 import org.wamblee.crawler.Page;
27 import org.wamblee.crawler.PageException;
28 import org.wamblee.crawler.kiss.main.SystemProperties;
29
30 /**
31  * Represents a television program.
32  *
33  * @author Erik Brakkee
34  */
35 public class Program {
36
37     private static final String ELEM_PROGRAM = "program";
38
39     private static final String ELEM_NAME = "name";
40
41     private static final String ELEM_KEYWORDS = "keywords";
42
43     private static final String ELEM_DESCRIPTION = "description";
44
45     private static final String ELEM_CHANNEL = "channel";
46
47     private static final String ELEM_INTERVAL = "interval";
48
49     private static final String ELEM_END_TIME = "end";
50
51     private static final String ELEM_BEGIN_TIME = "begin";
52
53     /**
54      * Lexicographical comparison of programs based on (time, title, channel).
55      * 
56      */
57     public static class TimeComparator implements Comparator<Program> {
58
59         /**
60          * Lexicographical comparison based on start time, program name, and
61          * channel.
62          * 
63          * @param aProgram1
64          *            First program.
65          * @param aProgram2
66          *            Second program.
67          * @return See {@link Comparator#compare(T, T)}
68          */
69         public int compare(Program aProgram1, Program aProgram2) {
70             int value = aProgram1.getInterval().getBegin().compareTo(
71                     aProgram2.getInterval().getBegin());
72             if (value != 0) {
73                 return value;
74             }
75             value = aProgram1.getName().compareTo(aProgram2.getName());
76             if (value != 0) {
77                 return value;
78             }
79             return aProgram1.getChannel().compareTo(aProgram2.getChannel());
80         }
81     }
82
83     private static final Log LOG = LogFactory.getLog(Program.class);
84
85     /**
86      * Name of the record action on the program details page.
87      */
88     private static final String RECORD_ACTION = "record";
89
90     /**
91      * Result of recording a program.
92      * 
93      */
94     public enum RecordingResult {
95         /**
96          * Successfully recorded.
97          */
98         OK,
99
100         /**
101          * Already recorded program.
102          */
103         DUPLICATE,
104
105         /**
106          * Recording conflict with another program.
107          */
108         CONFLICT,
109
110         /**
111          * Program occurred in the past.
112          */
113         OLDSHOW,
114
115         /**
116          * Program could not be recorded for technical reasons.
117          */
118         ERROR;
119     };
120
121     /**
122      * Indent string to use for pretty printing.
123      */
124     private static final String INDENT = "       ";
125
126     /**
127      * Channel the program is on.
128      */
129     private String _channel;
130
131     /**
132      * Program name.
133      */
134     private String _name;
135
136     /**
137      * Program description.
138      */
139     private String _description;
140
141     /**
142      * Keywords or classification of the program.
143      */
144     private String _keywords;
145
146     /**
147      * Time interval for the program (from/to).
148      */
149     private TimeInterval _interval;
150
151     /**
152      * Action to execute to obtain program information and/or record the
153      * program.
154      */
155     private Action _programInfo;
156
157     /**
158      * Constructs the program.
159      * 
160      * @param aChannel
161      *            Channel name.
162      * @param aName
163      *            Program name.
164      * @param aDescription
165      *            Description.
166      * @param aKeywords
167      *            Keywords/classification.
168      * @param aInterval
169      *            Time interval.
170      * @param aProgramInfo
171      *            Action to execute for detailed program information or for
172      *            recording the page.
173      */
174     public Program(String aChannel, String aName, String aDescription,
175             String aKeywords, TimeInterval aInterval, Action aProgramInfo) {
176         _channel = aChannel;
177         _name = aName;
178         _description = aDescription;
179         _keywords = aKeywords;
180         _interval = aInterval;
181         _programInfo = aProgramInfo;
182     }
183
184     /**
185      * Gets the channel.
186      * 
187      * @return Channel.
188      */
189     public String getChannel() {
190         return _channel;
191     }
192
193     /**
194      * Gets the program name.
195      * 
196      * @return Name.
197      */
198     public String getName() {
199         return _name;
200     }
201
202     /**
203      * Gets the description.
204      * 
205      * @return Description.
206      */
207     public String getDescription() {
208         return _description;
209     }
210
211     /**
212      * Gets the keywords/classification.
213      * 
214      * @return Keywords/classification
215      */
216     public String getKeywords() {
217         return _keywords;
218     }
219
220     /**
221      * Gets the time interval.
222      * 
223      * @return Time interval.
224      */
225     public TimeInterval getInterval() {
226         return _interval;
227     }
228
229     /**
230      * Checks if recording is possible.
231      * 
232      * @return True iff recording is possible.
233      */
234     public boolean isRecordingPossible() {
235         try {
236             return _programInfo.execute().getAction(RECORD_ACTION) != null;
237         } catch (PageException e) {
238             return false;
239         }
240     }
241
242     /**
243      * Records the show.
244      * 
245      * @return Status describing the result of recording.
246      */
247     public RecordingResult record() {
248         LOG.info("Recording " + this);
249         if (SystemProperties.isRecordDisabled()) {
250             return RecordingResult.OK;
251         }
252         try {
253             Action record = _programInfo.execute().getAction(RECORD_ACTION);
254             if (record == null) {
255                 LOG.info("  result: " + RecordingResult.OLDSHOW);
256                 return RecordingResult.OLDSHOW;
257             }
258             Page result = record.execute();
259             RecordingResult recordingResult = RecordingResult.valueOf(result
260                     .getContent().getText());
261             LOG.info("  result: " + recordingResult);
262             return recordingResult;
263         } catch (PageException e) {
264             LOG.warn("Technical problem recording program: '" + this + "'", e);
265             LOG.info("  result: " + RecordingResult.ERROR);
266             return RecordingResult.ERROR;
267         }
268     }
269
270     /**
271      * Accepts the visitor.
272      * 
273      * @param aVisitor
274      *            Visitor.
275      */
276     public void accept(Visitor aVisitor) {
277         aVisitor.visitProgram(this);
278     }
279
280     /*
281      * (non-Javadoc)
282      * 
283      * @see java.lang.Object#toString()
284      */
285     @Override
286     public String toString() {
287         return _interval + " - " + _name + " (" + _channel + "/" + _keywords
288                 + ")" + "\n"
289                 + (INDENT + _description).replaceAll("\n", "\n" + INDENT);
290     }
291
292     /*
293      * (non-Javadoc)
294      * 
295      * @see java.lang.Object#equals(java.lang.Object)
296      */
297     @Override
298     public boolean equals(Object aObject) {
299         if (!(aObject instanceof Program)) {
300             return false;
301         }
302         Program program = (Program) aObject;
303         return getName().equals(program.getName())
304                 && _programInfo.equals(program._programInfo);
305     }
306
307     /*
308      * (non-Javadoc)
309      * 
310      * @see java.lang.Object#hashCode()
311      */
312     @Override
313     public int hashCode() {
314         return getName().hashCode();
315     }
316
317     /**
318      * Converts program information to XML.
319      * 
320      * @return XML representation of program information.
321      */
322     public Element asXml() {
323         DocumentFactory factory = DocumentFactory.getInstance();
324         Element program = factory.createElement(ELEM_PROGRAM);
325         program.addElement(ELEM_NAME).setText(getName());
326         program.addElement(ELEM_DESCRIPTION).setText(getDescription());
327         program.addElement(ELEM_KEYWORDS).setText(getKeywords());
328         program.addElement(ELEM_CHANNEL).setText(getChannel());
329         Element interval = program.addElement(ELEM_INTERVAL);
330         interval.addElement(ELEM_BEGIN_TIME).setText(
331                 getInterval().getBegin().toString());
332         interval.addElement(ELEM_END_TIME).setText(
333                 getInterval().getEnd().toString());
334         return program;
335     }
336 }