/** * 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.logging.Logger; import org.freecolandroid.xml.stream.XMLStreamException; import org.freecolandroid.xml.stream.XMLStreamReader; import org.freecolandroid.xml.stream.XMLStreamWriter; import org.w3c.dom.Element; /** * Represents locatable goods of a specified type and amount. Use * AbstractGoods to represent abstract or potential goods that need * not be present in any particular location. * * @see AbstractGoods */ public class Goods extends AbstractGoods implements Locatable, Ownable, Named { private static Logger logger = Logger.getLogger(Goods.class.getName()); private Game game; private Location location; // ------------------------------------------------------------ constructor /** * Creates a standard <code>Goods</code>-instance given the place where * the goods is. * * This constructor only asserts that the game and * that the location (if given) can store goods. The goods will not * be added to the location (use Location.add for this). * * @param game The <code>Game</code> in which this object belongs * @param location The location of the goods (may be null) * @param type The type of the goods. * @param amount The amount of the goods. * * @throws IllegalArgumentException if the location cannot store any goods. */ public Goods(Game game, Location location, GoodsType type, int amount) { if (game == null) { throw new IllegalArgumentException("Parameter 'game' must not be 'null'."); } if (type == null) { throw new IllegalArgumentException("Parameter 'type' must not be 'null'."); } if (location != null && location.getGoodsContainer() == null){ throw new IllegalArgumentException("This location cannot store goods: " + location.toString()); } this.game = game; this.location = location; setType(type); setAmount(amount); } /** * Creates a new <code>Goods</code> instance. * * @param game a <code>Game</code> value * @param in a <code>XMLStreamReader</code> value * @exception XMLStreamException if an error occurs */ public Goods(Game game, XMLStreamReader in) throws XMLStreamException { this.game = game; readFromXML(in); } /** * Creates a new <code>Goods</code> instance. * * @param game a <code>Game</code> value * @param e an <code>Element</code> value */ public Goods(Game game, Element e) { this.game = game; readFromXMLElement(e); } // ------------------------------------------------------------ retrieval methods /** * Gets the owner of this <code>Ownable</code>. * * @return The <code>Player</code> controlling this * {@link Ownable}. */ public Player getOwner() { return (location instanceof Ownable) ? ((Ownable) location).getOwner() : null; } /** * Sets the owner of this <code>Ownable</code>. * * @param p The <code>Player</code> that should take ownership * of this {@link Ownable}. * @exception UnsupportedOperationException is always thrown by * this method. */ public void setOwner(Player p) { throw new UnsupportedOperationException(); } /** * Returns a textual representation of this object. * @return A <code>String</code> with the format: * <br>AMOUNT GOODSTYPE * <br><br>Example: * <br>15 Cotton */ public String toString() { return toString(this); } public static String toString(Goods goods) { return toString(goods.getType(), goods.getAmount()); } public static String toString(GoodsType goodsType, int amount) { return Integer.toString(amount) + " " + goodsType.getId(); } /** * Returns the name of this type of goods. * * @param sellable Whether this type of goods is sellable; * @return The name of this type of goods. */ public StringTemplate getLabel(boolean sellable) { return StringTemplate.template((sellable) ? "model.goods.goodsAmount" : "model.goods.goodsBoycotted") .addAmount("%amount%", getAmount()) .add("%goods%", getType().getNameKey()); } /** * Returns the <code>Tile</code> where this <code>Goods</code> is located, * or <code>null</code> if it's location is <code>Europe</code>. * * @return The Tile where this Unit is located. Or null if * its location is Europe. */ public Tile getTile() { return (location != null) ? location.getTile() : null; } /** * Gets the location of this goods. * * @return The goods location. */ public Location getLocation() { return location; } /** * Sets the location of the goods. * * @param location The new <code>Location</code> of the goods. */ public void setLocation(Location location) { this.location = location; } /** DO NOT USE, this is going away (into the server) soon. */ public void changeLocation(Location location) { if (location != null && location.getGoodsContainer() == null) { throw new IllegalArgumentException("Goods have to be located in a GoodsContainers."); } if (this.location != null) { this.location.remove(this); } this.location = null; if (location != null) { location.add(this); } this.location = location; } /** * Gets the amount of space this <code>Goods</code> take. * @return The amount. */ public int getSpaceTaken() { return 1; } /** * If the amount of goods is greater than the container can hold, * then this method adjusts the amount to the maximum amount possible. */ public void adjustAmount() { int maxAmount = location.getGoodsContainer().getGoodsCount(getType()); if (getAmount() > maxAmount) setAmount(maxAmount); } /** * Gets the game object this <code>Goods</code> belongs to. * @return The <code>Game</code>. */ public Game getGame() { return game; } @Override public int hashCode() { int value = 19; value = 303 * value + ((getLocation() == null) ? 1 : getLocation().getId().hashCode()); value = 303 * value + getType().hashCode(); value = 303 * value + getAmount(); return value; } @Override public boolean equals(Object obj) { if (obj instanceof Goods) { Goods g = (Goods) obj; return this.getLocation() == g.getLocation() && this.getType() == g.getType() && this.getAmount() == g.getAmount(); } return false; } /** * This method writes an XML-representation of this object to * the given stream. * * @param out The target stream. * @throws XMLStreamException if there are any problems writing * to the stream. */ public void toXMLImpl(XMLStreamWriter out) throws XMLStreamException { // Start element: out.writeStartElement(getXMLElementTagName()); out.writeAttribute("type", getType().getId()); out.writeAttribute("amount", Integer.toString(getAmount())); if (location != null) { out.writeAttribute("location", location.getId()); } else { logger.warning("Creating an XML-element for a 'Goods' without a 'Location'."); } out.writeEndElement(); } /** * Initialize this object from an XML-representation of this object. * * @param in The input stream with the XML. * @throws XMLStreamException if a problem was encountered * during parsing. */ protected void readFromXMLImpl(XMLStreamReader in) throws XMLStreamException { setType(game.getSpecification().getGoodsType(in.getAttributeValue(null, "type"))); setAmount(Integer.parseInt(in.getAttributeValue(null, "amount"))); final String locationStr = in.getAttributeValue(null, "location"); if (locationStr != null) { location = (Location) getGame().getFreeColGameObject(locationStr); } in.nextTag(); } /** * Gets the tag name of the root element representing this object. * * @return "goods". */ public static String getXMLElementTagName() { return "goods"; } }