1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/chess/src/main/java/org/apidesign/html/demo/chess/UIModel.java Tue Sep 24 22:37:17 2013 +0200
1.3 @@ -0,0 +1,315 @@
1.4 +/**
1.5 + * The MIT License (MIT)
1.6 + *
1.7 + * Copyright (C) 2013 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
1.8 + *
1.9 + * Permission is hereby granted, free of charge, to any person obtaining a copy
1.10 + * of this software and associated documentation files (the "Software"), to deal
1.11 + * in the Software without restriction, including without limitation the rights
1.12 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1.13 + * copies of the Software, and to permit persons to whom the Software is
1.14 + * furnished to do so, subject to the following conditions:
1.15 + *
1.16 + * The above copyright notice and this permission notice shall be included in
1.17 + * all copies or substantial portions of the Software.
1.18 + *
1.19 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1.20 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1.21 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1.22 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1.23 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1.24 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1.25 + * THE SOFTWARE.
1.26 + */
1.27 +package org.apidesign.html.demo.chess;
1.28 +
1.29 +import java.io.IOException;
1.30 +import java.net.URISyntaxException;
1.31 +import java.util.HashSet;
1.32 +import java.util.List;
1.33 +import java.util.Set;
1.34 +import java.util.logging.Level;
1.35 +import java.util.logging.Logger;
1.36 +import net.java.html.json.ComputedProperty;
1.37 +import net.java.html.json.Function;
1.38 +import net.java.html.json.Model;
1.39 +import net.java.html.json.ModelOperation;
1.40 +import net.java.html.json.OnPropertyChange;
1.41 +import net.java.html.json.OnReceive;
1.42 +import net.java.html.json.Property;
1.43 +
1.44 +/**
1.45 + *
1.46 + * @author Jaroslav Tulach <jtulach@netbeans.org>
1.47 + */
1.48 +@Model(className = "UI", properties = {
1.49 + @Property(name = "status", type = String.class),
1.50 + @Property(name = "selectedGameId", type = String.class),
1.51 + @Property(name = "boards", type = Board.class, array = true),
1.52 + @Property(name = "viewGames", type = Games.class),
1.53 + @Property(name = "settings", type = Settings.class),
1.54 + @Property(name = "connected", type = boolean.class),
1.55 + @Property(name = "disconnected", type = boolean.class),
1.56 +})
1.57 +public class UIModel {
1.58 + private static final Logger LOG = Logger.getLogger(UIModel.class.getName());
1.59 +
1.60 + @ComputedProperty static boolean settingsActive(String selectedGameId) {
1.61 + return selectedGameId == null;
1.62 + }
1.63 +
1.64 + @ComputedProperty static boolean viewGamesActive(String selectedGameId, boolean connected) {
1.65 + return selectedGameId == null && connected;
1.66 + }
1.67 +
1.68 + @ComputedProperty static Board selectedBoard(String selectedGameId, List<Board> boards) {
1.69 + Board active = null;
1.70 + for (Board b : boards) {
1.71 + b.setActive(false);
1.72 + if (selectedGameId != null && selectedGameId.equals(b.getGameId())) {
1.73 + b.setActive(true);
1.74 + active = b;
1.75 + }
1.76 + }
1.77 + return active;
1.78 + }
1.79 +
1.80 + @Function static void activateGame(UI m, Board data) {
1.81 + m.setSelectedGameId(data.getGameId());
1.82 + }
1.83 +
1.84 + @Function static void activateSettings(UI m) {
1.85 + m.setSelectedGameId(null);
1.86 + refreshGames(m);
1.87 + }
1.88 +
1.89 + @Function static void createGame(UI u) {
1.90 + u.setStatus("Creating new game...");
1.91 + Request r = new Request();
1.92 + r.setMsg(MsgType.CreateGame);
1.93 + r.setColor(Color.valueOf(u.getViewGames().getSelectedColor()));
1.94 + u.sendMsg(r);
1.95 + }
1.96 +
1.97 + @ModelOperation @Function static void refreshGames(UI u) {
1.98 + u.setStatus("Refreshing games...");
1.99 + Request r = new Request();
1.100 + r.setMsg(MsgType.QueryGames);
1.101 + u.sendMsg(r);
1.102 + }
1.103 +
1.104 + @ModelOperation static void sendMsg(UI ui, Request r) {
1.105 + final Settings sttngs = ui.getSettings();
1.106 +
1.107 + String url = sttngs.getUrl();
1.108 + r.setUsername(sttngs.getUsername());
1.109 + r.setPassword(sttngs.getPassword());
1.110 +
1.111 + LOG.log(Level.INFO, "Sending {0} to {1}", new Object[]{r, url});
1.112 + ui.queryServer(url, r);
1.113 + }
1.114 +
1.115 +
1.116 + @OnReceive(data = Request.class, url = "{url}", method = "WebSocket", onError = "wasAnError")
1.117 + static void queryServer(UI ui, Response r) {
1.118 + LOG.log(Level.INFO, "Received {0}", r);
1.119 + if (r == null) {
1.120 + ui.setDisconnected(false);
1.121 + verifyLogin(ui);
1.122 + return;
1.123 + }
1.124 + SWITCH: switch (MsgType.forResponse(r.getMsg())) {
1.125 + case CheckCredentials: {
1.126 + switch (r.getCheck()) {
1.127 + case NOT_REGISTERED:
1.128 + case VALID:
1.129 + ui.setConnected(true);
1.130 + ui.refreshGames();
1.131 + ui.setStatus("Connected.");
1.132 + return;
1.133 + case INVALID:
1.134 + ui.setStatus("Password is invalid");
1.135 + break;
1.136 + }
1.137 + disconnect(ui);
1.138 + }
1.139 +
1.140 + case QueryGames:
1.141 + ui.getViewGames().listGames(r.getGames(), ui.getSettings().getUsername());
1.142 + ui.setStatus("");
1.143 + break;
1.144 + case CreateGame: {
1.145 + ui.setStatus("Game " + r + " created");
1.146 + final Board b = Rules.createBoard();
1.147 + Rules.initBoard(
1.148 + b, r.getBoard().getWhites(),
1.149 + r.getBoard().getBlacks(),
1.150 + r.getTurn()
1.151 + );
1.152 + b.setGameId(r.getGameId());
1.153 + b.setWhitePlayer(r.getWhitePlayer());
1.154 + b.setBlackPlayer(r.getBlackPlayer());
1.155 + b.setPlayer(ui.getSettings().getUsername());
1.156 + b.updateSummary(r.getSummary());
1.157 + ui.getBoards().add(b);
1.158 + ui.setSelectedGameId(r.getGameId());
1.159 + UIModel.refreshGames(ui);
1.160 + break;
1.161 + }
1.162 + case SendMove: {
1.163 + if (r.getBoard() == null) {
1.164 + throw new NullPointerException("No board in " + r);
1.165 + }
1.166 + final Board b = findBoard(ui, r.getGameId());
1.167 + if (b == null) {
1.168 + break;
1.169 + }
1.170 + b.updateSummary(r.getSummary());
1.171 + final String errMsg = r.getError() == null ? null : r.getError().getMessage();
1.172 + final List<String> whites = r.getBoard().getWhites();
1.173 + final List<String> blacks = r.getBoard().getBlacks();
1.174 + final Color turn = r.getNextTurn();
1.175 + BoardModel.moveResponse(b, errMsg, whites, blacks, turn, r.getAlert());
1.176 + break;
1.177 + }
1.178 + case JoinGame: {
1.179 + Board b;
1.180 + if ((b = findBoard(ui, r.getGameId())) != null) {
1.181 + b.setWhitePlayer(r.getWhitePlayer());
1.182 + b.setBlackPlayer(r.getBlackPlayer());
1.183 + b.setPlayer(ui.getSettings().getUsername());
1.184 + b.updateSummary(r.getSummary());
1.185 + ui.setSelectedGameId(r.getGameId());
1.186 + break SWITCH;
1.187 + }
1.188 + ui.setStatus("Joining " + r.getGameId() + " as " + r.getColor());
1.189 + b = Rules.createBoard();
1.190 + Rules.initBoard(
1.191 + b, r.getBoard().getWhites(),
1.192 + r.getBoard().getBlacks(),
1.193 + r.getTurn()
1.194 + );
1.195 + b.setGameId(r.getGameId());
1.196 + b.setWhitePlayer(r.getWhitePlayer());
1.197 + b.setBlackPlayer(r.getBlackPlayer());
1.198 + b.setPlayer(ui.getSettings().getUsername());
1.199 + b.updateSummary(r.getSummary());
1.200 + if (r.getColor() == Color.B) {
1.201 + BoardModel.rotateBoard(b);
1.202 + }
1.203 + if (r.getMoves() != null) {
1.204 + for (String move : r.getMoves()) {
1.205 + Move m = BoardModel.MoveImpl.valueOf(move);
1.206 + b.getMoves().add(m);
1.207 + }
1.208 + } else {
1.209 + b.getMoves().clear();
1.210 + }
1.211 + ui.setSelectedGameId(b.getGameId());
1.212 + ui.getBoards().add(b);
1.213 + break;
1.214 + }
1.215 + case UpdateGame: {
1.216 + final Board b = findBoard(ui, r.getGameId());
1.217 + if (b == null) {
1.218 + break;
1.219 + }
1.220 + b.updateSummary(r.getSummary());
1.221 + final Move move = BoardModel.MoveImpl.valueOf(r.getFrom() + r.getTo());
1.222 + final List<String> whites = r.getBoard().getWhites();
1.223 + final List<String> blacks = r.getBoard().getBlacks();
1.224 + final Color turn = r.getNextTurn();
1.225 + BoardModel.moveUpdate(b, move, whites, blacks, turn, null);
1.226 + }
1.227 + }
1.228 + }
1.229 +
1.230 +
1.231 + private static Board findBoard(UI ui, String gameId) {
1.232 + for (Board tmp : ui.getBoards()) {
1.233 + if (tmp.getGameId().equals(gameId)) {
1.234 + return tmp;
1.235 + }
1.236 + }
1.237 + return null;
1.238 + }
1.239 +
1.240 +
1.241 + static void wasAnError(UI ui, Exception t) {
1.242 + if (t == null) {
1.243 + ui.setConnected(false);
1.244 + ui.setDisconnected(true);
1.245 + ui.setStatus("Disconnected.");
1.246 + } else {
1.247 + ui.setStatus("Error: " + t.getLocalizedMessage());
1.248 + }
1.249 + }
1.250 +
1.251 + @Function static void joinGame(UI u, Game data) {
1.252 + Request r = new Request();
1.253 + r.setMsg(MsgType.JoinGame);
1.254 + r.setObserver(false);
1.255 + r.setGameId(data.getGameId());
1.256 + u.sendMsg(r);
1.257 + }
1.258 +
1.259 + @Function static void observeGame(UI u, Game data) {
1.260 + Request r = new Request();
1.261 + r.setMsg(MsgType.JoinGame);
1.262 + r.setObserver(true);
1.263 + r.setGameId(data.getGameId());
1.264 + u.sendMsg(r);
1.265 + }
1.266 +
1.267 + private static final Set<UI> ACTIVE = new HashSet<>();
1.268 + @OnPropertyChange("connected") static void clearGames(UI m) {
1.269 + if (m.isDisconnected()) {
1.270 + m.getBoards().clear();
1.271 + ACTIVE.remove(m);
1.272 + } else {
1.273 + ACTIVE.add(m);
1.274 + }
1.275 + }
1.276 +
1.277 + static UI findUI(Board b) {
1.278 + for (UI ui : ACTIVE) {
1.279 + if (ui.getBoards().contains(b)) {
1.280 + return ui;
1.281 + }
1.282 + }
1.283 + return null;
1.284 + }
1.285 +
1.286 + @Function static void leave(UI ui, Board data) {
1.287 + ui.getBoards().remove(data);
1.288 + ui.setSelectedGameId(null);
1.289 + }
1.290 +
1.291 + @Function static void disconnect(UI ui) {
1.292 + ui.queryServer(ui.getSettings().getUrl(), null);
1.293 + ui.setStatus("Disconnecting...");
1.294 + }
1.295 +
1.296 + private static void verifyLogin(UI ui) {
1.297 + ui.setStatus("Verifying user credentials...");
1.298 + Request r = new Request();
1.299 + r.setMsg(MsgType.CheckCredentials);
1.300 + ui.sendMsg(r);
1.301 + }
1.302 +
1.303 + @Function static void reconnect(UI ui) {
1.304 + final Settings s = ui.getSettings();
1.305 + ui.setStatus("Connecting to the server...");
1.306 + ui.queryServer(s.getUrl(), null);
1.307 + s.write(ui);
1.308 + }
1.309 +
1.310 + public static void initialize(String... args) throws URISyntaxException, IOException {
1.311 + UI ui = new UI();
1.312 + ui.getSettings().read();
1.313 + ui.setStatus("Ready.");
1.314 + ui.setDisconnected(true);
1.315 + ui.applyBindings();
1.316 + }
1.317 +
1.318 +}