chess/src/main/java/com/oracle/chess/client/htmljava/UIModel.java
branchchess
changeset 49 945fbfff28f3
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/chess/src/main/java/com/oracle/chess/client/htmljava/UIModel.java	Tue Sep 24 22:20:24 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 com.oracle.chess.client.htmljava;
    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 +}