1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 package com.levelonelabs.aimbot.modules;
34
35 import java.io.BufferedReader;
36 import java.io.InputStreamReader;
37 import java.net.MalformedURLException;
38 import java.net.URL;
39 import java.net.URLConnection;
40 import java.util.ArrayList;
41 import java.util.HashMap;
42 import java.util.Iterator;
43 import java.util.List;
44 import java.util.Map;
45 import java.util.StringTokenizer;
46 import java.util.logging.Logger;
47
48 import javax.swing.text.MutableAttributeSet;
49 import javax.swing.text.html.HTML;
50 import javax.swing.text.html.HTML.Tag;
51 import javax.swing.text.html.HTMLEditorKit.ParserCallback;
52 import javax.swing.text.html.parser.ParserDelegator;
53
54 import com.levelonelabs.aim.AIMBuddy;
55 import com.levelonelabs.aimbot.AIMBot;
56 import com.levelonelabs.aimbot.BotModule;
57
58 /***
59 * Handles requests to get ski snow reports
60 *
61 * @author Scott Oster
62 *
63 * @created November 23, 2003
64 */
65 public class SkiReportModule extends BotModule {
66 private static final String MOUNTAIN_PREF = "mountain";
67 static Logger logger = Logger.getLogger(SkiReportModule.class.getName());
68 private static ArrayList services;
69
70 /***
71 * Initialize the service commands.
72 */
73 static {
74 services = new ArrayList();
75 services.add("ski");
76 services.add("snow");
77 services.add("mountains");
78 }
79
80 /***
81 * Constructor for StockModule.
82 *
83 * @param bot
84 */
85 public SkiReportModule(AIMBot bot) {
86 super(bot);
87 }
88
89 /***
90 * @see com.levelonelabs.aimbot.BotModule#getName()
91 */
92 public String getName() {
93 return "Ski Report Module";
94 }
95
96 /***
97 * @see com.levelonelabs.aimbot.BotModule#getServices()
98 */
99 public ArrayList getServices() {
100 return services;
101 }
102
103 /***
104 * @see com.levelonelabs.aimbot.BotModule#help()
105 */
106 public String help() {
107 StringBuffer sb = new StringBuffer();
108 sb
109 .append("<B>mountains <i>STATE ABBREVIATION</i></B> (displays the resort codes for the specified state code)\n");
110 sb
111 .append("<B>ski <i>STATE ABBREVIATION:RESORT CODE</i></B> (displays the ski reports for the given resort)\n");
112 sb
113 .append("* If the preference \"mountain\" is set, you can omit the [STATE ABBREVIATION:RESORT CODE] to use your default.");
114 return sb.toString();
115 }
116
117 /***
118 * Return snow report
119 *
120 * @param buddy
121 * the buddy
122 * @param query
123 * the weather request
124 */
125 public void performService(AIMBuddy buddy, String query) {
126 if (query.trim().toLowerCase().startsWith("snow")
127 || query.trim().toLowerCase().startsWith("ski")) {
128 StringTokenizer st = new StringTokenizer(query, " ");
129 String mntPref = buddy.getPreference(MOUNTAIN_PREF);
130 if ((mntPref == null) && (st.countTokens() < 2)) {
131 super.sendMessage(buddy, "ERROR:\n" + help());
132 } else {
133 String imcommand = st.nextToken();
134 String state = "";
135 String resortCode = "";
136 String code = "";
137 if (st.hasMoreElements()) {
138 code = ((String) st.nextElement()).trim();
139 } else if (mntPref != null) {
140 code = mntPref;
141 }
142
143 int ind = code.indexOf(":");
144 if (ind <= 0) {
145 super.sendMessage(buddy,
146 "ERROR: must use [STATE ABBREVIATION:RESORT CODE] format (e.g. CO:77)\n"
147 + help());
148 return;
149 } else {
150 state = code.substring(0, ind).toUpperCase();
151 resortCode = code.substring(ind + 1);
152 }
153 String result = "Couldn't get ski resort information.";
154 if (!resortCode.trim().equals("") && !state.trim().equals("")) {
155 SkiScraper scrapper = new SkiScraper(state, resortCode);
156 SnowReport temp = scrapper.getSnowReport();
157 if (temp != null) {
158 result = temp.getTitle() + "\n" + "<b>New Snow:</b> "
159 + temp.getNewSnow() + " \t"
160 + "<b>Surface:</b> " + temp.getSurfaceSnow()
161 + " \t" + "<b>Base:</b> "
162 + temp.getBaseDepth() + "\n"
163 + "<b>Open Runs:</b> " + temp.getRunsOpen()
164 + " \t" + "<b>Open Lifts:</b> "
165 + temp.getLiftsOpen() + " \t"
166 + "<b>Open Acres:</b> " + temp.getAcresOpen();
167
168 if (mntPref == null) {
169
170
171 buddy.setPreference(MOUNTAIN_PREF, state + ":"
172 + resortCode);
173 }
174 }
175 }
176 super.sendMessage(buddy, result);
177 }
178 } else if (query.trim().toLowerCase().startsWith("mountains")) {
179 StringTokenizer st = new StringTokenizer(query, " ");
180 if (st.countTokens() == 2) {
181 String imcommand = st.nextToken();
182 String state = st.nextToken().toUpperCase();
183
184 String result = "Couldn't get locate ski resorts in " + state;
185 if (state.length() == 2) {
186 MountainScraper scrapper = new MountainScraper(state);
187 Map mntMap = scrapper.getMountains();
188 if (mntMap.size() > 0) {
189 result = "Ski Resort codes for " + state + ":\n";
190 for (Iterator iter = mntMap.keySet().iterator(); iter
191 .hasNext(); ) {
192 String key = (String) iter.next();
193 String value = (String) mntMap.get(key);
194 logger.fine(value + "\t use --> " + state + ":"
195 + key);
196 result += (value + "\t --> <b>" + state + ":" + key + "</b>\n");
197 }
198 }
199 }
200 super.sendMessage(buddy, result);
201 } else {
202 super.sendMessage(buddy, help());
203 }
204 }
205 }
206
207 }
208
209 class MountainScraper extends ParserCallback {
210 static Logger logger = Logger.getLogger(TVListingsModule.class.getName());
211 private static final String BASE_URL = "http://www.onthesnow.com/";
212 private String state;
213 private List codes;
214 private List names;
215 private boolean validText = false;
216 private boolean validLink = false;
217 private boolean grabURLText = false;
218
219 /***
220 * Contructor for TVResultsScraper
221 *
222 * @param state
223 */
224 public MountainScraper(String state) {
225 this.state = state;
226 this.codes = new ArrayList();
227 this.names = new ArrayList();
228 }
229
230 /***
231 * Look for resort name and code
232 *
233 * @param t
234 * select or option tag
235 * @param a
236 * looks for name
237 * @param pos
238 * not used
239 */
240 public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) {
241 if (t == HTML.Tag.A && validLink) {
242 String urlString = a.getAttribute(HTML.Attribute.HREF).toString();
243 int ind = urlString.indexOf(BASE_URL + this.state);
244 if (ind >= 0) {
245 try {
246 String temp = urlString.substring(ind
247 + (BASE_URL + this.state + "/").length());
248 String code = temp.substring(ind, temp.indexOf("/"));
249 codes.add(code);
250 grabURLText = true;
251 } catch (Exception e) {
252 logger.fine("Parser didn't handle parsing [" + urlString
253 + "] cleanly:" + e.getMessage());
254 }
255 }
256 }
257 }
258
259 /***
260 * Looks for the end of table
261 *
262 * @param t
263 * table
264 * @param pos
265 * unused
266 */
267 public void handleEndTag(Tag t, int pos) {
268 if (t == HTML.Tag.TABLE && validText) {
269 validText = false;
270 }
271 }
272
273 /***
274 * Grab the resorts when appropriate
275 *
276 * @param data
277 * the text
278 * @param pos
279 * unused
280 */
281 public void handleText(char[] data, int pos) {
282 if (grabURLText == true) {
283 names.add(new String(data).trim());
284 grabURLText = false;
285 } else {
286 String line = new String(data).trim();
287
288 if (line.equals("Resort")) {
289 validLink = true;
290 }
291 }
292 }
293 /***
294 * Uses the parser to return a map of appropriate providers
295 *
296 * @return map of providers keyed by codes
297 */
298 public Map getMountains() {
299 HashMap result = new HashMap();
300 try {
301 URL url = new URL(BASE_URL + this.state + "/index.html");
302 logger.fine("Looking for mountains in:" + state + " using URL= "
303 + url);
304 URLConnection conn = url.openConnection();
305 BufferedReader br = new BufferedReader(new InputStreamReader(conn
306 .getInputStream()));
307 ParserDelegator pd = new ParserDelegator();
308 pd.parse(br, this, true);
309 if (codes.size() == names.size()) {
310 for (int i = 0; i < codes.size(); i++) {
311 result.put(codes.get(i), names.get(i));
312 }
313 }
314 } catch (Exception e) {
315 logger.fine("Error looking for mountains, ERROR:"
316 + e.getStackTrace());
317 return new HashMap();
318 }
319 return result;
320 }
321
322 /***
323 * Testing method
324 *
325 * @param args
326 * state
327 */
328 public static void main(String[] args) {
329 String state = args[0];
330 MountainScraper scrapper = new MountainScraper(state);
331 Map mounts = scrapper.getMountains();
332 for (Iterator iter = mounts.keySet().iterator(); iter.hasNext(); ) {
333 String key = (String) iter.next();
334 String value = (String) mounts.get(key);
335 System.out.println(value + "\t use --> " + key);
336 }
337 }
338 }
339
340 class SkiScraper extends ParserCallback {
341 static Logger logger = Logger.getLogger(SkiScraper.class.getName());
342 private static final String BASE_URL = "http://www.onthesnow.com/";
343 private static final String URL_END = "skireport.html";
344
345 boolean grabTitle = false;
346
347 private static final int WAIT_STATE = 0;
348 private static final int NEW_SNOW_STATE = 1;
349 private static final int BASE_DEPTH_STATE = 2;
350 private static final int SURFACE_SNOW_STATE = 3;
351 private static final int RUNS_OPEN_STATE = 4;
352 private static final int LIFTS_OPEN_STATE = 5;
353 private static final int ACRES_OPEN_STATE = 6;
354
355 private int machineState = WAIT_STATE;
356 private int statesVisited = 0;
357
358 private static final String NEW_SNOW_MARKER = "New Snow:";
359 private static final String BASE_DEPTH_MARKER = "Base Depth:";
360 private static final String SURFACE_SNOW_MARKER = "Surface Snow:";
361 private static final String RUNS_OPEN_MARKER = "Runs Open:";
362 private static final String LIFTS_OPEN_MARKER = "Lifts Open:";
363 private static final String ACRES_OPEN_MARKER = "Acres Open:";
364
365 private SnowReport result;
366 private String resortCode;
367 private String state;
368
369 /***
370 * Contructor for SkiScraper
371 *
372 * @param url
373 * @param show
374 */
375 public SkiScraper(String state, String resortCode) {
376 this.result = new SnowReport(state);
377 this.state = state;
378 this.resortCode = resortCode;
379 }
380
381 /***
382 * Looks for start of links, paragraphs and HRs
383 *
384 * @param t
385 * the tag
386 * @param a
387 * unused
388 * @param pos
389 * unused
390 */
391 public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) {
392 if (t == HTML.Tag.TITLE) {
393 grabTitle = true;
394 }
395 }
396
397 /***
398 * Grabs the show info
399 *
400 * @param data
401 * the text
402 * @param pos
403 * unused
404 */
405 public void handleText(char[] data, int pos) {
406 String line = new String(data).trim();
407 if (grabTitle) {
408 int ind = line.indexOf(":");
409 if (ind > 0) {
410 line = line.substring(0, ind);
411 }
412 this.result.setTitle(line);
413 grabTitle = false;
414 } else if (line.equals(ACRES_OPEN_MARKER)) {
415 machineState = ACRES_OPEN_STATE;
416 statesVisited++;
417 } else if (line.equals(BASE_DEPTH_MARKER)) {
418 machineState = BASE_DEPTH_STATE;
419 statesVisited++;
420 } else if (line.equals(LIFTS_OPEN_MARKER)) {
421 machineState = LIFTS_OPEN_STATE;
422 statesVisited++;
423 } else if (line.equals(NEW_SNOW_MARKER)) {
424 machineState = NEW_SNOW_STATE;
425 statesVisited++;
426 } else if (line.equals(RUNS_OPEN_MARKER)) {
427 machineState = RUNS_OPEN_STATE;
428 statesVisited++;
429 } else if (line.equals(SURFACE_SNOW_MARKER)) {
430 machineState = SURFACE_SNOW_STATE;
431 statesVisited++;
432 } else if (machineState != WAIT_STATE) {
433
434 switch (machineState) {
435 case ACRES_OPEN_STATE :
436 result.setAcresOpen(line);
437 machineState = WAIT_STATE;
438 break;
439 case BASE_DEPTH_STATE :
440 result.setBaseDepth(line);
441 machineState = WAIT_STATE;
442 break;
443 case LIFTS_OPEN_STATE :
444 result.setLiftsOpen(line);
445 machineState = WAIT_STATE;
446 break;
447 case NEW_SNOW_STATE :
448 result.setNewSnow(line);
449 machineState = WAIT_STATE;
450 break;
451 case RUNS_OPEN_STATE :
452 result.setRunsOpen(line);
453 machineState = WAIT_STATE;
454 break;
455 case SURFACE_SNOW_STATE :
456 result.setSurfaceSnow(line);
457 machineState = WAIT_STATE;
458 break;
459 }
460
461 }
462
463 }
464
465 /***
466 * Grabs the summary info
467 *
468 * @return The text
469 */
470 public SnowReport getSnowReport() {
471 URL url = null;
472 try {
473 url = new URL(BASE_URL + state + "/" + resortCode + "/" + URL_END);
474 } catch (MalformedURLException e) {
475 e.printStackTrace();
476 return null;
477 }
478
479 logger.fine("Looking for Snow report for resort " + resortCode
480 + " in state" + state + " using URL= " + url);
481 SnowReport tempResult;
482 try {
483 URLConnection conn = url.openConnection();
484 BufferedReader br = new BufferedReader(new InputStreamReader(conn
485 .getInputStream()));
486 ParserDelegator pd = new ParserDelegator();
487 pd.parse(br, this, true);
488
489 tempResult = result;
490 if (statesVisited != 6) {
491 tempResult = null;
492 }
493 } catch (Exception e) {
494
495 logger.severe(e.toString());
496 return null;
497 }
498
499 return tempResult;
500 }
501
502 /***
503 * Testing method
504 *
505 * @param args
506 * state
507 */
508 public static void main(String[] args) {
509 String state = args[0];
510 String code = args[1];
511 SkiScraper scrapper = new SkiScraper(state, code);
512 SnowReport report = scrapper.getSnowReport();
513 System.out.println(report);
514 }
515
516 } class SnowReport {
517 private String title;
518 private String newSnow;
519 private String baseDepth;
520 private String surfaceSnow;
521 private String runsOpen;
522 private String liftsOpen;
523 private String acresOpen;
524 private String state;
525
526 public SnowReport(String state) {
527 this.state = state;
528 }
529 /***
530 * @return
531 */
532 public String getAcresOpen() {
533 return acresOpen;
534 }
535
536 /***
537 * @return
538 */
539 public String getBaseDepth() {
540 return baseDepth;
541 }
542
543 /***
544 * @return
545 */
546 public String getLiftsOpen() {
547 return liftsOpen;
548 }
549
550 /***
551 * @return
552 */
553 public String getNewSnow() {
554 return newSnow;
555 }
556
557 /***
558 * @return
559 */
560 public String getRunsOpen() {
561 return runsOpen;
562 }
563
564 /***
565 * @return
566 */
567 public String getState() {
568 return state;
569 }
570
571 /***
572 * @return
573 */
574 public String getSurfaceSnow() {
575 return surfaceSnow;
576 }
577
578 /***
579 * @return
580 */
581 public String getTitle() {
582 return title;
583 }
584
585 /***
586 * @param string
587 */
588 public void setAcresOpen(String string) {
589 acresOpen = string;
590 }
591
592 /***
593 * @param string
594 */
595 public void setBaseDepth(String string) {
596 baseDepth = string;
597 }
598
599 /***
600 * @param string
601 */
602 public void setLiftsOpen(String string) {
603 liftsOpen = string;
604 }
605
606 /***
607 * @param string
608 */
609 public void setNewSnow(String string) {
610 newSnow = string;
611 }
612
613 /***
614 * @param string
615 */
616 public void setRunsOpen(String string) {
617 runsOpen = string;
618 }
619
620 /***
621 * @param string
622 */
623 public void setState(String string) {
624 state = string;
625 }
626
627 /***
628 * @param string
629 */
630 public void setSurfaceSnow(String string) {
631 surfaceSnow = string;
632 }
633
634 /***
635 * @param string
636 */
637 public void setTitle(String string) {
638 title = string;
639 }
640
641 public String toString() {
642 return title + ":\n" + "New Snow: " + newSnow + "\t\t" + "Surface: "
643 + surfaceSnow + "\t\t" + "Base: " + baseDepth + "\n"
644 + "Open Runs: " + runsOpen + "\t\t" + "Open Lifts: "
645 + liftsOpen + "\t\t" + "Open Acres: " + acresOpen;
646 }
647 }