View Javadoc

1   /*------------------------------------------------------------------------------
2    * The contents of this file are subject to the Mozilla Public License Version
3    * 1.1 (the "License"); you may not use this file except in compliance with
4    * the License. You may obtain a copy of the License at
5    * http://www.mozilla.org/MPL/
6    * Software distributed under the License is distributed on an "AS IS" basis,
7    * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
8    * the specific language governing rights and limitations under the License.
9    *
10   * The Original Code is levelonelabs.com code.
11   * The Initial Developer of the Original Code is Level One Labs. Portions
12   * created by the Initial Developer are Copyright (C) 2001 the Initial
13   * Developer. All Rights Reserved.
14   *
15   *         Contributor(s):
16   *             Scott Oster      (ostersc@alum.rpi.edu)
17   *             Steve Zingelwicz (sez@po.cwru.edu)
18   *             William Gorman   (willgorman@hotmail.com)
19   *
20   * Alternatively, the contents of this file may be used under the terms of
21   * either the GNU General Public License Version 2 or later (the "GPL"), or
22   * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
23   * in which case the provisions of the GPL or the LGPL are applicable
24   * instead of those above. If you wish to allow use of your version of this
25   * file only under the terms of either the GPL or the LGPL, and not to allow
26   * others to use your version of this file under the terms of the NPL, indicate
27   * your decision by deleting the provisions above and replace them with the
28   * notice and other provisions required by the GPL or the LGPL. If you do not
29   * delete the provisions above, a recipient may use your version of this file
30   * under the terms of any one of the NPL, the GPL or the LGPL.
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 							//if the buddy didnt have a mountain perference
170 							// set, set this one for him
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 			//ignore the time zone providers
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 			//read the machine
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 			//e.printStackTrace();
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 }