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

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

import com.hypixel.hytale.server.npc.instructions.RoleStateChange;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import com.hypixel.hytale.server.npc.asset.builder.Builder;
import java.util.function.Supplier;
import com.hypixel.hytale.server.npc.asset.builder.BuilderFactory;
import com.hypixel.hytale.server.npc.asset.builder.BuilderManager;
import com.hypixel.hytale.server.npc.sensorinfo.InfoProvider;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.server.npc.movement.controllers.MotionController;
import com.hypixel.hytale.server.npc.entities.NPCEntity;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.Ref;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import com.hypixel.hytale.server.npc.role.Role;
import com.hypixel.hytale.server.npc.instructions.ActionList;
import java.util.Iterator;
import java.util.List;
import com.hypixel.hytale.server.npc.asset.builder.StateMappingHelper;
import com.hypixel.hytale.server.npc.statetransition.builders.BuilderStateTransitionEdges;
import com.hypixel.hytale.server.npc.statetransition.builders.BuilderStateTransition;
import com.hypixel.hytale.server.npc.asset.builder.BuilderSupport;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.npc.statetransition.builders.BuilderStateTransitionController;
import javax.annotation.Nullable;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;

public class StateTransitionController
{
    private final Int2ObjectOpenHashMap<IActionListHolder> stateTransitionActions;
    @Nullable
    private IActionListHolder runningActions;
    
    public StateTransitionController(@Nonnull final BuilderStateTransitionController builder, @Nonnull final BuilderSupport support) {
        this.stateTransitionActions = new Int2ObjectOpenHashMap<IActionListHolder>();
        final StateMappingHelper stateHelper = support.getStateHelper();
        final List<BuilderStateTransition.StateTransition> stateTransitionEntries = builder.getStateTransitionEntries(support);
        for (final BuilderStateTransition.StateTransition stateTransitionEntry : stateTransitionEntries) {
            final ActionList actions = stateTransitionEntry.getActions();
            for (final BuilderStateTransitionEdges.StateTransitionEdges stateTransition : stateTransitionEntry.getStateTransitionEdges()) {
                final int priority = stateTransition.getPriority();
                final int[] fromStateIndices = (stateTransition.getFromStateIndices() != null) ? stateTransition.getFromStateIndices() : stateHelper.getAllMainStates();
                final int[] toStateIndices = (stateTransition.getToStateIndices() != null) ? stateTransition.getToStateIndices() : stateHelper.getAllMainStates();
                for (final int fromIndex : fromStateIndices) {
                    for (final int toIndex : toStateIndices) {
                        if (toIndex != fromIndex) {
                            final int combinedValue = indexStateTransitionEdge(fromIndex, toIndex);
                            final IActionListHolder currentList = this.stateTransitionActions.get(combinedValue);
                            if (currentList == null) {
                                this.stateTransitionActions.put(combinedValue, new PrioritisedActionList(priority, actions));
                            }
                            else {
                                CompositeActionList compositeActionList;
                                if (currentList instanceof CompositeActionList) {
                                    compositeActionList = (CompositeActionList)currentList;
                                }
                                else {
                                    compositeActionList = new CompositeActionList((PrioritisedActionList)currentList);
                                    this.stateTransitionActions.put(combinedValue, compositeActionList);
                                }
                                compositeActionList.addActionList(priority, actions);
                            }
                        }
                    }
                }
            }
        }
        this.stateTransitionActions.trim();
    }
    
    public void registerWithSupport(final Role role) {
        for (final IActionListHolder actions : this.stateTransitionActions.values()) {
            actions.registerWithSupport(role);
        }
    }
    
    public void motionControllerChanged(@Nullable final Ref<EntityStore> ref, @Nonnull final NPCEntity npcComponent, @Nullable final MotionController motionController, @Nullable final ComponentAccessor<EntityStore> componentAccessor) {
        for (final IActionListHolder actions : this.stateTransitionActions.values()) {
            actions.motionControllerChanged(ref, npcComponent, motionController, componentAccessor);
        }
    }
    
    public void loaded(final Role role) {
        for (final IActionListHolder actions : this.stateTransitionActions.values()) {
            actions.loaded(role);
        }
    }
    
    public void spawned(final Role role) {
        for (final IActionListHolder actions : this.stateTransitionActions.values()) {
            actions.spawned(role);
        }
    }
    
