package javastory.game;
import java.io.Serializable;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
public class Inventory implements Iterable<Item>, Serializable {
/**
*
*/
private static final long serialVersionUID = 4705767500488434915L;
private static final int MAX_CAPACITY = 96;
//
private final Map<Short, Item> inventory;
private byte capacity = 0;
private final InventoryType type;
/** Creates a new instance of Inventory */
public Inventory(final InventoryType type) {
this.inventory = Maps.newHashMap();
this.type = type;
}
public void addSlot(final byte slot) {
this.capacity += slot;
if (this.capacity > MAX_CAPACITY) {
this.capacity = MAX_CAPACITY;
}
}
public byte getSlotLimit() {
return this.capacity;
}
public void setSlotLimit(byte slot) {
if (slot > MAX_CAPACITY) {
slot = MAX_CAPACITY;
}
this.capacity = slot;
}
public Item findById(final int itemId) {
for (final Item item : this.inventory.values()) {
if (item.getItemId() == itemId) {
return item;
}
}
return null;
}
public int countById(final int itemId) {
int quantity = 0;
for (final Item item : this.inventory.values()) {
if (item.getItemId() == itemId) {
quantity += item.getQuantity();
}
}
return quantity;
}
public List<Item> listById(final int itemId) {
final List<Item> ret = Lists.newArrayList();
for (final Item item : this.inventory.values()) {
if (item.getItemId() == itemId) {
ret.add(item);
}
}
// the linkedhashmap does impose insert order as returned order but we
// can not guarantee that this is still the
// correct order - blargh, we could empty the map and reinsert in the
// correct order after each inventory
// addition, or we could use an array/list, it's only 255 entries
// anyway...
if (ret.size() > 1) {
Collections.sort(ret);
}
return ret;
}
public short addItem(final Item item) {
final short slotId = this.getNextFreeSlot();
if (slotId < 0) {
return -1;
}
this.inventory.put(slotId, item);
item.setPosition(slotId);
return slotId;
}
public void addFromDb(final Item item) {
if (item.getPosition() < 0 && !this.type.equals(InventoryType.EQUIPPED)) {
// This causes a lot of stuck problem, until we are done with
// position checking
return;
}
this.inventory.put(item.getPosition(), item);
}
public void move(final short sSlot, final short dSlot, final short slotMax) {
if (dSlot > this.capacity) {
return;
}
final Item source = this.inventory.get(sSlot);
final Item target = this.inventory.get(dSlot);
if (source == null) {
throw new IllegalStateException("The source slot is empty.");
}
if (target == null) {
source.setPosition(dSlot);
this.inventory.put(dSlot, source);
this.inventory.remove(sSlot);
} else if (target.getItemId() == source.getItemId()
&& !GameConstants.isThrowingStar(source.getItemId())
&& !GameConstants.isBullet(source.getItemId())) {
if (this.type.asNumber() == InventoryType.EQUIP.asNumber()) {
this.swap(target, source);
}
if (source.getQuantity() + target.getQuantity() > slotMax) {
source.setQuantity((short) (source.getQuantity()
+ target.getQuantity() - slotMax));
target.setQuantity(slotMax);
} else {
target.setQuantity((short) (source.getQuantity()
+ target.getQuantity()));
this.inventory.remove(sSlot);
}
} else {
this.swap(target, source);
}
}
private void swap(final Item source, final Item target) {
this.inventory.remove(source.getPosition());
this.inventory.remove(target.getPosition());
final short swapPos = source.getPosition();
source.setPosition(target.getPosition());
target.setPosition(swapPos);
this.inventory.put(source.getPosition(), source);
this.inventory.put(target.getPosition(), target);
}
public Item getItem(final short slot) {
return this.inventory.get(slot);
}
public void removeItem(final short slot) {
this.removeItem(slot, (short) 1, false);
}
public void removeItem(final short slot, final short quantity, final boolean allowZero) {
final Item item = this.inventory.get(slot);
if (item == null) { // TODO is it ok not to throw an exception here?
return;
}
item.setQuantity((short) (item.getQuantity() - quantity));
if (item.getQuantity() < 0) {
item.setQuantity((short) 0);
}
if (item.getQuantity() == 0 && !allowZero) {
this.removeSlot(slot);
}
}
public void removeSlot(final short slot) {
this.inventory.remove(slot);
}
public boolean isFull() {
return this.inventory.size() >= this.capacity;
}
public boolean isFull(final int margin) {
return this.inventory.size() + margin >= this.capacity;
}
public short getNextFreeSlot() {
if (this.isFull()) {
return -1;
}
for (short i = 1; i <= this.capacity; i++) {
if (!this.inventory.keySet().contains(i)) {
return i;
}
}
return -1;
}
public short getNumFreeSlot() {
if (this.isFull()) {
return 0;
}
byte free = 0;
for (short i = 1; i <= this.capacity; i++) {
if (!this.inventory.keySet().contains(i)) {
free++;
}
}
return free;
}
public InventoryType getType() {
return this.type;
}
@Override
public Iterator<Item> iterator() {
return Collections.unmodifiableCollection(this.inventory.values())
.iterator();
}
}