/**
* 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.Collections;
import java.util.List;
import java.util.Set;
public class BuildQueue<T extends BuildableType> implements Consumer {
public static enum CompletionAction {
/**
* Always remove the completed item. Not used by any build
* queue at the moment.
*/
REMOVE,
/**
* Remove the completed item unless it is the last item and
* several instances of the item can co-exist (which is true
* for units, but not buildings). This is the strategy used by
* the colony build queue.
*/
REMOVE_EXCEPT_LAST,
/**
* Shuffle the items rather than remove the completed
* item. This is the strategy used by the colony population
* queue.
*/
SHUFFLE,
/**
* Remove the completed item and add a random new item. This
* is the strategy of the immigration queue (which is not
* implemented as a build queue at the moment, however).
*/
ADD_RANDOM
};
/** A list of Buildable items. */
private List<T> buildQueue = new ArrayList<T>();
/**
* What to do when an item has been completed.
*/
private CompletionAction completionAction = CompletionAction.REMOVE;
private int priority = COLONY_PRIORITY;
private Colony colony;
public BuildQueue(Colony colony, CompletionAction action, int priority, T... items) {
this.colony = colony;
this.completionAction = action;
this.priority = priority;
for (T type : items) {
buildQueue.add(type);
}
}
/**
* Returns the type of building currently being built.
*
* @return The type of building currently being built.
*/
public T getCurrentlyBuilding() {
return (buildQueue.isEmpty()) ? null : buildQueue.get(0);
}
/**
* Sets the current type of buildable to be built and if it is a building
* insist that there is only one in the queue.
*
* @param buildable The <code>T</code> to build.
*/
public void setCurrentlyBuilding(T buildable) {
if (buildable instanceof BuildingType && buildQueue.contains(buildable)) {
buildQueue.remove(buildable);
}
buildQueue.add(0, buildable);
}
public void clear() {
buildQueue.clear();
}
public void add(T buildable) {
buildQueue.add(buildable);
}
public List<T> getValues() {
return buildQueue;
}
public void setValues(List<T> values) {
buildQueue = values;
}
public void remove(int index) {
buildQueue.remove(index);
}
public int size() {
return buildQueue.size();
}
public boolean isEmpty() {
return buildQueue.isEmpty();
}
/**
* Get the <code>CompletionAction</code> value.
*
* @return a <code>CompletionAction</code> value
*/
public final CompletionAction getCompletionAction() {
return completionAction;
}
/**
* Set the <code>CompletionAction</code> value.
*
* @param newCompletionAction The new CompletionAction value.
*/
public final void setCompletionAction(final CompletionAction newCompletionAction) {
this.completionAction = newCompletionAction;
}
// Interface Consumer
/**
* Returns true if this Consumer consumes the given GoodsType.
*
* @param goodsType a <code>GoodsType</code> value
* @return a <code>boolean</code> value
*/
public boolean consumes(GoodsType goodsType) {
return getCurrentlyBuilding() != null
&& getCurrentlyBuilding().getAmountRequiredOf(goodsType) > 0;
}
/**
* Returns a list of GoodsTypes this Consumer consumes.
*
* @return a <code>List</code> value
*/
public List<AbstractGoods> getConsumedGoods() {
T current = getCurrentlyBuilding();
if (current == null) {
return new ArrayList<AbstractGoods>();
} else {
return current.getGoodsRequired();
}
}
/**
* Return the <code>ProductionInfo</code> for this BuildQueue.
*
* @param input the goods available
* @return the <code>ProductionInfo</code> for this BuildQueue
*/
public ProductionInfo getProductionInfo(List<AbstractGoods> input) {
ProductionInfo result = new ProductionInfo();
T current = getCurrentlyBuilding();
if (current != null) {
// ATTENTION: this code presupposes that we will consume
// all required goods at once
boolean overflow = colony.getSpecification()
.getBoolean(GameOptions.SAVE_PRODUCTION_OVERFLOW);
List<AbstractGoods> consumption = new ArrayList<AbstractGoods>();
for (AbstractGoods required : current.getGoodsRequired()) {
boolean satisfied = false;
for (AbstractGoods available : input) {
if (required.getType() == available.getType()
&& required.getAmount() <= available.getAmount()) {
int amount = (overflow || required.getType().isStorable())
? required.getAmount()
: available.getAmount();
consumption.add(new AbstractGoods(required.getType(), amount));
satisfied = true;
break;
}
}
if (!satisfied) {
// don't build anything
return result;
}
}
result.setConsumption(consumption);
}
return result;
}
/**
* The priority of this Consumer. The higher the priority, the
* earlier will the Consumer be allowed to consume the goods it
* requires.
*
* @return an <code>int</code> value
*/
public int getPriority() {
return priority;
}
/**
* Returns whether the consumer has the ability with the given
* id. The two abilities most relevant to consumers are
* "consumeAllOrNothing", which implies that the consumer will not
* consume any goods if its requirements can not be met (used by
* the Colony when building), as well as
* "consumeOnlySurplusProduction", which implies that the consumer
* does not consume stored goods (used by the country and stables).
*
* @param id a <code>String</code> value
* @return a <code>boolean</code> value
*/
public boolean hasAbility(String id) {
return Ability.CONSUME_ALL_OR_NOTHING.equals(id);
}
/**
* {@inheritDoc}
*/
public Set<Modifier> getModifierSet(String id) {
return Collections.emptySet();
}
@Override
public String toString() {
String result = "BuildQueue:";
for (BuildableType item : buildQueue) {
result += " " + item.getId();
}
result += " [" + colony.getName() + "]";
return result;
}
}