package ch.sahits.game.openpatrician.model.impl;
import java.util.HashMap;
import ch.sahits.game.openpatrician.model.IPlayer;
import ch.sahits.game.openpatrician.model.product.AmountablePrice;
import ch.sahits.game.openpatrician.model.product.IWare;
/**
* This class represents an entity that can hold wares which can be moved
* @author Andi Hotz, (c) Sahits GmbH, 2011
* Created on Dec 17, 2011
*
*/
public class WareHolding {
/** Store the amount of wares in the city in the ware specific sizes */
final HashMap<IWare, AmountablePrice> wares = new HashMap<IWare, AmountablePrice>();
public WareHolding() {
super();
}
/**
* Add a new ware to the wares list
* @param ware
*/
protected void addNewWare(IWare ware, int amount){
if (containsWare(ware)){
throw new IllegalStateException("Ware ("+ware.name()+") does already exist");
}
AmountablePrice amountable = new AmountablePrice();
amountable.add(amount, 0);
wares.put(ware, amountable);
}
/**
* Retrieve the {@link AmountablePrice} of the ware as it is stored in the
* holding
* @param ware to be retrieved
* @return AmountablePrice object
*/
public AmountablePrice getWare(IWare ware) {
if (!containsWare(ware)){
addNewWare(ware,0);
}
AmountablePrice ret = wares.get(ware);
return ret;
}
/**
* Move ware into this holding. The player may be null and is not used in this
* base implementation, but subclasses may be interested for statistical reasons.
* This method is thread save.
* @param ware to be moved
* @param amount of the ware that is moved
* @param player that initiates the moving, may be null, e.g. if the moving is initiated by a city
* @return the effective amount that was moved. The amount may be positive if something was added, negative if
* the ware was removed from the holding or zero if nothing was moved.
*/
public int move(IWare ware, int amount, IPlayer player) {
synchronized (ware) { // There is still a problem with networked solution where the model of the city is replicated.
AmountablePrice amounted = getWare(ware);
if (amount<0 && containsWare(ware) && amounted!=null && -amount>amounted.getAmount()){ // remove more than is available
amount = -amounted.getAmount(); // remove everything
}
if (amount<0 && !containsWare(ware)){
amount = 0;
}
if (!containsWare(ware)){ // If the ware does not exist add it with amount 0
new IllegalStateException("All wares should be initialized, allowed in test").printStackTrace();
}
if (amount>0){ // amount was bought
amounted.add(amount, computeAVGPrice(ware, amount));
} else { // amount sold
amounted.remove(amount);
}
return amount;
}
}
/**
* Check if there is an amountable object for this ware
* @param ware
* @return
*/
protected final boolean containsWare(IWare ware) {
return wares.containsKey(ware);
}
/**
* Compute the average price for ware that is to be purchased in the specified
* amount. The additional variable of the available amount is supplied by {@link #getWare(IWare)}.
* Subclasses may override this method.
* @param ware for which the average price is to be computed
* @param amount amount that is bought
* @return
*/
protected int computeAVGPrice(IWare ware, int amount) {
int available = getWare(ware).getAmount();
return ware.computeSellPrice(available, amount);
}
}