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

package com.hypixel.hytale.assetstore.event;

import com.hypixel.hytale.assetstore.JsonAsset;
import java.util.Iterator;
import java.util.Collection;
import com.hypixel.hytale.common.util.FormatUtil;
import java.util.logging.Level;
import com.hypixel.hytale.logger.HytaleLogger;
import com.hypixel.hytale.assetstore.AssetStore;
import java.util.HashSet;
import com.hypixel.hytale.codec.ExtraInfo;
import com.hypixel.hytale.assetstore.AssetExtraInfo;
import com.hypixel.hytale.assetstore.AssetRegistry;
import java.util.Collections;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Set;
import javax.annotation.Nonnull;
import java.util.Map;
import com.hypixel.hytale.event.IProcessedEvent;
import com.hypixel.hytale.assetstore.AssetMap;
import com.hypixel.hytale.assetstore.map.JsonAssetWithMap;

public class GenerateAssetsEvent<K, T extends JsonAssetWithMap<K, M>, M extends AssetMap<K, T>> extends AssetsEvent<K, T> implements IProcessedEvent
{
    private final Class<T> tClass;
    private final M assetMap;
    @Nonnull
    private final Map<K, T> loadedAssets;
    private final Map<K, Set<K>> assetChildren;
    @Nonnull
    private final Map<K, T> unmodifiableLoadedAssets;
    private final Map<K, T> addedAssets;
    private final Map<K, Set<K>> addedAssetChildren;
    private final Map<Class<? extends JsonAssetWithMap<?, ?>>, Map<?, Set<K>>> addedChildAssetsMap;
    private long before;
    
    public GenerateAssetsEvent(final Class<T> tClass, final M assetMap, @Nonnull final Map<K, T> loadedAssets, final Map<K, Set<K>> assetChildren) {
        this.addedAssets = new ConcurrentHashMap<K, T>();
        this.addedAssetChildren = new ConcurrentHashMap<K, Set<K>>();
        this.addedChildAssetsMap = new ConcurrentHashMap<Class<? extends JsonAssetWithMap<?, ?>>, Map<?, Set<K>>>();
        this.tClass = tClass;
        this.assetMap = assetMap;
        this.loadedAssets = loadedAssets;
        this.assetChildren = assetChildren;
        this.unmodifiableLoadedAssets = Collections.unmodifiableMap((Map<? extends K, ? extends T>)loadedAssets);
        this.before = System.nanoTime();
    }
    
    public Class<T> getAssetClass() {
        return this.tClass;
    }
    
    @Nonnull
    public Map<K, T> getLoadedAssets() {
        return this.unmodifiableLoadedAssets;
    }
    
    public M getAssetMap() {
        return this.assetMap;
    }
    
    public void addChildAsset(final K childKey, final T asset, @Nonnull final K parent) {
        if (!this.loadedAssets.containsKey(parent) && ((AssetMap<K, JsonAsset>)this.assetMap).getAsset(parent) == null) {
            throw new IllegalArgumentException("Parent '" + String.valueOf(parent) + "' doesn't exist!");
        }
        if (parent.equals(childKey)) {
            throw new IllegalArgumentException("Unable to to add asset '" + String.valueOf(parent) + "' because it is its own parent!");
        }
        final AssetStore<K, T, M> assetStore = AssetRegistry.getAssetStore(this.tClass);
        final AssetExtraInfo<K> extraInfo = new AssetExtraInfo<K>(assetStore.getCodec().getData(asset));
        assetStore.getCodec().validate(asset, extraInfo);
        extraInfo.getValidationResults().logOrThrowValidatorExceptions(assetStore.getLogger());
        this.addedAssets.put(childKey, asset);
        this.addedAssetChildren.computeIfAbsent(parent, k -> new HashSet()).add(childKey);
    }
    
    @SafeVarargs
    public final void addChildAsset(final K childKey, final T asset, @Nonnull final K... parents) {
        for (int i = 0; i < parents.length; ++i) {
            final K parent = parents[i];
            if (!this.loadedAssets.containsKey(parent) && ((AssetMap<K, JsonAsset>)this.assetMap).getAsset(parent) == null) {
                throw new IllegalArgumentException("Parent at " + i + " '" + String.valueOf(parent) + "' doesn't exist!");
            }
            if (parent.equals(childKey)) {
                throw new IllegalArgumentException("Unable to to add asset '" + String.valueOf(parent) + "' because it is its own parent!");
            }
        }
        final AssetStore<K, T, M> assetStore = AssetRegistry.getAssetStore(this.tClass);
        final AssetExtraInfo<K> extraInfo = new AssetExtraInfo<K>(assetStore.getCodec().getData(asset));
        assetStore.getCodec().validate(asset, extraInfo);
        extraInfo.getValidationResults().logOrThrowValidatorExceptions(assetStore.getLogger());
        this.addedAssets.put(childKey, asset);
        for (final K parent2 : parents) {
            this.addedAssetChildren.computeIfAbsent(parent2, k -> new HashSet()).add(childKey);
        }
    }
    
