chess/src/main/java/com/oracle/chess/client/htmljava/UIModel.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 24 Sep 2013 22:20:24 +0200
branchchess
changeset 49 945fbfff28f3
permissions -rw-r--r--
Advanced version of the chess game
     1 /**
     2  * The MIT License (MIT)
     3  *
     4  * Copyright (C) 2013 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     5  *
     6  * Permission is hereby granted, free of charge, to any person obtaining a copy
     7  * of this software and associated documentation files (the "Software"), to deal
     8  * in the Software without restriction, including without limitation the rights
     9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    10  * copies of the Software, and to permit persons to whom the Software is
    11  * furnished to do so, subject to the following conditions:
    12  *
    13  * The above copyright notice and this permission notice shall be included in
    14  * all copies or substantial portions of the Software.
    15  *
    16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    22  * THE SOFTWARE.
    23  */
    24 package com.oracle.chess.client.htmljava;
    25 
    26 import java.io.IOException;
    27 import java.net.URISyntaxException;
    28 import java.util.HashSet;
    29 import java.util.List;
    30 import java.util.Set;
    31 import java.util.logging.Level;
    32 import java.util.logging.Logger;
    33 import net.java.html.json.ComputedProperty;
    34 import net.java.html.json.Function;
    35 import net.java.html.json.Model;
    36 import net.java.html.json.ModelOperation;
    37 import net.java.html.json.OnPropertyChange;
    38 import net.java.html.json.OnReceive;
    39 import net.java.html.json.Property;
    40 
    41 /**
    42  *
    43  * @author Jaroslav Tulach <jtulach@netbeans.org>
    44  */
    45 @Model(className = "UI", properties = {
    46     @Property(name = "status", type = String.class),
    47     @Property(name = "selectedGameId", type = String.class),
    48     @Property(name = "boards", type = Board.class, array = true),
    49     @Property(name = "viewGames", type = Games.class),
    50     @Property(name = "settings", type = Settings.class),
    51     @Property(name = "connected", type = boolean.class),
    52     @Property(name = "disconnected", type = boolean.class),
    53 })
    54 public class UIModel {
    55     private static final Logger LOG = Logger.getLogger(UIModel.class.getName());
    56     
    57     @ComputedProperty static boolean settingsActive(String selectedGameId) {
    58         return selectedGameId == null;
    59     }
    60     
    61     @ComputedProperty static boolean viewGamesActive(String selectedGameId, boolean connected) {
    62         return selectedGameId == null && connected;
    63     }
    64     
    65     @ComputedProperty static Board selectedBoard(String selectedGameId, List<Board> boards) {
    66         Board active = null;
    67         for (Board b : boards) {
    68             b.setActive(false);
    69             if (selectedGameId != null && selectedGameId.equals(b.getGameId())) {
    70                 b.setActive(true);
    71                 active = b;
    72             }
    73         }
    74         return active;
    75     }
    76     
    77     @Function static void activateGame(UI m, Board data) {
    78         m.setSelectedGameId(data.getGameId());
    79     }
    80 
    81     @Function static void activateSettings(UI m) {
    82         m.setSelectedGameId(null);
    83         refreshGames(m);
    84     }
    85     
    86     @Function static void createGame(UI u) {
    87         u.setStatus("Creating new game...");
    88         Request r = new Request();
    89         r.setMsg(MsgType.CreateGame);
    90         r.setColor(Color.valueOf(u.getViewGames().getSelectedColor()));
    91         u.sendMsg(r);
    92     }
    93 
    94     @ModelOperation @Function static void refreshGames(UI u) {
    95         u.setStatus("Refreshing games...");
    96         Request r = new Request();
    97         r.setMsg(MsgType.QueryGames);
    98         u.sendMsg(r);
    99     }
   100     
   101     @ModelOperation static void sendMsg(UI ui, Request r) {
   102         final Settings sttngs = ui.getSettings();
   103         
   104         String url = sttngs.getUrl();
   105         r.setUsername(sttngs.getUsername());
   106         r.setPassword(sttngs.getPassword());
   107         
   108         LOG.log(Level.INFO, "Sending {0} to {1}", new Object[]{r, url});
   109         ui.queryServer(url, r);
   110     }
   111     
   112     
   113     @OnReceive(data = Request.class, url = "{url}", method = "WebSocket", onError = "wasAnError") 
   114     static void queryServer(UI ui, Response r) {
   115         LOG.log(Level.INFO, "Received {0}", r);
   116         if (r == null) {
   117             ui.setDisconnected(false);
   118             verifyLogin(ui);
   119             return;
   120         }
   121         SWITCH: switch (MsgType.forResponse(r.getMsg())) {
   122             case CheckCredentials: {
   123                 switch (r.getCheck()) {
   124                     case NOT_REGISTERED:
   125                     case VALID:
   126                         ui.setConnected(true);
   127                         ui.refreshGames();
   128                         ui.setStatus("Connected.");
   129                         return;
   130                     case INVALID:
   131                         ui.setStatus("Password is invalid");
   132                         break;
   133                 }
   134                 disconnect(ui);
   135             }
   136                 
   137             case QueryGames:
   138                 ui.getViewGames().listGames(r.getGames(), ui.getSettings().getUsername());
   139                 ui.setStatus("");
   140                 break;
   141             case CreateGame: {
   142                 ui.setStatus("Game " + r + " created");
   143                 final Board b = Rules.createBoard();
   144                 Rules.initBoard(
   145                     b, r.getBoard().getWhites(),
   146                     r.getBoard().getBlacks(),
   147                     r.getTurn()
   148                 );
   149                 b.setGameId(r.getGameId());
   150                 b.setWhitePlayer(r.getWhitePlayer());
   151                 b.setBlackPlayer(r.getBlackPlayer());
   152                 b.setPlayer(ui.getSettings().getUsername());
   153                 b.updateSummary(r.getSummary());
   154                 ui.getBoards().add(b);
   155                 ui.setSelectedGameId(r.getGameId());
   156                 UIModel.refreshGames(ui);
   157                 break;
   158             }
   159             case SendMove: {
   160                 if (r.getBoard() == null) {
   161                     throw new NullPointerException("No board in " + r);
   162                 }
   163                 final Board b = findBoard(ui, r.getGameId());
   164                 if (b == null) {
   165                     break;
   166                 }
   167                 b.updateSummary(r.getSummary());
   168                 final String errMsg = r.getError() == null ? null : r.getError().getMessage();
   169                 final List<String> whites = r.getBoard().getWhites();
   170                 final List<String> blacks = r.getBoard().getBlacks();
   171                 final Color turn = r.getNextTurn();
   172                 BoardModel.moveResponse(b, errMsg, whites, blacks, turn, r.getAlert());
   173                 break;
   174             }
   175             case JoinGame: {
   176                 Board b;
   177                 if ((b = findBoard(ui, r.getGameId())) != null) {
   178                     b.setWhitePlayer(r.getWhitePlayer());
   179                     b.setBlackPlayer(r.getBlackPlayer());
   180                     b.setPlayer(ui.getSettings().getUsername());
   181                     b.updateSummary(r.getSummary());
   182                     ui.setSelectedGameId(r.getGameId());
   183                     break SWITCH;
   184                 }
   185                 ui.setStatus("Joining " + r.getGameId() + " as " + r.getColor());
   186                 b = Rules.createBoard();
   187                 Rules.initBoard(
   188                     b, r.getBoard().getWhites(),
   189                     r.getBoard().getBlacks(),
   190                     r.getTurn()
   191                 );
   192                 b.setGameId(r.getGameId());
   193                 b.setWhitePlayer(r.getWhitePlayer());
   194                 b.setBlackPlayer(r.getBlackPlayer());
   195                 b.setPlayer(ui.getSettings().getUsername());
   196                 b.updateSummary(r.getSummary());
   197                 if (r.getColor() == Color.B) {
   198                     BoardModel.rotateBoard(b);
   199                 }
   200                 if (r.getMoves() != null) {
   201                     for (String move : r.getMoves()) {
   202                         Move m = BoardModel.MoveImpl.valueOf(move);
   203                         b.getMoves().add(m);
   204                     }
   205                 } else {
   206                     b.getMoves().clear();
   207                 }
   208                 ui.setSelectedGameId(b.getGameId());
   209                 ui.getBoards().add(b);
   210                 break;
   211             }
   212             case UpdateGame: {
   213                 final Board b = findBoard(ui, r.getGameId());
   214                 if (b == null) {
   215                     break;
   216                 }
   217                 b.updateSummary(r.getSummary());
   218                 final Move move = BoardModel.MoveImpl.valueOf(r.getFrom() + r.getTo());
   219                 final List<String> whites = r.getBoard().getWhites();
   220                 final List<String> blacks = r.getBoard().getBlacks();
   221                 final Color turn = r.getNextTurn();
   222                 BoardModel.moveUpdate(b, move, whites, blacks, turn, null);
   223             }
   224         }
   225     }
   226 
   227 
   228     private static Board findBoard(UI ui, String gameId) {
   229         for (Board tmp : ui.getBoards()) {
   230             if (tmp.getGameId().equals(gameId)) {
   231                 return tmp;
   232             }
   233         }
   234         return null;
   235     }
   236     
   237     
   238     static void wasAnError(UI ui, Exception t) {
   239         if (t == null) {
   240             ui.setConnected(false);
   241             ui.setDisconnected(true);
   242             ui.setStatus("Disconnected.");
   243         } else {
   244             ui.setStatus("Error: " + t.getLocalizedMessage());
   245         }
   246     }
   247     
   248     @Function static void joinGame(UI u, Game data) {
   249         Request r = new Request();
   250         r.setMsg(MsgType.JoinGame);
   251         r.setObserver(false);
   252         r.setGameId(data.getGameId());
   253         u.sendMsg(r);
   254     }
   255 
   256     @Function static void observeGame(UI u, Game data) {
   257         Request r = new Request();
   258         r.setMsg(MsgType.JoinGame);
   259         r.setObserver(true);
   260         r.setGameId(data.getGameId());
   261         u.sendMsg(r);
   262     }
   263 
   264     private static final Set<UI> ACTIVE = new HashSet<>();
   265     @OnPropertyChange("connected") static void clearGames(UI m) {
   266         if (m.isDisconnected()) {
   267             m.getBoards().clear();
   268             ACTIVE.remove(m);
   269         } else {
   270             ACTIVE.add(m);
   271         }
   272     }
   273     
   274     static UI findUI(Board b) {
   275         for (UI ui : ACTIVE) {
   276             if (ui.getBoards().contains(b)) {
   277                 return ui;
   278             }
   279         }
   280         return null;
   281     }
   282     
   283     @Function static void leave(UI ui, Board data) {
   284         ui.getBoards().remove(data);
   285         ui.setSelectedGameId(null);
   286     }
   287     
   288     @Function static void disconnect(UI ui) {
   289         ui.queryServer(ui.getSettings().getUrl(), null);
   290         ui.setStatus("Disconnecting...");
   291     }
   292 
   293     private static void verifyLogin(UI ui) {
   294         ui.setStatus("Verifying user credentials...");
   295         Request r = new Request();
   296         r.setMsg(MsgType.CheckCredentials);
   297         ui.sendMsg(r);
   298     }
   299     
   300     @Function static void reconnect(UI ui) {
   301         final Settings s = ui.getSettings();
   302         ui.setStatus("Connecting to the server...");
   303         ui.queryServer(s.getUrl(), null);
   304         s.write(ui);
   305     }
   306     
   307     public static void initialize(String... args) throws URISyntaxException, IOException {
   308         UI ui = new UI();
   309         ui.getSettings().read();
   310         ui.setStatus("Ready.");
   311         ui.setDisconnected(true);
   312         ui.applyBindings();
   313     }
   314 
   315 }