    public void unloaded(final Role role) {
        for (final IActionListHolder actions : this.stateTransitionActions.values()) {
            actions.unloaded(role);
        }
    }
    
    public void removed(final Role role) {
        for (final IActionListHolder actions : this.stateTransitionActions.values()) {
            actions.removed(role);
        }
    }
    
    public void teleported(final Role role, final World from, final World to) {
        for (final IActionListHolder actions : this.stateTransitionActions.values()) {
            actions.teleported(role, from, to);
        }
    }
    
    public void clearOnce() {
        for (final IActionListHolder actions : this.stateTransitionActions.values()) {
            actions.clearOnce();
        }
    }
    
    public void initiateStateTransition(final int fromState, final int toState) {
        this.runningActions = this.stateTransitionActions.get(indexStateTransitionEdge(fromState, toState));
    }
    
    public boolean isRunningTransitionActions() {
        return this.runningActions != null;
    }
    
    public boolean runTransitionActions(final Ref<EntityStore> ref, final Role role, final double dt, final Store<EntityStore> store) {
        if (this.runningActions == null) {
            return false;
        }
        if (this.runningActions.canExecute(ref, role, null, dt, store) && this.runningActions.execute(ref, role, null, dt, store) && this.runningActions.hasCompletedRun()) {
            this.runningActions.clearOnce();
            this.runningActions = null;
            return false;
        }
        return true;
    }
    
    public static void registerFactories(@Nonnull final BuilderManager builderManager) {
        final BuilderFactory<StateTransitionController> transitionControllerFactory = new BuilderFactory<StateTransitionController>(StateTransitionController.class, "Type", (Supplier<Builder<StateTransitionController>>)BuilderStateTransitionController::new);
        builderManager.registerFactory(transitionControllerFactory);
        final BuilderFactory<BuilderStateTransition.StateTransition> transitionEntryFactory = new BuilderFactory<BuilderStateTransition.StateTransition>(BuilderStateTransition.StateTransition.class, "Type", (Supplier<Builder<BuilderStateTransition.StateTransition>>)BuilderStateTransition::new);
        builderManager.registerFactory(transitionEntryFactory);
        final BuilderFactory<BuilderStateTransitionEdges.StateTransitionEdges> transitionFactory = new BuilderFactory<BuilderStateTransitionEdges.StateTransitionEdges>(BuilderStateTransitionEdges.StateTransitionEdges.class, "Type", (Supplier<Builder<BuilderStateTransitionEdges.StateTransitionEdges>>)BuilderStateTransitionEdges::new);
        builderManager.registerFactory(transitionFactory);
    }
    
    public static int indexStateTransitionEdge(final int from, final int to) {
        return (from << 16) + to;
    }
    
    record PrioritisedActionList(int priority, ActionList actionList) implements IActionListHolder {
        @Override
        public boolean canExecute(@Nonnull final Ref<EntityStore> ref, @Nonnull final Role role, final InfoProvider sensorInfo, final double dt, @Nonnull final Store<EntityStore> store) {
            return this.actionList.canExecute(ref, role, sensorInfo, dt, store);
        }
        
        @Override
        public boolean execute(@Nonnull final Ref<EntityStore> ref, @Nonnull final Role role, final InfoProvider sensorInfo, final double dt, @Nonnull final Store<EntityStore> store) {
            return this.actionList.execute(ref, role, sensorInfo, dt, store);
        }
        
        @Override
        public boolean hasCompletedRun() {
            return this.actionList.hasCompletedRun();
        }
        
        @Override
        public void registerWithSupport(final Role role) {
            this.actionList.registerWithSupport(role);
        }
        
        @Override
        public void motionControllerChanged(@Nullable final Ref<EntityStore> ref, @Nonnull final NPCEntity npcComponent, final MotionController motionController, @Nullable final ComponentAccessor<EntityStore> componentAccessor) {
            this.actionList.motionControllerChanged(ref, npcComponent, motionController, componentAccessor);
        }
        
        @Override
        public void loaded(final Role role) {
            this.actionList.loaded(role);
        }
        
        @Override
        public void spawned(final Role role) {
            this.actionList.spawned(role);
        }
        
        @Override
        public void unloaded(final Role role) {
            this.actionList.unloaded(role);
        }
        
        @Override
        public void removed(final Role role) {
            this.actionList.removed(role);
        }
        
