package net.minecraft.data.tags;

import com.google.gson.GsonBuilder;
import org.apache.logging.log4j.LogManager;
import java.io.BufferedWriter;
import java.nio.file.Path;
import com.google.gson.JsonObject;
import java.io.IOException;
import java.nio.file.OpenOption;
import java.nio.file.attribute.FileAttribute;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.util.Objects;
import com.google.gson.JsonElement;
import java.util.function.Function;
import java.util.stream.Collectors;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagCollection;
import java.util.Optional;
import net.minecraft.data.HashCache;
import com.google.common.collect.Maps;
import net.minecraft.tags.Tag;
import java.util.Map;
import net.minecraft.core.Registry;
import net.minecraft.data.DataGenerator;
import com.google.gson.Gson;
import org.apache.logging.log4j.Logger;
import net.minecraft.data.DataProvider;

public abstract class TagsProvider<T> implements DataProvider {
    private static final Logger LOGGER;
    private static final Gson GSON;
    protected final DataGenerator generator;
    protected final Registry<T> registry;
    protected final Map<Tag<T>, Tag.Builder<T>> builders;
    
    protected TagsProvider(final DataGenerator gy, final Registry<T> gb) {
        this.builders = Maps.newLinkedHashMap();
        this.generator = gy;
        this.registry = gb;
    }
    
    protected abstract void addTags();
    
    @Override
    public void run(final HashCache ha) {
        this.builders.clear();
        this.addTags();
        final TagCollection<T> aba3 = new TagCollection<T>(sm -> Optional.empty(), "", false, "generated");
        final Map<ResourceLocation, Tag.Builder<T>> map4 = this.builders.entrySet().stream().collect(Collectors.toMap(entry -> entry.getKey().getId(), Map.Entry::getValue));
        aba3.load(map4);
        final JsonObject jsonObject5;
        final Path path6;
        String string7;
        String string8;
        BufferedWriter bufferedWriter9;
        final Throwable t2;
        aba3.getAllTags().forEach((sm, aaz) -> {
            jsonObject5 = aaz.serializeToJson(this.registry::getKey);
            path6 = this.getPath(sm);
            try {
                string7 = TagsProvider.GSON.toJson(jsonObject5);
                string8 = TagsProvider.SHA1.hashUnencodedChars(string7).toString();
                if (!Objects.equals(ha.getHash(path6), string8) || !Files.exists(path6)) {
                    Files.createDirectories(path6.getParent(), new FileAttribute[0]);
                    bufferedWriter9 = Files.newBufferedWriter(path6);
                    try {
                        bufferedWriter9.write(string7);
                    }
                    catch (Throwable t) {
                        throw t;
                    }
                    finally {
                        if (bufferedWriter9 != null) {
                            if (t2 != null) {
                                try {
                                    bufferedWriter9.close();
                                }
                                catch (Throwable exception) {
                                    t2.addSuppressed(exception);
                                }
                            }
                            else {
                                bufferedWriter9.close();
                            }
                        }
                    }
                }
                ha.putNew(path6, string8);
            }
            catch (IOException iOException7) {
                TagsProvider.LOGGER.error("Couldn't save tags to {}", path6, iOException7);
            }
            return;
        });
        this.useTags(aba3);
    }
    
    protected abstract void useTags(final TagCollection<T> aba);
    
    protected abstract Path getPath(final ResourceLocation sm);
    
    protected Tag.Builder<T> tag(final Tag<T> aaz) {
        return this.builders.computeIfAbsent(aaz, aaz -> Tag.Builder.tag());
    }
    
    static {
        LOGGER = LogManager.getLogger();
        GSON = new GsonBuilder().setPrettyPrinting().create();
    }
}
