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

package com.hypixel.hytale.server.npc.systems;

import java.util.Collection;
import java.util.ArrayDeque;
import com.hypixel.hytale.component.Resource;
import javax.annotation.Nullable;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.Holder;
import java.util.Deque;
import com.hypixel.hytale.component.ComponentAccessor;
import java.util.logging.Level;
import com.hypixel.hytale.component.AddReason;
import com.hypixel.hytale.server.npc.NPCPlugin;
import com.hypixel.hytale.server.core.modules.entity.repulsion.Repulsion;
import com.hypixel.hytale.server.npc.role.Role;
import com.hypixel.hytale.server.npc.entities.NPCEntity;
import com.hypixel.hytale.component.RemoveReason;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.component.dependency.SystemDependency;
import com.hypixel.hytale.component.dependency.Order;
import com.hypixel.hytale.component.dependency.Dependency;
import java.util.Set;
import com.hypixel.hytale.server.npc.valuestore.ValueStore;
import com.hypixel.hytale.server.npc.decisionmaker.stateevaluator.StateEvaluator;
import com.hypixel.hytale.server.npc.components.Timers;
import com.hypixel.hytale.server.npc.components.messaging.NPCEntityEventSupport;
import com.hypixel.hytale.server.npc.components.messaging.PlayerEntityEventSupport;
import com.hypixel.hytale.server.npc.components.messaging.NPCBlockEventSupport;
import com.hypixel.hytale.server.npc.components.messaging.PlayerBlockEventSupport;
import com.hypixel.hytale.server.npc.components.messaging.BeaconSupport;
import com.hypixel.hytale.component.ComponentType;
import com.hypixel.hytale.component.ResourceType;
import javax.annotation.Nonnull;
import com.hypixel.hytale.logger.HytaleLogger;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.system.tick.TickingSystem;

public class RoleChangeSystem extends TickingSystem<EntityStore>
{
    @Nonnull
    private static final HytaleLogger LOGGER;
    @Nonnull
    private final ResourceType<EntityStore, RoleChangeQueue> roleChangeQueueResourceType;
    @Nonnull
    private final ComponentType<EntityStore, BeaconSupport> beaconSupportComponentType;
    @Nonnull
    private final ComponentType<EntityStore, PlayerBlockEventSupport> playerBlockEventSupportComponentType;
    @Nonnull
    private final ComponentType<EntityStore, NPCBlockEventSupport> npcBlockEventSupportComponentType;
    @Nonnull
    private final ComponentType<EntityStore, PlayerEntityEventSupport> playerEntityEventSupportComponentType;
    @Nonnull
    private final ComponentType<EntityStore, NPCEntityEventSupport> npcEntityEventSupportComponentType;
    @Nonnull
    private final ComponentType<EntityStore, Timers> timersComponentType;
    @Nonnull
    private final ComponentType<EntityStore, StateEvaluator> stateEvaluatorComponentType;
    @Nonnull
    private final ComponentType<EntityStore, ValueStore> valueStoreComponentType;
    @Nonnull
    private final Set<Dependency<EntityStore>> dependencies;
    
    public RoleChangeSystem(@Nonnull final ResourceType<EntityStore, RoleChangeQueue> roleChangeQueueResourceType, @Nonnull final ComponentType<EntityStore, BeaconSupport> beaconSupportComponentType, @Nonnull final ComponentType<EntityStore, PlayerBlockEventSupport> playerBlockEventSupportComponentType, @Nonnull final ComponentType<EntityStore, NPCBlockEventSupport> npcBlockEventSupportComponentType, @Nonnull final ComponentType<EntityStore, PlayerEntityEventSupport> playerEntityEventSupportComponentType, @Nonnull final ComponentType<EntityStore, NPCEntityEventSupport> npcEntityEventSupportComponentType, @Nonnull final ComponentType<EntityStore, Timers> timersComponentType, @Nonnull final ComponentType<EntityStore, StateEvaluator> stateEvaluatorComponentType, @Nonnull final ComponentType<EntityStore, ValueStore> valueStoreComponentType) {
        this.dependencies = (Set<Dependency<EntityStore>>)Set.of(new SystemDependency(Order.AFTER, NewSpawnStartTickingSystem.class));
        this.roleChangeQueueResourceType = roleChangeQueueResourceType;
        this.beaconSupportComponentType = beaconSupportComponentType;
        this.playerBlockEventSupportComponentType = playerBlockEventSupportComponentType;
        this.npcBlockEventSupportComponentType = npcBlockEventSupportComponentType;
        this.playerEntityEventSupportComponentType = playerEntityEventSupportComponentType;
        this.npcEntityEventSupportComponentType = npcEntityEventSupportComponentType;
        this.timersComponentType = timersComponentType;
        this.stateEvaluatorComponentType = stateEvaluatorComponentType;
        this.valueStoreComponentType = valueStoreComponentType;
    }
    
