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

package com.hypixel.hytale.builtin.path;

import com.hypixel.hytale.component.system.EcsEvent;
import com.hypixel.hytale.builtin.buildertools.BuilderToolsPlugin;
import com.hypixel.hytale.server.core.prefab.event.PrefabPlaceEntityEvent;
import com.hypixel.hytale.component.system.WorldEventSystem;
import com.hypixel.hytale.component.Component;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.system.RefChangeSystem;
import com.hypixel.hytale.server.core.entity.nameplate.Nameplate;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.modules.entity.component.DisplayNameComponent;
import com.hypixel.hytale.component.Archetype;
import com.hypixel.hytale.server.core.modules.entity.EntityModule;
import com.hypixel.hytale.component.SystemGroup;
import com.hypixel.hytale.server.core.modules.entity.component.FromWorldGen;
import com.hypixel.hytale.component.dependency.SystemDependency;
import com.hypixel.hytale.server.core.modules.entity.system.ModelSystems;
import com.hypixel.hytale.component.dependency.Order;
import com.hypixel.hytale.component.RemoveReason;
import com.hypixel.hytale.server.core.prefab.PrefabCopyableComponent;
import com.hypixel.hytale.server.core.modules.entity.component.HiddenFromAdventurePlayers;
import com.hypixel.hytale.builtin.path.waypoint.IPrefabPathWaypoint;
import com.hypixel.hytale.builtin.path.path.IPrefabPath;
import com.hypixel.fastutil.ints.Int2ObjectConcurrentHashMap;
import com.hypixel.hytale.builtin.path.path.PatrolPath;
import java.util.logging.Level;
import java.util.UUID;
import java.nio.charset.StandardCharsets;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.component.AddReason;
import com.hypixel.hytale.component.Holder;
import javax.annotation.Nonnull;
import com.hypixel.hytale.component.query.Query;
import com.hypixel.hytale.component.dependency.Dependency;
import java.util.Set;
import com.hypixel.hytale.server.core.modules.entity.component.WorldGenId;
import com.hypixel.hytale.component.ResourceType;
import com.hypixel.hytale.server.core.modules.entity.component.ModelComponent;
import javax.annotation.Nullable;
import com.hypixel.hytale.builtin.path.entities.PatrolPathMarkerEntity;
import com.hypixel.hytale.component.ComponentType;
import com.hypixel.hytale.logger.HytaleLogger;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.system.HolderSystem;

public class PrefabPathSystems
{
    public static class AddOrRemove extends HolderSystem<EntityStore>
    {
        public static final HytaleLogger LOGGER;
        @Nullable
        private static final ComponentType<EntityStore, PatrolPathMarkerEntity> PATH_MARKER_ENTITY_COMPONENT_TYPE;
        private static final ComponentType<EntityStore, ModelComponent> MODEL_COMPONENT_TYPE;
        private static final ResourceType<EntityStore, WorldPathData> STORE_WORLD_PATH_DATA_RESOURCE_TYPE;
        private static final ComponentType<EntityStore, WorldGenId> WORLD_GEN_ID_COMPONENT_TYPE;
        private static final Set<Dependency<EntityStore>> DEPENDENCIES;
        
        @Nullable
        @Override
        public Query<EntityStore> getQuery() {
            return AddOrRemove.PATH_MARKER_ENTITY_COMPONENT_TYPE;
        }
        
        @Nonnull
        @Override
        public Set<Dependency<EntityStore>> getDependencies() {
            return AddOrRemove.DEPENDENCIES;
        }
        