    public <P extends JsonAssetWithMap<PK, ?>, PK> void addChildAssetWithReference(final K childKey, final T asset, final Class<P> parentAssetClass, @Nonnull final PK parentKey) {
        final Class kc = parentAssetClass;
        if (AssetRegistry.getAssetStore((Class<JsonAssetWithMap>)kc).getAssetMap().getAsset(parentKey) == null) {
            throw new IllegalArgumentException("Parent '" + String.valueOf(parentKey) + "' from " + String.valueOf(parentAssetClass) + " doesn't exist!");
        }
        if (parentKey.equals(childKey)) {
            throw new IllegalArgumentException("Unable to to add asset '" + String.valueOf(parentKey) + "' because it is its own parent!");
        }
        final AssetStore<K, T, M> assetStore = AssetRegistry.getAssetStore(this.tClass);
        final AssetExtraInfo<K> extraInfo = new AssetExtraInfo<K>(assetStore.getCodec().getData(asset));
        assetStore.getCodec().validate(asset, extraInfo);
        extraInfo.getValidationResults().logOrThrowValidatorExceptions(assetStore.getLogger());
        this.addedAssets.put(childKey, asset);
        ((Set)this.addedChildAssetsMap.computeIfAbsent((Class<? extends JsonAssetWithMap<?, ?>>)parentAssetClass, k -> new ConcurrentHashMap()).computeIfAbsent((Object)parentKey, k -> new HashSet())).add(childKey);
    }
    
    public void addChildAssetWithReferences(final K childKey, final T asset, @Nonnull final ParentReference<?, ?>... parents) {
        for (int i = 0; i < parents.length; ++i) {
            final ParentReference<?, ?> parent = parents[i];
            if (AssetRegistry.getAssetStore(parent.getParentAssetClass()).getAssetMap().getAsset(parent.getParentKey()) == null) {
                throw new IllegalArgumentException("Parent at " + i + " '" + String.valueOf(parent) + "' doesn't exist!");
            }
            if (parent.parentKey.equals(childKey)) {
                throw new IllegalArgumentException("Unable to to add asset '" + String.valueOf(parent.parentKey) + "' because it is its own parent!");
            }
        }
        final AssetStore<K, T, M> assetStore = AssetRegistry.getAssetStore(this.tClass);
        final AssetExtraInfo<K> extraInfo = new AssetExtraInfo<K>(assetStore.getCodec().getData(asset));
        assetStore.getCodec().validate(asset, extraInfo);
        extraInfo.getValidationResults().logOrThrowValidatorExceptions(assetStore.getLogger());
        this.addedAssets.put(childKey, asset);
        for (final ParentReference<?, ?> parent2 : parents) {
            this.addedChildAssetsMap.computeIfAbsent((Class<? extends JsonAssetWithMap<?, ?>>)parent2.parentAssetClass, k -> new ConcurrentHashMap()).computeIfAbsent((Object)parent2.parentKey, k -> new HashSet()).add(childKey);
        }
    }
    
    @Override
    public void processEvent(@Nonnull final String hookName) {
        HytaleLogger.getLogger().at(Level.INFO).log("Generated %d of %s from %s in %s", this.addedAssets.size(), this.tClass.getSimpleName(), hookName, FormatUtil.nanosToString(System.nanoTime() - this.before));
        this.loadedAssets.putAll((Map<? extends K, ? extends T>)this.addedAssets);
        this.addedAssets.clear();
        for (final Map.Entry<K, Set<K>> entry : this.addedAssetChildren.entrySet()) {
            final K parent = entry.getKey();
            this.assetChildren.computeIfAbsent(parent, k -> ConcurrentHashMap.newKeySet()).addAll(entry.getValue());
        }
        this.addedAssetChildren.clear();
        for (final Map.Entry<Class<? extends JsonAssetWithMap<?, ?>>, Map<?, Set<K>>> entry2 : this.addedChildAssetsMap.entrySet()) {
            final Class k = entry2.getKey();
            final AssetStore assetStore = AssetRegistry.getAssetStore((Class<JsonAssetWithMap>)k);
            for (final Map.Entry<?, Set<K>> childEntry : entry2.getValue().entrySet()) {
                assetStore.addChildAssetReferences(childEntry.getKey(), this.tClass, childEntry.getValue());
            }
        }
        this.addedChildAssetsMap.clear();
        this.before = System.nanoTime();
    }
    
    @Nonnull
    @Override
    public String toString() {
        return "GenerateAssetsEvent{tClass=" + String.valueOf(this.tClass) + ", loadedAssets.size()=" + this.loadedAssets.size() + ", " + super.toString();
    }
    
    public static class ParentReference<P extends JsonAssetWithMap<PK, ?>, PK>
    {
        private final Class<P> parentAssetClass;
        private final PK parentKey;
        
        public ParentReference(final Class<P> parentAssetClass, final PK parentKey) {
            this.parentAssetClass = parentAssetClass;
            this.parentKey = parentKey;
        }
        
        public Class<P> getParentAssetClass() {
            return this.parentAssetClass;
        }
        
        public PK getParentKey() {
            return this.parentKey;
        }
        
        @Nonnull
        @Override
        public String toString() {
            return "ParentReference{parentAssetClass=" + String.valueOf(this.parentAssetClass) + ", parentKey=" + String.valueOf(this.parentKey);
        }
    }
}