    @Nonnull
    @Override
    public Set<Dependency<EntityStore>> getDependencies() {
        return this.dependencies;
    }
    
    @Override
    public void tick(final float dt, final int systemIndex, @Nonnull final Store<EntityStore> store) {
        final RoleChangeQueue roleChangeQueueResource = store.getResource(this.roleChangeQueueResourceType);
        final Deque<RoleChangeRequest> requests = roleChangeQueueResource.requests;
        while (!requests.isEmpty()) {
            final RoleChangeRequest request = requests.poll();
            if (!request.reference.isValid()) {
                continue;
            }
            final Holder<EntityStore> holder = store.removeEntity(request.reference, RemoveReason.UNLOAD);
            final NPCEntity npcComponent = holder.getComponent(NPCEntity.getComponentType());
            assert npcComponent != null;
            npcComponent.setRole(null);
            holder.tryRemoveComponent(this.beaconSupportComponentType);
            holder.tryRemoveComponent(this.playerBlockEventSupportComponentType);
            holder.tryRemoveComponent(this.npcBlockEventSupportComponentType);
            holder.tryRemoveComponent(this.playerEntityEventSupportComponentType);
            holder.tryRemoveComponent(this.npcEntityEventSupportComponentType);
            holder.tryRemoveComponent(this.timersComponentType);
            holder.tryRemoveComponent(this.stateEvaluatorComponentType);
            holder.tryRemoveComponent(this.valueStoreComponentType);
            holder.tryRemoveComponent(Repulsion.getComponentType());
            npcComponent.setRoleName(NPCPlugin.get().getName(request.roleIndex));
            npcComponent.setRoleIndex(request.roleIndex);
            Ref<EntityStore> npcEntityReference;
            try {
                npcEntityReference = store.addEntity(holder, AddReason.LOAD);
            }
            catch (final Exception e) {
                RoleChangeSystem.LOGGER.at(Level.SEVERE).log("Failed to change role: %s", e.getMessage());
                continue;
            }
            if (npcEntityReference == null || !npcEntityReference.isValid()) {
                RoleChangeSystem.LOGGER.at(Level.SEVERE).log("Failed to change role: Could not re-add NPC entity to store");
            }
            else {
                if (request.changeAppearance) {
                    final Role role = npcComponent.getRole();
                    NPCEntity.setAppearance(npcEntityReference, role.getAppearanceName(), store);
                }
                if (request.state == null) {
                    continue;
                }
                final Role role = npcComponent.getRole();
                if (role == null) {
                    continue;
                }
                role.getStateSupport().setState(npcEntityReference, request.state, request.subState, store);
            }
        }
    }
    
    public static void requestRoleChange(@Nonnull final Ref<EntityStore> ref, @Nonnull final Role role, final int roleIndex, final boolean changeAppearance, @Nonnull final Store<EntityStore> store) {
        requestRoleChange(ref, role, roleIndex, changeAppearance, null, null, store);
    }
    
    public static void requestRoleChange(@Nonnull final Ref<EntityStore> ref, @Nonnull final Role role, final int roleIndex, final boolean changeAppearance, @Nullable final String state, @Nullable final String subState, @Nonnull final ComponentAccessor<EntityStore> store) {
        final RoleChangeQueue roleChangeResource = store.getResource(RoleChangeQueue.getResourceType());
        final Deque<RoleChangeRequest> queue = roleChangeResource.requests;
        queue.add(new RoleChangeRequest(ref, roleIndex, changeAppearance, state, subState));
        role.setRoleChangeRequested();
    }
    
    static {
        LOGGER = HytaleLogger.forEnclosingClass();
    }
    
    public static class RoleChangeQueue implements Resource<EntityStore>
    {
        @Nonnull
        private final Deque<RoleChangeRequest> requests;
        
        public RoleChangeQueue() {
            this.requests = new ArrayDeque<RoleChangeRequest>();
        }
        
        @Nonnull
        public static ResourceType<EntityStore, RoleChangeQueue> getResourceType() {
            return NPCPlugin.get().getRoleChangeQueueResourceType();
        }
        
        @Nonnull
        @Override
        public Resource<EntityStore> clone() {
            final RoleChangeQueue roleChangeQueue = new RoleChangeQueue();
            roleChangeQueue.requests.addAll(this.requests);
            return roleChangeQueue;
        }
    }
    
    private static class RoleChangeRequest
    {
        @Nonnull
        private final Ref<EntityStore> reference;
        private final int roleIndex;
        private final boolean changeAppearance;
        @Nullable
        private final String state;
        @Nullable
        private final String subState;
        
        private RoleChangeRequest(@Nonnull final Ref<EntityStore> reference, final int roleIndex, final boolean changeAppearance, @Nullable final String state, @Nullable final String subState) {
            this.reference = reference;
            this.roleIndex = roleIndex;
            this.changeAppearance = changeAppearance;
            this.state = state;
            this.subState = subState;
        }
    }
}
