// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.server.spawning.wrappers;

import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import java.util.logging.Level;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import com.hypixel.hytale.server.spawning.SpawningPlugin;
import com.hypixel.hytale.server.npc.NPCPlugin;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.server.core.universe.world.chunk.BlockChunk;
import com.hypixel.hytale.server.spawning.SpawningContext;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.modules.time.WorldTimeResource;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.ComponentAccessor;
import javax.annotation.Nullable;
import com.hypixel.hytale.server.core.modules.blockset.BlockSetModule;
import it.unimi.dsi.fastutil.ints.IntSet;
import com.hypixel.hytale.server.spawning.assets.spawns.LightType;
import java.util.HashSet;
import java.util.Set;
import com.hypixel.hytale.server.spawning.util.LightRangePredicate;
import com.hypixel.hytale.server.spawning.assets.spawns.config.RoleSpawnParameters;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.spawning.assets.spawns.config.NPCSpawn;

public abstract class SpawnWrapper<T extends NPCSpawn>
{
    protected final int spawnIndex;
    @Nonnull
    protected final T spawn;
    protected Int2ObjectMap<RoleSpawnParameters> roles;
    protected final LightRangePredicate lightRangePredicate;
    protected final Set<String> invalidNPCs;
    
    public SpawnWrapper(final int spawnIndex, @Nonnull final T spawn) {
        this.lightRangePredicate = new LightRangePredicate();
        this.invalidNPCs = new HashSet<String>();
        this.spawnIndex = spawnIndex;
        this.spawn = spawn;
        for (final LightType lightType : LightType.VALUES) {
            this.lightRangePredicate.setLightRange(lightType, spawn.getLightRange(lightType));
        }
        this.addRoles();
    }
    
    @Nonnull
    public T getSpawn() {
        return this.spawn;
    }
    
    public Int2ObjectMap<RoleSpawnParameters> getRoles() {
        return this.roles;
    }
    
    @Nullable
    public IntSet getSpawnBlockSet(final int roleIndex) {
        final int spawnBlockSet = this.roles.get(roleIndex).getSpawnBlockSetIndex();
        return (spawnBlockSet >= 0) ? BlockSetModule.getInstance().getBlockSets().get(spawnBlockSet) : null;
    }
    
    public int getSpawnFluidTag(final int roleIndex) {
        return this.roles.get(roleIndex).getSpawnFluidTagIndex();
    }
    
    public int getSpawnIndex() {
        return this.spawnIndex;
    }
    
    @Nonnull
    public LightRangePredicate getLightRangePredicate() {
        return this.lightRangePredicate;
    }
    
    public boolean hasInvalidNPC(final String name) {
        return this.invalidNPCs.contains(name);
    }
    
    public boolean spawnParametersMatch(@Nonnull final ComponentAccessor<EntityStore> componentAccessor) {
        final World world = componentAccessor.getExternalData().getWorld();
        final WorldTimeResource worldTimeResource = componentAccessor.getResource(WorldTimeResource.getResourceType());
        final double[] dayTimeRange = this.spawn.getDayTimeRange();
        final int[] moonPhaseRange = this.spawn.getMoonPhaseRange();
        final boolean withinTimeRange = this.spawn.isScaleDayTimeRange() ? worldTimeResource.isScaledDayTimeWithinRange(dayTimeRange[0], dayTimeRange[1]) : worldTimeResource.isDayTimeWithinRange(dayTimeRange[0], dayTimeRange[1]);
        return withinTimeRange && worldTimeResource.isMoonPhaseWithinRange(world, moonPhaseRange[0], moonPhaseRange[1]);
    }
    
    public boolean shouldDespawn(@Nonnull final World world, @Nonnull final WorldTimeResource timeManager) {
        final NPCSpawn.DespawnParameters despawnParams = this.spawn.getDespawnParameters();
        if (despawnParams == null) {
            return false;
        }
        final double[] dayTimeRange = despawnParams.getDayTimeRange();
        final int[] moonPhaseRange = despawnParams.getMoonPhaseRange();
        final boolean withinTimeRange = this.spawn.isScaleDayTimeRange() ? timeManager.isScaledDayTimeWithinRange(dayTimeRange[0], dayTimeRange[1]) : timeManager.isDayTimeWithinRange(dayTimeRange[0], dayTimeRange[1]);
        return world.getWorldConfig().isSpawningNPC() && withinTimeRange && timeManager.isMoonPhaseWithinRange(world, moonPhaseRange[0], moonPhaseRange[1]);
    }
    
    public boolean withinLightRange(@Nonnull final SpawningContext spawningContext) {
        final BlockChunk blockChunk = spawningContext.worldChunk.getBlockChunk();
        final Store<EntityStore> store = spawningContext.world.getEntityStore().getStore();
        final WorldTimeResource worldTimeResource = store.getResource(WorldTimeResource.getResourceType());
        return this.lightRangePredicate.test(blockChunk, spawningContext.xBlock, spawningContext.yBlock, spawningContext.zBlock, worldTimeResource.getSunlightFactor());
    }
    
    private void addRoles() {
        final NPCPlugin npcModule = NPCPlugin.get();
        final SpawningPlugin spawningModule = SpawningPlugin.get();
        final Int2ObjectOpenHashMap<RoleSpawnParameters> roles = new Int2ObjectOpenHashMap<RoleSpawnParameters>();
        for (final RoleSpawnParameters roleEntry : this.spawn.getNPCs()) {
            final String name = roleEntry.getId();
            final int roleIndex = npcModule.getIndex(name);
            if (roleIndex < 0) {
                this.invalidNPCs.add(name);
                spawningModule.getLogger().at(Level.WARNING).log("NPCSpawn %s references unknown NPC %s", this.spawn.getId(), name);
            }
            else {
                roles.put(roleIndex, roleEntry);
            }
        }
        roles.trim();
        this.roles = Int2ObjectMaps.unmodifiable((Int2ObjectMap<? extends RoleSpawnParameters>)roles);
    }
}
