webidor/src/main/java/cz/xelfi/quoridor/webidor/resources/Games.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 26 Sep 2009 21:47:02 +0200
changeset 114 ed560bfe37f0
parent 106 7d090f2c5b91
child 115 6a80463a74c0
permissions -rw-r--r--
Line can contain only black move
jtulach@36
     1
/*
jtulach@36
     2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
jtulach@36
     3
 *
jtulach@36
     4
 * The contents of this file are subject to the terms of either the GNU
jtulach@36
     5
 * General Public License Version 2 only ("GPL") or the Common
jtulach@36
     6
 * Development and Distribution License("CDDL") (collectively, the
jtulach@36
     7
 * "License"). You may not use this file except in compliance with the
jtulach@36
     8
 * License. You can obtain a copy of the License at
jtulach@36
     9
 * http://www.netbeans.org/cddl-gplv2.html
jtulach@36
    10
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
jtulach@36
    11
 * specific language governing permissions and limitations under the
jtulach@36
    12
 * License.  When distributing the software, include this License Header
jtulach@36
    13
 * Notice in each file and include the License file at
jtulach@36
    14
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
jtulach@36
    15
 * particular file as subject to the "Classpath" exception as provided
jtulach@36
    16
 * by Sun in the GPL Version 2 section of the License file that
jtulach@36
    17
 * accompanied this code. If applicable, add the following below the
jtulach@36
    18
 * License Header, with the fields enclosed by brackets [] replaced by
jtulach@36
    19
 * your own identifying information:
jtulach@36
    20
 * "Portions Copyrighted [year] [name of copyright owner]"
jtulach@36
    21
 *
jtulach@36
    22
 * Contributor(s):
jtulach@36
    23
 *
jtulach@36
    24
 * Portions Copyrighted 2009 Jaroslav Tulach
jtulach@36
    25
 */
jtulach@36
    26
jtulach@36
    27
package cz.xelfi.quoridor.webidor.resources;
jtulach@36
    28
jtulach@36
    29
import cz.xelfi.quoridor.IllegalPositionException;
jtulach@36
    30
import cz.xelfi.quoridor.webidor.*;
jtulach@36
    31
import cz.xelfi.quoridor.Move;
jtulach@37
    32
import java.io.BufferedReader;
jtulach@37
    33
import java.io.BufferedWriter;
jtulach@37
    34
import java.io.File;
jtulach@37
    35
import java.io.FileReader;
jtulach@37
    36
import java.io.FileWriter;
jtulach@36
    37
import java.io.IOException;
jtulach@37
    38
import java.io.PrintWriter;
jtulach@36
    39
import java.util.ArrayList;
jaroslav@96
    40
import java.util.Collections;
jaroslav@48
    41
import java.util.Date;
jtulach@36
    42
import java.util.List;
jtulach@37
    43
import java.util.logging.Level;
jtulach@37
    44
import java.util.logging.Logger;
jaroslav@100
    45
import javax.ws.rs.DefaultValue;
jtulach@36
    46
import javax.ws.rs.GET;
jtulach@36
    47
import javax.ws.rs.POST;
jtulach@36
    48
import javax.ws.rs.PUT;
jtulach@36
    49
import javax.ws.rs.Path;
jtulach@36
    50
import javax.ws.rs.PathParam;
jtulach@36
    51
import javax.ws.rs.Produces;
jtulach@36
    52
import javax.ws.rs.QueryParam;
jtulach@82
    53
import javax.ws.rs.WebApplicationException;
jtulach@36
    54
import javax.ws.rs.core.MediaType;
jtulach@82
    55
import javax.ws.rs.core.Response.Status;
jtulach@36
    56
jtulach@36
    57
/**
jtulach@36
    58
 *
jtulach@36
    59
 * @author Jaroslav Tulach <jtulach@netbeans.org>
jtulach@36
    60
 */
jtulach@36
    61
