checkstyle and checkdoc are now ok.
[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     /**
36      * Lexicographical comparison of programs based on (time, title, channel).
37      * 
38      */
39     public static class TimeSorter implements Comparator<Program> {
40
41         /**
42          * Lexicographical comparison based on start time, program name, and
43          * channel.
44          * 
45          * @param aProgram1
46          *            First program.
47          * @param aProgram2
48          *            Second program.
49          * @return See {@link Comparator#compare(T, T)}
50          */
51         public int compare(Program aProgram1, Program aProgram2) {
52             int value = aProgram1.getInterval().getBegin().compareTo(
53                     aProgram2.getInterval().getBegin());
54             if (value != 0) {
55                 return value;
56             }
57             value = aProgram1.getName().compareTo(aProgram2.getName());
58             if (value != 0) {
59                 return value;
60             }
61             return aProgram1.getChannel().compareTo(aProgram2.getChannel());
62         }
63     }
64
65     private static final Log LOG = LogFactory.getLog(Program.class);
66
67     /**
68      * Name of the record action on the program details page.
69      */
70     private static final String RECORD_ACTION = "record";
71
72     private static final String RESULT_ELEM = "result";
73
74     /**
75      * Result of recording a program.
76      * 
77      */
78     public enum RecordingResult {
79         /**
80          * Successfully recorded.
81          */
82         OK("Successfully recorded programs"),
83
84         /**
85          * Already recorded program.
86          */
87         DUPLICATE("Already recorded programs"),
88
89         /**
90          * Recording conflict with another program.
91          */
92         CONFLICT("Programs in conflict with another recorded program"),
93
94         /**
95          * Program occurred in the past.
96          */
97         OLDSHOW("Programs that occurred in the past"),
98
99         /**
100          * Program could not be recorded for technical reasons.
101          */
102         ERROR("Programs that could not be recorded for technical reasons");
103
104         private String _description;
105
106         private RecordingResult(String aDescription) {
107             _description = aDescription;
108         }
109
110         /**
111          * Gets the description. 
112          * @return Description. 
113          */
114         public String getDescription() {
115             return _description;
116         }
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             Action record = _programInfo.execute().getAction(RECORD_ACTION);
235             if (record == null) {
236                 return false;
237             }
238             return true;
239         } catch (PageException e) {
240             return false;
241         }
242     }
243
244     /**
245      * Records the show.
246      * 
247      * @return Status describing the result of recording.
248      */
249     public RecordingResult record() {
250         LOG.info("Recording " + this);
251         if (SystemProperties.isRecordDisabled()) {
252             return RecordingResult.OK;
253         }
254         try {
255             Action record = _programInfo.execute().getAction(RECORD_ACTION);
256             if (record == null) {
257                 LOG.info("  result: " + RecordingResult.OLDSHOW);
258                 return RecordingResult.OLDSHOW;
259             }
260             Page result = record.execute();
261             RecordingResult recordingResult = RecordingResult.valueOf(result
262                     .getContent().getText());
263             LOG.info("  result: " + recordingResult);
264             return recordingResult;
265         } catch (PageException e) {
266             LOG.warn("Technical problem recording program: '" + this + "'", e);
267             LOG.info("  result: " + RecordingResult.ERROR);
268             return RecordingResult.ERROR;
269         }
270     }
271
272     /**
273      * Accepts the visitor.
274      * 
275      * @param aVisitor
276      *            Visitor.
277      */
278     public void accept(Visitor aVisitor) {
279         aVisitor.visitProgram(this);
280     }
281
282     /*
283      * (non-Javadoc)
284      * 
285      * @see java.lang.Object#toString()
286      */
287     @Override
288     public String toString() {
289         return _interval + " - " + _name + " (" + _channel + "/" + _keywords
290                 + ")" + "\n"
291                 + (INDENT + _description).replaceAll("\n", "\n" + INDENT);
292     }
293
294     /*
295      * (non-Javadoc)
296      * 
297      * @see java.lang.Object#equals(java.lang.Object)
298      */
299     @Override
300     public boolean equals(Object aObject) {
301         if (!(aObject instanceof Program)) {
302             return false;
303         }
304         Program program = (Program) aObject;
305         return getName().equals(program.getName())
306                 && _programInfo.equals(program._programInfo);
307     }
308
309     /*
310      * (non-Javadoc)
311      * 
312      * @see java.lang.Object#hashCode()
313      */
314     @Override
315     public int hashCode() {
316         return getName().hashCode();
317     }
318
319     /**
320      * Converts program information to XML.
321      * 
322      * @return XML representation of program information.
323      */
324     public Element asXml() {
325         DocumentFactory factory = DocumentFactory.getInstance();
326         Element program = factory.createElement("program");
327         program.addElement("name").setText(getName());
328         program.addElement("description").setText(getDescription());
329         program.addElement("keywords").setText(getKeywords());
330         program.addElement("channel").setText(getChannel());
331         Element interval = program.addElement("interval");
332         interval.addElement("begin").setText(
333                 getInterval().getBegin().toString());
334         interval.addElement("end").setText(getInterval().getEnd().toString());
335         return program;
336     }
337 }