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

package com.hypixel.hytale.builtin.path.commands;

import com.hypixel.hytale.server.core.universe.world.path.WorldPathConfig;
import com.hypixel.hytale.server.core.command.system.arguments.system.OptionalArg;
import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
import java.util.concurrent.TimeUnit;
import com.hypixel.hytale.server.core.modules.entity.teleport.Teleport;
import com.hypixel.hytale.server.core.HytaleServer;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.CompletableFuture;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.command.system.arguments.types.ArgumentType;
import com.hypixel.hytale.server.core.command.system.arguments.types.ArgTypes;
import com.hypixel.hytale.server.core.command.system.arguments.system.RequiredArg;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.server.core.command.system.CommandContext;
import com.hypixel.hytale.server.core.command.system.basecommands.AbstractPlayerCommand;
import java.util.Collection;
import java.util.List;
import com.hypixel.hytale.math.vector.Transform;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import com.hypixel.hytale.server.core.entity.UUIDComponent;
import com.hypixel.hytale.builtin.path.WorldPathBuilder;
import javax.annotation.Nullable;
import com.hypixel.hytale.server.core.universe.world.path.WorldPath;
import com.hypixel.hytale.component.Store;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.server.core.command.system.AbstractCommand;
import com.hypixel.hytale.server.core.command.system.basecommands.AbstractCommandCollection;

public class WorldPathBuilderCommand extends AbstractCommandCollection
{
    public WorldPathBuilderCommand() {
        super("builder", "server.commands.worldpath.builder.desc");
        this.addSubCommand(new WorldPathBuilderStopCommand());
        this.addSubCommand(new WorldPathBuilderLoadCommand());
        this.addSubCommand(new WorldPathBuilderSimulateCommand());
        this.addSubCommand(new WorldPathBuilderClearCommand());
        this.addSubCommand(new WorldPathBuilderAddCommand());
        this.addSubCommand(new WorldPathBuilderSetCommand());
        this.addSubCommand(new WorldPathBuilderGotoCommand());
        this.addSubCommand(new WorldPathBuilderRemoveCommand());
        this.addSubCommand(new WorldPathBuilderSaveCommand());
    }
    
    @Nonnull
    private static WorldPathBuilder createBuilder(@Nonnull final Ref<EntityStore> ref, @Nonnull final Store<EntityStore> store, @Nullable final WorldPath existing) {
        final UUIDComponent uuidComponent = store.getComponent(ref, UUIDComponent.getComponentType());
        assert uuidComponent != null;
        final String name = "Builder-" + String.valueOf(uuidComponent.getUuid());
        final WorldPathBuilder builder = new WorldPathBuilder();
        if (existing == null) {
            builder.setPath(new WorldPath(name, new ObjectArrayList<Transform>()));
        }
        else {
            builder.setPath(new WorldPath(name, new ObjectArrayList<Transform>(existing.getWaypoints())));
        }
        return builder;
    }
    
    @Nullable
    private static WorldPathBuilder getBuilder(@Nonnull final Ref<EntityStore> ref, @Nonnull final Store<EntityStore> store) {
        return store.getComponent(ref, WorldPathBuilder.getComponentType());
    }
    
    @Nonnull
    private static WorldPathBuilder getOrCreateBuilder(@Nonnull final Ref<EntityStore> ref, @Nonnull final Store<EntityStore> store) {
        final WorldPathBuilder builder = store.getComponent(ref, WorldPathBuilder.getComponentType());
        if (builder != null) {
            return builder;
        }
        return putBuilder(ref, store, createBuilder(ref, store, null));
    }
    
    @Nullable
    private static WorldPath removeBuilder(@Nonnull final Ref<EntityStore> ref, @Nonnull final Store<EntityStore> store) {
        final WorldPathBuilder worldPath = store.getComponent(ref, WorldPathBuilder.getComponentType());
        if (worldPath != null) {
            store.removeComponent(ref, WorldPathBuilder.getComponentType());
            return worldPath.getPath();
        }
        return null;
    }
    
