package joshie.harvest.town.data;
import joshie.harvest.api.buildings.Building;
import joshie.harvest.api.buildings.BuildingLocation;
import joshie.harvest.api.calendar.CalendarDate;
import joshie.harvest.api.calendar.Festival;
import joshie.harvest.api.calendar.Season;
import joshie.harvest.api.npc.NPC;
import joshie.harvest.api.quests.Quest;
import joshie.harvest.api.town.Town;
import joshie.harvest.buildings.BuildingStage;
import joshie.harvest.core.helpers.NBTHelper;
import joshie.harvest.knowledge.letter.LetterData;
import joshie.harvest.quests.data.QuestData;
import joshie.harvest.shops.data.ShopData;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.Rotation;
import net.minecraft.util.math.BlockPos;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
public abstract class TownData<Q extends QuestData, L extends LetterData> implements Town {
protected final Set<NPC> inhabitants = new HashSet<>();
protected final ShopData shops = new ShopData();
protected Map<ResourceLocation, TownBuilding> buildings = new HashMap<>();
protected LinkedList<BuildingStage> buildingQueue = new LinkedList<>();
protected Festival festival = Festival.NONE;
protected int festivalDays;
protected CalendarDate birthday;
protected Quest dailyQuest;
protected BlockPos townCentre;
protected UUID uuid;
/** Overriden to actually return what we should **/
public abstract Q getQuests();
public abstract L getLetters();
public boolean isNull() {
return false;
}
public Quest getDailyQuest() {
return dailyQuest;
}
public CalendarDate getBirthday() {
return birthday;
}
public UUID getID() {
return uuid;
}
public ShopData getShops() {
return shops;
}
public TownBuilding getBuilding(Building building) {
return buildings.get(building.getResource());
}
/** Building currently being worked on **/
public BuildingStage getCurrentlyBuilding() {
return buildingQueue.size() > 0 ? buildingQueue.getFirst() : null;
}
/** If this building is being built currently **/
public boolean isBuilding(Building building) {
if (building == null) return buildingQueue.size() > 0;
return buildingQueue.contains(new BuildingStage(building, BlockPos.ORIGIN, Rotation.NONE));
}
public boolean hasBuilding(ResourceLocation building) {
return buildings.get(building) != null;
}
@Override
public boolean hasBuilding(Building building) {
return buildings.get(building.getResource()) != null;
}
@Override
public boolean hasNPC(NPC npc) {
return getInhabitants().contains(npc);
}
public boolean hasBuildings(ResourceLocation[] buildings) {
for (ResourceLocation building: buildings) {
if (this.buildings.get(building) == null) return false;
}
return true;
}
@Override
public int getBuildingCount() {
return getBuildings().size();
}
@Override
@Nullable
public BlockPos getCoordinatesFor(@Nonnull BuildingLocation location) {
TownBuilding building = buildings.get(location.getBuilding().getResource());
return building != null ? building.getRealCoordinatesFor(location.getLocation()) : null;
}
@Override
@Nullable
public BlockPos getCoordinatesFromOffset(Building building, BlockPos offset) {
TownBuilding townBuilding = buildings.get(building.getResource());
return townBuilding != null ? townBuilding.getTransformedPosition(offset) : null;
}
@Nonnull
public Festival getFestival() {
return festival;
}
public Set<NPC> getInhabitants() {
return inhabitants;
}
public Collection<TownBuilding> getBuildings() {
return buildings.values();
}
@Nonnull
public BlockPos getTownCentre() {
return townCentre;
}
public void readFromNBT(NBTTagCompound nbt) {
if (nbt.hasKey("Created")) birthday = CalendarDate.fromNBT(nbt.getCompoundTag("Created"));
else birthday = new CalendarDate(0, Season.SPRING, 0);
shops.readFromNBT(nbt);
uuid = NBTHelper.readUUID("Town", nbt);
townCentre = NBTHelper.readBlockPos("TownCentre", nbt);
NBTHelper.readMap("TownBuildingList", TownBuilding.class, buildings, nbt);
NBTHelper.readList("CurrentlyBuilding", BuildingStage.class, buildingQueue, nbt);
for (TownBuilding building: buildings.values()) {
inhabitants.addAll(building.building.getInhabitants());
}
if (nbt.hasKey("DailyQuest")) {
dailyQuest = Quest.REGISTRY.getValue(new ResourceLocation(nbt.getString("DailyQuest")));
dailyQuest.readFromNBT(nbt.getCompoundTag("DailyQuestData"));
}
if (nbt.hasKey("Festival")) {
festival = Festival.REGISTRY.get(new ResourceLocation(nbt.getString("Festival")));
festivalDays = nbt.getInteger("FestivalDaysRemaining");
}
//Fix the broken festivla if it applies
if (festival == null) festival = Festival.NONE;
}
public NBTTagCompound writeToNBT(NBTTagCompound nbt) {
nbt.setTag("Created", birthday.toNBT());
shops.writeToNBT(nbt);
NBTHelper.writeBlockPos("TownCentre", nbt, townCentre);
NBTHelper.writeUUID("Town", nbt, uuid);
NBTHelper.writeMap("TownBuildingList", nbt, buildings);
NBTHelper.writeList("CurrentlyBuilding", nbt, buildingQueue);
if (dailyQuest != null) {
nbt.setString("DailyQuest", dailyQuest.getRegistryName().toString());
nbt.setTag("DailyQuestData", dailyQuest.writeToNBT(new NBTTagCompound()));
}
if (festival != null) {
nbt.setString("Festival", festival.getResource().toString());
nbt.setInteger("FestivalDaysRemaining", festivalDays);
}
return nbt;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TownData townData = (TownData) o;
return uuid != null ? uuid.equals(townData.uuid) : townData.uuid == null;
}
@Override
public int hashCode() {
return uuid != null ? uuid.hashCode() : 0;
}
}