/** * 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 org.freecolandroid.xml.stream.XMLStreamException; import org.freecolandroid.xml.stream.XMLStreamReader; import org.freecolandroid.xml.stream.XMLStreamWriter; public final class GoodsType extends FreeColGameObjectType { private boolean isFarmed; private boolean isFood; private boolean ignoreLimit; private boolean newWorldGoods; /** * Whether this type of goods is required for building. */ private boolean buildingMaterial; /** * Whether this type of goods is required for building equipment * that grants an offence bonus or defence bonus. */ private boolean militaryGoods; /** * Whether these are trade goods that can only be obtained in * Europe. */ private boolean tradeGoods; /** * Whether this type of goods can be stored in a warehouse. */ private boolean storable; private GoodsType madeFrom; private GoodsType makes; private GoodsType storedAs; private int initialAmount; private int initialPrice; private int priceDiff; /** * The number of units required to breed this type of goods. This * obviously only applies to animals. */ private int breedingNumber = INFINITY; /** * The price of this type of goods. This is only used for goods * that can not be traded in the market, such as hammers. */ private int price = INFINITY; // ----------------------------------------------------------- constructors public GoodsType(String id, Specification specification) { super(id, specification); } // ----------------------------------------------------------- retriveal methods public StringTemplate getLabel(boolean sellable) { return StringTemplate.key(getNameKey()); } public boolean isRawMaterial() { return makes != null; } public boolean isRefined() { return madeFrom != null; } public GoodsType getRawMaterial() { return madeFrom; } public GoodsType getProducedMaterial() { return makes; } public boolean isFarmed() { return isFarmed; } public boolean limitIgnored() { return ignoreLimit; } public boolean isNewWorldGoodsType() { return newWorldGoods; } public boolean isNewWorldLuxuryType() { return (madeFrom != null && madeFrom.isNewWorldGoodsType()); } public final String getWorkingAsKey() { return getId() + ".workingAs"; } /** * Get the <code>ImmigrationType</code> value. * * @return a <code>boolean</code> value */ public boolean isImmigrationType() { return !getModifierSet("model.modifier.immigration").isEmpty(); } /** * Get the <code>LibertyType</code> value. * * @return a <code>boolean</code> value */ public boolean isLibertyType() { return !getModifierSet("model.modifier.liberty").isEmpty(); } public boolean isStorable() { return storable; } public boolean isStoredAs() { return storedAs!=null; } public GoodsType getStoredAs() { if (storedAs==null) { return this; } else { return storedAs; } } public int getInitialAmount() { return initialAmount; } public int getInitialSellPrice() { return initialPrice; } public int getInitialBuyPrice() { return initialPrice + priceDiff; } public int getPriceDifference() { return priceDiff; } // TODO: give this some meaning // Originally intended for when there are no static variables public boolean isFoodType() { return isFood; } public GoodsType outputType() { return makes; } public GoodsType inputType() { return madeFrom; } /** * Returns true if this type of goods is required for building a * BuildableType. * * @return a <code>boolean</code> value * @see BuildableType */ public boolean isBuildingMaterial() { return buildingMaterial; } /** * Set the <code>BuildingMaterial</code> value. * * @param newBuildingMaterial The new BuildingMaterial value. */ public void setBuildingMaterial(final boolean newBuildingMaterial) { this.buildingMaterial = newBuildingMaterial; } /** * Returns the production chain of the goods type, beginning with * a raw material that can not be produced from any other. The * last element of the production chain is the goods type itself. * * @return the production chain of the goods type */ public List<GoodsType> getProductionChain() { List<GoodsType> result = new ArrayList<GoodsType>(); GoodsType currentGoods = this; while (currentGoods != null) { result.add(0, currentGoods); currentGoods = currentGoods.madeFrom; } return result; } /** * Returns true if this type of goods is required for producing a * type of goods required for building a BuildableType. * * @return a <code>boolean</code> value * @see BuildableType */ public boolean isRawBuildingMaterial() { if (this.madeFrom!=null) { return false; } GoodsType refinedType = makes; while (refinedType != null) { if (refinedType.isBuildingMaterial()) { return true; } else { refinedType = refinedType.makes; } } return false; } /** * Get the <code>MilitaryGoods</code> value. * * @return a <code>boolean</code> value */ public boolean isMilitaryGoods() { return militaryGoods; } /** * Set the <code>MilitaryGoods</code> value. * * @param newMilitaryGoods The new MilitaryGoods value. */ public void setMilitaryGoods(final boolean newMilitaryGoods) { this.militaryGoods = newMilitaryGoods; } /** * Get the <code>TradeGoods</code> value. * * @return a <code>boolean</code> value */ public boolean isTradeGoods() { return tradeGoods; } /** * Whether this type of goods produces liberty points. * * @return a <code>boolean</code> value */ public boolean isLibertyGoodsType() { return getFeatureContainer().containsModifierKey("model.modifier.liberty"); } /** * Whether this type of goods causes immigration. * * @return a <code>boolean</code> value */ public boolean isImmigrationGoodsType() { return getFeatureContainer().containsModifierKey("model.modifier.immigration"); } /** * Get the <code>BreedingNumber</code> value. * * @return an <code>int</code> value */ public int getBreedingNumber() { return breedingNumber; } /** * Set the <code>BreedingNumber</code> value. * * @param newBreedingNumber The new BreedingNumber value. */ public void setBreedingNumber(final int newBreedingNumber) { this.breedingNumber = newBreedingNumber; } /** * Returns <code>true</code> if this type of Goods is * breedable. This should only be true for animals, such as * horses. * * @return a <code>boolean</code> value */ public boolean isBreedable() { return breedingNumber != INFINITY; } /** * Get the <code>Price</code> value. * * @return an <code>int</code> value */ public int getPrice() { return price; } /** * Set the <code>Price</code> value. * * @param newPrice The new Price value. */ public void setPrice(final int newPrice) { this.price = newPrice; } /** * Makes an XML-representation of this object. * * @param out The output stream. * @throws XMLStreamException if there are any problems writing to the * stream. */ protected void toXMLImpl(XMLStreamWriter out) throws XMLStreamException { super.toXML(out, getXMLElementTagName()); } /** * Write the attributes of this object to a stream. * * @param out The target stream. * @throws XMLStreamException if there are any problems writing to * the stream. */ @Override protected void writeAttributes(XMLStreamWriter out) throws XMLStreamException { super.writeAttributes(out); out.writeAttribute("is-farmed", Boolean.toString(isFarmed)); out.writeAttribute("is-food", Boolean.toString(isFood)); out.writeAttribute("ignore-limit", Boolean.toString(ignoreLimit)); out.writeAttribute("new-world-goods", Boolean.toString(newWorldGoods)); out.writeAttribute("trade-goods", Boolean.toString(tradeGoods)); out.writeAttribute("storable", Boolean.toString(storable)); if (breedingNumber != INFINITY) { out.writeAttribute("breeding-number", Integer.toString(breedingNumber)); } if (price != INFINITY) { out.writeAttribute("price", Integer.toString(price)); } if (madeFrom != null) { out.writeAttribute("made-from", madeFrom.getId()); } if (storedAs != null) { out.writeAttribute("stored-as", storedAs.getId()); } } /** * Write the children of this object to a stream. * * @param out The target stream. * @throws XMLStreamException if there are any problems writing to * the stream. */ @Override protected void writeChildren(XMLStreamWriter out) throws XMLStreamException { super.writeChildren(out); if (initialAmount > 0) { out.writeStartElement("market"); out.writeAttribute("initial-amount", Integer.toString(initialAmount)); out.writeAttribute("initial-price", Integer.toString(initialPrice)); out.writeAttribute("price-difference", Integer.toString(priceDiff)); out.writeEndElement(); } } /** * Reads the attributes of this object from an XML stream. * * @param in The XML input stream. * @throws XMLStreamException if a problem was encountered * during parsing. */ @Override protected void readAttributes(XMLStreamReader in) throws XMLStreamException { super.readAttributes(in); isFarmed = getAttribute(in, "is-farmed", false); isFood = getAttribute(in, "is-food", false); ignoreLimit = getAttribute(in, "ignore-limit", false); newWorldGoods = getAttribute(in, "new-world-goods", false); tradeGoods = getAttribute(in, "trade-goods", false); breedingNumber = getAttribute(in, "breeding-number", INFINITY); price = getAttribute(in, "price", INFINITY); madeFrom = getSpecification().getType(in, "made-from", GoodsType.class, null); if (madeFrom != null) { madeFrom.makes = this; } storable = getAttribute(in, "storable", true); storedAs = getSpecification().getType(in, "stored-as", GoodsType.class, null); } /** * Reads a child object. * * @param in The XML stream to read. * @exception XMLStreamException if an error occurs */ @Override protected void readChild(XMLStreamReader in) throws XMLStreamException { String childName = in.getLocalName(); if ("market".equals(childName)) { initialAmount = Integer.parseInt(in.getAttributeValue(null, "initial-amount")); initialPrice = getAttribute(in, "initial-price", 1); priceDiff = getAttribute(in, "price-difference", 1); in.nextTag(); // close this element } else { super.readChild(in); } } /** * Returns the tag name of the root element representing this object. * * @return "goods-type". */ public static String getXMLElementTagName() { return "goods-type"; } }