package joshie.harvest.quests.town.festivals.contest;
import com.google.common.collect.Lists;
import joshie.harvest.api.npc.NPC;
import joshie.harvest.buildings.HFBuildings;
import joshie.harvest.core.helpers.EntityHelper;
import joshie.harvest.core.helpers.NBTHelper;
import joshie.harvest.quests.town.festivals.Place;
import joshie.harvest.town.TownHelper;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
public abstract class ContestEntries<O, E extends ContestEntry, Q extends QuestContest> {
protected final List<E> entries = new ArrayList<>();
protected final BlockPos[] locations;
protected final NPC[] npcs;
protected Set<UUID> selecting = new HashSet<>();
protected List<Pair<String, Integer>> entryNames;
protected Set<NPC> usedNPCS;
public ContestEntries(BlockPos[] locations, NPC[] npcs) {
this.locations = locations;
this.npcs = npcs;
}
public void setEntryNames(List<Pair<String, Integer>> list) {
this.entryNames = list;
}
public List<Pair<String, Integer>> getNames() {
return entryNames;
}
public Set<UUID> getSelecting() {
return selecting;
}
public E getEntry(Place place) {
return entries.get(place.ordinal());
}
public NPC[] getNPCs() {
return npcs;
}
public void complete(World world) {}
@Nullable
E getEntryFromStall(int stall) {
for (E entry: entries) {
if (entry.getStall() == stall) return entry;
}
return null;
}
protected void validateExistingEntries(World world) {
Iterator<E> it = entries.iterator();
while (it.hasNext()) {
E entry = it.next();
if (entry.isInvalid(world)) {
it.remove(); //Remove the entries as they are no longer valid
}
}
}
@Nullable
BlockPos getLocationFromNPC(@Nonnull NPC npc) {
for (E entry: entries) {
if (entry.getNPC() == npc) {
return locations[entry.getStall() - 1];
}
}
return null;
}
protected abstract void createEntry(EntityPlayer player, World world, BlockPos pos, int stall);
@SuppressWarnings("all")
public static <O> O getNextEntry(EntityPlayer player, Set<O> used, O... o) {
List<O> names = Lists.newArrayList(o);
Collections.shuffle(names);
for (O name: names) {
if (!used.contains(name) && isValid(player, name)) {
used.add(name);
return name;
}
}
return o[0];
}
private static boolean isValid(EntityPlayer player, Object o) {
return !(o instanceof NPC) || TownHelper.getClosestTownToEntity(player, false).hasNPC((NPC)o);
}
public void startContest(EntityPlayer player) {
World world = player.worldObj;
if (entries.size() < 4) {
usedNPCS = new HashSet<>();
for (int i = 1; i <= 4 && entries.size() < 4; i++) {
if (!isEntered(i)) {
BlockPos pos = TownHelper.getClosestTownToEntity(player, false).getCoordinatesFromOffset(HFBuildings.FESTIVAL_GROUNDS, locations[i - 1]);
createEntry(player, world, pos, i);
}
}
}
}
@SuppressWarnings("unchecked")
public void sort(Q quest, World world) {
entries.sort((o1, o2) -> ((Integer)o2.getScore(quest, world)).compareTo(o1.getScore(quest, world)));
}
public abstract List<Pair<O, Integer>> getAvailableEntries(EntityPlayer player);
public abstract void enter(EntityPlayer player, O key, int value);
public boolean isSelecting(EntityPlayer player) {
return selecting.contains(EntityHelper.getPlayerUUID(player));
}
public boolean isEntered(EntityPlayer player) {
UUID uuid = EntityHelper.getEntityUUID(player);
for (E entry: entries) {
if (uuid.equals(entry.getPlayerUUID())) return true;
}
return false;
}
protected boolean isEntered(int stall) {
for (E entry: entries) {
if (stall == entry.getStall()) return true;
}
return false;
}
public abstract List<Pair<String, Integer>> getAvailableEntryNames(EntityPlayer player);
protected abstract E fromNBT(NBTTagCompound tag);
public void readFromNBT(NBTTagCompound nbt) {
entries.clear(); //Read in the player entries
NBTTagList entryList = nbt.getTagList("Entries", 10);
for (int i = 0; i < entryList.tagCount(); i++) {
NBTTagCompound tag = entryList.getCompoundTagAt(i);
E entry = fromNBT(tag);
if (entry != null) {
entries.add(entry);
}
}
selecting = NBTHelper.readUUIDSet(nbt, "Selecting");
}
public NBTTagCompound writeToNBT(NBTTagCompound nbt) {
NBTTagList entryList = new NBTTagList();
for (E entry: entries) {
entryList.appendTag(entry.toNBT());
}
nbt.setTag("Entries", entryList);
NBTHelper.writeUUIDSet(nbt, "Selecting", selecting);
return nbt;
}
}