/**
* 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.common.model;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
/**
* This class contains the mutable tile data visible to a specific player.
*
* Sometimes a tile contains information that should not be given to a
* player. For instance; a settlement that was built after the player last
* viewed the tile.
*
* The <code>toXMLElement</code> of {@link Tile} uses information from
* this class to hide information that is not available.
*/
public class PlayerExploredTile extends FreeColGameObject {
private static final Logger logger = Logger.getLogger(PlayerExploredTile.class.getName());
// The owner of this view.
private Player player;
// The tile viewed.
private Tile tile;
// The owner of the tile.
private Player owner;
// The owning settlement of the tile, if any.
private Settlement owningSettlement;
// All known TileItems.
private final List<TileItem> tileItems = new ArrayList<TileItem>();
// Colony data.
private int colonyUnitCount = 0;
private String colonyStockadeKey = null;
// IndianSettlement data.
private UnitType skill = null;
private GoodsType[] wantedGoods = { null, null, null };
private Unit missionary = null;
/**
* Creates a new <code>PlayerExploredTile</code>.
*
* @param player The <code>Player</code> that owns this view.
* @param tile The <code>Tile</code> to view.
*/
public PlayerExploredTile(Game game, Player player, Tile tile) {
super(game);
this.player = player;
this.tile = tile;
}
/**
* Initialize this object from an XML-representation of this object.
*
* @param in The XML stream to read the data from.
* @throws XMLStreamException if an error occurred during parsing.
*/
public PlayerExploredTile(Game game, XMLStreamReader in) throws XMLStreamException {
super(game, in);
readFromXML(in);
}
/**
* Update this PlayerExploredTile with the current state of its tile.
*
* @param full If true, update information hidden by settlements.
*/
public void update(boolean full) {
owner = tile.getOwner();
owningSettlement = tile.getOwningSettlement();
tileItems.clear();
TileItemContainer tic = tile.getTileItemContainer();
if (tic != null) {
tileItems.addAll(tic.getImprovements());
if (tic.getResource() != null) {
tileItems.add(tic.getResource());
}
if (tic.getLostCityRumour() != null) {
tileItems.add(tic.getLostCityRumour());
}
}
Colony colony = tile.getColony();
if (colony == null) {
colonyUnitCount = -1;
colonyStockadeKey = null;
} else {
colonyUnitCount = colony.getUnitCount();
colonyStockadeKey = colony.getTrueStockadeKey();
}
IndianSettlement is = tile.getIndianSettlement();
if (is == null) {
missionary = null;
skill = null;
wantedGoods = new GoodsType[] { null, null, null };
} else {
missionary = is.getMissionary();
if (full) {
skill = is.getLearnableSkill();
}
// Do not hide. Has to be visible for the pre-speak-to-chief
// dialog message. Yes this is odd.
wantedGoods = is.getWantedGoods();
}
}
// Trivial public accessors.
public Player getOwner() {
return owner;
}
public Settlement getOwningSettlement() {
return owningSettlement;
}
public List<TileItem> getAllTileItems() {
return new ArrayList<TileItem>(tileItems);
}
public int getColonyUnitCount() {
return colonyUnitCount;
}
public String getColonyStockadeKey() {
return colonyStockadeKey;
}
public Unit getMissionary() {
return missionary;
}
public UnitType getSkill() {
return skill;
}
public GoodsType[] getWantedGoods() {
return wantedGoods;
}
// Only needed for 0.9.x workaround in Tile.readFromXML.
public void setOwner(Player owner) {
this.owner = owner;
}
public void setOwningSettlement(Settlement owningSettlement) {
this.owningSettlement = owningSettlement;
}
public void setColonyUnitCount(int colonyUnitCount) {
this.colonyUnitCount = colonyUnitCount;
}
public void setColonyStockadeKey(String colonyStockadeKey) {
this.colonyStockadeKey = colonyStockadeKey;
}
public void setMissionary(Unit missionary) {
this.missionary = missionary;
}
// End 0.9.x workarounds.
/**
* This method writes an XML-representation of this object to the
* given stream.
*
* Only attributes visible to the given <code>Player</code> will
* be added to that representation if <code>showAll</code> is set
* to <code>false</code>.
*
* @param out The target stream.
* @param player The <code>Player</code> this XML-representation
* should be made for, or <code>null</code> if
* <code>showAll == true</code>.
* @param showAll Only attributes visible to <code>player</code> will
* be added to the representation if <code>showAll</code>
* is set to <i>false</i>.
* @param toSavedGame If <code>true</code> then information that is
* only needed when saving a game is added.
* @throws XMLStreamException if there are any problems writing to the
* stream.
*/
public void toXMLImpl(XMLStreamWriter out, Player player,
boolean showAll, boolean toSavedGame)
throws XMLStreamException {
// Start element:
out.writeStartElement(getXMLElementTagName());
out.writeAttribute(ID_ATTRIBUTE, getId());
out.writeAttribute("player", player.getId());
out.writeAttribute("tile", tile.getId());
if (owner != null) {
out.writeAttribute("owner", owner.getId());
}
if (owningSettlement != null) {
out.writeAttribute("owningSettlement", owningSettlement.getId());
}
if (colonyUnitCount > 0) {
out.writeAttribute("colonyUnitCount",
Integer.toString(colonyUnitCount));
}
if (colonyStockadeKey != null) {
out.writeAttribute("colonyStockadeKey", colonyStockadeKey);
}
if (skill != null) {
writeAttribute(out, "learnableSkill", skill);
}
if (wantedGoods[0] != null) {
writeAttribute(out, "wantedGoods0", wantedGoods[0]);
}
if (wantedGoods[1] != null) {
writeAttribute(out, "wantedGoods1", wantedGoods[1]);
}
if (wantedGoods[2] != null) {
writeAttribute(out, "wantedGoods2", wantedGoods[2]);
}
// Attributes end here
if (missionary != null) {
out.writeStartElement("missionary");
missionary.toXML(out, player, showAll, toSavedGame);
out.writeEndElement();
}
for (TileItem ti : tileItems) {
ti.toXML(out, player, showAll, toSavedGame);
}
out.writeEndElement();
}
/**
* Initialize this object from an XML-representation of this object.
*
* @param in The input stream with the XML.
* @throws XMLStreamException if an error occurred during parsing.
*/
protected void readAttributes(XMLStreamReader in) throws XMLStreamException {
Specification spec = getSpecification();
Game game = getGame();
super.readAttributes(in);
player = getFreeColGameObject(in, "player", Player.class);
tile = getFreeColGameObject(in, "tile", Tile.class);
owner = getFreeColGameObject(in, "owner", Player.class, null);
owningSettlement = getFreeColGameObject(in, "owningSettlement",
Settlement.class, null);
colonyUnitCount = getAttribute(in, "colonyUnitCount", 0);
colonyStockadeKey = in.getAttributeValue(null, "colonyStockadeKey");
skill = spec.getType(in, "learnableSkill", UnitType.class, null);
wantedGoods[0] = spec.getType(in, "wantedGoods0", GoodsType.class,
null);
wantedGoods[1] = spec.getType(in, "wantedGoods1", GoodsType.class,
null);
wantedGoods[2] = spec.getType(in, "wantedGoods2", GoodsType.class,
null);
tileItems.clear();
missionary = null;
}
protected void readChild(XMLStreamReader in) throws XMLStreamException {
Game game = getGame();
if (in.getLocalName().equals(IndianSettlement.MISSIONARY_TAG_NAME)) {
in.nextTag(); // advance to the Unit tag
missionary = updateFreeColGameObject(in, Unit.class);
in.nextTag(); // close <missionary> tag
} else if (in.getLocalName().equals(Resource.getXMLElementTagName())) {
Resource resource = game.getFreeColGameObject(in.getAttributeValue(null, ID_ATTRIBUTE),
Resource.class);
if (resource != null) {
resource.readFromXML(in);
} else {
resource = new Resource(game, in);
}
tileItems.add(resource);
} else if (in.getLocalName().equals(LostCityRumour.getXMLElementTagName())) {
LostCityRumour lostCityRumour = game.getFreeColGameObject(in.getAttributeValue(null, ID_ATTRIBUTE),
LostCityRumour.class);
if (lostCityRumour != null) {
lostCityRumour.readFromXML(in);
} else {
lostCityRumour = new LostCityRumour(game, in);
}
tileItems.add(lostCityRumour);
} else if (in.getLocalName().equals(TileImprovement.getXMLElementTagName())) {
TileImprovement ti = game.getFreeColGameObject(in.getAttributeValue(null, ID_ATTRIBUTE),
TileImprovement.class);
if (ti != null) {
ti.readFromXML(in);
} else {
ti = new TileImprovement(game, in);
}
tileItems.add(ti);
} else {
logger.warning("Unknown tag: " + in.getLocalName()
+ " loading PlayerExploredTile");
in.nextTag();
}
}
/**
* Returns the tag name of the root element representing this object.
*
* @return "playerExploredTile".
*/
public static String getXMLElementTagName() {
return "playerExploredTile";
}
}