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

package com.hypixel.hytale.server.core.modules.interaction.system;

import com.hypixel.hytale.component.Component;
import com.hypixel.hytale.component.system.RefChangeSystem;
import java.util.Iterator;
import com.hypixel.hytale.server.core.modules.interaction.interaction.config.RootInteraction;
import com.hypixel.hytale.protocol.InteractionType;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import com.hypixel.hytale.protocol.ComponentUpdateType;
import com.hypixel.hytale.protocol.ComponentUpdate;
import java.util.Map;
import com.hypixel.hytale.server.core.modules.interaction.Interactions;
import com.hypixel.hytale.server.core.modules.entity.tracker.EntityTrackerSystems;
import com.hypixel.hytale.component.system.RefSystem;
import com.hypixel.hytale.server.core.modules.interaction.IInteractionSimulationHandler;
import com.hypixel.hytale.server.core.entity.LivingEntity;
import com.hypixel.hytale.server.core.modules.interaction.InteractionSimulationHandler;
import com.hypixel.hytale.component.AddReason;
import com.hypixel.hytale.component.Holder;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.component.system.HolderSystem;
import javax.annotation.Nullable;
import com.hypixel.hytale.server.core.modules.entity.damage.DamageModule;
import com.hypixel.hytale.component.SystemGroup;
import it.unimi.dsi.fastutil.objects.ObjectList;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.RemoveReason;
import java.util.logging.Level;
import com.hypixel.hytale.protocol.Packet;
import com.hypixel.hytale.protocol.packets.interaction.SyncInteractionChains;
import com.hypixel.hytale.protocol.packets.interaction.SyncInteractionChain;
import com.hypixel.hytale.server.core.universe.PlayerRef;
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.server.core.modules.interaction.InteractionModule;
import com.hypixel.hytale.server.core.entity.InteractionManager;
import com.hypixel.hytale.component.ComponentType;
import javax.annotation.Nonnull;
import com.hypixel.hytale.logger.HytaleLogger;
import com.hypixel.hytale.server.core.modules.entitystats.EntityStatsSystems;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.system.tick.EntityTickingSystem;

public class InteractionSystems
{
    public static class TickInteractionManagerSystem extends EntityTickingSystem<EntityStore> implements EntityStatsSystems.StatModifyingSystem
    {
        @Nonnull
        private static final HytaleLogger LOGGER;
        @Nonnull
        private final ComponentType<EntityStore, InteractionManager> interactionManagerComponent;
        
        public TickInteractionManagerSystem() {
            this.interactionManagerComponent = InteractionModule.get().getInteractionManagerComponent();
        }
        
        @Override
        public Query<EntityStore> getQuery() {
            return this.interactionManagerComponent;
        }
        