public final class Games {
jtulach@82
    62
    private final Quoridor quoridor;
jaroslav@48
    63
    private final List<Game> games = new ArrayList<Game>();
jtulach@37
    64
    private final File dir;
jtulach@37
    65
    private static final Logger LOG = Logger.getLogger(Games.class.getName());
jtulach@37
    66
jtulach@82
    67
    public Games(File dir, Quoridor quoridor) {
jtulach@37
    68
        this.dir = dir;
jtulach@82
    69
        this.quoridor = quoridor;
jtulach@37
    70
        File[] arr = dir.listFiles();
jtulach@37
    71
        if (arr != null) {
jtulach@37
    72
            for (File f : arr) {
jtulach@37
    73
                try {
jtulach@37
    74
                    Game g = readGame(f);
jtulach@37
    75
                    games.add(g);
jtulach@37
    76
                } catch (IOException ex) {
jtulach@37
    77
                    LOG.log(Level.WARNING, "Wrong game in " + f, ex);
jtulach@37
    78
                }
jtulach@37
    79
            }
jtulach@37
    80
        }
jtulach@37
    81
    }
jtulach@36
    82
jtulach@36
    83
    @POST
jaroslav@48
    84
    @Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
jaroslav@48
    85
    public GameId createGame(
jtulach@82
    86
        @QueryParam("loginID") String id,
jtulach@38
    87
        @QueryParam("white") String white,
jtulach@38
    88
        @QueryParam("black") String black
jaroslav@48
    89
    ) throws IOException {
jtulach@82
    90
        String logUser = quoridor.isLoggedIn(id);
jtulach@82
    91
        if (logUser == null) {
jtulach@82
    92
            throw new WebApplicationException(Status.UNAUTHORIZED);
jtulach@82
    93
        }
jtulach@38
    94
        if (white == null) {
jtulach@82
    95
            throw new WebApplicationException(Status.PRECONDITION_FAILED);
jtulach@38
    96
        }
jtulach@38
    97
        if (black == null) {
jtulach@82
    98
            throw new WebApplicationException(Status.PRECONDITION_FAILED);
jtulach@38
    99
        }
jtulach@82
   100
        if (!logUser.equals(white) && !logUser.equals(black)) {
jtulach@82
   101
            throw new WebApplicationException(Status.PRECONDITION_FAILED);
jtulach@82
   102
        }
jtulach@82
   103
jtulach@38
   104
        Game g = new Game(white, black);
jaroslav@48
   105
        storeGame(g);
jtulach@36
   106
        games.add(g);
jaroslav@48
   107
        return g.getId();
jtulach@36
   108
    }
jtulach@36
   109
jtulach@38
   110
    @GET
jtulach@38
   111
    @Path("{id}")
jtulach@38
   112
    @Produces(MediaType.TEXT_PLAIN)
jaroslav@106
   113
    public String getBoard(
jaroslav@106
   114
        @PathParam("id") String id,
jaroslav@106
   115
        @QueryParam("move") @DefaultValue("-1") int move
jaroslav@106
   116
    ) {
jaroslav@106
   117
        Game g = findGame(id, move);
jtulach@38
   118
        if (g == null) {
jtulach@38
   119
            throw new IllegalArgumentException("Unknown game " + id);
jtulach@38
   120
        }
jtulach@38
   121
        return g.getBoard().toString();
jtulach@38
   122
    }
jtulach@38
   123
jaroslav@46
   124
    @GET
jaroslav@46
   125
    @Path("{id}")
jaroslav@48
   126
    @Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
jaroslav@100
   127
    public Game getBoardInfo(
jaroslav@100
   128
        @PathParam("id") String id,
jaroslav@100
   129
        @QueryParam("move") @DefaultValue("-1") int move
jaroslav@100
   130
    ) {
jaroslav@100
   131
        return findGame(id, move);
jaroslav@46
   132
    }
jaroslav@46
   133
jtulach@36
   134
    @PUT
jtulach@36
   135
    @Path("{id}")
jaroslav@48
   136
    @Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
jaroslav@48
   137
    public GameId applyMove(
jtulach@82
   138
        @QueryParam("loginID") String loginId,
jtulach@38
   139
        @PathParam("id") String id,
jtulach@38
   140
        @QueryParam("player") String player,
jtulach@38
   141
        @QueryParam("move") String move
jtulach@38
   142
    ) throws IllegalPositionException {
jtulach@82
   143
        String logUser = quoridor.isLoggedIn(loginId);
jtulach@82
   144
        if (logUser == null) {
jtulach@82
   145
            throw new WebApplicationException(Status.UNAUTHORIZED);
jtulach@82
   146
        }
jtulach@82
   147
        if (!logUser.equals(player)) {
jtulach@82
   148
            throw new WebApplicationException(Status.UNAUTHORIZED);
jtulach@82
   149
        }
jtulach@82
   150
jtulach@36
   151
        Game g = findGame(id);
jtulach@36
   152
        if (g == null) {
jtulach@36
   153
            throw new IllegalArgumentException("Unknown game " + id);
jtulach@36
   154
        }
jtulach@36
   155
        Move m = Move.valueOf(move);
jtulach@79
   156
        g.apply(player, m, new Date());
jtulach@37
   157
        try {
jtulach@37
   158
            storeGame(g);
jtulach@37
   159
        } catch (IOException ex) {
jtulach@37
   160
            LOG.log(Level.WARNING, "Cannot store game " + id, ex);
jtulach@37
   161
        }
jaroslav@48
   162
        return g.getId();
jtulach@36
   163
    }
jtulach@36
   164
jtulach@36
   165
    @GET
jaroslav@48
   166
    @Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
jaroslav@48
   167
    public List<GameId> listGames() {
jaroslav@48
   168
        List<GameId> arr = new ArrayList<GameId>(games.size());
jaroslav@48
   169
        for (Game g : games) {
jaroslav@48
   170
            arr.add(g.getId());
jaroslav@48
   171
        }
jaroslav@96
   172
        Collections.sort(arr, GameId.NEWEST_FIRST);
jaroslav@48
   173
        return arr;
jaroslav@48
   174
    }
jaroslav@48
   175
jtulach@36
   176
    public List<Game> getGames() {
jtulach@36
   177
        return games;
jtulach@36
   178
    }
jtulach@36
   179
jtulach@36
   180
    private Game findGame(String id) {
jtulach@36
   181
        for (Game g : games) {
jaroslav@48
   182
            if (g.getId().getId().equals(id)) {
jtulach@36
   183
                return g;
jtulach@36
   184
            }
jtulach@36
   185
        }
jtulach@36
   186
        return null;
jtulach@36
   187
    }
jaroslav@100
   188
    private Game findGame(String id, int move) {
jaroslav@100
   189
        Game g = findGame(id);
jaroslav@100
   190
        if (g == null) {
jaroslav@100
   191
            throw new IllegalArgumentException("Unknown game " + id);
jaroslav@100
   192
        }
jaroslav@100
   193
        try {
jaroslav@100
   194
            return move == -1 ? g : g.snapshot(move);
jaroslav@100
   195
        } catch (IllegalPositionException ex) {
jaroslav@100
   196
            Logger.getLogger(Games.class.getName()).log(Level.SEVERE, null, ex);
jaroslav@100
   197
            return null;
jaroslav@100
   198
        }
jaroslav@100
   199
    }
jtulach@36
   200
jtulach@37
   201
    private Game readGame(File f) throws IOException {
jtulach@37
   202
        BufferedReader r = new BufferedReader(new FileReader(f));
jtulach@37
   203
        String white = null;
jtulach@37
   204
        String black = null;
jtulach@37
   205
        Game g = null;
jtulach@37
   206
        for (;;) {
jtulach@37
   207
            String line = r.readLine();
jtulach@37
   208
            if (line == null) {
jaroslav@48
   209
                line = "finish";
jtulach@37
   210
            }
jtulach@39
   211
            line = line.trim();
jtulach@39
   212
            if (line.length() == 0) {
jtulach@39
   213
                continue;
jtulach@39
   214
            }
jtulach@37
   215
            if (line.startsWith("# white: ")) {
jtulach@37
   216
                white = line.substring(9);
jtulach@37
   217
                continue;
jtulach@37
   218
            }
jtulach@37
   219
            if (line.startsWith("# black: ")) {
jtulach@37
   220
                black = line.substring(9);
jtulach@37
   221
                continue;
jtulach@37
   222
            }
jtulach@37
   223
            if (line.startsWith("#")) {
jtulach@37
   224
                continue;
jtulach@37
   225
            }
jtulach@37
   226
            if (white == null || black == null) {
jtulach@37
   227
                throw new IOException("Missing white and black identification in " + f);
jtulach@37
   228
            }
jtulach@37
   229
            if (g == null) {
jtulach@78
   230
                GameId id = new GameId(f.getName(), white, black, new Date(f.lastModified()), new Date(f.lastModified()), GameStatus.whiteMove);
jaroslav@48
   231
                g = new Game(id);
jaroslav@48
   232
            }
jaroslav@114
   233
            int hash = line.indexOf('#');
jaroslav@114
   234
            if (hash >= 0) {
jaroslav@114
   235
                line = line.substring(0, hash);
jaroslav@114
   236
            }
jaroslav@48
   237
            if (line.equals("finish")) {
jaroslav@48
   238
                break;
jtulach@37
   239
            }
jtulach@37
   240
            String[] moves = line.split(" ");
jtulach@37
   241
            if (moves.length == 0) {
jtulach@37
   242
                continue;
jtulach@37
   243
            }
jtulach@37
   244
            if (moves.length > 2) {
jtulach@37
   245
                throw new IOException("Too much moves on line: " + line);
jtulach@37
   246
            }
jtulach@37
   247
            try {
jaroslav@114
   248
                if (!"...".equals(moves[0])) {
jaroslav@114
   249
                    g.apply(white, Move.valueOf(moves[0]), null);
jaroslav@114
   250
                }
jtulach@37
   251
                if (moves.length == 2) {
jtulach@79
   252
                    g.apply(black, Move.valueOf(moves[1]), null);
jtulach@37
   253
                }
jtulach@37
   254
            } catch (IllegalPositionException ex) {
jtulach@37
   255
                throw new IOException("Wrong move: " + ex.getMessage());
jtulach@37
   256
            }
jtulach@37
   257
        }
jtulach@37
   258
        if (g == null) {
jtulach@37
   259
            throw new IOException("No moves in " + f);
jtulach@37
   260
        }
jtulach@37
   261
        return g;
jtulach@36
   262
    }
jtulach@36
   263
jtulach@37
   264
    private void storeGame(Game g) throws IOException {
jtulach@37
   265
        dir.mkdirs();
jaroslav@48
   266
        File f = new File(dir, g.getId().getId());
jtulach@37
   267
        PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(f)));
jaroslav@48
   268
        pw.println("# white: " + g.getId().getWhite());
jaroslav@48
   269
        pw.println("# black: " + g.getId().getBlack());
jtulach@77
   270
        pw.println("# status: " + g.getId().getStatus());
jtulach@37
   271
        int cnt = 0;
jtulach@37
   272
        for (Move m : g.getMoves()) {
jtulach@37
   273
            pw.print(m.toString());
jtulach@37
   274
            if (++cnt % 2 == 0) {
jtulach@37
   275
                pw.println();
jtulach@37
   276
            } else {
jtulach@37
   277
                pw.print(' ');
jtulach@37
   278
            }
jtulach@37
   279
        }
jtulach@37
   280
        pw.println();
jtulach@37
   281
        pw.println();
jtulach@37
   282
        pw.flush();
jtulach@37
   283
        pw.close();
jtulach@37
   284
    }
jtulach@36
   285
}