/** * Copyright (C) 2002-2012 The FreeCol Team * * This file is part of FreeCol. * * FreeCol is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * FreeCol is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with FreeCol. If not, see <http://www.gnu.org/licenses/>. */ package net.sf.freecol.client.control; import java.util.logging.Logger; import org.freecolandroid.repackaged.javax.swing.SwingUtilities; import org.freecolandroid.xml.stream.XMLStreamException; import org.freecolandroid.xml.stream.XMLStreamReader; import org.freecolandroid.xml.stream.XMLStreamWriter; import net.sf.freecol.FreeCol; import net.sf.freecol.client.FreeColClient; import net.sf.freecol.client.gui.GUI; import net.sf.freecol.common.model.FreeColObject; import net.sf.freecol.common.model.Game; import net.sf.freecol.common.model.Nation; import net.sf.freecol.common.model.NationOptions.NationState; import net.sf.freecol.common.model.NationType; import net.sf.freecol.common.model.Player; import net.sf.freecol.common.networking.ChatMessage; import net.sf.freecol.common.networking.Connection; import net.sf.freecol.common.networking.StreamedMessageHandler; import net.sf.freecol.common.option.MapGeneratorOptions; import net.sf.freecol.common.option.OptionGroup; import org.w3c.dom.Element; import org.w3c.dom.NodeList; /** * Handles the network messages that arrives before the game starts. */ public final class PreGameInputHandler extends InputHandler implements StreamedMessageHandler { private static final Logger logger = Logger.getLogger(PreGameInputHandler.class.getName()); /** * The constructor to use. * @param freeColClient The main controller. */ public PreGameInputHandler(FreeColClient freeColClient, GUI gui) { super(freeColClient, gui); } /** * Deals with incoming messages that have just been received. * * @param connection The <code>Connection</code> the message was received on. * @param element The root element of the message. * @return The reply. */ public synchronized Element handle(Connection connection, Element element) { Element reply = null; if (element != null) { String type = element.getTagName(); if (type.equals("addPlayer")) { reply = addPlayer(element); } else if (type.equals("removePlayer")) { reply = removePlayer(element); } else if (type.equals("updateGameOptions")) { reply = updateGameOptions(element); } else if (type.equals("updateMapGeneratorOptions")) { reply = updateMapGeneratorOptions(element); } else if (type.equals("chat")) { reply = chat(element); } else if (type.equals("playerReady")) { reply = playerReady(element); } else if (type.equals("updateNation")) { reply = updateNation(element); } else if (type.equals("updateNationType")) { reply = updateNationType(element); } else if (type.equals("setAvailable")) { reply = setAvailable(element); } else if (type.equals("startGame")) { reply = startGame(element); } else if (type.equals("logout")) { reply = logout(element); } else if (type.equals("disconnect")) { reply = disconnect(element); } else if (type.equals("error")) { reply = error(element); } else if (type.equals("multiple")) { reply = multiple(connection, element); } else { logger.warning("Message is of unsupported type \"" + type + "\"."); } } return reply; } /** * Handles the main element of an XML message. * * @param connection The connection the message came from. * @param in The stream containing the message. * @param out The output stream for the reply. */ public void handle(Connection connection, XMLStreamReader in, XMLStreamWriter out) { if (in.getLocalName().equals("updateGame")) { updateGame(connection, in, out); } else { logger.warning("Unkown (streamed) request: " + in.getLocalName()); } } /** * Checks if the message handler support the given message. * @param tagName The tag name of the message to check. * @return The result. */ public boolean accepts(String tagName) { return tagName.equals("updateGame"); } /** * Handles an "addPlayer"-message. * * @param element The element (root element in a DOM-parsed XML tree) that * holds all the information. */ private Element addPlayer(Element element) { Game game = getFreeColClient().getGame(); Element playerElement = (Element) element.getElementsByTagName(Player.getXMLElementTagName()).item(0); if (game.getFreeColGameObject(playerElement.getAttribute(FreeColObject.ID_ATTRIBUTE)) == null) { Player newPlayer = new Player(game, playerElement); getFreeColClient().getGame().addPlayer(newPlayer); } else { game.getFreeColGameObject(playerElement.getAttribute(FreeColObject.ID_ATTRIBUTE)).readFromXMLElement(playerElement); } gui.refreshPlayersTable(); return null; } /** * Handles a "removePlayer"-message. * * @param element The element (root element in a DOM-parsed XML tree) that * holds all the information. */ private Element removePlayer(Element element) { Game game = getFreeColClient().getGame(); Element playerElement = (Element) element.getElementsByTagName(Player.getXMLElementTagName()).item(0); Player player = new Player(game, playerElement); getFreeColClient().getGame().removePlayer(player); gui.refreshPlayersTable(); return null; } /** * Handles an "updateGameOptions"-message. * * @param element The element (root element in a DOM-parsed XML tree) that * holds all the information. */ private Element updateGameOptions(Element element) { Game game = getFreeColClient().getGame(); Element mgoElement = (Element) element.getElementsByTagName("gameOptions").item(0); OptionGroup gameOptions = game.getSpecification().getOptionGroup("gameOptions"); gameOptions.readFromXMLElement(mgoElement); gui.updateGameOptions(); return null; } /** * Handles an "updateMapGeneratorOptions"-message. * * @param element The element (root element in a DOM-parsed XML tree) that * holds all the information. */ private Element updateMapGeneratorOptions(Element element) { Element mgoElement = (Element) element.getElementsByTagName(MapGeneratorOptions.getXMLElementTagName()).item(0); getFreeColClient().getGame().getMapGeneratorOptions().readFromXMLElement(mgoElement); gui.updateMapGeneratorOptions(); return null; } /** * Handles a "chat"-message. * * @param element The element (root element in a DOM-parsed XML tree) that * holds all the information. * @return Null. */ private Element chat(Element element) { ChatMessage chatMessage = new ChatMessage(getGame(), element); gui.displayChat(chatMessage.getPlayer().getName(), chatMessage.getMessage(), chatMessage.isPrivate()); return null; } /** * Handles a PlayerReady message. * * @param element The element (root element in a DOM-parsed XML tree) that * holds all the information. */ private Element playerReady(Element element) { Game game = getFreeColClient().getGame(); Player player = (Player) game.getFreeColGameObject(element.getAttribute("player")); boolean ready = Boolean.valueOf(element.getAttribute("value")).booleanValue(); player.setReady(ready); gui.refreshPlayersTable(); return null; } /** * Handles an "updateNation"-message. * * @param element The element (root element in a DOM-parsed XML tree) that * holds all the information. */ private Element updateNation(Element element) { Game game = getFreeColClient().getGame(); Player player = (Player) game.getFreeColGameObject(element.getAttribute("player")); Nation nation = getGame().getSpecification().getNation(element.getAttribute("value")); player.setNation(nation); gui.refreshPlayersTable(); return null; } /** * Handles an "updateNationType"-message. * * @param element The element (root element in a DOM-parsed XML tree) that * holds all the information. */ private Element updateNationType(Element element) { Game game = getFreeColClient().getGame(); Player player = (Player) game.getFreeColGameObject(element.getAttribute("player")); NationType nationType = getGame().getSpecification().getNationType(element.getAttribute("value")); player.setNationType(nationType); gui.refreshPlayersTable(); return null; } /** * Handles a "setAvailable"-message. * * @param element The element (root element in a DOM-parsed XML tree) that * holds all the information. */ private Element setAvailable(Element element) { Nation nation = getGame().getSpecification().getNation(element.getAttribute("nation")); NationState state = Enum.valueOf(NationState.class, element.getAttribute("state")); getFreeColClient().getGame().getNationOptions().setNationState(nation, state); gui.refreshPlayersTable(); return null; } /** * Handles an "updateGame"-message. * @param connection The <code>Connection</code> the message * will be read from. * @param in The stream to read the message from. * @param out The stream for the reply. */ private void updateGame(Connection connection, XMLStreamReader in, XMLStreamWriter out) { try { in.nextTag(); getFreeColClient().getGame().readFromXML(in); } catch (XMLStreamException e) { logger.warning(e.toString()); } } /** * Handles an "startGame"-message. * * @param element The element (root element in a DOM-parsed XML tree) that * holds all the information. */ private Element startGame(Element element) { /* Wait until map is received from server, sometimes this message arrives * when map is still null. Wait in other thread in order not to block and * it can receive the map. */ new Thread(FreeCol.CLIENT_THREAD+"Starting game") { @Override public void run() { while (getFreeColClient().getGame().getMap() == null) { try { Thread.sleep(200); } catch (Exception ex) {} } SwingUtilities.invokeLater(new Runnable() { public void run() { getFreeColClient().getPreGameController().startGame(); } }); } }.start(); return null; } /** * Handles an "logout"-message. * * @param element The element (root element in a DOM-parsed XML tree) that * holds all the information. */ private Element logout(Element element) { Game game = getFreeColClient().getGame(); String playerID = element.getAttribute("player"); // For now we ignore the 'reason' attibute, we could display the reason to the user. Player player = (Player) game.getFreeColGameObject(playerID); game.removePlayer(player); gui.refreshPlayersTable(); return null; } /** * Handles an "error"-message. * * @param element The element (root element in a DOM-parsed XML tree) that * holds all the information. */ private Element error(Element element) { if (element.hasAttribute("messageID")) { gui.errorMessage(element.getAttribute("messageID"), element.getAttribute("message")); } else { gui.errorMessage(null, element.getAttribute("message")); } return null; } /** * Handle all the children of this element. * * @param connection <code>Connection</code> * @param element The element (root element in a DOM-parsed XML tree) that * holds all the information. * @return <code>Element</code> */ public Element multiple(Connection connection, Element element) { NodeList nodes = element.getChildNodes(); Element reply = null; for (int i = 0; i < nodes.getLength(); i++) { reply = handle(connection, (Element) nodes.item(i)); } return reply; } }