/*
OrpheusMS: MapleStory Private Server based on OdinMS
Copyright (C) 2012 Aaron Weiss
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package client;
import constants.ItemConstants;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
*
* @author Matze
*/
public class MapleInventory implements Iterable<IItem> {
private Map<Byte, IItem> inventory = new LinkedHashMap<Byte, IItem>();
private byte slotLimit;
private MapleInventoryType type;
private boolean checked = false;
public MapleInventory(MapleInventoryType type, byte slotLimit) {
this.inventory = new LinkedHashMap<Byte, IItem>();
this.type = type;
this.slotLimit = slotLimit;
}
public boolean isExtendableInventory() { // not sure about cash, basing this
// on the previous one.
return !(type.equals(MapleInventoryType.UNDEFINED) || type.equals(MapleInventoryType.EQUIPPED) || type.equals(MapleInventoryType.CASH));
}
public boolean isEquipInventory() {
return type.equals(MapleInventoryType.EQUIP) || type.equals(MapleInventoryType.EQUIPPED);
}
public byte getSlotLimit() {
return slotLimit;
}
public void setSlotLimit(int newLimit) {
slotLimit = (byte) newLimit;
}
public IItem findById(int itemId) {
for (IItem item : inventory.values()) {
if (item.getItemId() == itemId) {
return item;
}
}
return null;
}
public int countById(int itemId) {
int possesed = 0;
for (IItem item : inventory.values()) {
if (item.getItemId() == itemId) {
possesed += item.getQuantity();
}
}
return possesed;
}
public List<IItem> listById(int itemId) {
List<IItem> ret = new ArrayList<IItem>();
for (IItem item : inventory.values()) {
if (item.getItemId() == itemId) {
ret.add(item);
}
}
if (ret.size() > 1) {
Collections.sort(ret);
}
return ret;
}
public Collection<IItem> list() {
return inventory.values();
}
public byte addItem(IItem item) {
byte slotId = getNextFreeSlot();
if (slotId < 0) {
return -1;
}
inventory.put(slotId, item);
item.setPosition(slotId);
return slotId;
}
public void addFromDB(IItem item) {
if (item.getPosition() < 0 && !type.equals(MapleInventoryType.EQUIPPED)) {
throw new RuntimeException("Item with negative position in non-equipped IV wtf?");
}
inventory.put(item.getPosition(), item);
}
public void move(byte sSlot, byte dSlot, short slotMax) {
Item source = (Item) inventory.get(sSlot);
Item target = (Item) inventory.get(dSlot);
if (source == null) {
throw new RuntimeException("Trying to move empty slot");
}
if (target == null) {
source.setPosition(dSlot);
inventory.put(dSlot, source);
inventory.remove(sSlot);
} else if (target.getItemId() == source.getItemId() && !ItemConstants.isRechargable(source.getItemId())) {
if (type.getType() == MapleInventoryType.EQUIP.getType()) {
swap(target, source);
}
if (source.getQuantity() + target.getQuantity() > slotMax) {
short rest = (short) ((source.getQuantity() + target.getQuantity()) - slotMax);
source.setQuantity(rest);
target.setQuantity(slotMax);
} else {
target.setQuantity((short) (source.getQuantity() + target.getQuantity()));
inventory.remove(sSlot);
}
} else {
swap(target, source);
}
}
private void swap(IItem source, IItem target) {
inventory.remove(source.getPosition());
inventory.remove(target.getPosition());
byte swapPos = source.getPosition();
source.setPosition(target.getPosition());
target.setPosition(swapPos);
inventory.put(source.getPosition(), source);
inventory.put(target.getPosition(), target);
}
public IItem getItem(byte slot) {
return inventory.get(slot);
}
public void removeItem(byte slot) {
removeItem(slot, (short) 1, false);
}
public void removeItem(byte slot, short quantity, boolean allowZero) {
IItem item = 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) {
removeSlot(slot);
}
}
public void removeSlot(byte slot) {
inventory.remove(slot);
}
public boolean isFull() {
return inventory.size() >= slotLimit;
}
public boolean isFull(int margin) {
return inventory.size() + margin >= slotLimit;
}
public byte getNextFreeSlot() {
if (isFull()) {
return -1;
}
for (byte i = 1; i <= slotLimit; i++) {
if (!inventory.keySet().contains(i)) {
return i;
}
}
return -1;
}
public byte getNumFreeSlot() {
if (isFull()) {
return 0;
}
byte free = 0;
for (byte i = 1; i <= slotLimit; i++) {
if (!inventory.keySet().contains(i)) {
free++;
}
}
return free;
}
public MapleInventoryType getType() {
return type;
}
@Override
public Iterator<IItem> iterator() {
return Collections.unmodifiableCollection(inventory.values()).iterator();
}
public Collection<MapleInventory> allInventories() {
return Collections.singletonList(this);
}
public IItem findByCashId(int cashId) {
boolean isRing = false;
IEquip equip = null;
for (IItem item : inventory.values()) {
if (item.getType() == IItem.EQUIP) {
equip = (IEquip) item;
isRing = equip.getRingId() > -1;
}
if ((item.getPetId() > -1 ? item.getPetId() : isRing ? equip.getRingId() : item.getCashId()) == cashId)
return item;
}
return null;
}
public boolean checked() {
return checked;
}
public void checked(boolean yes) {
checked = yes;
}
}