package net.minecraft.client.searchtree;

import com.google.common.collect.Iterators;
import com.google.common.collect.PeekingIterator;
import com.google.common.collect.AbstractIterator;
import java.util.Comparator;
import java.util.Locale;
import java.util.Iterator;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import com.google.common.collect.Lists;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import java.util.List;
import net.minecraft.resources.ResourceLocation;
import java.util.stream.Stream;
import java.util.function.Function;

public class ReloadableIdSearchTree<T> implements MutableSearchTree<T> {
    protected SuffixArray<T> namespaceTree;
    protected SuffixArray<T> pathTree;
    private final Function<T, Stream<ResourceLocation>> idGetter;
    private final List<T> contents;
    private final Object2IntMap<T> orderT;
    
    public ReloadableIdSearchTree(final Function<T, Stream<ResourceLocation>> function) {
        this.namespaceTree = new SuffixArray<T>();
        this.pathTree = new SuffixArray<T>();
        this.contents = Lists.newArrayList();
        this.orderT = (Object2IntMap<T>)new Object2IntOpenHashMap();
        this.idGetter = function;
    }
    
    @Override
    public void refresh() {
        this.namespaceTree = new SuffixArray<T>();
        this.pathTree = new SuffixArray<T>();
        for (final T object3 : this.contents) {
            this.index(object3);
        }
        this.namespaceTree.generate();
        this.pathTree.generate();
    }
    
    @Override
    public void add(final T object) {
        this.orderT.put(object, this.contents.size());
        this.contents.add(object);
        this.index(object);
    }
    
    @Override
    public void clear() {
        this.contents.clear();
        this.orderT.clear();
    }
    
    protected void index(final T object) {
        this.idGetter.apply(object).forEach(sm -> {
            this.namespaceTree.add(object, sm.getNamespace().toLowerCase(Locale.ROOT));
            this.pathTree.add(object, sm.getPath().toLowerCase(Locale.ROOT));
        });
    }
    
    protected int comparePosition(final T object1, final T object2) {
        return Integer.compare(this.orderT.getInt(object1), this.orderT.getInt(object2));
    }
    
    @Override
    public List<T> search(final String string) {
        final int integer3 = string.indexOf(58);
        if (integer3 == -1) {
            return this.pathTree.search(string);
        }
        final List<T> list4 = this.namespaceTree.search(string.substring(0, integer3).trim());
        final String string2 = string.substring(integer3 + 1).trim();
        final List<T> list5 = this.pathTree.search(string2);
        return Lists.newArrayList(new IntersectionIterator<>(list4.iterator(), list5.iterator(), this::comparePosition));
    }
    
    public static class IntersectionIterator<T> extends AbstractIterator<T> {
        private final PeekingIterator<T> firstIterator;
        private final PeekingIterator<T> secondIterator;
        private final Comparator<T> orderT;
        
        public IntersectionIterator(final Iterator<T> iterator1, final Iterator<T> iterator2, final Comparator<T> comparator) {
            this.firstIterator = Iterators.<T>peekingIterator(iterator1);
            this.secondIterator = Iterators.<T>peekingIterator(iterator2);
            this.orderT = comparator;
        }
        
        @Override
        protected T computeNext() {
            while (this.firstIterator.hasNext() && this.secondIterator.hasNext()) {
                final int integer2 = this.orderT.compare(this.firstIterator.peek(), this.secondIterator.peek());
                if (integer2 == 0) {
                    this.secondIterator.next();
                    return this.firstIterator.next();
                }
                if (integer2 < 0) {
                    this.firstIterator.next();
                }
                else {
                    this.secondIterator.next();
                }
            }
            return this.endOfData();
        }
    }
}
