/**
* 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.HashMap;
import java.util.List;
import java.util.Map;
public class ProductionMap {
public class ProductionTree {
/**
* The abstract goods all other types of goods in this tree are
* finally stored as.
*/
private AbstractGoods root;
/**
* The abstract goods that are actually produced.
*/
private List<AbstractGoods> leafs;
public ProductionTree(AbstractGoods root, AbstractGoods... leafs) {
if (leafs.length > 0) {
this.leafs = new ArrayList<AbstractGoods>();
int amount = root.getAmount();
for (AbstractGoods leaf : leafs) {
this.leafs.add(new AbstractGoods(leaf));
amount += leaf.getAmount();
}
this.root = new AbstractGoods(root.getType(), amount);
} else {
this.root = new AbstractGoods(root);
}
}
/**
* Get the <code>Root</code> value.
*
* @return an <code>AbstractGoods</code> value
*/
public final AbstractGoods getRoot() {
return root;
}
/**
* Set the <code>Root</code> value.
*
* @param newRoot The new Root value.
*/
public final void setRoot(final AbstractGoods newRoot) {
this.root = newRoot;
}
/**
* Get the <code>Leafs</code> value.
*
* @return a <code>List<AbstractGoods></code> value
*/
public final List<AbstractGoods> getLeafs() {
return leafs;
}
/**
* Set the <code>Leafs</code> value.
*
* @param newLeafs The new Leafs value.
*/
public final void setLeafs(final List<AbstractGoods> newLeafs) {
this.leafs = newLeafs;
}
public void add(AbstractGoods goods) {
if (goods.getType().getStoredAs() != root.getType()) {
throw new IllegalArgumentException(goods.getType().getId() + " is not stored as "
+ root.getType());
} else {
for (AbstractGoods leaf : leafs) {
if (leaf.getType() == goods.getType()) {
leaf.setAmount(leaf.getAmount() + goods.getAmount());
root.setAmount(root.getAmount() + goods.getAmount());
return;
}
}
leafs.add(new AbstractGoods(goods));
root.setAmount(root.getAmount() + goods.getAmount());
}
}
public int remove(AbstractGoods goods) {
int consumed = goods.getAmount();
if (goods.getType() == root.getType()) {
if (consumed > root.getAmount()) {
consumed = root.getAmount();
root.setAmount(0);
} else {
root.setAmount(root.getAmount() - consumed);
}
for (AbstractGoods leaf : leafs) {
leaf.setAmount(Math.min(leaf.getAmount(), root.getAmount()));
}
} else {
for (AbstractGoods leaf : leafs) {
if (leaf.getType() == goods.getType()) {
if (consumed > leaf.getAmount()) {
consumed = leaf.getAmount();
leaf.setAmount(0);
} else {
leaf.setAmount(leaf.getAmount() - consumed);
}
root.setAmount(root.getAmount() - consumed);
break;
}
}
}
return consumed;
}
public AbstractGoods get(GoodsType type) {
if (root.getType() == type) {
return root;
} else {
for (AbstractGoods leaf : leafs) {
if (leaf.getType() == type) {
return new AbstractGoods(type, leaf.getAmount());
}
}
}
return null;
}
}
private Map<GoodsType, Object> cache = new HashMap<GoodsType, Object>();
public AbstractGoods get(GoodsType type) {
Object value = cache.get(type);
if (value == null) {
return new AbstractGoods(type, 0);
} else if (value instanceof Integer) {
return new AbstractGoods(type, (Integer) value);
} else {
return ((ProductionTree) value).get(type);
}
}
public void add(AbstractGoods goods) {
GoodsType goodsType = goods.getType();
Object value = cache.get(goodsType);
if (value == null) {
// no entry yet
GoodsType rootType = goodsType.getStoredAs();
if (rootType == goodsType) {
cache.put(goodsType, goods.getAmount());
} else {
// is leaf of production tree
value = cache.get(rootType);
if (value instanceof ProductionTree) {
// entry is already present
((ProductionTree) value).add(goods);
} else {
// add new root entry
Integer amount = (value == null) ? 0 : (Integer) value;
value = new ProductionTree(new AbstractGoods(rootType, amount), goods);
cache.put(rootType, value);
}
// add the same entry for the goods type itself
cache.put(goodsType, value);
}
} else if (value instanceof Integer) {
cache.put(goodsType, (Integer) value + goods.getAmount());
} else {
((ProductionTree) value).add(goods);
}
}
public void remove(AbstractGoods goods) {
Object value = cache.get(goods.getType());
if (value instanceof ProductionTree) {
((ProductionTree) value).remove(goods);
} else {
add(new AbstractGoods(goods.getType(), -goods.getAmount()));
}
}
public void add(List<AbstractGoods> goods) {
for (AbstractGoods g : goods) {
add(g);
}
}
public void remove(List<AbstractGoods> goods) {
for (AbstractGoods g : goods) {
remove(g);
}
}
}