package net.minecraft.tags;

import javax.annotation.Nullable;
import com.google.common.collect.Sets;
import java.util.Collection;
import com.google.common.collect.ImmutableSet;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.Set;
import java.util.function.Function;
import net.minecraft.resources.ResourceLocation;
import com.google.common.collect.Lists;
import java.util.Optional;
import java.util.List;

public class StaticTagHelper<T> {
    private final TagCollection<T> empty;
    private TagCollection<T> source;
    private final List<Wrapper<T>> wrappers;
    
    public StaticTagHelper() {
        this.empty = new TagCollection<T>(uh -> Optional.empty(), "", "");
        this.source = this.empty;
        this.wrappers = Lists.newArrayList();
    }
    
    public Tag.Named<T> bind(final String string) {
        final Wrapper<T> a3 = new Wrapper<T>(new ResourceLocation(string));
        this.wrappers.add(a3);
        return a3;
    }
    
    public void resetToEmpty() {
        this.source = this.empty;
        final Tag<T> adf2 = SetTag.empty();
        this.wrappers.forEach(a -> a.rebind(uh -> adf2));
    }
    
    public void reset(final TagCollection<T> adg) {
        this.source = adg;
        this.wrappers.forEach(a -> a.rebind(adg::getTag));
    }
    
    public TagCollection<T> getAllTags() {
        return this.source;
    }
    
    public List<Wrapper<T>> getWrappers() {
        return this.wrappers;
    }
    
    public Set<ResourceLocation> getMissingTags(final TagCollection<T> adg) {
        final Set<ResourceLocation> set3 = this.wrappers.stream().map(Wrapper::getName).collect(Collectors.toSet());
        final ImmutableSet<ResourceLocation> immutableSet4 = ImmutableSet.<ResourceLocation>copyOf(adg.getAvailableTags());
        return Sets.<ResourceLocation>difference(set3, immutableSet4);
    }
    
    public static class Wrapper<T> implements Tag.Named<T> {
        @Nullable
        private Tag<T> tag;
        protected final ResourceLocation name;
        
        private Wrapper(final ResourceLocation uh) {
            this.name = uh;
        }
        
        @Override
        public ResourceLocation getName() {
            return this.name;
        }
        
        private Tag<T> resolve() {
            if (this.tag == null) {
                throw new IllegalStateException("Tag " + this.name + " used before it was bound");
            }
            return this.tag;
        }
        
        void rebind(final Function<ResourceLocation, Tag<T>> function) {
            this.tag = function.apply(this.name);
        }
        
        @Override
        public boolean contains(final T object) {
            return this.resolve().contains(object);
        }
        
        @Override
        public List<T> getValues() {
            return this.resolve().getValues();
        }
    }
}
