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

package com.hypixel.hytale.assetstore;

import java.util.Collection;
import java.util.ArrayList;
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import java.util.Collections;
import java.util.Iterator;
import java.util.function.BiFunction;
import com.hypixel.hytale.common.util.ArrayUtil;
import it.unimi.dsi.fastutil.ints.IntSets;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.util.HashMap;
import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import java.util.List;
import com.hypixel.hytale.assetstore.map.JsonAssetWithMap;
import java.util.Map;
import javax.annotation.Nonnull;
import com.hypixel.hytale.codec.validation.ValidationResults;
import java.util.function.Function;
import javax.annotation.Nullable;
import java.nio.file.Path;
import com.hypixel.hytale.codec.ExtraInfo;

public class AssetExtraInfo<K> extends ExtraInfo
{
    @Nullable
    private final Path assetPath;
    private final Data data;
    
    public AssetExtraInfo(final Data data) {
        super(Integer.MAX_VALUE, (Function<ExtraInfo, ValidationResults>)AssetValidationResults::new);
        this.assetPath = null;
        this.data = data;
    }
    
    public AssetExtraInfo(final Path assetPath, final Data data) {
        super(Integer.MAX_VALUE, (Function<ExtraInfo, ValidationResults>)AssetValidationResults::new);
        this.assetPath = assetPath;
        this.data = data;
    }
    
    @Nonnull
    public String generateKey() {
        return "*" + String.valueOf(this.getKey()) + "_" + this.peekKey('_');
    }
    
    public K getKey() {
        return (K)this.getData().getKey();
    }
    
    @Nullable
    public Path getAssetPath() {
        return this.assetPath;
    }
    
    public Data getData() {
        return this.data;
    }
    
    @Override
    public void appendDetailsTo(@Nonnull final StringBuilder sb) {
        sb.append("Id: ").append(this.getKey()).append("\n");
        if (this.assetPath != null) {
            sb.append("Path: ").append(this.assetPath).append("\n");
        }
    }
    
    @Override
    public AssetValidationResults getValidationResults() {
        return (AssetValidationResults)super.getValidationResults();
    }
    
    @Nonnull
    @Override
    public String toString() {
        return "AssetExtraInfo{assetPath=" + String.valueOf(this.assetPath) + ", data=" + String.valueOf(this.data) + "} " + super.toString();
    }
    
    public static class Data
    {
        public static final char TAG_VALUE_SEPARATOR = '=';
        private Map<Class<? extends JsonAssetWithMap>, List<Object>> containedAssets;
        private Map<Class<? extends JsonAssetWithMap>, List<RawAsset<Object>>> containedRawAssets;
        @Nullable
        private Data containerData;
        private Class<? extends JsonAsset<?>> assetClass;
        private Object key;
        private Object parentKey;
        private final Map<String, String[]> rawTags;
        private final Int2ObjectMap<IntSet> tagStorage;
        private final Int2ObjectMap<IntSet> unmodifiableTagStorage;
        private final IntSet expandedTagStorage;
        private final IntSet unmodifiableExpandedTagStorage;
        
        public <K> Data(final Class<? extends JsonAsset<K>> assetClass, final K key, final K parentKey) {
            this.rawTags = new HashMap<String, String[]>(0);
            this.tagStorage = new Int2ObjectOpenHashMap<IntSet>(0);
            this.unmodifiableTagStorage = new Int2ObjectOpenHashMap<IntSet>(0);
            this.expandedTagStorage = new IntOpenHashSet(0);
            this.unmodifiableExpandedTagStorage = IntSets.unmodifiable(this.expandedTagStorage);
            this.assetClass = assetClass;
            this.key = key;
            this.parentKey = parentKey;
        }
        
