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

package com.hypixel.hytale.builtin.buildertools.prefabeditor.commands;

import com.hypixel.hytale.server.core.command.system.arguments.system.Argument;
import com.hypixel.hytale.server.core.command.system.arguments.system.AbstractOptionalArg;
import java.util.List;
import com.hypixel.hytale.server.core.prefab.selection.standard.BlockSelection;
import com.hypixel.hytale.builtin.buildertools.prefabeditor.PrefabEditSession;
import com.hypixel.hytale.builtin.buildertools.prefabeditor.PrefabEditSessionManager;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import com.hypixel.hytale.server.core.command.system.CommandSender;
import com.hypixel.hytale.builtin.buildertools.prefabeditor.saving.PrefabSaver;
import com.hypixel.hytale.server.core.modules.singleplayer.SingleplayerModule;
import com.hypixel.hytale.builtin.buildertools.prefabeditor.PrefabEditingMetadata;
import com.hypixel.hytale.builtin.buildertools.prefabeditor.saving.PrefabSaverSettings;
import com.hypixel.hytale.builtin.buildertools.BuilderToolsPlugin;
import com.hypixel.hytale.server.core.entity.entities.Player;
import java.util.concurrent.CompletableFuture;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.server.core.command.system.CommandContext;
import com.hypixel.hytale.common.util.PathUtil;
import com.hypixel.hytale.server.core.prefab.PrefabStore;
import java.nio.file.Path;
import com.hypixel.hytale.server.core.command.system.arguments.system.FlagArg;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.server.core.command.system.basecommands.AbstractAsyncPlayerCommand;

public class PrefabEditSaveCommand extends AbstractAsyncPlayerCommand
{
    @Nonnull
    private static final Message MESSAGE_COMMANDS_EDIT_PREFAB_NOT_IN_EDIT_SESSION;
    @Nonnull
    private static final Message MESSAGE_PATH_OUTSIDE_PREFABS_DIR;
    @Nonnull
    private final FlagArg saveAllArg;
    @Nonnull
    private final FlagArg noEntitiesArg;
    @Nonnull
    private final FlagArg emptyArg;
    @Nonnull
    private final FlagArg confirmArg;
    
    private static boolean isPathInAllowedPrefabDirectory(@Nonnull final Path path) {
        final PrefabStore prefabStore = PrefabStore.get();
        return PathUtil.isChildOf(prefabStore.getServerPrefabsPath(), path) || PathUtil.isChildOf(prefabStore.getAssetPrefabsPath(), path) || PathUtil.isChildOf(prefabStore.getWorldGenPrefabsPath(), path);
    }
    
    public PrefabEditSaveCommand() {
        super("save", "server.commands.editprefab.save.desc");
        this.saveAllArg = ((AbstractOptionalArg<FlagArg, DataType>)this.withFlagArg("saveAll", "server.commands.editprefab.save.saveAll.desc")).addAliases("all");
        this.noEntitiesArg = this.withFlagArg("noEntities", "server.commands.editprefab.save.noEntities.desc");
        this.emptyArg = this.withFlagArg("empty", "server.commands.editprefab.save.empty.desc");
        this.confirmArg = this.withFlagArg("confirm", "server.commands.editprefab.save.confirm.desc");
    }
    