    @Nonnull
    private static WorldPathBuilder putBuilder(@Nonnull final Ref<EntityStore> ref, @Nonnull final Store<EntityStore> store, @Nonnull final WorldPathBuilder builder) {
        store.putComponent(ref, WorldPathBuilder.getComponentType(), builder);
        return builder;
    }
    
    private static class WorldPathBuilderStopCommand extends AbstractPlayerCommand
    {
        public WorldPathBuilderStopCommand() {
            super("stop", "server.commands.worldpath.builder.stop.desc");
        }
        
        @Override
        protected void execute(@Nonnull final CommandContext context, @Nonnull final Store<EntityStore> store, @Nonnull final Ref<EntityStore> ref, @Nonnull final PlayerRef playerRef, @Nonnull final World world) {
            WorldPathBuilderCommand.removeBuilder(ref, store);
        }
    }
    
    private static class WorldPathBuilderLoadCommand extends AbstractPlayerCommand
    {
        @Nonnull
        private final RequiredArg<String> nameArg;
        
        public WorldPathBuilderLoadCommand() {
            super("load", "server.commands.worldpath.builder.load.desc");
            this.nameArg = this.withRequiredArg("name", "server.commands.worldpath.builder.load.name.desc", ArgTypes.STRING);
        }
        
        @Override
        protected void execute(@Nonnull final CommandContext context, @Nonnull final Store<EntityStore> store, @Nonnull final Ref<EntityStore> ref, @Nonnull final PlayerRef playerRef, @Nonnull final World world) {
            final String name = this.nameArg.get(context);
            final WorldPath worldPath = world.getWorldPathConfig().getPath(name);
            if (worldPath == null) {
                context.sendMessage(Message.translation("server.universe.worldpath.noPathFound").param("path", name));
                return;
            }
            WorldPathBuilderCommand.putBuilder(ref, store, WorldPathBuilderCommand.createBuilder(ref, store, worldPath));
        }
    }
    
    private static class WorldPathBuilderSimulateCommand extends AbstractPlayerCommand
    {
        public WorldPathBuilderSimulateCommand() {
            super("simulate", "server.commands.worldpath.builder.simulate.desc");
        }
        
        @Override
        protected void execute(@Nonnull final CommandContext context, @Nonnull final Store<EntityStore> store, @Nonnull final Ref<EntityStore> ref, @Nonnull final PlayerRef playerRef, @Nonnull final World world) {
            final WorldPathBuilder builder = WorldPathBuilderCommand.getBuilder(ref, store);
            if (builder == null) {
                return;
            }
            final ObjectArrayList<Transform> waypoints = new ObjectArrayList<Transform>(builder.getPath().getWaypoints());
            final CompletableFuture<Void> future = new CompletableFuture<Void>();
            final ScheduledFuture<?>[] scheduledFuture = { HytaleServer.SCHEDULED_EXECUTOR.scheduleWithFixedDelay(() -> {
                    final Transform transform = (Transform)waypoints.removeFirst();
                    if (transform == null) {
                        future.complete(null);
                        scheduledFuture[0].cancel(false);
                    }
                    else {
                        world.execute(() -> {
                            final Teleport teleportComponent = Teleport.createForPlayer(transform);
                            store.addComponent(ref, Teleport.getComponentType(), teleportComponent);
                        });
                    }
                }, 1L, 1L, TimeUnit.SECONDS) };
        }
    }
    
    private static class WorldPathBuilderClearCommand extends AbstractPlayerCommand
    {
        @Nonnull
        private static final Message MESSAGE_UNIVERSE_WORLD_PATH_POINTS_CLEARED;
        
        public WorldPathBuilderClearCommand() {
            super("clear", "server.commands.worldpath.builder.clear.desc");
        }
        
