jtulach@36: /* jtulach@36: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. jtulach@36: * jtulach@36: * The contents of this file are subject to the terms of either the GNU jtulach@36: * General Public License Version 2 only ("GPL") or the Common jtulach@36: * Development and Distribution License("CDDL") (collectively, the jtulach@36: * "License"). You may not use this file except in compliance with the jtulach@36: * License. You can obtain a copy of the License at jtulach@36: * http://www.netbeans.org/cddl-gplv2.html jtulach@36: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the jtulach@36: * specific language governing permissions and limitations under the jtulach@36: * License. When distributing the software, include this License Header jtulach@36: * Notice in each file and include the License file at jtulach@36: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this jtulach@36: * particular file as subject to the "Classpath" exception as provided jtulach@36: * by Sun in the GPL Version 2 section of the License file that jtulach@36: * accompanied this code. If applicable, add the following below the jtulach@36: * License Header, with the fields enclosed by brackets [] replaced by jtulach@36: * your own identifying information: jtulach@36: * "Portions Copyrighted [year] [name of copyright owner]" jtulach@36: * jtulach@36: * Contributor(s): jtulach@36: * jtulach@36: * Portions Copyrighted 2009 Jaroslav Tulach jtulach@36: */ jtulach@36: jtulach@36: package cz.xelfi.quoridor.webidor.resources; jtulach@36: jtulach@36: import cz.xelfi.quoridor.IllegalPositionException; jtulach@36: import cz.xelfi.quoridor.webidor.*; jtulach@36: import cz.xelfi.quoridor.Move; jtulach@91: import cz.xelfi.quoridor.visidor.Visidor; jtulach@91: import java.awt.Image; jtulach@37: import java.io.BufferedReader; jtulach@37: import java.io.BufferedWriter; jtulach@37: import java.io.File; jtulach@37: import java.io.FileReader; jtulach@37: import java.io.FileWriter; jtulach@36: import java.io.IOException; jtulach@37: import java.io.PrintWriter; jtulach@36: import java.util.ArrayList; jaroslav@48: import java.util.Date; jtulach@36: import java.util.List; jtulach@37: import java.util.logging.Level; jtulach@37: import java.util.logging.Logger; jtulach@36: import javax.ws.rs.GET; jtulach@36: import javax.ws.rs.POST; jtulach@36: import javax.ws.rs.PUT; jtulach@36: import javax.ws.rs.Path; jtulach@36: import javax.ws.rs.PathParam; jtulach@36: import javax.ws.rs.Produces; jtulach@36: import javax.ws.rs.QueryParam; jtulach@82: import javax.ws.rs.WebApplicationException; jtulach@36: import javax.ws.rs.core.MediaType; jtulach@82: import javax.ws.rs.core.Response.Status; jtulach@36: jtulach@36: /** jtulach@36: * jtulach@36: * @author Jaroslav Tulach jtulach@36: */ jtulach@36: public final class Games { jtulach@82: private final Quoridor quoridor; jaroslav@48: private final List games = new ArrayList(); jtulach@37: private final File dir; jtulach@37: private static final Logger LOG = Logger.getLogger(Games.class.getName()); jtulach@37: jtulach@82: public Games(File dir, Quoridor quoridor) { jtulach@37: this.dir = dir; jtulach@82: this.quoridor = quoridor; jtulach@37: File[] arr = dir.listFiles(); jtulach@37: if (arr != null) { jtulach@37: for (File f : arr) { jtulach@37: try { jtulach@37: Game g = readGame(f); jtulach@37: games.add(g); jtulach@37: } catch (IOException ex) { jtulach@37: LOG.log(Level.WARNING, "Wrong game in " + f, ex); jtulach@37: } jtulach@37: } jtulach@37: } jtulach@37: } jtulach@36: jtulach@36: @POST jaroslav@48: @Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML }) jaroslav@48: public GameId createGame( jtulach@82: @QueryParam("loginID") String id, jtulach@38: @QueryParam("white") String white, jtulach@38: @QueryParam("black") String black jaroslav@48: ) throws IOException { jtulach@82: String logUser = quoridor.isLoggedIn(id); jtulach@82: if (logUser == null) { jtulach@82: throw new WebApplicationException(Status.UNAUTHORIZED); jtulach@82: } jtulach@38: if (white == null) { jtulach@82: throw new WebApplicationException(Status.PRECONDITION_FAILED); jtulach@38: } jtulach@38: if (black == null) { jtulach@82: throw new WebApplicationException(Status.PRECONDITION_FAILED); jtulach@38: } jtulach@82: if (!logUser.equals(white) && !logUser.equals(black)) { jtulach@82: throw new WebApplicationException(Status.PRECONDITION_FAILED); jtulach@82: } jtulach@82: jtulach@38: Game g = new Game(white, black); jaroslav@48: storeGame(g); jtulach@36: games.add(g); jaroslav@48: return g.getId(); jtulach@36: } jtulach@36: jtulach@38: @GET jtulach@38: @Path("{id}") jtulach@38: @Produces(MediaType.TEXT_PLAIN) jtulach@38: public String getBoard(@PathParam("id") String id) { jtulach@38: Game g = findGame(id); jtulach@38: if (g == null) { jtulach@38: throw new IllegalArgumentException("Unknown game " + id); jtulach@38: } jtulach@38: return g.getBoard().toString(); jtulach@38: } jtulach@38: jaroslav@46: @GET jaroslav@46: @Path("{id}") jtulach@91: @Produces("image/png") jtulach@91: public Image getBoardImage(@PathParam("id") String id) { jtulach@91: Game g = findGame(id); jtulach@91: if (g == null) { jtulach@91: throw new IllegalArgumentException("Unknown game " + id); jtulach@91: } jtulach@91: return Visidor.draw(g.getBoard()); jtulach@91: } jtulach@91: jtulach@91: @GET jtulach@91: @Path("{id}") jaroslav@48: @Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML }) jaroslav@48: public Game getBoardInfo(@PathParam("id") String id) { jaroslav@46: Game g = findGame(id); jaroslav@46: if (g == null) { jaroslav@46: throw new IllegalArgumentException("Unknown game " + id); jaroslav@46: } jaroslav@48: return g; jaroslav@46: } jaroslav@46: jtulach@36: @PUT jtulach@36: @Path("{id}") jaroslav@48: @Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML }) jaroslav@48: public GameId applyMove( jtulach@82: @QueryParam("loginID") String loginId, jtulach@38: @PathParam("id") String id, jtulach@38: @QueryParam("player") String player, jtulach@38: @QueryParam("move") String move jtulach@38: ) throws IllegalPositionException { jtulach@82: String logUser = quoridor.isLoggedIn(loginId); jtulach@82: if (logUser == null) { jtulach@82: throw new WebApplicationException(Status.UNAUTHORIZED); jtulach@82: } jtulach@82: if (!logUser.equals(player)) { jtulach@82: throw new WebApplicationException(Status.UNAUTHORIZED); jtulach@82: } jtulach@82: jtulach@36: Game g = findGame(id); jtulach@36: if (g == null) { jtulach@36: throw new IllegalArgumentException("Unknown game " + id); jtulach@36: } jtulach@36: Move m = Move.valueOf(move); jtulach@79: g.apply(player, m, new Date()); jtulach@37: try { jtulach@37: storeGame(g); jtulach@37: } catch (IOException ex) { jtulach@37: LOG.log(Level.WARNING, "Cannot store game " + id, ex); jtulach@37: } jaroslav@48: return g.getId(); jtulach@36: } jtulach@36: jtulach@36: @GET jaroslav@48: @Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_XML }) jaroslav@48: public List listGames() { jaroslav@48: List arr = new ArrayList(games.size()); jaroslav@48: for (Game g : games) { jaroslav@48: arr.add(g.getId()); jaroslav@48: } jaroslav@48: return arr; jaroslav@48: } jaroslav@48: jtulach@36: public List getGames() { jtulach@36: return games; jtulach@36: } jtulach@36: jtulach@36: private Game findGame(String id) { jtulach@36: for (Game g : games) { jaroslav@48: if (g.getId().getId().equals(id)) { jtulach@36: return g; jtulach@36: } jtulach@36: } jtulach@36: return null; jtulach@36: } jtulach@36: jtulach@37: private Game readGame(File f) throws IOException { jtulach@37: BufferedReader r = new BufferedReader(new FileReader(f)); jtulach@37: String white = null; jtulach@37: String black = null; jtulach@37: Game g = null; jtulach@37: for (;;) { jtulach@37: String line = r.readLine(); jtulach@37: if (line == null) { jaroslav@48: line = "finish"; jtulach@37: } jtulach@39: line = line.trim(); jtulach@39: if (line.length() == 0) { jtulach@39: continue; jtulach@39: } jtulach@37: if (line.startsWith("# white: ")) { jtulach@37: white = line.substring(9); jtulach@37: continue; jtulach@37: } jtulach@37: if (line.startsWith("# black: ")) { jtulach@37: black = line.substring(9); jtulach@37: continue; jtulach@37: } jtulach@37: if (line.startsWith("#")) { jtulach@37: continue; jtulach@37: } jtulach@37: if (white == null || black == null) { jtulach@37: throw new IOException("Missing white and black identification in " + f); jtulach@37: } jtulach@37: if (g == null) { jtulach@78: GameId id = new GameId(f.getName(), white, black, new Date(f.lastModified()), new Date(f.lastModified()), GameStatus.whiteMove); jaroslav@48: g = new Game(id); jaroslav@48: } jaroslav@48: if (line.equals("finish")) { jaroslav@48: break; jtulach@37: } jtulach@37: String[] moves = line.split(" "); jtulach@37: if (moves.length == 0) { jtulach@37: continue; jtulach@37: } jtulach@37: if (moves.length > 2) { jtulach@37: throw new IOException("Too much moves on line: " + line); jtulach@37: } jtulach@37: try { jtulach@79: g.apply(white, Move.valueOf(moves[0]), null); jtulach@37: if (moves.length == 2) { jtulach@79: g.apply(black, Move.valueOf(moves[1]), null); jtulach@37: } jtulach@37: } catch (IllegalPositionException ex) { jtulach@37: throw new IOException("Wrong move: " + ex.getMessage()); jtulach@37: } jtulach@37: } jtulach@37: if (g == null) { jtulach@37: throw new IOException("No moves in " + f); jtulach@37: } jtulach@37: return g; jtulach@36: } jtulach@36: jtulach@37: private void storeGame(Game g) throws IOException { jtulach@37: dir.mkdirs(); jaroslav@48: File f = new File(dir, g.getId().getId()); jtulach@37: PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(f))); jaroslav@48: pw.println("# white: " + g.getId().getWhite()); jaroslav@48: pw.println("# black: " + g.getId().getBlack()); jtulach@77: pw.println("# status: " + g.getId().getStatus()); jtulach@37: int cnt = 0; jtulach@37: for (Move m : g.getMoves()) { jtulach@37: pw.print(m.toString()); jtulach@37: if (++cnt % 2 == 0) { jtulach@37: pw.println(); jtulach@37: } else { jtulach@37: pw.print(' '); jtulach@37: } jtulach@37: } jtulach@37: pw.println(); jtulach@37: pw.println(); jtulach@37: pw.flush(); jtulach@37: pw.close(); jtulach@37: } jtulach@36: }