241089b1e7de507d8189a1f1081f386d6ad2eb04
[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 TimeSorter 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("Successfully recorded programs"),
97
98         /**
99          * Already recorded program.
100          */
101         DUPLICATE("Already recorded programs"),
102
103         /**
104          * Recording conflict with another program.
105          */
106         CONFLICT("Programs in conflict with another recorded program"),
107
108         /**
109          * Program occurred in the past.
110          */
111         OLDSHOW("Programs that occurred in the past"),
112
113         /**
114          * Program could not be recorded for technical reasons.
115          */
116         ERROR("Programs that could not be recorded for technical reasons");
117
118         private String _description;
119
120         private RecordingResult(String aDescription) {
121             _description = aDescription;
122         }
123
124         /**
125          * Gets the description.
126          * 
127          * @return Description.
128          */
129         public String getDescription() {
130             return _description;
131         }
132     };
133
134     /**
135      * Indent string to use for pretty printing.
136      */
137     private static final String INDENT = "       ";
138
139     /**
140      * Channel the program is on.
141      */
142     private String _channel;
143
144     /**
145      * Program name.
146      */
147     private String _name;
148
149     /**
150      * Program description.
151      */
152     private String _description;
153
154     /**
155      * Keywords or classification of the program.
156      */
157     private String _keywords;
158
159     /**
160      * Time interval for the program (from/to).
161      */
162     private TimeInterval _interval;
163
164     /**
165      * Action to execute to obtain program information and/or record the
166      * program.
167      */
168     private Action _programInfo;
169
170     /**
171      * Constructs the program.
172      * 
173      * @param aChannel
174      *            Channel name.
175      * @param aName
176      *            Program name.
177      * @param aDescription
178      *            Description.
179      * @param aKeywords
180      *            Keywords/classification.
181      * @param aInterval
182      *            Time interval.
183      * @param aProgramInfo
184      *            Action to execute for detailed program information or for
185      *            recording the page.
186      */
187     public Program(String aChannel, String aName, String aDescription,
188             String aKeywords, TimeInterval aInterval, Action aProgramInfo) {
189         _channel = aChannel;
190         _name = aName;
191         _description = aDescription;
192         _keywords = aKeywords;
193         _interval = aInterval;
194         _programInfo = aProgramInfo;
195     }
196
197     /**
198      * Gets the channel.
199      * 
200      * @return Channel.
201      */
202     public String getChannel() {
203         return _channel;
204     }
205
206     /**
207      * Gets the program name.
208      * 
209      * @return Name.
210      */
211     public String getName() {
212         return _name;
213     }
214
215     /**
216      * Gets the description.
217      * 
218      * @return Description.
219      */
220     public String getDescription() {
221         return _description;
222     }
223
224     /**
225      * Gets the keywords/classification.
226      * 
227      * @return Keywords/classification
228      */
229     public String getKeywords() {
230         return _keywords;
231     }
232
233     /**
234      * Gets the time interval.
235      * 
236      * @return Time interval.
237      */
238     public TimeInterval getInterval() {
239         return _interval;
240     }
241
242     /**
243      * Checks if recording is possible.
244      * 
245      * @return True iff recording is possible.
246      */
247     public boolean isRecordingPossible() {
248         try {
249             Action record = _programInfo.execute().getAction(RECORD_ACTION);
250             if (record == null) {
251                 return false;
252             }
253             return true;
254         } catch (PageException e) {
255             return false;
256         }
257     }
258
259     /**
260      * Records the show.
261      * 
262      * @return Status describing the result of recording.
263      */
264     public RecordingResult record() {
265         LOG.info("Recording " + this);
266         if (SystemProperties.isRecordDisabled()) {
267             return RecordingResult.OK;
268         }
269         try {
270             Action record = _programInfo.execute().getAction(RECORD_ACTION);
271             if (record == null) {
272                 LOG.info("  result: " + RecordingResult.OLDSHOW);
273                 return RecordingResult.OLDSHOW;
274             }
275             Page result = record.execute();
276             RecordingResult recordingResult = RecordingResult.valueOf(result
277                     .getContent().getText());
278             LOG.info("  result: " + recordingResult);
279             return recordingResult;
280         } catch (PageException e) {
281             LOG.warn("Technical problem recording program: '" + this + "'", e);
282             LOG.info("  result: " + RecordingResult.ERROR);
283             return RecordingResult.ERROR;
284         }
285     }
286
287     /**
288      * Accepts the visitor.
289      * 
290      * @param aVisitor
291      *            Visitor.
292      */
293     public void accept(Visitor aVisitor) {
294         aVisitor.visitProgram(this);
295     }
296
297     /*
298      * (non-Javadoc)
299      * 
300      * @see java.lang.Object#toString()
301      */
302     @Override
303     public String toString() {
304         return _interval + " - " + _name + " (" + _channel + "/" + _keywords
305                 + ")" + "\n"
306                 + (INDENT + _description).replaceAll("\n", "\n" + INDENT);
307     }
308
309     /*
310      * (non-Javadoc)
311      * 
312      * @see java.lang.Object#equals(java.lang.Object)
313      */
314     @Override
315     public boolean equals(Object aObject) {
316         if (!(aObject instanceof Program)) {
317             return false;
318         }
319         Program program = (Program) aObject;
320         return getName().equals(program.getName())
321                 && _programInfo.equals(program._programInfo);
322     }
323
324     /*
325      * (non-Javadoc)
326      * 
327      * @see java.lang.Object#hashCode()
328      */
329     @Override
330     public int hashCode() {
331         return getName().hashCode();
332     }
333
334     /**
335      * Converts program information to XML.
336      * 
337      * @return XML representation of program information.
338      */
339     public Element asXml() {
340         DocumentFactory factory = DocumentFactory.getInstance();
341         Element program = factory.createElement(ELEM_PROGRAM);
342         program.addElement(ELEM_NAME).setText(getName());
343         program.addElement(ELEM_DESCRIPTION).setText(getDescription());
344         program.addElement(ELEM_KEYWORDS).setText(getKeywords());
345         program.addElement(ELEM_CHANNEL).setText(getChannel());
346         Element interval = program.addElement(ELEM_INTERVAL);
347         interval.addElement(ELEM_BEGIN_TIME).setText(
348                 getInterval().getBegin().toString());
349         interval.addElement(ELEM_END_TIME).setText(
350                 getInterval().getEnd().toString());
351         return program;
352     }
353 }