001/*
002 * This file is part of Baritone.
003 *
004 * Baritone is free software: you can redistribute it and/or modify
005 * it under the terms of the GNU Lesser General Public License as published by
006 * the Free Software Foundation, either version 3 of the License, or
007 * (at your option) any later version.
008 *
009 * Baritone is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012 * GNU Lesser General Public License for more details.
013 *
014 * You should have received a copy of the GNU Lesser General Public License
015 * along with Baritone.  If not, see <https://www.gnu.org/licenses/>.
016 */
017
018package baritone.api.command.datatypes;
019
020import baritone.api.command.argument.IArgConsumer;
021import baritone.api.command.exception.CommandException;
022
023import java.io.File;
024import java.io.IOException;
025import java.io.UncheckedIOException;
026import java.nio.file.FileSystems;
027import java.nio.file.InvalidPathException;
028import java.nio.file.Path;
029import java.util.Locale;
030import java.util.Objects;
031import java.util.stream.Stream;
032
033import static baritone.api.utils.Helper.HELPER;
034
035public enum RelativeFile implements IDatatypePost<File, File> {
036    INSTANCE;
037
038    @Override
039    public File apply(IDatatypeContext ctx, File original) throws CommandException {
040        if (original == null) {
041            original = new File("./");
042        }
043
044        Path path;
045        try {
046            path = FileSystems.getDefault().getPath(ctx.getConsumer().getString());
047        } catch (InvalidPathException e) {
048            throw new IllegalArgumentException("invalid path");
049        }
050        return getCanonicalFileUnchecked(original.toPath().resolve(path).toFile());
051    }
052
053    @Override
054    public Stream<String> tabComplete(IDatatypeContext ctx) {
055        return Stream.empty();
056    }
057
058    /**
059     * Seriously
060     *
061     * @param file File
062     * @return Canonical file of file
063     * @author LoganDark
064     */
065    private static File getCanonicalFileUnchecked(File file) {
066        try {
067            return file.getCanonicalFile();
068        } catch (IOException e) {
069            throw new UncheckedIOException(e);
070        }
071    }
072
073    public static Stream<String> tabComplete(IArgConsumer consumer, File base0) throws CommandException {
074        // I will not make the caller deal with this, seriously
075        // Tab complete code is beautiful and I'm not going to bloat it with dumb ass checked exception bullshit -LoganDark
076
077        // lol owned -Brady
078
079        File base = getCanonicalFileUnchecked(base0);
080        String currentPathStringThing = consumer.getString();
081        Path currentPath = FileSystems.getDefault().getPath(currentPathStringThing);
082        Path basePath = currentPath.isAbsolute() ? currentPath.getRoot() : base.toPath();
083        boolean useParent = !currentPathStringThing.isEmpty() && !currentPathStringThing.endsWith(File.separator);
084        File currentFile = currentPath.isAbsolute() ? currentPath.toFile() : new File(base, currentPathStringThing);
085        return Stream.of(Objects.requireNonNull(getCanonicalFileUnchecked(
086                useParent
087                        ? currentFile.getParentFile()
088                        : currentFile
089        ).listFiles()))
090                .map(f -> (currentPath.isAbsolute() ? f : basePath.relativize(f.toPath()).toString()) +
091                        (f.isDirectory() ? File.separator : ""))
092                .filter(s -> s.toLowerCase(Locale.US).startsWith(currentPathStringThing.toLowerCase(Locale.US)))
093                .filter(s -> !s.contains(" "));
094    }
095
096    public static File gameDir() {
097        File gameDir = HELPER.mc.gameDir.getAbsoluteFile();
098        if (gameDir.getName().equals(".")) {
099            return gameDir.getParentFile();
100        }
101        return gameDir;
102    }
103}