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

package com.hypixel.hytale.builtin.npccombatactionevaluator.memory;

import java.util.logging.Level;
import com.hypixel.hytale.protocol.GameMode;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.server.core.modules.entity.damage.DeathComponent;
import java.util.List;
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.component.ArchetypeChunk;
import com.hypixel.hytale.component.query.Query;
import com.hypixel.hytale.component.dependency.SystemDependency;
import com.hypixel.hytale.server.npc.systems.RoleSystems;
import com.hypixel.hytale.component.dependency.Order;
import com.hypixel.hytale.component.dependency.Dependency;
import java.util.Set;
import com.hypixel.hytale.component.ComponentType;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.system.tick.EntityTickingSystem;
import javax.annotation.Nonnull;
import com.hypixel.hytale.logger.HytaleLogger;

public class TargetMemorySystems
{
    @Nonnull
    public static final HytaleLogger LOGGER;
    
    static {
        LOGGER = HytaleLogger.forEnclosingClass();
    }
    
    public static class Ticking extends EntityTickingSystem<EntityStore>
    {
        @Nonnull
        private static final String HOSTILE = "hostile";
        @Nonnull
        private static final String FRIENDLY = "friendly";
        @Nonnull
        private final ComponentType<EntityStore, TargetMemory> targetMemoryComponentType;
        @Nonnull
        private final Set<Dependency<EntityStore>> dependencies;
        
        public Ticking(@Nonnull final ComponentType<EntityStore, TargetMemory> targetMemoryComponentType) {
            this.targetMemoryComponentType = targetMemoryComponentType;
            this.dependencies = (Set<Dependency<EntityStore>>)Set.of(new SystemDependency(Order.BEFORE, RoleSystems.BehaviourTickSystem.class));
        }
        
        @Override
        public boolean isParallel(final int archetypeChunkSize, final int taskCount) {
            return EntityTickingSystem.maybeUseParallel(archetypeChunkSize, taskCount);
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return this.targetMemoryComponentType;
        }
        
        @Nonnull
        @Override
        public Set<Dependency<EntityStore>> getDependencies() {
            return this.dependencies;
        }
        
        @Override
        public void tick(final float dt, final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final TargetMemory targetMemoryComponent = archetypeChunk.getComponent(index, this.targetMemoryComponentType);
            assert targetMemoryComponent != null;
            final Int2FloatOpenHashMap hostileMap = targetMemoryComponent.getKnownHostiles();
            final List<Ref<EntityStore>> hostileList = targetMemoryComponent.getKnownHostilesList();
            iterateMemory(dt, index, archetypeChunk, commandBuffer, hostileList, hostileMap, "hostile");
            final Int2FloatOpenHashMap friendlyMap = targetMemoryComponent.getKnownFriendlies();
            final List<Ref<EntityStore>> friendlyList = targetMemoryComponent.getKnownFriendliesList();
            iterateMemory(dt, index, archetypeChunk, commandBuffer, friendlyList, friendlyMap, "friendly");
            final Ref<EntityStore> closestHostileRef = targetMemoryComponent.getClosestHostile();
            if (closestHostileRef != null && !isValidTarget(closestHostileRef, commandBuffer)) {
                targetMemoryComponent.setClosestHostile(null);
            }
        }
        
        private static void iterateMemory(final float dt, final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, @Nonnull final CommandBuffer<EntityStore> commandBuffer, @Nonnull final List<Ref<EntityStore>> targetsList, @Nonnull final Int2FloatOpenHashMap targetsMap, @Nonnull final String type) {
            for (int i = targetsList.size() - 1; i >= 0; --i) {
                final Ref<EntityStore> ref = targetsList.get(i);
                if (!isValidTarget(ref, commandBuffer)) {
                    removeEntry(index, archetypeChunk, i, ref, targetsList, targetsMap, type);
                }
                else {
                    final float timeRemaining = targetsMap.mergeFloat(ref.getIndex(), -dt, Float::sum);
                    if (timeRemaining <= 0.0f) {
                        removeEntry(index, archetypeChunk, i, ref, targetsList, targetsMap, type);
                    }
                }
            }
        }
        
        private static boolean isValidTarget(@Nonnull final Ref<EntityStore> targetRef, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            if (!targetRef.isValid()) {
                return false;
            }
            if (commandBuffer.getArchetype(targetRef).contains(DeathComponent.getComponentType())) {
                return false;
            }
            final Player targetPlayerComponent = commandBuffer.getComponent(targetRef, Player.getComponentType());
            return targetPlayerComponent == null || targetPlayerComponent.getGameMode() == GameMode.Adventure;
        }
        
        private static void removeEntry(final int index, @Nonnull final ArchetypeChunk<EntityStore> archetypeChunk, final int targetIndex, @Nonnull final Ref<EntityStore> targetRef, @Nonnull final List<Ref<EntityStore>> targetsList, @Nonnull final Int2FloatOpenHashMap targetsMap, @Nonnull final String type) {
            targetsMap.remove(targetRef.getIndex());
            targetsList.remove(targetIndex);
            final HytaleLogger.Api context = TargetMemorySystems.LOGGER.at(Level.FINEST);
            if (context.isEnabled()) {
                context.log("%s: Removed lost %s target %s", archetypeChunk.getReferenceTo(index), type, targetRef);
            }
        }
    }
}
