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