        public <K> Data(@Nullable final Data containerData, final Class<? extends JsonAsset<K>> aClass, final K key, final K parentKey, final boolean inheritContainerTags) {
            this(aClass, key, parentKey);
            this.containerData = containerData;
            if (containerData != null && inheritContainerTags) {
                this.putTags(containerData.rawTags);
            }
        }
        
        public Class<? extends JsonAsset<?>> getAssetClass() {
            return this.assetClass;
        }
        
        public Object getKey() {
            return this.key;
        }
        
        public Object getParentKey() {
            return this.parentKey;
        }
        
        @Nonnull
        public Data getRootContainerData() {
            Data temp;
            for (temp = this; temp.containerData != null; temp = temp.containerData) {}
            return temp;
        }
        
        @Nullable
        public Data getContainerData() {
            return this.containerData;
        }
        
        @Nullable
        public <K> K getContainerKey(final Class<? extends JsonAsset<K>> aClass) {
            if (this.containerData == null) {
                return null;
            }
            if (this.containerData.assetClass.equals(aClass)) {
                return (K)this.containerData.key;
            }
            return (K)this.containerData.getContainerKey((Class<? extends JsonAsset<Object>>)aClass);
        }
        
        public void putTags(@Nonnull final Map<String, String[]> tags) {
            for (Map.Entry<String, String[]> entry : tags.entrySet()) {
                final String tag = entry.getKey().intern();
                this.rawTags.merge(tag, entry.getValue(), (BiFunction<? super String[], ? super String[], ? extends String[]>)ArrayUtil::combine);
                final IntSet tagIndexes = this.ensureTag(tag);
                final String[] array = entry.getValue();
                for (int length = array.length, i = 0; i < length; ++i) {
                    final String value = array[i];
                    tagIndexes.add(AssetRegistry.getOrCreateTagIndex(value));
                    this.ensureTag(value);
                    this.rawTags.putIfAbsent(value, ArrayUtil.EMPTY_STRING_ARRAY);
                    final String valueTag = (tag + "=" + value).intern();
                    this.rawTags.putIfAbsent(valueTag, ArrayUtil.EMPTY_STRING_ARRAY);
                    this.ensureTag(valueTag);
                }
            }
        }
        
        @Nonnull
        public Map<String, String[]> getRawTags() {
            return Collections.unmodifiableMap((Map<? extends String, ? extends String[]>)this.rawTags);
        }
        
        @Nonnull
        public Int2ObjectMap<IntSet> getTags() {
            return Int2ObjectMaps.unmodifiable((Int2ObjectMap<? extends IntSet>)this.unmodifiableTagStorage);
        }
        
        @Nonnull
        public IntSet getExpandedTagIndexes() {
            return this.unmodifiableExpandedTagStorage;
        }
        
        public IntSet getTag(final int tagIndex) {
            return this.unmodifiableTagStorage.getOrDefault(tagIndex, IntSets.EMPTY_SET);
        }
        
        public <K, T extends JsonAssetWithMap<K, M>, M extends AssetMap<K, T>> void addContainedAsset(final Class<T> assetClass, final T asset) {
            if (this.containedAssets == null) {
                this.containedAssets = new HashMap<Class<? extends JsonAssetWithMap>, List<Object>>();
            }
            this.containedAssets.computeIfAbsent((Class<? extends JsonAssetWithMap>)assetClass, k -> new ArrayList()).add(asset);
        }
        
        public <K, T extends JsonAssetWithMap<K, M>, M extends AssetMap<K, T>> void addContainedAsset(final Class<T> assetClass, final RawAsset<K> rawAsset) {
            if (this.containedRawAssets == null) {
                this.containedRawAssets = new HashMap<Class<? extends JsonAssetWithMap>, List<RawAsset<Object>>>();
            }
            this.containedRawAssets.computeIfAbsent((Class<? extends JsonAssetWithMap>)assetClass, k -> new ArrayList()).add((Object)rawAsset);
        }
        
