Coverage Report - com.buckosoft.fibs.BuckoFIBS.GameManager
 
Classes in this File Line Coverage Branch Coverage Complexity
GameManager
0%
0/355
0%
0/100
4
 
 1  
 /******************************************************************************
 2  
  * GameManager.java - Manage all of the moves that happen in a single game
 3  
  * $Id$
 4  
  * 
 5  
  * BuckoFIBS - Backgammon by BuckoSoft
 6  
  * Copyright© 2009,2010 - Dick Balaska - BuckoSoft, Corp.
 7  
  * 
 8  
  * $Log$
 9  
  * Revision 1.29  2013/09/12 06:37:01  dick
 10  
  * Doubles dispatches gameEvents.
 11  
  *
 12  
  * Revision 1.28  2011/09/23 02:58:39  dick
 13  
  * Rework a little bit when position gets updated. (and still needs work).
 14  
  *
 15  
  * Revision 1.27  2011/07/16 02:33:09  dick
 16  
  * Add YouDouble.
 17  
  *
 18  
  * Revision 1.26  2011/07/04 03:43:07  dick
 19  
  * Add FirstMove handling.
 20  
  *
 21  
  * Revision 1.25  2011/06/18 19:29:48  dick
 22  
  * Work on resigning and YouCantMove.
 23  
  *
 24  
  * Revision 1.24  2011/06/14 19:18:07  dick
 25  
  * Add YouCantMove handling.
 26  
  * Bearing off only affects You.  Others will get a move message.
 27  
  *
 28  
  * Revision 1.23  2011/06/13 04:42:41  dick
 29  
  * Handle FIBS_PlayerWantsToResign.
 30  
  *
 31  
  * Revision 1.22  2011/06/10 20:41:17  dick
 32  
  * Add Undo to sendGameEvent().
 33  
  * queueGameEvent() tweakage.
 34  
  *
 35  
  * Revision 1.21  2011/06/05 06:56:41  dick
 36  
  * Handle AcceptsAndWins
 37  
  *
 38  
  * Revision 1.20  2011/06/02 19:11:20  dick
 39  
  * Deal with resign messages.
 40  
  *
 41  
  * Revision 1.19  2011/05/23 05:55:42  dick
 42  
  * Add youMoved() which removes any pending "YourMove" from the queue.
 43  
  *
 44  
  * Revision 1.18  2011/05/23 01:11:17  dick
 45  
  * Add playPaused() skeleton.
 46  
  *
 47  
  * Revision 1.17  2011/05/22 05:09:45  dick
 48  
  * Add AcceptReject double.
 49  
  * Fix game opening sequence.
 50  
  *
 51  
  * Revision 1.16  2011/05/21 20:18:29  dick
 52  
  * Sorting dice works.
 53  
  *
 54  
  * Revision 1.15  2011/05/21 04:59:56  dick
 55  
  * Work on GUI integration.
 56  
  * Add the preStartList for events that can't go out before the first board.
 57  
  *
 58  
  * Revision 1.14  2011/05/18 05:55:18  dick
 59  
  * Nice watching, Still needs work for playing.
 60  
  *
 61  
  * Revision 1.13  2011/05/17 23:11:26  dick
 62  
  * Working on passing replay commands to the animator.
 63  
  *
 64  
  * Revision 1.12  2011/05/16 14:18:29  dick
 65  
  * Add support for the CantMove event.
 66  
  *
 67  
  * Revision 1.11  2011/05/16 11:33:58  dick
 68  
  * Add FIBS_PlayerRolls.
 69  
  *
 70  
  * Revision 1.10  2011/05/15 18:17:15  dick
 71  
  * Working on why the last GameMove is empty, instead of bearing off the last checkers.
 72  
  *
 73  
  * Revision 1.9  2011/05/15 02:19:12  dick
 74  
  * GameLine becomes GameBoard.
 75  
  * Rearrange a whole bunch of packages.
 76  
  *
 77  
  * Revision 1.8  2011/05/14 04:43:01  dick
 78  
  * I needed to deal with some lightweight Boards.
 79  
  * So finally make the primary document Document
 80  
  * and demote just the Board handling to a domain object.
 81  
  *
 82  
  * Revision 1.7  2011/05/13 18:24:06  dick
 83  
  * Working on turning off animation, which should skip move events
 84  
  * and just display boards.
 85  
  *
 86  
  * Revision 1.6  2011/05/13 14:29:02  dick
 87  
  * Work with GameEvents, not Lines.
 88  
  *
 89  
  * Revision 1.5  2011/05/11 22:22:42  dick
 90  
  * Working on animating moves.
 91  
  *
 92  
  * Revision 1.4  2011/05/10 16:08:20  dick
 93  
  * Fix the javadoc pointers to the source code.
 94  
  *
 95  
  * Revision 1.3  2010/03/03 13:12:21  inim
 96  
  * Replaced (c) sign in comment mangled by CVS default encoding back to UTF-8
 97  
  *
 98  
  * Revision 1.2  2010/03/03 12:19:49  inim
 99  
  * 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.
 100  
  *
 101  
  * Revision 1.1  2010/02/04 05:57:53  inim
 102  
  * Mavenized project folder layout
 103  
  *
 104  
  * Revision 1.7  2009/02/23 09:44:54  dick
 105  
  * Javadoc.
 106  
  *
 107  
  * Revision 1.6  2009/02/14 13:13:21  dick
 108  
  * BuckoFIBS is released under the GNU license.
 109  
  * Javadoc.
 110  
  *
 111  
  * Revision 1.5  2009/02/11 09:01:20  dick
 112  
  * Don't initialize your turn if its not your turn or you're not playing.
 113  
  *
 114  
  * Revision 1.4  2009/01/31 08:53:08  dick
 115  
  * We're moving checkers, not dice.
 116  
  *
 117  
  * Revision 1.3  2009/01/31 08:48:23  dick
 118  
  * Line contains info about and GameManager initializes YourMove.
 119  
  *
 120  
  * Revision 1.2  2009/01/31 06:08:11  dick
 121  
  * React to the replay buttons being pressed.
 122  
  *
 123  
  * Revision 1.1  2009/01/28 22:26:52  dick
 124  
  * Skeleton GameManager.
 125  
  */
 126  
 
 127  
 /* 
 128  
  * This program is free software: you can redistribute it and/or modify
 129  
  * it under the terms of the GNU General Public License as published by
 130  
  * the Free Software Foundation, either version 3 of the License, or
 131  
  * (at your option) any later version.
 132  
  *
 133  
  * This program is distributed in the hope that it will be useful,
 134  
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 135  
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 136  
  * GNU General Public License for more details.
 137  
  *
 138  
  * You should have received a copy of the GNU General Public License
 139  
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 140  
  *
 141  
  * The Original Code is BuckoFIBS, <http://www.buckosoft.com/BuckoFIBS/>.
 142  
  * The Initial Developer of the Original Code is Dick Balaska and BuckoSoft, Corp.
 143  
  * 
 144  
  */
 145  
 package com.buckosoft.fibs.BuckoFIBS;
 146  
 
 147  
 import java.util.LinkedList;
 148  
 
 149  
 import org.slf4j.Logger;
 150  
 import org.slf4j.LoggerFactory;
 151  
 
 152  
 import com.buckosoft.fibs.BuckoFIBS.AudioManager.Cue;
 153  
 import com.buckosoft.fibs.BuckoFIBS.gui.MainDialog;
 154  
 import com.buckosoft.fibs.BuckoFIBS.gui.MainDialogI;
 155  
 import com.buckosoft.fibs.BuckoFIBS.gui.boardTab.ReplayToolbarI;
 156  
 import com.buckosoft.fibs.domain.Board;
 157  
 import com.buckosoft.fibs.domain.CookieString;
 158  
 import com.buckosoft.fibs.domain.gameEvent.GameEvent;
 159  
 import com.buckosoft.fibs.domain.gameEvent.GameEventAcceptAndWin;
 160  
 import com.buckosoft.fibs.domain.gameEvent.GameEventBoard;
 161  
 import com.buckosoft.fibs.domain.gameEvent.GameEventCantMove;
 162  
 import com.buckosoft.fibs.domain.gameEvent.GameEventDouble;
 163  
 import com.buckosoft.fibs.domain.gameEvent.GameEventFirstMove;
 164  
 import com.buckosoft.fibs.domain.gameEvent.GameEventFirstRoll;
 165  
 import com.buckosoft.fibs.domain.gameEvent.GameEventMove;
 166  
 import com.buckosoft.fibs.domain.gameEvent.GameEventPleaseAcceptOrRejectDouble;
 167  
 import com.buckosoft.fibs.domain.gameEvent.GameEventPleaseAcceptOrRejectResign;
 168  
 import com.buckosoft.fibs.domain.gameEvent.GameEventPleaseMove;
 169  
 import com.buckosoft.fibs.domain.gameEvent.GameEventPleaseRollOrDouble;
 170  
 import com.buckosoft.fibs.domain.gameEvent.GameEventRejectResign;
 171  
 import com.buckosoft.fibs.domain.gameEvent.GameEventResign;
 172  
 import com.buckosoft.fibs.domain.gameEvent.GameEventRoll;
 173  
 import com.buckosoft.fibs.domain.gameEvent.GameEventYouDouble;
 174  
 import com.buckosoft.fibs.domain.gameEvent.GameEvent.Life;
 175  
 import com.buckosoft.fibs.domain.gameEvent.GameEvent.Type;
 176  
 import com.buckosoft.fibs.net.FIBSMessages;
 177  
 
 178  
 /** Track each turn in a game. 
 179  
  * Provides the ability to go back and forth through the game moves list.
 180  
  * We receive game events from CommandDispatcher and send them to AnimationManager.
 181  
  * @author Dick Balaska
 182  
  * @since 2009/01/28
 183  
  * @version $Revision$ <br> $Date$
 184  
  * @see <a href="http://cvs.buckosoft.com/Projects/BuckoFIBS/BuckoFIBS/src/main/java/com/buckosoft/fibs/BuckoFIBS/GameManager.java">cvs GameManager.java</a>
 185  
  */
 186  
 public class GameManager implements FIBSMessages {
 187  
         private        final static boolean DEBUG = true;
 188  
         private        final static boolean DEBUGsend = true;
 189  
         private        final static boolean DEBUGpos = true;
 190  
         private        final static boolean DEBUGJibsBoard = true;
 191  
         
 192  0
         private Logger logger = LoggerFactory.getLogger(getClass());
 193  
 
 194  
         private int                                 position;
 195  
         private        ReplayToolbarI                replayToolbar;
 196  
         private        MainDialogI                        mainDialog;
 197  
         private        BFProperties                bfProps;
 198  
 
 199  
         private final static int Undo                = -2;
 200  
         private final static int Backward        = -1;
 201  
         private final static int Start                =  0;
 202  
         private final static int Forward        =  1;
 203  
 
 204  0
         private LinkedList<GameEvent>        preStartList = new LinkedList<GameEvent>();
 205  
         //        private        boolean                                        resumingMatch = false;
 206  
 
 207  
         /** Construct a GameManager */
 208  0
         public GameManager() {
 209  0
         }
 210  
 
 211  
         /** Set the reference to the ReplayToolbar so that we can turn on and off his buttons
 212  
          * @param replayToolbar The replayToolbar
 213  
          */
 214  
         public void setReplayToolbar(ReplayToolbarI replayToolbar) {
 215  0
                 this.replayToolbar = replayToolbar;
 216  0
         }
 217  
 
 218  
         /** Set the reference to the instance of MainDialog
 219  
          * @param mainDialog The MainDialog that is running
 220  
          */
 221  
         public        void setMainDialog(MainDialog mainDialog) {
 222  0
                 this.mainDialog = mainDialog;
 223  0
         }
 224  
 
 225  
         /** Set the reference to the properties
 226  
          * @param bfProperties
 227  
          */
 228  
         public void setProperties(BFProperties bfProperties) {
 229  0
                 this.bfProps = bfProperties;
 230  0
         }
 231  
 
 232  
         /** Reset a game to have no moves stored.
 233  
          * @param resumeMatch true if we are resuming a match
 234  
          */
 235  
         public void reset(boolean resumeMatch) {
 236  
 //                this.resumingMatch = resumeMatch;
 237  0
                 gameEvents.clear();
 238  0
                 preStartList.clear();
 239  0
                 position = 0;
 240  
                 if (DEBUGpos)
 241  0
                         logger.info("reset: pos = " + this.position);
 242  0
                 updateToolbarButtons();
 243  0
         }
 244  
 
 245  
         /** Fibs says it is our turn
 246  
          */
 247  
         public        void onRollOrDouble() {
 248  0
                 queueGameEvent(new GameEventPleaseRollOrDouble());
 249  0
         }
 250  
 
 251  
         /** Player has taken his turn, moved his checkers and picked up the dice.
 252  
          */
 253  
         public void youMoved() {
 254  0
                 this.mainDialog.playSound(Cue.PickUpDice);
 255  0
                 this.mainDialog.updateBoard();
 256  
                 //this.mainDialog.youCantMove();                // you can't move because your turn is over
 257  
 /*                Iterator<GameEvent> iter = gameEvents.iterator();
 258  
                 while (iter.hasNext()) {
 259  
                         GameEvent ge = iter.next();
 260  
                         if (ge.getType() == Type.PleaseMove) {
 261  
                                 iter.remove();
 262  
                                 break;
 263  
                         }
 264  
                 }
 265  0
 */        }
 266  
 
 267  
         /** Add a FIBS game event message to our game 
 268  
          * @param cs The Cookie and String from {@link ClientReceiveParser}
 269  
          */
 270  
         public void addEvent(CookieString cs) {
 271  
                 if (DEBUG)
 272  0
                         logger.info("addEvent: " + cs.getCookie() + " " + cs.getString());
 273  0
                 switch (cs.getCookie()) {
 274  
                 case FIBS_Board:
 275  0
                         addBoardLine(cs.getString());
 276  0
                         break;
 277  
                 case FIBS_PlayerMoves:
 278  0
                         addMove(cs.getString());
 279  0
                         break;
 280  
                 case FIBS_BearingOff:
 281  0
                         addBearingOff(cs.getString());
 282  0
                         break;
 283  
                 case FIBS_YouRoll:
 284  
                 case FIBS_PlayerRolls:
 285  0
                         addRoll(cs.getString());
 286  0
                         break;
 287  
                 case FIBS_CantMove:
 288  0
                         addCantMove(cs.getString());
 289  0
                         break;
 290  
                 case FIBS_YouCantMove:
 291  0
                         addYouCantMove(cs.getString());
 292  0
                         break;
 293  
                 case FIBS_PleaseMove:
 294  0
                         addPleaseMove(cs.getString());
 295  0
                         break;
 296  
                 case FIBS_YourTurnToMove:
 297  0
                         addYourTurnToMove(cs.getString());
 298  0
                         break;
 299  
                 case FIBS_MakesFirstMove:
 300  0
                         addFirstMove(cs.getString());
 301  0
                         break;
 302  
                 case FIBS_FirstRoll:
 303  0
                         addFirstRoll(cs.getString());
 304  0
                         break;
 305  
                 case FIBS_StartingNewGame:
 306  0
                         addStartNewGame(cs.getString());
 307  0
                         break;
 308  
                 case FIBS_NewMatchAck2:
 309  0
                         addPlayerJoinsYou(cs.getString());
 310  0
                         break;
 311  
                 case FIBS_Turn:
 312  0
                         addResumeYourTurn(cs.getString());
 313  0
                         break;
 314  
                 case FIBS_AcceptRejectDouble:
 315  0
                         addAcceptRejectDouble(cs.getString());
 316  0
                         break;
 317  
                 case FIBS_PlayerWantsToResign:
 318  
                 case FIBS_WatchResign:
 319  
                 case FIBS_YouResign:
 320  0
                         addResign(cs.getString());
 321  0
                         break;
 322  
                 case FIBS_ResignRefused:
 323  0
                         addResignRefused(cs.getString());
 324  0
                         break;
 325  
                 case FIBS_AcceptWins:
 326  0
                         addAcceptsAndWins(cs.getString());
 327  0
                         break;
 328  
                 case FIBS_YouDouble:
 329  0
                         addYouDouble(cs.getString());
 330  0
                         break;
 331  
                 case FIBS_Doubles:
 332  0
                         addOtherDoubles(cs.getString());
 333  0
                         break;
 334  
                 default:
 335  0
                         logger.warn("Unhandled event: (" + cs.getCookie() + ") "+ cs.getString());
 336  
                         break;
 337  
                 }
 338  0
         }
 339  
 
 340  
         /** Starting a new game against Player. "<code>Starting a new game with dickbalaska.</code>"
 341  
          * This resets the GameManager and generates a fake board, just so we have something to work against
 342  
          *  until a real board arrives.
 343  
          * @param s The string to parse. 
 344  
          */
 345  
         private void addStartNewGame(String s) {
 346  0
                 reset(false);
 347  0
                 GameEventBoard gb = new GameEventBoard();
 348  0
                 Board b = gb.getBoard();
 349  0
                 b.setStartPositions();
 350  0
                 b.setPlayerName(Board.O, "You");
 351  0
                 String ss[] = s.split(" ");
 352  0
                 b.setPlayerName(Board.X, ss[5]);
 353  
                 if (DEBUG)
 354  0
                         logger.info("addStartNewGame: opponent=" + ss[5]);
 355  0
                 queueGameEvent(gb);
 356  0
         }
 357  
         /** Handle "<code>** Player dickbalaska has joined you for a 5 point match.</code>"
 358  
          * This is the same as addStartNewGame() except the opponent joined your invite.
 359  
          * @param s The String to parse
 360  
          */
 361  
         private void addPlayerJoinsYou(String s) {
 362  0
                 reset(false);
 363  0
                 GameEventBoard gb = new GameEventBoard();
 364  0
                 Board b = gb.getBoard();
 365  0
                 b.setStartPositions();
 366  0
                 b.setPlayerName(Board.O, "You");
 367  0
                 String ss[] = s.split(" ");
 368  0
                 b.setPlayerName(Board.X, ss[2]);
 369  
                 if (DEBUG)
 370  0
                         logger.info("addPlayerJoinsYou: opponent=" + ss[2]);
 371  0
                 queueGameEvent(gb);
 372  0
         }
 373  
         /** Resume a match, and it's this player's turn upcoming
 374  
          * @param s "<code>turn: Bucko.</code>"
 375  
          */
 376  
         private void addResumeYourTurn(String s) {
 377  0
                 GameEventRoll gr = new GameEventRoll();
 378  0
                 String[] ss = s.split(" ");
 379  0
                 gr.setPlayerName(ss[1].substring(0, ss[1].length()-1));
 380  0
                 this.preStartList.add(gr);                        // let the board fill out the values...
 381  
                 if (DEBUG)
 382  0
                         logger.info("addResumeYourTurn: addPreStart: " + gr.toString());
 383  0
                 if (gr.getPlayerName().equals(this.mainDialog.getDocument().getName())) {
 384  0
                         GameEventPleaseMove gpm = new GameEventPleaseMove();
 385  0
                         gpm.setCheckersToMove(2);
 386  0
                         gpm.setDice(gr.getDice());
 387  0
                         this.preStartList.add(gpm);
 388  
                         if (DEBUG)
 389  0
                                 logger.info("addResumeYourTurn: addPreStart: " + gpm.toString());
 390  
                 }
 391  
 
 392  0
         }
 393  
         /** Add this board line to the game log
 394  
          * @param s The board to add
 395  
          */
 396  
         private void addBoardLine(String s) {
 397  0
                 GameEventBoard gb = new GameEventBoard(s);
 398  0
                 queueGameEvent(gb);
 399  0
                 if (!this.preStartList.isEmpty()) {
 400  0
                         Board b = gb.getBoard();
 401  
                         if (DEBUGJibsBoard)
 402  0
                                 this.mainDialog.writeGameMessageln("board:" + b.getPlayerName()[0] + ":" + b.getPlayerName()[1]);
 403  
 
 404  0
                         b.setSortDice(this.bfProps.isHighDieLeft());
 405  0
                         this.mainDialog.getDocument().setBoard(b);
 406  0
                         for (GameEvent ge : this.preStartList) {
 407  
                                 if (DEBUG)
 408  0
                                         logger.info("Sending preStart: " + ge.toString());
 409  0
                                 if (ge.getType() == Type.Roll) {
 410  0
                                         GameEventRoll gr = (GameEventRoll)ge;
 411  0
                                         if (gr.getDice()[0] == 0) {                // Do we need the dice roll from the board?
 412  0
                                                 if (this.bfProps.isHighDieLeft())
 413  0
                                                 gr.getDice()[0] = b.getDice()[Board.O][0];
 414  0
                                                 gr.getDice()[1] = b.getDice()[Board.O][1];
 415  
                                         }
 416  
                                 }
 417  0
                                 queueGameEvent(ge);
 418  0
                         }
 419  
 //                        this.resumingMatch = false;
 420  0
                         this.preStartList.clear();
 421  
                 }
 422  0
         }
 423  
         private void addMove(String s) {
 424  0
                 GameEventMove gm = new GameEventMove();
 425  0
                 gm.parse(s);
 426  0
                 gm.setWho(this.mainDialog.getDocument().getBoard().getXOFromName(gm.getPlayerName()));
 427  0
                 gm.setDirection(this.mainDialog.getDocument().getBoard().getDirectionFromName(gm.getPlayerName()));
 428  
                 if (DEBUG)
 429  0
                         logger.info("addMove: " + s);
 430  0
                 queueGameEvent(gm);
 431  0
         }
 432  
         /** Bearing off is just a move that comes in funny.
 433  
          * It is only important for You.  Opponents and watchers also get a move, so we'll use that.
 434  
          * @param s 'Bearing off: 6 o 2 o '
 435  
          */
 436  
         private void addBearingOff(String s) {
 437  0
                 GameEventRoll gr = (GameEventRoll)getLastOf(Type.Roll);
 438  0
                 if (!gr.getPlayerName().equals("You"))
 439  0
                         return;
 440  0
                 GameEventMove gm = new GameEventMove();
 441  0
                 gm.parseBearingOff(s);
 442  0
                 gm.setWho(Board.O);
 443  
                 if (DEBUG)
 444  0
                         logger.info("addBearingOff: " + s);
 445  0
                 queueGameEvent(gm);
 446  
                 
 447  0
         }
 448  
         private        void addRoll(String s) {
 449  0
                 GameEventRoll gr = new GameEventRoll();
 450  0
                 gr.parse(s);
 451  0
                 gr.setWho(this.mainDialog.getDocument().getBoard().getXOFromName(gr.getPlayerName()));
 452  
                 if (DEBUG) {
 453  0
                         logger.info("addRoll: " + s + " who:" + gr.getWho());
 454  
                 }
 455  0
                 queueGameEvent(gr);
 456  0
         }
 457  
         private        void addFirstRoll(String s) {
 458  0
                 GameEventFirstRoll gfr = new GameEventFirstRoll();
 459  0
                 gfr.parse(s);
 460  
                 //gfr.setWho(this.mainDialog.getDocument().getBoard().getXOFromName(gfr.getPlayerName()));
 461  
                 if (DEBUG) {
 462  0
                         logger.info("addRoll: " + s + " who:" + gfr.getWho());
 463  
                 }
 464  0
                 queueGameEvent(gfr);
 465  0
         }
 466  
         private void addYouCantMove(String unused) {
 467  0
                 GameEventCantMove gcm = new GameEventCantMove();
 468  0
                 gcm.setWho(Board.O);
 469  
                 if (DEBUG)
 470  0
                         logger.info("addYouCantMove: " + " who:" + gcm.getWho());
 471  0
                 queueGameEvent(gcm);
 472  
                 
 473  0
         }
 474  
         private        void addCantMove(String s) {
 475  0
                 GameEventCantMove gcm = new GameEventCantMove();
 476  0
                 gcm.parse(s);
 477  0
                 gcm.setWho(this.mainDialog.getDocument().getBoard().getXOFromName(gcm.getPlayerName()));
 478  
                 if (DEBUG)
 479  0
                         logger.info("addCantMove: " + s + " who:" + gcm.getWho());
 480  0
                 queueGameEvent(gcm);
 481  0
         }
 482  
         /** Called when the current event is your move.
 483  
          * @param checkersToMove The number of checkers you have to move.
 484  
          */
 485  
         private void addPleaseMove(String s) {
 486  0
                 GameEventPleaseMove gpm = new GameEventPleaseMove();
 487  0
                 gpm.parse(s);
 488  0
                 GameEventRoll gr = (GameEventRoll)getLastOf(Type.Roll);
 489  0
                 gpm.setDice(gr.getDice());
 490  
                 if (DEBUG)
 491  0
                         logger.info("addPleaseMove: toMove=" + gpm.getCheckersToMove());
 492  0
                 queueGameEvent(gpm);
 493  0
         }
 494  
         /** Called if You are taking the first turn of the game. "<code>It's your turn to move.</code>"
 495  
          * @param unused
 496  
          */
 497  
         private void addYourTurnToMove(String s) {
 498  0
                 addFirstMove(s);
 499  0
                 GameEventPleaseMove gpm = new GameEventPleaseMove();
 500  
                 //gpm.parse(s);
 501  0
                 gpm.setCheckersToMove(2);
 502  0
                 GameEventRoll gr = (GameEventRoll)getLastOf(Type.Roll);
 503  0
                 if (gr == null)
 504  0
                         gr = (GameEventRoll)getLastOf(Type.FirstRoll);
 505  0
                 gpm.setDice(gr.getDice());
 506  
                 if (DEBUG)
 507  0
                         logger.info("addYourTurnToMove: toMove=" + gpm.getCheckersToMove());
 508  0
                 queueGameEvent(gpm);
 509  0
         }
 510  
         private void addFirstMove(String s) {
 511  0
                 GameEventFirstMove gefm = new GameEventFirstMove();
 512  0
                 GameEventFirstRoll gefr = (GameEventFirstRoll)getLastOf(Type.FirstRoll);
 513  0
                 GameEventBoard geb = (GameEventBoard)getLastOf(Type.Board);
 514  0
                 gefm.parse(s, gefr, geb.getBoard());
 515  
                 if (DEBUG)
 516  0
                         logger.info("addFirstMove:");
 517  0
                 queueGameEvent(gefm);
 518  
                 
 519  0
         }
 520  
         private void addResign(String s) {
 521  0
                 GameEventResign ger = new GameEventResign();
 522  0
                 GameEventBoard geb = (GameEventBoard)getLastOf(Type.Board);
 523  0
                 Board b = geb.getBoard();
 524  0
                 ger.parse(s, b);
 525  
                 
 526  
                 if (DEBUG)
 527  0
                         logger.info("addResign: s=" + s);
 528  0
                 queueGameEvent(ger);
 529  0
                 GameEventPleaseAcceptOrRejectResign geparr = new GameEventPleaseAcceptOrRejectResign();
 530  0
                 geparr.setWho(ger.getWho());
 531  0
                 geparr.setResigningPoints(ger.getResigningPoints());
 532  0
                 queueGameEvent(geparr);
 533  0
         }
 534  
         private void addResignRefused(String unused) {
 535  0
                 GameEventPleaseAcceptOrRejectResign geparr =
 536  0
                         (GameEventPleaseAcceptOrRejectResign)getLastOf(Type.PleaseAcceptOrRejectResign);
 537  0
                 if (geparr == null)
 538  0
                         return;                        // not enough info to properly work from this (player is most likely starting to watch in mid-game).
 539  0
                 GameEventRejectResign gerr = new GameEventRejectResign();
 540  0
                 gerr.setWho(geparr.getWho() == Board.X ? Board.O : Board.X);
 541  0
                 GameEventPleaseAcceptOrRejectResign gepaorr = (GameEventPleaseAcceptOrRejectResign)getLastOf(Type.PleaseAcceptOrRejectResign);
 542  0
                 gerr.setResigningPoints(gepaorr.getResigningPoints());
 543  0
                 queueGameEvent(gerr);
 544  0
         }
 545  
         private void addAcceptsAndWins(String s) {
 546  0
                 GameEventAcceptAndWin geaaw = new GameEventAcceptAndWin();
 547  0
                 GameEventBoard geb = (GameEventBoard)getLastOf(Type.Board);
 548  0
                 Board b = geb.getBoard();
 549  0
                 geaaw.parse(s, b);
 550  0
                 queueGameEvent(geaaw);
 551  0
         }
 552  
         private void addYouDouble(String s) {
 553  0
                 GameEventYouDouble geyd = new GameEventYouDouble();
 554  0
                 GameEventBoard geb = (GameEventBoard)getLastOf(Type.Board);
 555  0
                 Board b = geb.getBoard();
 556  0
                 b.setWasDoubled(b.getXO());
 557  0
                 geyd.setCubeBefore(b.getCube());
 558  0
                 geyd.setWhoDoubled(b.getXO());
 559  0
                 logger.info("who = " + geb.getBoard().getXOAsText());
 560  0
                 logger.info("geyd.whoDoubled = " + geyd.getWhoDoubled());
 561  0
                 queueGameEvent(geyd);
 562  0
                 GameEventPleaseAcceptOrRejectDouble gepard = new GameEventPleaseAcceptOrRejectDouble();
 563  0
                 gepard.setGuiEvent(false);
 564  0
                 gepard.setWhoDoubled(geyd.getWhoDoubled());
 565  0
                 logger.info("gepard.setWhoDoubled = " + gepard.getWhoDoubled());
 566  0
                 queueGameEvent(gepard);
 567  
 
 568  0
         }
 569  
 
 570  
         private void addOtherDoubles(String s) {
 571  0
                 GameEventDouble ged = new GameEventDouble();
 572  0
                 GameEventBoard geb = (GameEventBoard)getLastOf(Type.Board);
 573  0
                 Board b = geb.getBoard();
 574  0
                 ged.parse(s, b);
 575  0
                 b.setWasDoubled(ged.getWhoDoubled());
 576  
                 if (DEBUG)
 577  0
                         logger.info("addOtherDoubles: s=" + s);
 578  0
                 queueGameEvent(ged);
 579  0
                 GameEventPleaseAcceptOrRejectDouble gepard = new GameEventPleaseAcceptOrRejectDouble();
 580  0
                 gepard.setGuiEvent(false);
 581  0
                 gepard.setWhoDoubled(ged.getWhoDoubled());
 582  0
                 queueGameEvent(gepard);
 583  0
         }
 584  
         private void addAcceptRejectDouble(String s) {
 585  0
                 GameEventDouble ged = new GameEventDouble();
 586  0
                 GameEventBoard geb = (GameEventBoard)getLastOf(Type.Board);
 587  0
                 Board b = geb.getBoard();
 588  0
                 ged.parse(s, b);
 589  0
                 b.setWasDoubled(ged.getWhoDoubled());
 590  
 
 591  
                 if (DEBUG)
 592  0
                         logger.info("addDoubles to You: s=" + s);
 593  0
                 queueGameEvent(ged);
 594  0
                 GameEventPleaseAcceptOrRejectDouble gepard = new GameEventPleaseAcceptOrRejectDouble();
 595  
                 //gepard.setWho(Board.X);
 596  
                 if (DEBUG)
 597  0
                         logger.info("addAcceptRejectDouble: add PleaseAcceptRejectDouble");
 598  0
                 queueGameEvent(gepard);
 599  0
         }
 600  
 
 601  
         ///////////////////////////////////////////////////////////////////////////
 602  
         /** Go to the first event in the game log
 603  
          */
 604  
         public void goFirst() {
 605  0
                 this.position = 1;
 606  
                 if (DEBUGpos)
 607  0
                         logger.info("goFirst: pos = " + this.position);
 608  0
                 sendGameEvent(Start);
 609  0
                 updateToolbarButtons();
 610  0
         }
 611  
 
 612  
         /** Go to the previous event in the game log
 613  
          */
 614  
         public void goPrev() {
 615  0
                 if (this.position > 1)
 616  0
                         this.position--;
 617  
                 if (DEBUGpos)
 618  0
                         logger.info("goPrev: pos = " + this.position);
 619  0
                 sendGameEvent(Backward);
 620  0
                 updateToolbarButtons();
 621  0
         }
 622  
 
 623  
         /** Go to the next event in the game log
 624  
          */
 625  
         public void goNext() {
 626  0
                 if (this.position < this.gameEvents.size())
 627  0
                         this.position++;
 628  
                 if (DEBUGpos)
 629  0
                         logger.info("goNext: pos = " + this.position);
 630  0
                 sendGameEvent(Forward);
 631  0
                 updateToolbarButtons();
 632  0
         }
 633  
 
 634  
         /** Go to the last event in the game log
 635  
          */
 636  
         public void goLast() {
 637  0
                 this.position = this.gameEvents.size();
 638  
                 if (DEBUGpos)
 639  0
                         logger.info("goLast: pos = " + this.position);
 640  0
                 sendGameEvent(Forward);
 641  0
                 updateToolbarButtons();
 642  0
         }
 643  
 
 644  
         /** Undo a partial move, start your turn over.
 645  
          */
 646  
         public void goUndo() {
 647  0
                 sendGameEvent(Undo);
 648  0
         }
 649  
 
 650  
         /** Play or Paused pressed */
 651  
         public void goPlayPaused() {
 652  
                 
 653  0
         }
 654  
 
 655  
         ///////////////////////////////////////////////////////////////////////////
 656  
         ///////////////////////////////////////////////////////////////////////////
 657  
         /** Send the current Event to the display.
 658  
          * If animation is off, then skip animation events by moving to prev/next.
 659  
          * Synchronized because the timer thread can enter here
 660  
          * @param dir The direction to skip to, if need be. {@link #Forward} or {@link #Backward}
 661  
          */
 662  
         private        synchronized void sendGameEvent(int dir) {
 663  
                 //int localpos = this.position;
 664  
                 if (DEBUGsend || DEBUGpos)
 665  0
                         logger.info("sendGameEvent: position=" + this.position + " size=" + this.gameEvents.size());
 666  0
                 if (dir == Undo) {
 667  
                         // We assume it is a legit undo.
 668  
                         // We are going to look for board-rolls-board and rewind to that first board.
 669  0
                         boolean lastBoardWasSeen = false;
 670  0
                         GameEvent ge = null;
 671  
                         int        k;
 672  0
                         for (k = this.gameEvents.size()-1; k >= 0; k--) {
 673  0
                                 ge = this.gameEvents.get(k);
 674  0
                                 if (ge.getType() == Type.Board) {
 675  0
                                         if (lastBoardWasSeen) {
 676  0
                                                 break;
 677  
                                         }
 678  0
                                         lastBoardWasSeen = true;
 679  
                                 }
 680  0
                                 ge = null;
 681  
                         }
 682  0
                         if (ge != null) {
 683  0
                                 for (position = k; position < this.gameEvents.size(); position++) {
 684  0
                                         ge = this.gameEvents.get(position);
 685  0
                                         this.mainDialog.moveEvent(ge);
 686  
                                 }
 687  
                         }
 688  
                 }
 689  0
                 if (dir == Forward && this.replayToolbar.isPlayPause()) {
 690  
                         
 691  
                 }
 692  
                 while (true) {
 693  0
                         GameEvent ge = this.gameEvents.get(this.position-1);
 694  
                         if (DEBUGsend)
 695  0
                                 logger.debug("send: loop top: pos=" + this.position + " ge=" + ge.getType().toString());
 696  0
                         if (ge.getType() == Type.Board) {
 697  
 //                                GameBoard gb = (GameBoard)ge;
 698  
 //                                Board board = this.mainDialog.getDocument().getBoard();
 699  
 //                                if (board.isYouPlaying() && board.isYourMove() && position == gameEvents.size())
 700  
 //                                        this.mainDialog.yourMove(gb.getCheckersToMove());
 701  
                                 if (DEBUGsend) {
 702  0
                                         logger.debug("sendToAnimate a: pos=" + position + " size=" + this.gameEvents.size());
 703  0
                                         logger.debug("sendToAnimtate a:  " + ge.getType().toString());
 704  
                                 }
 705  0
                                 this.mainDialog.moveEvent(ge);
 706  0
                                 if ((bfProps.isAnimateMoves() && this.position == gameEvents.size())
 707  
                                                 || dir == Start) {
 708  0
                                         return;
 709  
                                 }
 710  0
                                 if (this.position >= gameEvents.size()) {        // unless it is the last one in the list
 711  
                                         if (DEBUGsend || DEBUGpos)
 712  0
                                                 logger.info("send: End of list: Don't bump pos " + this.position + " after sending board");
 713  0
                                         updateToolbarButtons();
 714  0
                                         return;
 715  
                                 }
 716  0
                                 this.position += dir;
 717  
                                 if (DEBUGsend || DEBUGpos)
 718  0
                                         logger.info("send: Set pos to " + this.position + " after sending board");
 719  0
                                 updateToolbarButtons();
 720  
                         } else {
 721  0
                                 if (bfProps.isAnimateMoves()) {
 722  
                                         if (DEBUGsend) {
 723  0
                                                 logger.info("sendToAnimate b: pos=" + position + " size=" + this.gameEvents.size());
 724  0
                                                 logger.info("sendToAnimate b:  " + ge.getType().toString());
 725  
                                         }
 726  0
                                         this.mainDialog.moveEvent(ge);
 727  0
                                         updateToolbarButtons();
 728  0
                                         return;                                
 729  
                                 }
 730  0
                                 if (dir == Forward) {                                // going forward?
 731  0
                                         if (this.position < gameEvents.size()) {
 732  0
                                                 this.position++;                                                                // try to skip ahead
 733  
                                         }
 734  
                                         if (DEBUGsend || DEBUGpos)
 735  0
                                                 logger.info("send: skip position to " + this.position + " gameEvents.size=" + gameEvents.size());
 736  0
                                         if (this.position >= gameEvents.size()) {        // unless it is the last one in the list
 737  
                                                 if (DEBUGsend || DEBUGpos) {
 738  0
                                                         logger.info("sendToAnimate c: pos=" + position + " size=" + this.gameEvents.size());
 739  0
                                                         logger.info("sendToAnimate c:  " + ge.getType().toString());
 740  
                                                 }
 741  0
                                                 this.mainDialog.moveEvent(ge);
 742  
                                                 //this.position = localpos;
 743  
                                                 if (DEBUGsend || DEBUGpos)
 744  0
                                                         logger.info("send: pos = " + this.position + " and send nothing");
 745  0
                                                 updateToolbarButtons();
 746  0
                                                 return;
 747  
                                         }
 748  
                                         if (DEBUGsend)
 749  0
                                                 logger.info("send: Skipping this event");
 750  0
                                         continue;
 751  
                                 }
 752  0
                                 this.position--;
 753  0
                                 if (this.position < 1) {
 754  0
                                         this.position = 1;
 755  
                                         if (DEBUGsend) {
 756  0
                                                 logger.info("sendToAnimate d: pos=" + position + " size=" + this.gameEvents.size());
 757  0
                                                 logger.info("sendToAnimate d:  " + ge.getType().toString());
 758  
                                         }
 759  0
                                         this.mainDialog.moveEvent(ge);
 760  0
                                         updateToolbarButtons();
 761  0
                                         return;
 762  
                                 }
 763  
                         }
 764  0
                 }
 765  
         }
 766  
 
 767  0
         private LinkedList<GameEvent>        gameEvents = new LinkedList<GameEvent>();
 768  
 
 769  
         /** All write access to the gameEvents list is via this function.
 770  
          * @param gameEvent The event to queue at the end.
 771  
          */
 772  
         private        void queueGameEvent(GameEvent gameEvent) {
 773  
                 if (DEBUG)
 774  0
                         logger.debug("queueGameEvent: a position=" + this.position + " size=" + this.gameEvents.size());
 775  0
                 if (!gameEvents.isEmpty()) {
 776  0
                         GameEvent old = gameEvents.getLast();
 777  0
                         if (old.getLife() == Life.Transient) {
 778  0
                                 if (this.position == gameEvents.size())
 779  0
                                         this.position--;
 780  0
                                 gameEvents.removeLast();
 781  
                                 if (DEBUG) {
 782  0
                                         logger.debug("queueGameEvent: b position=" + this.position + " size=" + this.gameEvents.size());
 783  0
                                         logger.debug("queueGameEvent: b remove old=" +  old.getType().toString());
 784  
                                 }
 785  
 //                                if (gameEvent.getType() == Type.Board) {
 786  
 //                                        GameEventBoard gb = (GameEventBoard)gameEvent;
 787  
 //                                        gb.setPostEvent(old);
 788  
 //                                        if (DEBUG)
 789  
 //                                                logger.info("queueGameEvent: set post=" + old.getType().toString());
 790  
 //                                }
 791  
                         }
 792  
                 }
 793  0
                 gameEvents.add(gameEvent);
 794  
                 if (DEBUG)
 795  0
                         logger.debug("queueGameEvent: queued: " + gameEvent.toString());
 796  
                 if (DEBUG)
 797  0
                         logger.debug("queueGameEvent: c position=" + this.position + " size=" + this.gameEvents.size());
 798  0
                 boolean shouldMove = this.replayToolbar.isPlayPause();
 799  0
                 if (shouldMove) {
 800  0
                         this.position++;
 801  0
                         sendGameEvent(Forward);
 802  
                 } else {
 803  0
                         updateToolbarButtons();
 804  
                 }
 805  0
         }
 806  
 
 807  
         private        GameEvent        getLastOf(Type eventType) {
 808  0
                 GameEvent ret = null;
 809  0
                 for (GameEvent ge : gameEvents) {
 810  0
                         if (ge.getType() == eventType)
 811  0
                                 ret = ge;
 812  0
                 }
 813  0
                 return(ret);
 814  
         }
 815  
 
 816  
         private        void updateToolbarButtons() {
 817  0
                 this.replayToolbar.getJButtonFirst().setEnabled(position > 1);
 818  0
                 this.replayToolbar.getJButtonBack().setEnabled( position > 1);
 819  0
                 this.replayToolbar.getJButtonNext().setEnabled( position < gameEvents.size());
 820  0
                 this.replayToolbar.getJButtonEnd().setEnabled(  position < gameEvents.size());
 821  0
         }
 822  
         
 823  
         // Timer goes here
 824  
 }