    @Nonnull
    @Override
    protected CompletableFuture<Void> executeAsync(@Nonnull final CommandContext context, @Nonnull final Store<EntityStore> store, @Nonnull final Ref<EntityStore> ref, @Nonnull final PlayerRef playerRef, @Nonnull final World world) {
        final Player playerComponent = store.getComponent(ref, Player.getComponentType());
        assert playerComponent != null;
        final PrefabEditSessionManager prefabEditSessionManager = BuilderToolsPlugin.get().getPrefabEditSessionManager();
        final PrefabEditSession prefabEditSession = prefabEditSessionManager.getPrefabEditSession(playerRef.getUuid());
        if (prefabEditSession == null) {
            context.sendMessage(PrefabEditSaveCommand.MESSAGE_COMMANDS_EDIT_PREFAB_NOT_IN_EDIT_SESSION);
            return CompletableFuture.completedFuture((Void)null);
        }
        final PrefabSaverSettings prefabSaverSettings = new PrefabSaverSettings();
        prefabSaverSettings.setBlocks(true);
        prefabSaverSettings.setEntities(!this.noEntitiesArg.provided(context));
        prefabSaverSettings.setOverwriteExisting(true);
        prefabSaverSettings.setEmpty(((Argument<Arg, Boolean>)this.emptyArg).get(context));
        final boolean confirm = this.confirmArg.provided(context);
        if (this.saveAllArg.provided(context)) {
            final PrefabEditingMetadata[] values = prefabEditSession.getLoadedPrefabMetadata().values().toArray(new PrefabEditingMetadata[0]);
            int readOnlyCount = 0;
            for (final PrefabEditingMetadata value : values) {
                if (value.isReadOnly()) {
                    ++readOnlyCount;
                }
            }
            if (readOnlyCount > 0 && !confirm) {
                context.sendMessage(Message.translation("server.commands.editprefab.save.readOnlyNeedsConfirm").param("count", readOnlyCount));
                return CompletableFuture.completedFuture((Void)null);
            }
            if (!SingleplayerModule.isOwner(playerRef)) {
                for (final PrefabEditingMetadata value : values) {
                    final Path savePath = getWritableSavePath(value, confirm);
                    if (!isPathInAllowedPrefabDirectory(savePath)) {
                        context.sendMessage(PrefabEditSaveCommand.MESSAGE_PATH_OUTSIDE_PREFABS_DIR);
                        return CompletableFuture.completedFuture((Void)null);
                    }
                }
            }
            context.sendMessage(Message.translation("server.commands.editprefab.save.saveAll.start").param("amount", values.length));
            final CompletableFuture<Boolean>[] prefabSavingFutures = new CompletableFuture[values.length];
            for (int i = 0; i < values.length; ++i) {
                final PrefabEditingMetadata value2 = values[i];
                final Path savePath2 = getWritableSavePath(value2, confirm);
                prefabSavingFutures[i] = PrefabSaver.savePrefab(playerComponent, world, savePath2, value2.getAnchorPoint(), value2.getMinPoint(), value2.getMaxPoint(), value2.getPastePosition(), value2.getOriginalFileAnchor(), prefabSaverSettings);
            }
            return CompletableFuture.allOf((CompletableFuture<?>[])prefabSavingFutures).thenAccept(unused -> {
                final List<Integer> failedPrefabFutures = new IntArrayList();
                for (int i2 = 0; i2 < prefabSavingFutures.length; ++i2) {
                    if (prefabSavingFutures[i2].join()) {
                        values[i2].setDirty(false);
                    }
                    else {
                        failedPrefabFutures.add(i2);
                    }
                }
                context.sendMessage(Message.translation("server.commands.editprefab.save.saveAll.success").param("successes", prefabSavingFutures.length - failedPrefabFutures.size()).param("failures", failedPrefabFutures.size()));
            });
        }
        else {
            final PrefabEditingMetadata selectedPrefab = prefabEditSession.getSelectedPrefab(playerRef.getUuid());
            if (selectedPrefab == null) {
                context.sendMessage(Message.translation("server.commands.editprefab.noPrefabSelected"));
                return CompletableFuture.completedFuture((Void)null);
            }
            if (selectedPrefab.isReadOnly() && !confirm) {
                final Path redirectPath = getWritableSavePath(selectedPrefab, true);
                context.sendMessage(Message.translation("server.commands.editprefab.save.readOnlyNeedsConfirmSingle").param("path", selectedPrefab.getPrefabPath().toString()).param("redirectPath", redirectPath.toString()));
                return CompletableFuture.completedFuture((Void)null);
            }
            final BlockSelection selection = BuilderToolsPlugin.getState(playerComponent, playerRef).getSelection();
            if (!selectedPrefab.getMinPoint().equals(selection.getSelectionMin()) || !selectedPrefab.getMaxPoint().equals(selection.getSelectionMax())) {
                context.sendMessage(Message.translation("server.commands.editprefab.save.selectionMismatch"));
                return CompletableFuture.completedFuture((Void)null);
            }
            final Path savePath3 = getWritableSavePath(selectedPrefab, confirm);
            if (!SingleplayerModule.isOwner(playerRef) && !isPathInAllowedPrefabDirectory(savePath3)) {
                context.sendMessage(PrefabEditSaveCommand.MESSAGE_PATH_OUTSIDE_PREFABS_DIR);
                return CompletableFuture.completedFuture((Void)null);
            }
            final Path savePath;
            return PrefabSaver.savePrefab(playerComponent, world, savePath3, selectedPrefab.getAnchorPoint(), selectedPrefab.getMinPoint(), selectedPrefab.getMaxPoint(), selectedPrefab.getPastePosition(), selectedPrefab.getOriginalFileAnchor(), prefabSaverSettings).thenAccept(success -> {
                if (success) {
                    selectedPrefab.setDirty(false);
                }
                context.sendMessage(Message.translation("server.commands.editprefab.save." + (((boolean)success) ? "success" : "failure")).param("name", savePath.toString()));
            });
        }
    }
    
    @Nonnull
    private static Path getWritableSavePath(@Nonnull final PrefabEditingMetadata metadata, final boolean confirm) {
        if (!metadata.isReadOnly() || !confirm) {
            return metadata.getPrefabPath();
        }
        final Path originalPath = metadata.getPrefabPath();
        final String fileName = originalPath.getFileName().toString();
        final Path parent = originalPath.getParent();
        if (parent != null && parent.getFileName() != null) {
            final String parentName = parent.getFileName().toString();
            return PrefabStore.get().getServerPrefabsPath().resolve(parentName).resolve(fileName);
        }
        return PrefabStore.get().getServerPrefabsPath().resolve(fileName);
    }
    
    static {
        MESSAGE_COMMANDS_EDIT_PREFAB_NOT_IN_EDIT_SESSION = Message.translation("server.commands.editprefab.notInEditSession");
        MESSAGE_PATH_OUTSIDE_PREFABS_DIR = Message.translation("server.builderTools.attemptedToSaveOutsidePrefabsDir");
    }
}