        @Override
        protected void execute(@Nonnull final CommandContext context, @Nonnull final Store<EntityStore> store, @Nonnull final Ref<EntityStore> ref, @Nonnull final PlayerRef playerRef, @Nonnull final World world) {
            final WorldPathBuilder builder = WorldPathBuilderCommand.getBuilder(ref, store);
            if (builder == null) {
                return;
            }
            builder.getPath().getWaypoints().clear();
            context.sendMessage(WorldPathBuilderClearCommand.MESSAGE_UNIVERSE_WORLD_PATH_POINTS_CLEARED);
        }
        
        static {
            MESSAGE_UNIVERSE_WORLD_PATH_POINTS_CLEARED = Message.translation("server.universe.worldpath.pointsCleared");
        }
    }
    
    private static class WorldPathBuilderAddCommand extends AbstractPlayerCommand
    {
        @Nonnull
        private static final Message MESSAGE_UNIVERSE_WORLD_PATH_POINT_ADDED;
        
        public WorldPathBuilderAddCommand() {
            super("add", "server.commands.worldpath.builder.add.desc");
        }
        
        @Override
        protected void execute(@Nonnull final CommandContext context, @Nonnull final Store<EntityStore> store, @Nonnull final Ref<EntityStore> ref, @Nonnull final PlayerRef playerRef, @Nonnull final World world) {
            final TransformComponent transformComponent = store.getComponent(ref, TransformComponent.getComponentType());
            assert transformComponent != null;
            final Transform transform = transformComponent.getTransform().clone();
            WorldPathBuilderCommand.getOrCreateBuilder(ref, store).getPath().getWaypoints().add(transform);
            context.sendMessage(WorldPathBuilderAddCommand.MESSAGE_UNIVERSE_WORLD_PATH_POINT_ADDED);
        }
        
        static {
            MESSAGE_UNIVERSE_WORLD_PATH_POINT_ADDED = Message.translation("server.universe.worldpath.pointAdded");
        }
    }
    
    private static class WorldPathBuilderSetCommand extends AbstractPlayerCommand
    {
        @Nonnull
        private static final Message MESSAGE_UNIVERSE_WORLD_PATH_POINT_SET;
        @Nonnull
        private final OptionalArg<Integer> indexArg;
        
        public WorldPathBuilderSetCommand() {
            super("set", "server.commands.worldpath.builder.set.desc");
            this.indexArg = this.withOptionalArg("index", "server.commands.worldpath.builder.set.index.desc", ArgTypes.INTEGER);
        }
        
        @Override
        protected void execute(@Nonnull final CommandContext context, @Nonnull final Store<EntityStore> store, @Nonnull final Ref<EntityStore> ref, @Nonnull final PlayerRef playerRef, @Nonnull final World world) {
            final WorldPathBuilder builder = WorldPathBuilderCommand.getBuilder(ref, store);
            if (builder == null) {
                return;
            }
            final TransformComponent transformComponent = store.getComponent(ref, TransformComponent.getComponentType());
            assert transformComponent != null;
            final WorldPath worldPath = builder.getPath();
            final int index = this.indexArg.provided(context) ? this.indexArg.get(context) : (worldPath.getWaypoints().size() - 1);
            worldPath.getWaypoints().set(index, transformComponent.getTransform().clone());
            context.sendMessage(WorldPathBuilderSetCommand.MESSAGE_UNIVERSE_WORLD_PATH_POINT_SET);
        }
        
        static {
            MESSAGE_UNIVERSE_WORLD_PATH_POINT_SET = Message.translation("server.universe.worldpath.pointSet");
        }
    }
    
    private static class WorldPathBuilderGotoCommand extends AbstractPlayerCommand
    {
        @Nonnull
        private final RequiredArg<Integer> indexArg;
        
        public WorldPathBuilderGotoCommand() {
            super("goto", "server.commands.worldpath.builder.goto.desc");
            this.indexArg = this.withRequiredArg("index", "server.commands.worldpath.builder.goto.index.desc", ArgTypes.INTEGER);
        }
        