        @Override
        public void onEntityAdd(@Nonnull final Holder<EntityStore> holder, @Nonnull final AddReason reason, @Nonnull final Store<EntityStore> store) {
            final PatrolPathMarkerEntity pathMarker = holder.getComponent(AddOrRemove.PATH_MARKER_ENTITY_COMPONENT_TYPE);
            final WorldPathData worldPathData = store.getResource(AddOrRemove.STORE_WORLD_PATH_DATA_RESOURCE_TYPE);
            final WorldGenId worldGenIdComponent = holder.getComponent(AddOrRemove.WORLD_GEN_ID_COMPONENT_TYPE);
            final int worldgenId = (worldGenIdComponent != null) ? worldGenIdComponent.getWorldGenId() : 0;
            final String pathName = pathMarker.getPathName();
            UUID pathId = pathMarker.getPathId();
            if (pathId == null) {
                pathId = UUID.nameUUIDFromBytes((pathName + worldgenId).getBytes(StandardCharsets.UTF_8));
                pathMarker.setPathId(pathId);
                final int lastIndex = pathName.lastIndexOf(126);
                if (lastIndex != -1) {
                    pathMarker.setPathName(pathName.substring(0, lastIndex));
                    pathMarker.markNeedsSave();
                    AddOrRemove.LOGGER.at(Level.INFO).log("Migrating path marker from path %s to use new UUID %s", pathName, pathId);
                }
            }
            final IPrefabPath path = worldPathData.getOrConstructPrefabPath(worldgenId, pathId, pathName, (Int2ObjectConcurrentHashMap.IntBiObjFunction<UUID, String, IPrefabPath>)PatrolPath::new);
            path.addLoadedWaypoint(pathMarker, pathMarker.getTempPathLength(), pathMarker.getOrder(), worldgenId);
            pathMarker.setParentPath(path);
            holder.putComponent(AddOrRemove.MODEL_COMPONENT_TYPE, new ModelComponent(PathPlugin.get().getPathMarkerModel()));
            pathMarker.markNeedsSave();
            holder.ensureComponent(HiddenFromAdventurePlayers.getComponentType());
            holder.ensureComponent(PrefabCopyableComponent.getComponentType());
        }
        
        @Override
        public void onEntityRemoved(@Nonnull final Holder<EntityStore> holder, @Nonnull final RemoveReason reason, @Nonnull final Store<EntityStore> store) {
            final PatrolPathMarkerEntity pathMarker = holder.getComponent(PatrolPathMarkerEntity.getComponentType());
            final WorldPathData worldPathData = store.getResource(WorldPathData.getResourceType());
            final WorldGenId worldGenIdComponent = holder.getComponent(AddOrRemove.WORLD_GEN_ID_COMPONENT_TYPE);
            final int worldgenId = (worldGenIdComponent != null) ? worldGenIdComponent.getWorldGenId() : 0;
            switch (reason) {
                case UNLOAD: {
                    worldPathData.unloadPrefabPathWaypoint(worldgenId, pathMarker.getPathId(), pathMarker.getOrder());
                    break;
                }
                case REMOVE: {
                    final UUID path = pathMarker.getPathId();
                    if (path != null) {
                        worldPathData.removePrefabPathWaypoint(worldgenId, path, pathMarker.getOrder());
                        break;
                    }
                    break;
                }
            }
        }
        
        static {
            LOGGER = HytaleLogger.forEnclosingClass();
            PATH_MARKER_ENTITY_COMPONENT_TYPE = PatrolPathMarkerEntity.getComponentType();
            MODEL_COMPONENT_TYPE = ModelComponent.getComponentType();
            STORE_WORLD_PATH_DATA_RESOURCE_TYPE = WorldPathData.getResourceType();
            WORLD_GEN_ID_COMPONENT_TYPE = WorldGenId.getComponentType();
            DEPENDENCIES = Set.of(new SystemDependency(Order.BEFORE, ModelSystems.ModelSpawned.class));
        }
    }
    
    public static class AddedFromWorldGen extends HolderSystem<EntityStore>
    {
        @Nullable
        private static final ComponentType<EntityStore, PatrolPathMarkerEntity> PATH_MARKER_ENTITY_COMPONENT_TYPE;
        private static final ComponentType<EntityStore, WorldGenId> WORLD_GEN_ID_COMPONENT_TYPE;
        private static final ComponentType<EntityStore, FromWorldGen> FROM_WORLD_GEN_COMPONENT_TYPE;
        private static final Query<EntityStore> QUERY;
        private static final Set<Dependency<EntityStore>> DEPENDENCIES;
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return AddedFromWorldGen.QUERY;
        }
        
        @Nonnull
        @Override
        public Set<Dependency<EntityStore>> getDependencies() {
            return AddedFromWorldGen.DEPENDENCIES;
        }
        
