package org.mafagafogigante.dungeon.entity.items;
import org.mafagafogigante.dungeon.date.Date;
import org.mafagafogigante.dungeon.entity.creatures.CorpseItemPresetFactory;
import org.mafagafogigante.dungeon.entity.creatures.Creature;
import org.mafagafogigante.dungeon.game.Id;
import org.mafagafogigante.dungeon.logging.DungeonLogger;
import org.jetbrains.annotations.NotNull;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Provides methods to create different items for the game.
*/
public final class ItemFactory implements Serializable {
private final Map<Id, ItemPreset> itemPresets = new HashMap<>();
private ItemFactoryRestrictions restrictions;
// The flag that indicates we have already refreshed this ItemFactory with the resource files.
// An ItemFactory is refreshed after construction, but not after deserialization.
private transient boolean refreshed = true;
/**
* Constructs an ItemFactory from one or more ItemPresetFactories.
*/
public ItemFactory(@NotNull ItemPresetFactory... itemPresetFactories) {
for (ItemPresetFactory itemPresetFactory : itemPresetFactories) {
addAllPresets(itemPresetFactory.getItemPresets());
}
createUniquenessRestrictions();
}
private Object readResolve() throws ObjectStreamException {
refreshed = false;
return this;
}
/**
* Iterates over all presets of a Collection, adding them to this factory after they are validated.
*/
private void addAllPresets(Collection<ItemPreset> presets) {
for (ItemPreset preset : presets) {
Id id = preset.getId();
if (itemPresets.containsKey(id)) {
throw new IllegalArgumentException("factory already contains a preset with the Id " + preset.getId() + ".");
}
itemPresets.put(id, preset);
}
}
private void createUniquenessRestrictions() {
Set<Id> uniqueIds = new HashSet<>();
for (ItemPreset itemPreset : getItemPresets().values()) {
if (itemPreset.isUnique()) {
uniqueIds.add(itemPreset.getId());
}
}
restrictions = new UniquenessRestrictions(uniqueIds);
}
/**
* Returns an unmodifiable view of the ItemPreset map.
*/
private Map<Id, ItemPreset> getItemPresets() {
if (!refreshed) {
refreshItemPresets();
}
return Collections.unmodifiableMap(itemPresets);
}
/**
* Returns whether or not this ItemFactory can make an Item with the specified Id based on its restrictions.
*/
public boolean canMakeItem(@NotNull Id id) {
return restrictions.canMakeItem(id);
}
/**
* Attempts to create an item from the ItemPreset specified by an ID with the provided creation date.
*
* <p>The caller should ensure that this ItemFactory can make this item after taking its restrictions into account by
* calling canMakeItem with this Id.
*
* @param id the ID of the preset, not null
* @param date the creation date of the item, not null
* @return an Item with the specified creation date
*/
public Item makeItem(@NotNull Id id, @NotNull Date date) {
ItemPreset itemPreset = getItemPresets().get(id);
if (itemPreset == null) {
throw new IllegalArgumentException("id (" + id + ") does not correspond to an ItemPreset.");
}
Item item = new Item(itemPreset, date);
restrictions.registerItem(item.getId());
return item;
}
private void refreshItemPresets() {
DungeonLogger.info("Refreshing item presets.");
ItemPresetFactory jsonItemPresetFactory = new JsonItemPresetFactory("items.json");
for (ItemPreset preset : jsonItemPresetFactory.getItemPresets()) {
if (!itemPresets.containsKey(preset.getId())) {
itemPresets.put(preset.getId(), preset);
}
}
refreshed = true;
}
/**
* Makes a corpse from the provided Creature. The creation Date of the corpse should be the Date of death.
*
* @param creature the Creature object
* @param date the Date when the Creature died
* @return an Item that represents the corpse of the Creature
*/
public Item makeCorpse(Creature creature, Date date) {
if (!creature.hasTag(Creature.Tag.CORPSE)) {
throw new AssertionError("Called makeCorpse for Creature that does not have the CORPSE tag!");
}
// Corpses should never be restricted.
return makeItem(CorpseItemPresetFactory.makeCorpseIdFromCreatureId(creature.getId()), date);
}
}