        @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 Ref<EntityStore> ref = archetypeChunk.getReferenceTo(index);
            try {
                final InteractionManager interactionManager = archetypeChunk.getComponent(index, this.interactionManagerComponent);
                assert interactionManager != null;
                final PlayerRef playerRef = archetypeChunk.getComponent(index, PlayerRef.getComponentType());
                interactionManager.tick(ref, commandBuffer, dt);
                final ObjectList<SyncInteractionChain> syncPackets = interactionManager.getSyncPackets();
                if (playerRef != null && !syncPackets.isEmpty()) {
                    playerRef.getPacketHandler().writeNoCache(new SyncInteractionChains(syncPackets.toArray(SyncInteractionChain[]::new)));
                    syncPackets.clear();
                }
            }
            catch (final Throwable e) {
                TickInteractionManagerSystem.LOGGER.at(Level.SEVERE).withCause(e).log("Exception while ticking entity interactions! Removing!");
                commandBuffer.removeEntity(ref, RemoveReason.REMOVE);
            }
        }
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return DamageModule.get().getGatherDamageGroup();
        }
        
        static {
            LOGGER = HytaleLogger.forEnclosingClass();
        }
    }
    
    public static class PlayerAddManagerSystem extends HolderSystem<EntityStore>
    {
        @Nonnull
        private final Query<EntityStore> query;
        
        public PlayerAddManagerSystem() {
            this.query = (Query<EntityStore>)Query.and(Player.getComponentType(), PlayerRef.getComponentType(), Query.not((Query<Object>)InteractionModule.get().getInteractionManagerComponent()));
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return this.query;
        }
        
        @Override
        public void onEntityAdd(@Nonnull final Holder<EntityStore> holder, @Nonnull final AddReason reason, @Nonnull final Store<EntityStore> store) {
            final Player playerComponent = holder.getComponent(Player.getComponentType());
            assert playerComponent != null;
            final PlayerRef playerRefComponent = holder.getComponent(PlayerRef.getComponentType());
            assert playerRefComponent != null;
            holder.addComponent(InteractionModule.get().getInteractionManagerComponent(), new InteractionManager(playerComponent, playerRefComponent, new InteractionSimulationHandler()));
        }
        
        @Override
        public void onEntityRemoved(@Nonnull final Holder<EntityStore> holder, @Nonnull final RemoveReason reason, @Nonnull final Store<EntityStore> store) {
        }
    }
    
    public static class CleanUpSystem extends RefSystem<EntityStore>
    {
        @Nonnull
        private final ComponentType<EntityStore, InteractionManager> interactionComponentType;
        
        public CleanUpSystem() {
            this.interactionComponentType = InteractionModule.get().getInteractionManagerComponent();
        }
        
        @Override
        public void onEntityAdded(@Nonnull final Ref<EntityStore> ref, @Nonnull final AddReason reason, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
        }
        
        @Override
        public void onEntityRemove(@Nonnull final Ref<EntityStore> ref, @Nonnull final RemoveReason reason, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final InteractionManager interactionManager = store.getComponent(ref, this.interactionComponentType);
            assert interactionManager != null;
            interactionManager.clear();
        }
        
        @Override
        public Query<EntityStore> getQuery() {
            return this.interactionComponentType;
        }
    }
    
    public static class TrackerTickSystem extends EntityTickingSystem<EntityStore>
    {
        @Nonnull
        private final ComponentType<EntityStore, EntityTrackerSystems.Visible> visibleComponentType;
        @Nonnull
        private final Query<EntityStore> query;
        
        public TrackerTickSystem() {
            this.visibleComponentType = EntityTrackerSystems.Visible.getComponentType();
            this.query = (Query<EntityStore>)Query.and(this.visibleComponentType, Interactions.getComponentType());
        }
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return EntityTrackerSystems.QUEUE_UPDATE_GROUP;
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return this.query;
        }
        
        @Override
        public boolean isParallel(final int archetypeChunkSize, final int taskCount) {
            return EntityTickingSystem.maybeUseParallel(archetypeChunkSize, taskCount);
        }
        
        @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 EntityTrackerSystems.Visible visibleComponentType = archetypeChunk.getComponent(index, this.visibleComponentType);
            assert visibleComponentType != null;
            final Interactions interactionsComponent = archetypeChunk.getComponent(index, Interactions.getComponentType());
            assert interactionsComponent != null;
            final Ref<EntityStore> ref = archetypeChunk.getReferenceTo(index);
            if (interactionsComponent.consumeNetworkOutdated()) {
                queueUpdatesFor(ref, visibleComponentType.visibleTo, interactionsComponent);
            }
            else if (!visibleComponentType.newlyVisibleTo.isEmpty()) {
                queueUpdatesFor(ref, visibleComponentType.newlyVisibleTo, interactionsComponent);
            }
        }
        
        private static void queueUpdatesFor(@Nonnull final Ref<EntityStore> ref, @Nonnull final Map<Ref<EntityStore>, EntityTrackerSystems.EntityViewer> visibleTo, @Nonnull final Interactions component) {
            final ComponentUpdate componentUpdate = new ComponentUpdate();
            componentUpdate.type = ComponentUpdateType.Interactions;
            final Object2IntOpenHashMap<InteractionType> interactions = new Object2IntOpenHashMap<InteractionType>();
            for (final Map.Entry<InteractionType, String> entry : component.getInteractions().entrySet()) {
                interactions.put(entry.getKey(), RootInteraction.getRootInteractionIdOrUnknown(entry.getValue()));
            }
            componentUpdate.interactions = interactions;
            componentUpdate.interactionHint = component.getInteractionHint();
            for (final EntityTrackerSystems.EntityViewer viewer : visibleTo.values()) {
                viewer.queueUpdate(ref, componentUpdate);
            }
        }
    }
    
    public static class EntityTrackerRemove extends RefChangeSystem<EntityStore, Interactions>
    {
        private final ComponentType<EntityStore, EntityTrackerSystems.Visible> visibleComponentType;
        
        public EntityTrackerRemove(final ComponentType<EntityStore, EntityTrackerSystems.Visible> visibleComponentType) {
            this.visibleComponentType = visibleComponentType;
        }
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return this.visibleComponentType;
        }
        
        @Nonnull
        @Override
        public ComponentType<EntityStore, Interactions> componentType() {
            return Interactions.getComponentType();
        }
        
        @Override
        public void onComponentAdded(@Nonnull final Ref<EntityStore> ref, @Nonnull final Interactions component, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
        }
        
        @Override
        public void onComponentSet(@Nonnull final Ref<EntityStore> ref, final Interactions oldComponent, @Nonnull final Interactions newComponent, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
        }
        
        @Override
        public void onComponentRemoved(@Nonnull final Ref<EntityStore> ref, @Nonnull final Interactions component, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final EntityTrackerSystems.Visible visible = commandBuffer.getComponent(ref, this.visibleComponentType);
            if (visible != null) {
                for (final EntityTrackerSystems.EntityViewer viewer : visible.visibleTo.values()) {
                    viewer.queueRemove(ref, ComponentUpdateType.Interactions);
                }
            }
        }
    }
}