        @Nullable
        @Override
        public SystemGroup<EntityStore> getGroup() {
            return EntityModule.get().getPreClearMarkersGroup();
        }
        
        @Override
        public void onEntityAdd(@Nonnull final Holder<EntityStore> holder, @Nonnull final AddReason reason, @Nonnull final Store<EntityStore> store) {
            holder.putComponent(AddedFromWorldGen.WORLD_GEN_ID_COMPONENT_TYPE, new WorldGenId(holder.getComponent(AddedFromWorldGen.FROM_WORLD_GEN_COMPONENT_TYPE).getWorldGenId()));
        }
        
        @Override
        public void onEntityRemoved(@Nonnull final Holder<EntityStore> holder, @Nonnull final RemoveReason reason, @Nonnull final Store<EntityStore> store) {
        }
        
        static {
            PATH_MARKER_ENTITY_COMPONENT_TYPE = PatrolPathMarkerEntity.getComponentType();
            WORLD_GEN_ID_COMPONENT_TYPE = WorldGenId.getComponentType();
            FROM_WORLD_GEN_COMPONENT_TYPE = FromWorldGen.getComponentType();
            QUERY = Query.and(AddedFromWorldGen.PATH_MARKER_ENTITY_COMPONENT_TYPE, AddedFromWorldGen.FROM_WORLD_GEN_COMPONENT_TYPE);
            DEPENDENCIES = Set.of(new SystemDependency(Order.BEFORE, AddOrRemove.class));
        }
    }
    
    public static class NameplateHolderSystem extends HolderSystem<EntityStore>
    {
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return Archetype.of(PatrolPathMarkerEntity.getComponentType());
        }
        
        @Override
        public void onEntityAdd(@Nonnull final Holder<EntityStore> holder, @Nonnull final AddReason reason, @Nonnull final Store<EntityStore> store) {
            final PatrolPathMarkerEntity patrolPathMarkerComponent = holder.getComponent(PatrolPathMarkerEntity.getComponentType());
            assert patrolPathMarkerComponent != null;
            DisplayNameComponent displayNameComponent = holder.getComponent(DisplayNameComponent.getComponentType());
            String displayName = "";
            if (displayNameComponent == null) {
                final String legacyDisplayName = patrolPathMarkerComponent.getLegacyDisplayName();
                displayName = ((legacyDisplayName != null) ? legacyDisplayName : "Path Marker");
                final Message legacyDisplayNameMessage = Message.raw(displayName);
                displayNameComponent = new DisplayNameComponent(legacyDisplayNameMessage);
                holder.putComponent(DisplayNameComponent.getComponentType(), displayNameComponent);
            }
            final Nameplate nameplateComponent = holder.getComponent(Nameplate.getComponentType());
            if (nameplateComponent == null) {
                holder.putComponent(Nameplate.getComponentType(), new Nameplate(displayName));
            }
        }
        
        @Override
        public void onEntityRemoved(@Nonnull final Holder<EntityStore> holder, @Nonnull final RemoveReason reason, @Nonnull final Store<EntityStore> store) {
        }
    }
    
    public static class NameplateRefChangeSystem extends RefChangeSystem<EntityStore, DisplayNameComponent>
    {
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return PatrolPathMarkerEntity.getComponentType();
        }
        
        @Nonnull
        @Override
        public ComponentType<EntityStore, DisplayNameComponent> componentType() {
            return DisplayNameComponent.getComponentType();
        }
        
        @Override
        public void onComponentAdded(@Nonnull final Ref<EntityStore> ref, @Nonnull final DisplayNameComponent component, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final Nameplate nameplateComponent = commandBuffer.ensureAndGetComponent(ref, Nameplate.getComponentType());
            nameplateComponent.setText((component.getDisplayName() != null) ? component.getDisplayName().getAnsiMessage() : "");
        }
        
        @Override
        public void onComponentSet(@Nonnull final Ref<EntityStore> ref, final DisplayNameComponent oldComponent, @Nonnull final DisplayNameComponent newComponent, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final Nameplate nameplateComponent = commandBuffer.ensureAndGetComponent(ref, Nameplate.getComponentType());
            nameplateComponent.setText((newComponent.getDisplayName() != null) ? newComponent.getDisplayName().getAnsiMessage() : "");
        }
        
        @Override
        public void onComponentRemoved(@Nonnull final Ref<EntityStore> ref, @Nonnull final DisplayNameComponent component, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final Nameplate nameplateComponent = commandBuffer.ensureAndGetComponent(ref, Nameplate.getComponentType());
            nameplateComponent.setText("");
        }
    }
    
    public static class WorldGenChangeSystem extends RefChangeSystem<EntityStore, WorldGenId>
    {
        @Nonnull
        private static final Message MESSAGE_PREFABS_UNKNOWN;
        
        @Nonnull
        @Override
        public Query<EntityStore> getQuery() {
            return PatrolPathMarkerEntity.getComponentType();
        }
        
        @Nonnull
        @Override
        public ComponentType<EntityStore, WorldGenId> componentType() {
            return WorldGenId.getComponentType();
        }
        
        @Override
        public void onComponentAdded(@Nonnull final Ref<EntityStore> ref, @Nonnull final WorldGenId component, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final PatrolPathMarkerEntity patrolPathMarkerComponent = commandBuffer.getComponent(ref, PatrolPathMarkerEntity.getComponentType());
            assert patrolPathMarkerComponent != null;
            final String displayName = PatrolPathMarkerEntity.generateDisplayName(component.getWorldGenId(), patrolPathMarkerComponent);
            final Message displayNameMessage = Message.raw(displayName);
            commandBuffer.putComponent(ref, DisplayNameComponent.getComponentType(), new DisplayNameComponent(displayNameMessage));
        }
        
        @Override
        public void onComponentSet(@Nonnull final Ref<EntityStore> ref, @Nullable final WorldGenId oldComponent, @Nonnull final WorldGenId newComponent, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            final PatrolPathMarkerEntity patrolPathMarkerComponent = commandBuffer.getComponent(ref, PatrolPathMarkerEntity.getComponentType());
            assert patrolPathMarkerComponent != null;
            final String displayName = PatrolPathMarkerEntity.generateDisplayName(newComponent.getWorldGenId(), patrolPathMarkerComponent);
            final Message displayNameMessage = Message.raw(displayName);
            commandBuffer.putComponent(ref, DisplayNameComponent.getComponentType(), new DisplayNameComponent(displayNameMessage));
        }
        
        @Override
        public void onComponentRemoved(@Nonnull final Ref<EntityStore> ref, @Nonnull final WorldGenId component, @Nonnull final Store<EntityStore> store, @Nonnull final CommandBuffer<EntityStore> commandBuffer) {
            commandBuffer.putComponent(ref, DisplayNameComponent.getComponentType(), new DisplayNameComponent(WorldGenChangeSystem.MESSAGE_PREFABS_UNKNOWN));
        }
        
        static {
            MESSAGE_PREFABS_UNKNOWN = Message.translation("server.prefabs.unknown");
        }
    }
    
    public static class PrefabPlaceEntityEventSystem extends WorldEventSystem<EntityStore, PrefabPlaceEntityEvent>
    {
        public PrefabPlaceEntityEventSystem() {
            super(PrefabPlaceEntityEvent.class);
        }
        
        @Override
        public void handle(@Nonnull final Store store, @Nonnull final CommandBuffer commandBuffer, @Nonnull final PrefabPlaceEntityEvent event) {
            final Holder<EntityStore> holder = event.getHolder();
            final PatrolPathMarkerEntity patrolPathMarkerComponent = holder.getComponent(PatrolPathMarkerEntity.getComponentType());
            if (patrolPathMarkerComponent == null) {
                return;
            }
            final String pathName = patrolPathMarkerComponent.getPathName();
            final UUID pathId = patrolPathMarkerComponent.getPathId();
            if (pathId == null) {
                final String newPathName = pathName.substring(0, pathName.lastIndexOf(126));
                patrolPathMarkerComponent.setPathName(newPathName);
            }
            final UUID newPathId = BuilderToolsPlugin.get().getNewPathIdOnPrefabPasted(pathId, patrolPathMarkerComponent.getPathName(), event.getPrefabId());
            patrolPathMarkerComponent.setPathId(newPathId);
        }
    }
}