        public <K> void fetchContainedAssets(final K key, @Nonnull final Map<Class<? extends JsonAssetWithMap>, Map<K, List<Object>>> containedAssets) {
            if (this.containedAssets == null) {
                return;
            }
            for (final Map.Entry<Class<? extends JsonAssetWithMap>, List<Object>> entry : this.containedAssets.entrySet()) {
                ((List)containedAssets.computeIfAbsent((Class<? extends JsonAssetWithMap>)entry.getKey(), k -> new HashMap()).computeIfAbsent((Object)key, k -> new ArrayList(3))).addAll(entry.getValue());
            }
        }
        
        public <K> void fetchContainedRawAssets(final K key, @Nonnull final Map<Class<? extends JsonAssetWithMap>, Map<K, List<RawAsset<Object>>>> containedAssets) {
            if (this.containedRawAssets == null) {
                return;
            }
            for (final Map.Entry<Class<? extends JsonAssetWithMap>, List<RawAsset<Object>>> entry : this.containedRawAssets.entrySet()) {
                ((List)containedAssets.computeIfAbsent((Class<? extends JsonAssetWithMap>)entry.getKey(), k -> new HashMap()).computeIfAbsent((Object)key, k -> new ArrayList(3))).addAll(entry.getValue());
            }
        }
        
        public <K, T extends JsonAssetWithMap<K, M>, M extends AssetMap<K, T>> boolean containsAsset(final Class<T> tClass, final K key) {
            if (this.containedAssets != null) {
                final List<T> assets = (List<T>)this.containedAssets.get(tClass);
                if (assets != null) {
                    final Function<T, K> keyFunction = AssetRegistry.getAssetStore(tClass).getKeyFunction();
                    for (final T asset : assets) {
                        if (key.equals(keyFunction.apply(asset))) {
                            return true;
                        }
                    }
                }
            }
            if (this.containedRawAssets != null) {
                final List<RawAsset<T>> rawAssets = (List<RawAsset<T>>)this.containedRawAssets.get(tClass);
                if (rawAssets != null) {
                    for (final RawAsset<T> rawAsset : rawAssets) {
                        if (key.equals(rawAsset.getKey())) {
                            return true;
                        }
                    }
                }
            }
            return false;
        }
        
        public void loadContainedAssets(final boolean reloading) {
            if (this.containedAssets != null) {
                for (final Map.Entry<Class<? extends JsonAssetWithMap>, List<Object>> entry : this.containedAssets.entrySet()) {
                    AssetRegistry.getAssetStore(entry.getKey()).loadAssets("Hytale:Hytale", (List<JsonAssetWithMap>)entry.getValue(), AssetUpdateQuery.DEFAULT, reloading);
                }
            }
            if (this.containedRawAssets != null) {
                for (final Map.Entry<Class<? extends JsonAssetWithMap>, List<RawAsset<Object>>> entry2 : this.containedRawAssets.entrySet()) {
                    AssetRegistry.getAssetStore(entry2.getKey()).loadBuffersWithKeys("Hytale:Hytale", entry2.getValue(), AssetUpdateQuery.DEFAULT, reloading);
                }
            }
        }
        
        @Nonnull
        private IntSet ensureTag(@Nonnull final String tag) {
            final int idx = AssetRegistry.getOrCreateTagIndex(tag);
            this.expandedTagStorage.add(idx);
            return this.tagStorage.computeIfAbsent(idx, k -> {
                final IntSet set = new IntOpenHashSet(3);
                this.unmodifiableTagStorage.put(k, IntSets.unmodifiable(set));
                return set;
            });
        }
        
        @Nonnull
        @Override
        public String toString() {
            return "Data{containedAssets=" + String.valueOf(this.containedRawAssets) + ", rawTags=" + String.valueOf(this.rawTags) + ", parent=" + String.valueOf(this.containerData) + ", assetClass=" + String.valueOf(this.assetClass) + ", key=" + String.valueOf(this.key);
        }
    }
}