        @Override
        public void teleported(final Role role, final World from, final World to) {
            this.actionList.teleported(role, from, to);
        }
        
        @Override
        public void clearOnce() {
            this.actionList.clearOnce();
        }
    }
    
    private static class CompositeActionList implements IActionListHolder
    {
        private final List<PrioritisedActionList> actionLists;
        private int currentIndex;
        
        private CompositeActionList(final PrioritisedActionList initialActionList) {
            (this.actionLists = new ObjectArrayList<PrioritisedActionList>()).add(initialActionList);
        }
        
        private void addActionList(final int priority, final ActionList actionList) {
            for (int i = 0; i < this.actionLists.size(); ++i) {
                if (priority > this.actionLists.get(i).priority) {
                    this.actionLists.add(i, new PrioritisedActionList(priority, actionList));
                    return;
                }
            }
            this.actionLists.add(new PrioritisedActionList(priority, actionList));
        }
        
        @Override
        public boolean canExecute(@Nonnull final Ref<EntityStore> ref, @Nonnull final Role role, final InfoProvider sensorInfo, final double dt, @Nonnull final Store<EntityStore> store) {
            if (this.currentIndex >= this.actionLists.size()) {
                this.currentIndex = 0;
            }
            return this.actionLists.get(this.currentIndex).actionList.canExecute(ref, role, sensorInfo, dt, store);
        }
        
        @Override
        public boolean execute(@Nonnull final Ref<EntityStore> ref, @Nonnull final Role role, final InfoProvider sensorInfo, final double dt, @Nonnull final Store<EntityStore> store) {
            final PrioritisedActionList actionList = this.actionLists.get(this.currentIndex);
            if (!actionList.actionList.canExecute(ref, role, sensorInfo, dt, store)) {
                return false;
            }
            if (actionList.actionList.execute(ref, role, sensorInfo, dt, store) && actionList.actionList.hasCompletedRun()) {
                ++this.currentIndex;
                return true;
            }
            return false;
        }
        
        @Override
        public boolean hasCompletedRun() {
            if (this.currentIndex >= this.actionLists.size()) {
                this.currentIndex = 0;
                return true;
            }
            return false;
        }
        
        @Override
        public void registerWithSupport(final Role role) {
            for (final PrioritisedActionList actionList : this.actionLists) {
                actionList.actionList.registerWithSupport(role);
            }
        }
        
        @Override
        public void motionControllerChanged(@Nullable final Ref<EntityStore> ref, @Nonnull final NPCEntity npcComponent, final MotionController motionController, @Nullable final ComponentAccessor<EntityStore> componentAccessor) {
            for (final PrioritisedActionList actionList : this.actionLists) {
                actionList.actionList.motionControllerChanged(ref, npcComponent, motionController, componentAccessor);
            }
        }
        
        @Override
        public void loaded(final Role role) {
            for (final PrioritisedActionList actionList : this.actionLists) {
                actionList.actionList.loaded(role);
            }
        }
        
        @Override
        public void spawned(final Role role) {
            for (final PrioritisedActionList actionList : this.actionLists) {
                actionList.actionList.spawned(role);
            }
        }
        
        @Override
        public void unloaded(final Role role) {
            for (final PrioritisedActionList actionList : this.actionLists) {
                actionList.actionList.unloaded(role);
            }
        }
        
        @Override
        public void removed(final Role role) {
            for (final PrioritisedActionList actionList : this.actionLists) {
                actionList.actionList.removed(role);
            }
        }
        
        @Override
        public void teleported(final Role role, final World from, final World to) {
            for (final PrioritisedActionList actionList : this.actionLists) {
                actionList.actionList.teleported(role, from, to);
            }
        }
        
        @Override
        public void clearOnce() {
            for (final PrioritisedActionList actionList : this.actionLists) {
                actionList.actionList.clearOnce();
            }
        }
    }
    
    private interface IActionListHolder extends RoleStateChange
    {
        boolean canExecute(final Ref<EntityStore> p0, final Role p1, final InfoProvider p2, final double p3, final Store<EntityStore> p4);
        
        boolean execute(final Ref<EntityStore> p0, final Role p1, final InfoProvider p2, final double p3, final Store<EntityStore> p4);
        
        boolean hasCompletedRun();
        
        void clearOnce();
    }
}