        @Override
        protected void execute(@Nonnull final CommandContext context, @Nonnull final Store<EntityStore> store, @Nonnull final Ref<EntityStore> ref, @Nonnull final PlayerRef playerRef, @Nonnull final World world) {
            final WorldPathBuilder builder = WorldPathBuilderCommand.getBuilder(ref, store);
            if (builder == null) {
                return;
            }
            final Integer index = this.indexArg.get(context);
            final WorldPath worldPath = builder.getPath();
            final Transform waypointTransform = worldPath.getWaypoints().get(index);
            final Teleport teleportComponent = Teleport.createForPlayer(null, waypointTransform);
            store.addComponent(ref, Teleport.getComponentType(), teleportComponent);
            context.sendMessage(Message.translation("server.universe.worldpath.teleportedToPoint").param("index", index));
        }
    }
    
    private static class WorldPathBuilderRemoveCommand extends AbstractPlayerCommand
    {
        @Nonnull
        private final RequiredArg<Integer> indexArg;
        
        public WorldPathBuilderRemoveCommand() {
            super("remove", "server.commands.worldpath.builder.remove.desc");
            this.indexArg = this.withRequiredArg("index", "server.commands.worldpath.builder.remove.index.desc", ArgTypes.INTEGER);
        }
        
        @Override
        protected void execute(@Nonnull final CommandContext context, @Nonnull final Store<EntityStore> store, @Nonnull final Ref<EntityStore> ref, @Nonnull final PlayerRef playerRef, @Nonnull final World world) {
            final WorldPathBuilder builder = WorldPathBuilderCommand.getBuilder(ref, store);
            if (builder == null) {
                return;
            }
            final int index = this.indexArg.get(context);
            builder.getPath().getWaypoints().remove(index);
            context.sendMessage(Message.translation("server.universe.worldpath.removedIndex").param("index", index));
        }
    }
    
    private static class WorldPathBuilderSaveCommand extends AbstractPlayerCommand
    {
        @Nonnull
        private static final Message MESSAGE_UNIVERSE_WORLD_PATH_NO_POINTS_DEFINED;
        @Nonnull
        private static final Message MESSAGE_UNIVERSE_WORLD_PATH_SAVED;
        @Nonnull
        private final RequiredArg<String> nameArg;
        
        public WorldPathBuilderSaveCommand() {
            super("save", "server.commands.worldpath.builder.save.desc");
            this.nameArg = this.withRequiredArg("name", "server.commands.worldpath.builder.save.name.desc", ArgTypes.STRING);
        }
        
        @Override
        protected void execute(@Nonnull final CommandContext context, @Nonnull final Store<EntityStore> store, @Nonnull final Ref<EntityStore> ref, @Nonnull final PlayerRef playerRef, @Nonnull final World world) {
            final String name = this.nameArg.get(context);
            final WorldPath path = WorldPathBuilderCommand.removeBuilder(ref, store);
            if (path == null || path.getWaypoints().isEmpty()) {
                context.sendMessage(WorldPathBuilderSaveCommand.MESSAGE_UNIVERSE_WORLD_PATH_NO_POINTS_DEFINED);
                return;
            }
            final WorldPathConfig worldPathConfig = world.getWorldPathConfig();
            final WorldPath worldPath = new WorldPath(name, path.getWaypoints());
            worldPathConfig.putPath(worldPath);
            worldPathConfig.save(world);
            context.sendMessage(WorldPathBuilderSaveCommand.MESSAGE_UNIVERSE_WORLD_PATH_SAVED);
        }
        
        static {
            MESSAGE_UNIVERSE_WORLD_PATH_NO_POINTS_DEFINED = Message.translation("server.universe.worldpath.noPointsDefined");
            MESSAGE_UNIVERSE_WORLD_PATH_SAVED = Message.translation("server.universe.worldpath.saved");
        }
    }
}
