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

package com.hypixel.hytale.builtin.tagset;

import com.hypixel.hytale.assetstore.JsonAsset;
import javax.annotation.Nullable;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import java.util.logging.Level;
import it.unimi.dsi.fastutil.objects.Object2IntMaps;
import com.hypixel.hytale.common.util.StringUtil;
import java.util.function.IntConsumer;
import java.util.function.Consumer;
import java.util.Objects;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import java.util.Map;
import javax.annotation.Nonnull;
import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;

public class TagSetLookupTable<T extends TagSet>
{
    @Nonnull
    private Int2ObjectMap<IntSet> tagMatcher;
    
    public TagSetLookupTable(@Nonnull final Map<String, T> tagSetMap, @Nonnull final Object2IntMap<String> tagSetIndexMap, @Nonnull final Object2IntMap<String> tagIndexMap) {
        this.tagMatcher = new Int2ObjectOpenHashMap<IntSet>();
        this.createTagMap(tagSetMap, tagSetIndexMap, tagIndexMap);
    }
    
    private void createTagMap(@Nonnull final Map<String, T> tagSetMap, @Nonnull final Object2IntMap<String> tagSetIndexMap, @Nonnull final Object2IntMap<String> tagIndexMap) {
        final IntArrayList path = new IntArrayList();
        tagSetMap.forEach((key, entry) -> {
            final int id = tagSetIndexMap.getOrDefault(key, -1);
            if (id < 0 || !this.tagMatcher.containsKey(id)) {
                try {
                    this.createTagSet(entry, tagSetMap, tagSetIndexMap, tagIndexMap, path);
                }
                catch (final IllegalStateException e) {
                    throw new IllegalStateException(key + ": ", (Throwable)e);
                }
                path.clear();
            }
        });
    }
    
    @Nonnull
    private IntSet createTagSet(@Nonnull final T tagSet, @Nonnull final Map<String, T> tagSetMap, @Nonnull final Object2IntMap<String> tagSetIndexMap, @Nonnull final Object2IntMap<String> tagIndexMap, @Nonnull final IntArrayList path) {
        final IntOpenHashSet set = new IntOpenHashSet();
        final int index = tagSetIndexMap.getInt(((JsonAsset<Object>)tagSet).getId());
        if (path.contains(index)) {
            throw new IllegalStateException("Cyclic reference to set detected: " + (String)tagSet.getId());
        }
        path.add(index);
        this.tagMatcher.put(index, set);
        if (!tagIndexMap.isEmpty()) {
            final String[] includedTagSets = tagSet.getIncludedTagSets();
            if (includedTagSets != null) {
                for (final String tag5 : includedTagSets) {
                    final String tag = tag5;
                    final IntOpenHashSet obj = set;
                    Objects.requireNonNull(obj);
                    this.consumeSet(tag5, tagSetMap, tagSetIndexMap, tagIndexMap, path, (Consumer<IntSet>)obj::addAll);
                }
            }
            final String[] excludedTagSets = tagSet.getExcludedTagSets();
            if (excludedTagSets != null) {
                for (final String tag6 : excludedTagSets) {
                    final String tag2 = tag6;
                    final IntOpenHashSet obj2 = set;
                    Objects.requireNonNull(obj2);
                    this.consumeSet(tag6, tagSetMap, tagSetIndexMap, tagIndexMap, path, (Consumer<IntSet>)obj2::removeAll);
                }
            }
            final String[] includedTags = tagSet.getIncludedTags();
            if (includedTags != null) {
                for (final String tag7 : includedTags) {
                    final String tag3 = tag7;
                    final IntOpenHashSet obj3 = set;
                    Objects.requireNonNull(obj3);
                    this.consumeTag(tag7, tagSet, tagIndexMap, obj3::add);
                }
            }
            final String[] excludedTags = tagSet.getExcludedTags();
            if (excludedTags != null) {
                for (final String tag8 : excludedTags) {
                    final String tag4 = tag8;
                    final IntOpenHashSet obj4 = set;
                    Objects.requireNonNull(obj4);
                    this.consumeTag(tag8, tagSet, tagIndexMap, obj4::remove);
                }
            }
        }
        return set;
    }
    
    private void consumeSet(final String tag, @Nonnull final Map<String, T> tagSetMap, @Nonnull final Object2IntMap<String> tagSetIndexMap, @Nonnull final Object2IntMap<String> tagIndexMap, @Nonnull final IntArrayList path, @Nonnull final Consumer<IntSet> predicate) {
        final IntSet s = this.getOrCreateTagSet(tag, tagSetMap, tagSetIndexMap, tagIndexMap, path);
        if (s != null) {
            predicate.accept(s);
        }
    }
    
    private void consumeTag(@Nonnull final String tag, @Nonnull final T tagSet, @Nonnull final Object2IntMap<String> tagIndexMap, @Nonnull final IntConsumer predicate) {
        if (StringUtil.isGlobPattern(tag)) {
            final ObjectIterator<Object2IntMap.Entry<String>> it = Object2IntMaps.fastIterator(tagIndexMap);
            while (it.hasNext()) {
                final Object2IntMap.Entry<String> entry = it.next();
                if (StringUtil.isGlobMatching(tag, entry.getKey())) {
                    predicate.accept(entry.getIntValue());
                }
            }
            return;
        }
        final int index = tagIndexMap.getOrDefault(tag, -1);
        if (index >= 0) {
            predicate.accept(index);
            return;
        }
        TagSetPlugin.get().getLogger().at(Level.WARNING).log("Tag Set '%s' references '%s' which is not a pattern and does not otherwise exist", ((JsonAsset<Object>)tagSet).getId(), tag);
    }
    
    @Nullable
    private IntSet getOrCreateTagSet(final String identifier, @Nonnull final Map<String, T> tagSetMap, @Nonnull final Object2IntMap<String> tagSetIndexMap, @Nonnull final Object2IntMap<String> tagIndexMap, @Nonnull final IntArrayList path) {
        final int tagSetIndex = tagSetIndexMap.getOrDefault(identifier, -1);
        IntSet intSet = null;
        if (tagSetIndex >= 0 && this.tagMatcher.containsKey(tagSetIndex)) {
            if (path.contains(tagSetIndex)) {
                throw new IllegalStateException("Cyclic reference to set detected: " + identifier);
            }
            path.add(tagSetIndex);
            intSet = this.tagMatcher.get(tagSetIndex);
        }
        else {
            final T set = tagSetMap.get(identifier);
            if (set != null) {
                intSet = this.createTagSet(set, tagSetMap, tagSetIndexMap, tagIndexMap, path);
            }
            else {
                TagSetPlugin.get().getLogger().at(Level.WARNING).log("Creating tag sets: Tag Set '%s' does not exist, but is being referenced as a tag", identifier);
            }
        }
        path.removeInt(path.size() - 1);
        return intSet;
    }
    
    @Nonnull
    public Int2ObjectMap<IntSet> getFlattenedSet() {
        return this.tagMatcher;
    }
}
