View Javadoc
1   /******************************************************************************
2    * ClientReceiveParser.java - Parse messages received from the network.
3    * $Id$
4    * 
5    * BuckoFIBS - Backgammon by BuckoSoft
6    * Copyright© 2009,2010 - Dick Balaska - BuckoSoft, Corp.
7    * 
8    * $Log$
9    * Revision 1.28  2013/09/12 06:36:33  dick
10   * Doubles dispatches gameEvents.
11   *
12   * Revision 1.27  2011/07/16 02:40:13  dick
13   * Add CantWatchSelf.
14   * YouDouble becomes a gameManager message.
15   *
16   * Revision 1.26  2011/07/04 03:39:16  dick
17   * Route more messages through the GameManager.
18   *
19   * Revision 1.25  2011/06/22 05:53:58  dick
20   * You Tell PlayerX is different than the other messages.
21   * Add NobodyHeardYou.
22   *
23   * Revision 1.24  2011/06/18 19:30:32  dick
24   * Resigning and new game messages.
25   *
26   * Revision 1.23  2011/06/14 19:13:52  dick
27   * YouCantMove is a GameEvent.
28   *
29   * Revision 1.22  2011/06/13 04:43:19  dick
30   * FIBS_PlayerWantsToResign is now a GameManager message.
31   *
32   * Revision 1.21  2011/06/05 06:57:46  dick
33   * playerListPane becomes playerListTab.
34   * Select the profile into the database upon login.
35   *
36   * Revision 1.20  2011/06/02 18:48:41  dick
37   * 3 more FIBS messages become GameEvents.
38   *
39   * Revision 1.19  2011/05/31 19:35:54  dick
40   * Fix new user registration.  FIBS_OneUserPerPerson is our cue to send the data.
41   *
42   * Revision 1.18  2011/05/22 22:58:59  dick
43   * GAME_MOVE becomes GAME_EVENT.
44   *
45   * Revision 1.17  2011/05/22 05:10:16  dick
46   * AcceptRejectDouble and BearingOff go to the GameManager.
47   *
48   * Revision 1.16  2011/05/21 04:56:42  dick
49   * Work on integrating GUI game functions by routing them through the game manager now.
50   * Particularly, YourMove and ResumeGame.
51   *
52   * Revision 1.15  2011/05/17 22:53:25  dick
53   * FIBS_YouRoll gets dispatched to the GameManager.
54   *
55   * Revision 1.14  2011/05/15 02:18:18  dick
56   * Gather the events to send to the GameManager.
57   *
58   * Revision 1.13  2011/05/14 04:43:01  dick
59   * I needed to deal with some lightweight Boards.
60   * So finally make the primary document Document
61   * and demote just the Board handling to a domain object.
62   *
63   * Revision 1.12  2011/05/13 14:57:00  dick
64   * Route game move messages through the GameManager so they can be animated.
65   *
66   * Revision 1.11  2011/05/11 22:22:42  dick
67   * Working on animating moves.
68   *
69   * Revision 1.10  2011/05/10 16:08:20  dick
70   * Fix the javadoc pointers to the source code.
71   *
72   * Revision 1.9  2011/01/04 17:31:45  dick
73   * Update the player in the playlist when we get new whoinfo on him.
74   *
75   * Revision 1.8  2010/12/29 07:46:35  dick
76   * Add WaitForLastInvitation and WaitForAcceptResign.
77   *
78   * Revision 1.7  2010/12/22 04:34:14  dick
79   * Set the chatPane combobox before setting the player.
80   *
81   * Revision 1.6  2010/03/03 13:12:21  inim
82   * Replaced (c) sign in comment mangled by CVS default encoding back to UTF-8
83   *
84   * Revision 1.5  2010/03/03 12:19:49  inim
85   * Moved source to UTF8 encoding from CP1252 encoding. To this end all source files' (c) message was updated to "Copyright© 2009,2010 - Dick Balaska - BuckoSoft, Corp.". This replaces the (c) sign to UTF8, and adds the new year 2010.
86   *
87   * Revision 1.4  2010/02/15 09:22:22  dick
88   * Play audio cues when Your opponent doubles or when he drops the match.
89   *
90   * Revision 1.3  2010/02/09 02:57:39  dick
91   * Don't do autoGreedyBearoff if only watching a match.
92   *
93   * Revision 1.2  2010/02/08 09:14:13  dick
94   * Add support for autoGreedyBearoff.  When the game turns to a race, enable greedy bearoffs.
95   *
96   * Revision 1.1  2010/02/04 05:57:53  inim
97   * Mavenized project folder layout
98   *
99   * Revision 1.60  2010/01/25 21:09:58  dick
100  * Remove the savedMatch icon from the playerList when the match is done.
101  * Set the chatPane to "Tell (lastOpponent)".
102  *
103  * Revision 1.59  2010/01/23 06:14:35  dick
104  * Handle removedFinishedMatch().  Handle youInvited().
105  *
106  * Revision 1.58  2009/05/09 03:42:27  dick
107  * Add PlayerBannedWatch and Doesn'tWantYouToWatch.
108  *
109  * Revision 1.57  2009/03/16 18:52:17  dick
110  * Play the YourTurn sound only if you can actually move.  (Respond to the "Please move" message.)
111  *
112  * Revision 1.56  2009/03/04 19:06:26  dick
113  * Do message routing for the PlayerReportPane.
114  *
115  * Revision 1.55  2009/02/27 05:47:41  dick
116  * Handle the whois "last logout" line.
117  *
118  * Revision 1.54  2009/02/25 09:41:12  dick
119  * Handle ATTENTION messages from FIBS when it is shutting down.
120  *
121  * Revision 1.53  2009/02/25 07:42:54  dick
122  * Calculate the duration of the match and store that with the FinishedMatch, will make a nice statistic someday.
123  *
124  * Revision 1.52  2009/02/24 05:48:47  dick
125  * Handle connectionAborted() and ERROR from the ClientAdapter.
126  *
127  * Revision 1.51  2009/02/22 07:05:47  dick
128  * if props.isDisplayRecv() then display them all.
129  *
130  * Revision 1.50  2009/02/21 17:59:42  dick
131  * Update the RatingGraphPanel when a match is complete.
132  *
133  * Revision 1.49  2009/02/20 10:21:23  dick
134  * Fill out a FinishedMatch and send it to the database.
135  *
136  * Revision 1.48  2009/02/17 21:12:56  dick
137  * Display unknown messages as an error, not as an unhandled cookie.
138  * (We know that the cookie is "unknown").
139  *
140  * Revision 1.47  2009/02/16 06:57:07  dick
141  * Dispatch to ROLL_OR_DOUBLE instead of calling the methods directly.
142  *
143  * Revision 1.46  2009/02/14 12:19:15  dick
144  * Between move work.
145  *
146  * Revision 1.45  2009/02/12 06:25:06  dick
147  * Update the board when resuming a match.
148  *
149  * Revision 1.44  2009/02/11 09:05:48  dick
150  * Better beginning and ending your turn.
151  *
152  * Revision 1.43  2009/02/09 22:44:28  dick
153  * shutdown() cancels pending timers.
154  * Handle resign (both ways).
155  *
156  * Revision 1.42  2009/02/06 07:56:48  dick
157  * Working on doubles.
158  *
159  * Revision 1.41  2009/02/03 09:44:18  dick
160  * Just give us a handle to MainDialog already.
161  * Add some audio events.
162  *
163  * Revision 1.40  2009/02/02 08:42:24  dick
164  * Several various message cleanups.
165  *
166  * Revision 1.39  2009/02/01 23:22:59  dick
167  * FIBS_Done is an in-game message.
168  *
169  * Revision 1.38  2009/02/01 21:15:06  dick
170  * Fire off a "show saved" message after we have finished who'ing.
171  *
172  * Revision 1.37  2009/01/31 08:46:25  dick
173  * Fire off a 'who' 1 second after we finish the initial table.  FIBS doesn't send all the players across.
174  * YourMove goes to the GameManager now.
175  *
176  * Revision 1.36  2009/01/31 06:08:49  dick
177  * Dispatch board and double commands to the GameManager.
178  *
179  * Revision 1.35  2009/01/29 08:27:05  dick
180  * Dispose of "waves" commands gracefully.
181  *
182  * Revision 1.34  2009/01/28 22:28:27  dick
183  * Try a different Javadoc reference to the Mode.
184  *
185  * Revision 1.33  2009/01/28 22:26:22  dick
186  * Javadoc.
187  *
188  * Revision 1.32  2009/01/28 19:42:47  dick
189  * Prettier cvs link in the javadoc.
190  *
191  * Revision 1.31  2009/01/28 08:34:18  dick
192  * If we get a FIBS_Unknown, then display the previous message too, because it's probably
193  * a busted end-of-string detector from the previous message.
194  *
195  * Revision 1.30  2009/01/27 19:14:31  dick
196  * Handle savedMatch as a warning.
197  *
198  * Revision 1.29  2009/01/27 06:54:23  dick
199  * uninvite us if a player starts playing.
200  *
201  * Revision 1.28  2009/01/27 05:44:43  dick
202  * public parseMessage becomes private dispatchMessage because the entry point is now the Adapter's dispatch().
203  *
204  * Revision 1.27  2009/01/26 17:35:15  dick
205  * Push the CookieMonster down to the ClientConnection.  ClientAdapter now emits the cookie with the string.
206  * There are many messages besides the known "BadBoard" messages that are a result of runon messages (missing crlf).
207  * CookieMonster is going to need to do a full regexp scan and see if there is anything on the right that needs to be pushed back as another message.
208  *
209  * Revision 1.26  2009/01/26 07:22:51  dick
210  * Process the "You Roll" command as a yourMove trigger.
211  *
212  * Revision 1.25  2009/01/24 17:05:05  dick
213  * Add parseReplayMessage(s).
214  *
215  * Revision 1.24  2009/01/18 04:51:26  dick
216  * add dispatch(YOUR_MOVE);
217  * CommandDispatcher becomes CommandDispatcherImpl.
218  * I should probably abstract out the methods that are being directly called in the Impl.
219  *
220  * Revision 1.23  2009/01/13 18:27:39  dick
221  * Handle Ready To Play
222  *
223  * Revision 1.22  2009/01/12 21:59:39  dick
224  * Javadoc.
225  *
226  * Revision 1.21  2009/01/12 20:08:29  dick
227  * Implement ClientAdapter as part of the new ClientConnection decoupling.
228  *
229  * Revision 1.20  2009/01/10 05:04:02  dick
230  * Handle match over messages special.  Fibs doesn't send a final board after the match is over, so we have to fake it out.
231  *
232  * Revision 1.19  2009/01/09 19:09:32  dick
233  * Handle the FIBS_Timeout message.
234  * Handle more game messages.
235  *
236  * Revision 1.18  2009/01/09 08:10:02  dick
237  * Chat, game, and system message routing.
238  *
239  * Revision 1.17  2009/01/07 02:32:45  dick
240  * Better resetting of our state between client connections.
241  *
242  * Revision 1.16  2009/01/06 08:05:28  dick
243  * Handle registering a new user.
244  *
245  * Revision 1.15  2008/12/20 23:02:10  dick
246  * Support for Own Info.
247  *
248  * Revision 1.14  2008/12/15 01:47:36  dick
249  * Just echo FirstRoll and MakesFirstMove
250  *
251  * Revision 1.13  2008/12/14 06:43:23  dick
252  * Add YouAreWatching (switch to board).
253  * Only display a Cookie? if the pref says to.
254  *
255  * Revision 1.12  2008/12/13 06:57:11  dick
256  * Move ClientConnection, CookieMonster, and FIBSMessages to their own network package.
257  *
258  * Revision 1.11  2008/12/13 06:20:49  dick
259  * Dispatch NetworkConnected when we receive the welcome message.
260  *
261  * Revision 1.10  2008/12/11 20:27:33  dick
262  * Handle CantInviteSelf, StartingNewGame, and Board.
263  *
264  * Revision 1.9  2008/12/11 09:58:50  dick
265  * Display Network In messages in a different color.
266  *
267  * Revision 1.8  2008/12/11 08:46:19  dick
268  * parse incoming Chat Message.
269  *
270  * Revision 1.7  2008/12/10 17:59:25  dick
271  * Display system messages in color.
272  *
273  * Revision 1.6  2008/12/09 19:32:36  dick
274  * Add Goodbye and NewMatchRequest handling.
275  *
276  * Revision 1.5  2008/12/09 01:48:55  dick
277  * Early CookieMonster integration.
278  *
279  * Revision 1.4  2008/12/07 22:52:27  dick
280  * Start playing with the cookie monster.
281  *
282  * Revision 1.3  2008/04/05 01:42:11  dick
283  * Add eol when outputting the motd.
284  *
285  * Revision 1.2  2008/04/01 04:21:26  dick
286  * Handle player logging out.
287  *
288  * Revision 1.1  2008/03/31 07:08:00  dick
289  * Parse messages received from the network.
290  *
291  */
292 
293 /* 
294  * This program is free software: you can redistribute it and/or modify
295  * it under the terms of the GNU General Public License as published by
296  * the Free Software Foundation, either version 3 of the License, or
297  * (at your option) any later version.
298  *
299  * This program is distributed in the hope that it will be useful,
300  * but WITHOUT ANY WARRANTY; without even the implied warranty of
301  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
302  * GNU General Public License for more details.
303  *
304  * You should have received a copy of the GNU General Public License
305  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
306  *
307  * The Original Code is BuckoFIBS, <http://www.buckosoft.com/BuckoFIBS/>.
308  * The Initial Developer of the Original Code is Dick Balaska and BuckoSoft, Corp.
309  * 
310  */
311 package com.buckosoft.fibs.BuckoFIBS;
312 
313 import java.util.Date;
314 import java.util.Timer;
315 import java.util.TimerTask;
316 
317 import com.buckosoft.fibs.BuckoFIBS.AudioManager.Cue;
318 import com.buckosoft.fibs.BuckoFIBS.gui.MainDialog;
319 import com.buckosoft.fibs.BuckoFIBS.gui.SystemMessagesTextPane;
320 import com.buckosoft.fibs.BuckoFIBS.gui.chatWindow.ChatPane;
321 import com.buckosoft.fibs.domain.CookieString;
322 import com.buckosoft.fibs.domain.FinishedMatch;
323 import com.buckosoft.fibs.domain.Player;
324 import com.buckosoft.fibs.net.ClientAdapter;
325 import com.buckosoft.fibs.net.ClientConnection;
326 import com.buckosoft.fibs.net.FIBSMessages;
327 
328 
329 /** Parse and dispatch messages received from the network.
330  * @author Dick Balaska
331  * @since 2008/03/31
332  * @version $Revision$ <br> $Date$
333  * @see <a href="http://cvs.buckosoft.com/Projects/BuckoFIBS/BuckoFIBS/src/main/java/com/buckosoft/fibs/BuckoFIBS/ClientReceiveParser.java">cvs ClientReceiveParser.java</a>
334  */
335 public class ClientReceiveParser implements FIBSMessages, ClientAdapter {
336 	private	final static boolean DEBUG = false;
337 
338 	/** We connect to fibs in either normal communications mode, or a special "Register new user" mode.
339 	 */
340 	public enum Mode {
341 		/** Default, normal fibs connection */
342 		Run,
343 		/** Special register new user commands are needed. */
344 		Register
345 	}
346 	private	MainDialog		mainDialog;
347 	private	CommandDispatcher	commandDispatcher = null;
348 	private	BFProperties		properties = null;
349 	private ClientConnection clientConnection = null;
350 	private	Mode			mode = Mode.Run;
351 	private	final static String eol = "\r\n";
352 
353 	private	String lastInviter = null;
354 	private	String lastMessage0;
355 	private	String lastMessage1;
356 	private int		lastCookie0;
357 	private int		lastCookie1;
358 	
359 	private	boolean	whoVirgin = true;
360 	private	boolean needSavedGames = true;
361 	private	Date	matchStartTime = null;
362 //	private	boolean	matchResuming = false;
363 	private	boolean	matchResumingYourTurn = false;
364 
365 	private	FinishedMatch		finishedMatch = null;
366 
367 	/** Set the reference to the instance of MainDialog
368 	 * @param mainDialog The MainDialog that is running
369 	 */
370 	public	void setMainDialog(MainDialog mainDialog) {
371 		this.mainDialog = mainDialog;
372 	}
373 
374 	/** Set the reference to our CommandDispatcher
375 	 * @param commandDispatcher The CommandDispatcher
376 	 */
377 	public void setCommandDispatcher(CommandDispatcher commandDispatcher) {
378 		this.commandDispatcher = commandDispatcher;
379 	}
380 
381 	/** Set the reference to our ClientConnection
382 	 * @param clientConnection The ClientConnection
383 	 */
384 	public void setClientConnection(ClientConnection clientConnection) {
385 		this.clientConnection = clientConnection;
386 	}
387 
388 	/** Set the Properties/User preferences
389 	 * @param properties The loaded properties
390 	 */
391 	public	void setProperties(BFProperties properties) {
392 		this.properties = properties;
393 	}
394 
395 	/** We connect to fibs in either normal communications mode, or a special "Register new user" mode.
396 	 * @param mode The mode that we should parse messages in
397 	 * @see com.buckosoft.fibs.BuckoFIBS.ClientReceiveParser.Mode
398 	 */
399 	public void setMode(Mode mode) {
400 		this.mode = mode;
401 		clientConnection.resetFIBSCookieMonster();
402 	}
403 
404 	/** Kill all timers and tasks this object owns as we prepare to go bye-bye.
405 	 */
406 	public void shutdown() {
407 		if (this.myTimer != null) {
408 			this.myTimer.cancel();
409 			this.myTimer = null;
410 		}
411 		if (this.myTimerSavedGames != null) {
412 			this.myTimerSavedGames.cancel();
413 			this.myTimerSavedGames = null;
414 		}
415 		if (this.myTimerTaskSavedGames != null) {
416 			this.myTimerTaskSavedGames.cancel();
417 			this.myTimerTaskSavedGames = null;
418 		}
419 	}
420 
421 	private void dispatchMessage(int cookie, String s) {
422 		CookieString gl;
423 		lastMessage1 = lastMessage0;
424 		lastMessage0 = s;
425 		lastCookie1 = lastCookie0;
426 		lastCookie0 = cookie;
427 		if (DEBUG)
428 			System.out.println("cookie = " + cookie);
429 		if (this.properties.isDisplayRecv())
430 			this.commandDispatcher.writeSystemMessageln(SystemMessagesTextPane.NETWORKMSG, s);
431 		if (mode == Mode.Register) {
432 			parseMessageRegister(s, cookie);
433 			return;
434 		}
435 		switch (cookie) {
436 		// These do nothing here.
437 		case CLIP_MOTD_END:
438 		case FIBS_BoardstyleSetTo:
439 		case FIBS_SavedMatchesHeader:
440 		case FIBS_Empty:
441 		case FIBS_UsersHeardYou:	// JavaFIBS puts this in the status bar, which i don't have
442 		case FIBS_YouAlreadyRolled:
443 			break;
444 		case CLIP_OWN_INFO:
445 			this.commandDispatcher.dispatch(CommandDispatcher.Command.OWN_INFO, s);
446 			break;
447 		case CLIP_WHO_INFO:
448 			parseWhoInfo(s);
449 			break;
450 		case CLIP_WHO_END:
451 			handleWhoEnd();
452 			break;
453 		case FIBS_SavedMatchPlaying:
454 		case FIBS_SavedMatchReady:
455 		case FIBS_SavedMatch:
456 			//if (DEBUG)
457 				System.out.println(s);
458 			this.commandDispatcher.dispatch(CommandDispatcher.Command.SAVED_MATCH, s);
459 			break;
460 		case FIBS_NoSavedMatch:
461 			showErrorMessage(s);
462 			this.commandDispatcher.dispatch(CommandDispatcher.Command.SAVED_MATCH, s);
463 			break;
464 		case FIBS_LoginPrompt:
465 			whoVirgin = true;
466 			this.commandDispatcher.writeSystemMessageln(s);
467 			this.mainDialog.getDB().setActiveProfile(this.properties.getSelectedProfile());
468 			this.mainDialog.updateRatingPanel();
469 			this.mainDialog.setPlayerListTabVisible();
470 			clientConnection.sendLogin();
471 			break;
472 		case CLIP_LOGIN:
473 			parsePlayerLoggedIn(s);
474 			break;
475 		case CLIP_LOGOUT:
476 			parsePlayerLoggedOut(s);
477 			break;
478 		case FIBS_OpponentLogsOut:
479 		case FIBS_OpponentLeftGame:
480 			parseAbortMatch(s);
481 			break;
482 		case FIBS_Goodbye:
483 			disconnectFromServer();
484 			break;
485 		case FIBS_Timeout:
486 			this.commandDispatcher.writeSystemMessageln(SystemMessagesTextPane.NETWORKMSG, s);
487 			disconnectFromServer();
488 			break;
489 		case CLIP_WELCOME:
490 			this.commandDispatcher.dispatch(CommandDispatcher.Command.NETWORK_CONNECTED);
491 			break;
492 		case FIBS_YouAreWatching:
493 			this.commandDispatcher.writeSystemMessageln(SystemMessagesTextPane.NETWORKMSG, s);
494 			this.commandDispatcher.dispatch(CommandDispatcher.Command.WATCHING);
495 			break;
496 		case CLIP_SAYS:
497 			if (s.startsWith("12 RepBotNG ")) {
498 				this.mainDialog.getPlayerReportPane().receiveLine(s, cookie);
499 				return;
500 			}
501 			parseChatMessage(s, cookie);
502 			break;
503 		case CLIP_WHISPERS:
504 		case CLIP_KIBITZES:
505 			parseChatMessage(s, cookie);
506 			break;
507 		case CLIP_SHOUTS:
508 			if (s.startsWith("13 MissManners"))
509 				this.commandDispatcher.dispatch(CommandDispatcher.Command.MISS_MANNERS, s);
510 			if(!properties.isMsgIgnoreShouts())
511 				parseChatMessage(s, cookie);
512 			break;
513 		case CLIP_YOU_SAY:
514 			parseChatMessage(s, cookie);
515 			break;
516 		case CLIP_YOU_SHOUT:
517 		case CLIP_YOU_WHISPER:
518 		case CLIP_YOU_KIBITZ:
519 			parseYouChatMessage(s, cookie);
520 			break;
521 		case FIBS_NobodyHeardYou:
522 			this.commandDispatcher.writeChatMessageln(null, cookie, s);
523 		case FIBS_Waves:
524 		case FIBS_WavesAgain:
525 			if(!properties.isMsgIgnoreShouts())
526 				parseWavesMessage(s);
527 			break;
528 		case FIBS_NewMatchRequest:
529 		case FIBS_ResumeMatchRequest:
530 			parseInvite(s);
531 			break;
532 		case FIBS_CantInviteSelf:
533 		case FIBS_CantWatchSelf:
534 		case FIBS_NotInteresting:
535 		case FIBS_PlayerNotPlaying:
536 		case FIBS_PlayerRefusingGames:
537 		case FIBS_NotYourTurnToRoll:
538 		case FIBS_NotYourTurnToMove:
539 		case FIBS_PlayerBannedWatch:
540 		case FIBS_DoesntWantYouToWatch:
541 			showErrorMessage(s);
542 			break;
543 		case FIBS_ResumeMatchAck0:
544 		case FIBS_ResumeMatchAck5:
545 			displayGameMessage(s);
546 			startNewGame(true);
547 //			this.matchResuming = true;
548 			break;
549 		case FIBS_Turn:
550 			displayGameMessage(s);
551 			parseResumeMatchTurn(s, cookie);
552 			break;
553 		case FIBS_MatchLength:
554 			displayGameMessage(s);
555 			parseResumeMatchLength(s);
556 			break;
557 		case FIBS_Board:
558 			if (DEBUG)
559 				System.out.println(s);
560 			this.mainDialog.getDocument().getBoard().parseFibsBoard(s);
561 			gl = new CookieString(cookie, s);
562 			this.commandDispatcher.dispatch(CommandDispatcher.Command.GAME_EVENT, gl);
563 			if (this.matchResumingYourTurn) {
564 				if (this.mainDialog.getDocument().getBoard().isYouMayDouble()) {
565 					if (this.mainDialog.getDocument().getBoard().getDice()[0][0] == 0) {
566 						this.commandDispatcher.dispatch(CommandDispatcher.Command.ROLL_OR_DOUBLE);
567 					}
568 				}
569 				this.matchResumingYourTurn = false; 
570 			}
571 			doAutoGreedyBearoff();
572 			break;
573 		case FIBS_NewMatchAck10:
574 			this.commandDispatcher.writeSystemMessageln(SystemMessagesTextPane.NETWORKMSG, s);
575 			this.mainDialog.setGameMessagesTabVisible();
576 			break;
577 		case FIBS_NewMatchAck2:
578 		case FIBS_FirstRoll:
579 		case FIBS_MakesFirstMove:
580 		case FIBS_PlayerRolls:
581 		case FIBS_YouRoll:
582 		case FIBS_PlayerMoves:
583 		case FIBS_CantMove:
584 		case FIBS_OnlyPossibleMove:
585 		case FIBS_PleaseMove:
586 		case FIBS_YourTurnToMove:
587 		case FIBS_AcceptRejectDouble:
588 		case FIBS_WatchResign:
589 		case FIBS_ResignRefused:
590 		case FIBS_AcceptWins:
591 		case FIBS_PlayerWantsToResign:
592 		case FIBS_YouCantMove:
593 		case FIBS_BearingOff:
594 		case FIBS_YouAcceptAndWin:
595 		case FIBS_YouResign:
596 		case FIBS_YouReject:
597 		case FIBS_YouDouble:
598 			displayGameMessage(s);
599 			gl = new CookieString(cookie, s);
600 			this.commandDispatcher.dispatch(CommandDispatcher.Command.GAME_EVENT, gl);
601 			break;
602 		case FIBS_StartingNewGame:
603 			startNewGame(false);
604 			displayGameMessage(s);
605 			gl = new CookieString(cookie, s);
606 			this.commandDispatcher.dispatch(CommandDispatcher.Command.GAME_EVENT, gl);
607 			break;
608 		case FIBS_YouWinMatch:
609 		case FIBS_PlayerWinsMatch:
610 			parseMatchOverMessage(s, cookie);
611 			displayGameMessage(s);
612 			break;
613 		case FIBS_ReadyTrue:
614 		case FIBS_ReadyFalse:
615 			parseReadyMessage(cookie);
616 			break;
617 //		case FIBS_AcceptRejectDouble:
618 //			handleAcceptRejectDouble();
619 //			break;
620 		case FIBS_JoinNextGame: 
621 			this.commandDispatcher.writeNetworkMessageln("join");
622 			break;
623 		case FIBS_PlayerWinsGame:
624 		case FIBS_ScoreUpdate:
625 		case FIBS_ResignWins:
626 		case FIBS_PlayerStartsWatching:
627 		case FIBS_PointsFor:
628 		case FIBS_YouWinGame:
629 		case FIBS_CantMoveFirstMove:
630 		case FIBS_RollBeforeMove:
631 		case FIBS_Done:
632 		case FIBS_GreedyTrue:			// XXX: Someday, change the icon on this state
633 		case FIBS_GreedyFalse:
634 		case FIBS_ResignYouWin:
635 		case FIBS_PleaseWaitForJoin:
636 		case FIBS_YouGiveUp:
637 		case FIBS_MustMove:
638 			displayGameMessage(s);
639 			break;
640 		case FIBS_PlayerAcceptsDouble:
641 			gl = new CookieString(cookie, s);
642 			this.commandDispatcher.dispatch(CommandDispatcher.Command.GAME_EVENT, gl);
643 			this.mainDialog.getDocument().setYouDouble(false);
644 			displayGameMessage(s);
645 			break;
646 		case FIBS_DidntDoubleOrResign:
647 			displayGameError(s);
648 			break;
649 		case FIBS_PlayersStartingMatch:
650 		case FIBS_PlayerStopsWatching:
651 		case FIBS_PlayersStartingUnlimitedMatch:
652 		case FIBS_ResumingLimitedMatch:
653 		case FIBS_ResumingUnlimitedMatch:
654 		case FIBS_MatchResult:
655 			parseOtherMatchMessage(s);
656 			break;
657 		case FIBS_PlayerInfoStart:
658 		case FIBS_LastLogin:
659 		case FIBS_StillLoggedIn:
660 		case FIBS_NotLoggedIn:
661 		case FIBS_ReadyWatchingPlaying:
662 		case FIBS_RatingExperience:
663 		case FIBS_NoEmail:
664 		case FIBS_EmailAddress:
665 		case FIBS_IsPlayingWith:
666 		case FIBS_HasSavedGames:
667 		case FIBS_HasNoSavedGames:
668 		case FIBS_NoInfo:
669 			this.mainDialog.getPlayerReportPane().receiveLine(s, cookie);
670 //			this.commandDispatcher.writeSystemMessageln(SystemMessagesTextPane.NETWORKMSG, s);
671 			break;
672 		// Just echo the message to the window
673 		case FIBS_PreLogin:
674 		case CLIP_MOTD_BEGIN:
675 		case FIBS_TypeJoin:
676 		case FIBS_YouStopWatching:
677 		case FIBS_YouAlreadyPlaying:
678 		case FIBS_AlreadyPlaying:
679 		case FIBS_LastLogout:
680 		case FIBS_NotPlaying:
681 		case FIBS_NoUser:
682 		case FIBS_EchoJunk:
683 		case FIBS_WaitForLastInvitation:
684 		case FIBS_WaitForAcceptResign:
685 		case FIBS_YourEmailChanged:
686 			this.commandDispatcher.writeSystemMessageln(SystemMessagesTextPane.NETWORKMSG, s);
687 			break;
688 		case FIBS_DidntInvite:
689 		case FIBS_NotWatchingPlaying:
690 		case FIBS_NoSavedGames:
691 			this.commandDispatcher.writeSystemMessageln(SystemMessagesTextPane.NETWORKMSG, s);
692 			this.mainDialog.setSystemMessagesTabVisible();
693 			break;
694 		case FIBS_WARNINGSavedMatch:
695 			parseInviteWarning(s);
696 			break;
697 		case FIBS_DoubleTrue:
698 			parseDoublesOnOff(true);
699 			displayGameMessage(s);
700 			break;
701 		case FIBS_DoubleFalse:
702 			parseDoublesOnOff(false);
703 			displayGameMessage(s);
704 			break;
705 		case FIBS_Doubles:
706 			parseDoubles(s);
707 			gl = new CookieString(cookie, s);
708 			this.commandDispatcher.dispatch(CommandDispatcher.Command.GAME_EVENT, gl);
709 			displayGameMessage(s);
710 			break;
711 		case FIBS_YouAcceptDouble:
712 			displayGameMessage(s);
713 			this.mainDialog.getDocument().setYouDouble(false);
714 			this.mainDialog.updateBoard();
715 			break;
716 		case FIBS_RollOrDouble:
717 			this.commandDispatcher.dispatch(CommandDispatcher.Command.ROLL_OR_DOUBLE);
718 			break;
719 //		case FIBS_YourTurnToMove:	// First roll of the game, always 2 moves
720 //			this.commandDispatcher.dispatch(CommandDispatcher.Command.YOUR_MOVE, "2");
721 //			break;
722 		case FIBS_YouInvited:
723 			parseYouInvited(s);
724 			break;
725 //		case FIBS_PleaseMove:
726 //			parsePleaseMove(s);
727 //			this.mainDialog.playSound(Cue.YourTurn);
728 //			displayGameMessage(s);
729 //			break;
730 		case FIBS_ATTENTION:
731 		case FIBS_ShuttingDown:
732 		case FIBS_Rebooting:
733 			this.mainDialog.playSound(Cue.FibsAttention);
734 		case FIBS_GamesWillBeSaved:
735 		case FIBS_UnknownCommand:
736 		case FIBS_GameWasSaved:
737 			this.commandDispatcher.writeSystemMessageln(SystemMessagesTextPane.ERROR, s);
738 			break;
739 		case FIBS_Unknown:
740 			this.commandDispatcher.writeSystemMessageln(SystemMessagesTextPane.ERROR, "Unknown message from FIBS: '" + s + "'");
741 			this.commandDispatcher.writeSystemMessageln(SystemMessagesTextPane.ERROR, "First char is " + new Integer(s.charAt(0)));
742 			break;
743 		default:
744 			if (this.commandDispatcher.getProperties().isDEBUG_ShowUnhandledCookies()) {
745 				String t = "Cookie? " + cookie + " '" + s + "'";
746 				this.commandDispatcher.writeSystemMessageln(SystemMessagesTextPane.ERROR, t);
747 				System.out.println(t);
748 				t = "Last message was " + lastCookie1 + " '" + lastMessage1 + "'";
749 				if (cookie == FIBS_Unknown) {
750 					this.commandDispatcher.writeSystemMessageln(SystemMessagesTextPane.ERROR, t);
751 					System.out.println(t);
752 				}
753 			}
754 			break;
755 		}
756 	}
757 
758 //	/** Replay a message from a saved game or a previous move in this game
759 //	 * @param s
760 //	 */
761 /*	public void parseReplayMessage(int cookie, String s) {
762 		if (DEBUG)
763 			System.out.println("cookie = " + cookie);
764 		switch (cookie) {
765 		case FIBS_Board:
766 			this.commandDispatcher.dispatch(CommandDispatcher.Command.FIBS_BOARD, s);
767 			break;
768 		default:
769 //			if (this.commandDispatcher.getProperties().isDEBUG_ShowUnhandledCookies())
770 				this.commandDispatcher.writeSystemMessageln(SystemMessagesTextPane.ERROR, "Replay? " + cookie + " '" + s + "'");
771 			break;
772 		}
773 	}
774 */
775 	private enum RegState {
776 		name,
777 		password,
778 		password1,
779 		done
780 	}
781 	private RegState regState = RegState.name;
782 	
783 	private void parseMessageRegister(String s, int fibsCookie) {
784 		int profileId = this.commandDispatcher.getProperties().getSelectedProfile();
785 		String password;
786 		switch (fibsCookie) {
787 		case FIBS_LoginPrompt:
788 			this.commandDispatcher.writeRegisterUserMessage("Logging in...");
789 			this.commandDispatcher.writeSystemMessageln(s);
790 			clientConnection.sendMessage("guest" + eol);
791 			break;
792 		case FIBS_OneUserPerPerson:
793 			String userName = this.commandDispatcher.getProperties().getUserName(profileId);
794 			this.commandDispatcher.writeRegisterUserMessage("Registering user " + userName);
795 			this.clientConnection.sendMessage("name " + userName + eol);
796 			regState = RegState.password;
797 			break;
798 
799 		case FIBS_GivePassword:
800 			password = this.commandDispatcher.getProperties().getPassword(profileId);
801 			this.clientConnection.sendMessage(password + eol);
802 			break;
803 		case FIBS_RetypePassword:
804 			password = this.commandDispatcher.getProperties().getPassword(profileId);
805 			this.clientConnection.sendMessage(password + eol);
806 			break;
807 		case FIBS_YouAreRegistered:
808 			this.commandDispatcher.writeRegisterUserMessage("Success!");
809 //			this.clientConnection.sendMessage("bye" + eol);
810 			this.commandDispatcher.dispatch(CommandDispatcher.Command.CONNECT_TO_SERVER);
811 			break;
812 		case FIBS_UseAnotherName:
813 			this.commandDispatcher.dispatch(CommandDispatcher.Command.BAD_NEW_USER, s);
814 			break;
815 		case CLIP_MOTD_BEGIN:
816 			if (regState == RegState.password) {
817 				password = this.commandDispatcher.getProperties().getPassword(profileId);
818 				this.clientConnection.sendMessage(password + eol);
819 				regState = RegState.password1;
820 				break;
821 			}
822 			if (regState == RegState.password1) {
823 				password = this.commandDispatcher.getProperties().getPassword(profileId);
824 				this.clientConnection.sendMessage(password + eol);
825 				regState = RegState.done;
826 				break;
827 			}
828 		}
829 	}
830 
831 	private void showErrorMessage(String s) {
832 		this.commandDispatcher.writeSystemMessageln(SystemMessagesTextPane.ERROR, s);
833 	}
834 
835 	private void disconnectFromServer() {
836 		this.commandDispatcher.dispatch(CommandDispatcher.Command.SHUTTING_DOWN);
837 		this.clientConnection.resetFIBSCookieMonster();
838 	}
839 
840 	private	void parseWhoInfo(String s) {
841 		Player p = new Player();
842 		p.parsePlayer(s);
843 		if (this.finishedMatch != null && p.getName().equals(this.mainDialog.getDocument().getName())) {
844 			this.finishedMatch.setRatingAfterMatch(p.getRating());
845 			this.mainDialog.getDB().store(this.finishedMatch);
846 			this.finishedMatch = null;
847 			this.mainDialog.updateRatingPanel();
848 			this.mainDialog.getDB().updateOpponent(p);
849 			this.mainDialog.getPlayerListTab().getPlayerTableModel().playerChanged(p);
850 		}
851 		this.commandDispatcher.dispatch(CommandDispatcher.Command.PLAYER_CHANGED, p);
852 	}
853 
854 	private void handleWhoEnd() {
855 		if (this.whoVirgin) {
856 			sendDelayedWhoCommand();
857 		} else if (this.needSavedGames) {
858 			sendDelayedSavedGamesCommand();
859 			this.needSavedGames = false;
860 		}
861 	}
862 
863 	private	void parsePlayerLoggedOut(String s) {
864 		String[] ss = s.split(" ");
865 		this.commandDispatcher.dispatch(CommandDispatcher.Command.PLAYER_GONE, ss[1]);
866 		if (this.properties.isMsgLoginsAndOuts())
867 			this.commandDispatcher.writeSystemMessageln(SystemMessagesTextPane.NORMAL, ss[2] + " " + ss[3] + " " + ss[4]);
868 	}
869 
870 	private	void parseAbortMatch(String s) {
871 		this.commandDispatcher.writeSystemMessageln(SystemMessagesTextPane.ERROR, s);
872 		this.mainDialog.playSound(Cue.MatchAborted);
873 		this.commandDispatcher.writeNetworkMessageln("show saved");
874 	}
875 
876 	/** Just log the player to the messages list.
877 	 * Adding the player to the table comes with the CLIP_WHO_INFO message
878 	 * @param s The Login message
879 	 */
880 	private void parsePlayerLoggedIn(String s) {
881 		String[] ss = s.split(" ");
882 		if (this.properties.isMsgLoginsAndOuts())
883 			this.commandDispatcher.writeSystemMessageln(SystemMessagesTextPane.NORMAL, ss[2] + " " + ss[3] + " " + ss[4]);
884 	}
885 
886 	private void parseOtherMatchMessage(String s) {
887 		if (this.properties.isMsgOtherMatchInfo())
888 			this.commandDispatcher.writeSystemMessageln(SystemMessagesTextPane.NORMAL, s);
889 	}
890 
891 	private void parseInvite(String s) {
892 		String[] ss = s.split(" ");
893 		this.commandDispatcher.dispatch(CommandDispatcher.Command.INVITED, 
894 				ss[0], 
895 				ss[3].equals("resume") ? ss[3] : ss[5]);
896 		lastInviter = ss[0];
897 	}
898 
899 	private void parseInviteWarning(String s) {
900 		if (lastInviter != null) {
901 			this.commandDispatcher.dispatch(CommandDispatcher.Command.INVITE_WARNING, lastInviter, s);
902 		}
903 	}
904 
905 	private	void parseYouInvited(String s) {
906 		String[] ss = s.split(" ");
907 		this.commandDispatcher.dispatch(CommandDispatcher.Command.YOU_INVITED, ss[3]);
908 		this.commandDispatcher.writeSystemMessageln(SystemMessagesTextPane.NORMAL, s);
909 	}
910 
911 	private	void parseDoubles(String s) {
912 		this.commandDispatcher.writeNetworkMessageln("board");
913 	}
914 
915 	private	void startNewGame(boolean resume) {
916 		if (this.matchStartTime == null)
917 			this.matchStartTime = new Date();
918 		if (!resume)
919 			this.commandDispatcher.dispatch(CommandDispatcher.Command.START_GAME);
920 		else
921 			this.commandDispatcher.dispatch(CommandDispatcher.Command.RESUME_GAME);
922 			
923 	}
924 
925 	private void displayGameMessage(String s) {
926 		this.commandDispatcher.writeGameMessageln(s);
927 	}
928 	private void displayGameError(String s) {
929 		this.commandDispatcher.writeGameErrorln(s);
930 	}
931 
932 	private void parseMatchOverMessage(String s, int cookie) {
933 		String[] ss = s.split(" ");
934 		this.commandDispatcher.dispatch(CommandDispatcher.Command.MATCH_OVER, ss[0], ss[6]);
935 		String opponentName = this.mainDialog.getDocument().getBoard().getPlayerName()[1];
936 		int[] scores = this.mainDialog.getDocument().getBoard().getMatchScore();
937 		if (this.mainDialog.getDocument().getBoard().isYouPlaying()) {
938 			this.finishedMatch = new FinishedMatch();
939 			this.finishedMatch.setMatchPoints(Integer.parseInt(ss[3]));
940 			this.finishedMatch.setYourScore(scores[0]);
941 			this.finishedMatch.setOpponentScore(scores[1]);
942 			Date endDate = new Date();
943 			this.finishedMatch.setDate(endDate);
944 			this.finishedMatch.setDuration((int)((endDate.getTime()-this.matchStartTime.getTime())/1000));
945 			this.matchStartTime = null;
946 			this.mainDialog.getDocument().removeSavedMatch(opponentName);
947 			Player op = this.mainDialog.getDB().getPlayer(opponentName);
948 			if (op == null) {
949 				op = this.mainDialog.getPlayerTableModel().getPlayer(opponentName);
950 				this.mainDialog.getDB().store(op);
951 			}
952 			op.setSavedMatch(null);						// remove the icon from the player list
953 			this.finishedMatch.setOpponentId(op.getId());
954 			this.commandDispatcher.dispatch(CommandDispatcher.Command.PLAYER_CHANGED, op);
955 
956 			this.mainDialog.getChatPane().setupComboBoxCommand(ChatPane.Command.Tell);
957 			this.mainDialog.getChatPane().maybeAddPlayer(opponentName);
958 		}
959 	}
960 
961 	private void parseDoublesOnOff(boolean onoff) {
962 		this.commandDispatcher.dispatch(CommandDispatcher.Command.TOGGLE_DOUBLE, new Boolean(onoff));
963 		
964 	}
965 
966 	private void parseReadyMessage(int cookie) {
967 		boolean b = false;
968 		if (cookie == FIBS_ReadyTrue)
969 			b = true;
970 		this.commandDispatcher.dispatch(CommandDispatcher.Command.READY_TO_PLAY, new Boolean(b));
971 	}
972 
973 	private void parseChatMessage(String s, int cookie) {
974 		int i = s.indexOf(' ', 3);
975 		if (i == -1)
976 			return;
977 		String name = s.substring(3, i);
978 		String text = s.substring(i+1);
979 		this.mainDialog.playSound(Cue.ChatReceived);
980 		this.commandDispatcher.writeChatMessageln(name, cookie, text);
981 	}
982 
983 	private void parseYouChatMessage(String s, int cookie) {
984 		this.mainDialog.playSound(Cue.ChatReceived);
985 		this.commandDispatcher.writeChatMessageln(null, cookie, s.substring(3));
986 	}
987 	
988 	private void parseWavesMessage(String s) {
989 		this.commandDispatcher.writeSystemMessageln(s);
990 	}
991 
992 	private void parseResumeMatchTurn(String s, int cookie) {
993 		String t = s.substring(6, s.length()-1);
994 		if (this.mainDialog.getDocument().getName().equals(t)) {
995 			this.matchResumingYourTurn = true;
996 			CookieString cs = new CookieString(cookie, s);
997 			this.commandDispatcher.dispatch(CommandDispatcher.Command.GAME_EVENT, cs);
998 		}
999 	}
1000 
1001 	private void parseResumeMatchLength(String s) {
1002 		
1003 	}
1004 
1005 //	private void handleAcceptRejectDouble() {
1006 //		this.commandDispatcher.dispatch(CommandDispatcher.Command.ACCEPT_OR_DECLINE_DOUBLE);
1007 //	}
1008 
1009 	private void doAutoGreedyBearoff() {
1010 		if (!this.mainDialog.getDocument().getBoard().isYouPlaying())
1011 			return;
1012 		if (!this.properties.isAutoGreedyBearOff())
1013 			return;
1014 		if (this.mainDialog.getDocument().isGreedy())
1015 			return;
1016 		if (this.mainDialog.getDocument().getBoard().isRace())
1017 			this.commandDispatcher.dispatch(CommandDispatcher.Command.TOGGLE_GREEDY_BEAROFF);
1018 	}
1019 
1020 	/* (non-Javadoc)
1021 	 * @see com.buckosoft.fibs.net.ClientAdapter#dispatch(java.lang.String)
1022 	 */
1023 	@Override
1024 	public void dispatch(int cookie, String s) {
1025 		this.dispatchMessage(cookie, s);
1026 	}
1027 
1028 	/* (non-Javadoc)
1029 	 * @see com.buckosoft.fibs.net.ClientAdapter#writeSystemMessageln(com.buckosoft.fibs.net.ClientAdapter.MessageRoute, java.lang.String)
1030 	 */
1031 	@Override
1032 	public void writeSystemMessageln(MessageRoute route, String s) {
1033 		this.writeSystemMessage(route, s + eol);
1034 	}
1035 
1036 	/* (non-Javadoc)
1037 	 * @see com.buckosoft.fibs.net.ClientAdapter#writeSystemMessage(com.buckosoft.fibs.net.ClientAdapter.MessageRoute, java.lang.String)
1038 	 */
1039 	@Override
1040 	public void writeSystemMessage(MessageRoute route, String s) {
1041 		if (route == ClientAdapter.MessageRoute.NETWORKOUT)
1042 			this.commandDispatcher.writeSystemMessage(SystemMessagesTextPane.NETWORKOUT, s);
1043 		else if (route == ClientAdapter.MessageRoute.DEBUG)
1044 			this.commandDispatcher.writeSystemMessage(SystemMessagesTextPane.DEBUG, s);
1045 		else if (route == ClientAdapter.MessageRoute.SYSTEM)
1046 			this.commandDispatcher.writeSystemMessage(SystemMessagesTextPane.NORMAL, s);
1047 		else if (route == ClientAdapter.MessageRoute.ERROR)
1048 			this.commandDispatcher.writeSystemMessage(SystemMessagesTextPane.ERROR, s);
1049 	}
1050 
1051 	
1052 	@Override
1053 	public void connectionAborted() {
1054 		this.commandDispatcher.dispatch(CommandDispatcher.Command.DISCONNECT_FROM_NETWORK);
1055 	}
1056 
1057 
1058 	//////////////////////////////////////////////////////////////////////////
1059 	// Timer task which does a "who" after a couple of seconds in order to grab
1060 	// more of the players on FIBS.
1061 	private	Timer	myTimer = null;
1062 	private	TimerTask	myTimerTask = null;
1063 
1064 	private	void	sendDelayedWhoCommand() {
1065 		if (myTimer != null) {
1066 			return;
1067 		}
1068 		myTimer = new Timer();
1069 		try {
1070 			myTimerTask = new MyTimerTask(this);
1071 			myTimer.schedule(myTimerTask, 2000);
1072 		} catch (IllegalStateException e) {
1073 			e.printStackTrace();
1074 		}
1075 	}
1076 
1077 	private class MyTimerTask extends TimerTask {
1078 		private	ClientReceiveParser crp;
1079 
1080 		MyTimerTask(ClientReceiveParser crp) {
1081 			super();
1082 			this.crp = crp;
1083 		}
1084 		/* (non-Javadoc)
1085 		 * @see java.util.TimerTask#run()
1086 		 */
1087 		@Override
1088 		public void run() {
1089 			this.crp.commandDispatcher.writeNetworkMessageln("who");
1090 			this.crp.whoVirgin = false;
1091 			this.crp.myTimer.cancel();
1092 			this.crp.myTimer = null;
1093 		}
1094 	}
1095 
1096 	//////////////////////////////////////////////////////////////////////////
1097 	// Timer task which does a "who" after a couple of seconds in order to grab
1098 	// more of the players on FIBS.
1099 	private	Timer	myTimerSavedGames = null;
1100 	private	TimerTask	myTimerTaskSavedGames = null;
1101 
1102 	private	void	sendDelayedSavedGamesCommand() {
1103 		if (myTimerSavedGames != null) {
1104 			return;
1105 		}
1106 		myTimerSavedGames = new Timer();
1107 		try {
1108 			myTimerTaskSavedGames = new MyTimerTaskSavedGames(this);
1109 			myTimerSavedGames.schedule(myTimerTaskSavedGames, 1000);
1110 		} catch (IllegalStateException e) {
1111 			e.printStackTrace();
1112 		}
1113 	}
1114 
1115 	private class MyTimerTaskSavedGames extends TimerTask {
1116 		private	ClientReceiveParser crp;
1117 
1118 		MyTimerTaskSavedGames(ClientReceiveParser crp) {
1119 			super();
1120 			this.crp = crp;
1121 		}
1122 		/* (non-Javadoc)
1123 		 * @see java.util.TimerTask#run()
1124 		 */
1125 		@Override
1126 		public void run() {
1127 			this.crp.commandDispatcher.writeNetworkMessageln("show saved");
1128 			this.crp.myTimerSavedGames.cancel();
1129 			this.crp.myTimerSavedGames = null;
1130 			this.crp.myTimerTaskSavedGames.cancel();
1131 			this.crp.myTimerTaskSavedGames = null;
1132 		}
1133 	}
1134 
1135 }