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

package com.hypixel.hytale.assetstore;

import java.util.Collections;
import java.util.HashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import com.hypixel.hytale.assetstore.event.RemoveAssetStoreEvent;
import com.hypixel.hytale.event.IEventDispatcher;
import com.hypixel.hytale.assetstore.event.RegisterAssetStoreEvent;
import javax.annotation.Nonnull;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import java.util.concurrent.locks.StampedLock;
import java.util.concurrent.atomic.AtomicInteger;
import com.hypixel.hytale.assetstore.map.JsonAssetWithMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;

public class AssetRegistry
{
    public static final ReadWriteLock ASSET_LOCK;
    public static boolean HAS_INIT;
    public static final int TAG_NOT_FOUND = Integer.MIN_VALUE;
    private static final Map<Class<? extends JsonAssetWithMap>, AssetStore<?, ?, ?>> storeMap;
    private static final Map<Class<? extends JsonAssetWithMap>, AssetStore<?, ?, ?>> storeMapUnmodifiable;
    private static final AtomicInteger NEXT_TAG_INDEX;
    private static final StampedLock TAG_LOCK;
    private static final Object2IntMap<String> TAG_MAP;
    private static final Object2IntMap<String> CLIENT_TAG_MAP;
    
    @Nonnull
    public static Map<Class<? extends JsonAssetWithMap>, AssetStore<?, ?, ?>> getStoreMap() {
        return AssetRegistry.storeMapUnmodifiable;
    }
    
    public static <K, T extends JsonAssetWithMap<K, M>, M extends AssetMap<K, T>> AssetStore<K, T, M> getAssetStore(final Class<T> tClass) {
        return (AssetStore)AssetRegistry.storeMap.get(tClass);
    }
    
    @Nonnull
    public static <K, T extends JsonAssetWithMap<K, M>, M extends AssetMap<K, T>, S extends AssetStore<K, T, M>> S register(@Nonnull final S assetStore) {
        AssetRegistry.ASSET_LOCK.writeLock().lock();
        try {
            if (AssetRegistry.storeMap.putIfAbsent(((AssetStore<K, ? extends JsonAssetWithMap, M>)assetStore).getAssetClass(), assetStore) != null) {
                throw new IllegalArgumentException("Asset Store already exists for " + String.valueOf(assetStore.getAssetClass()));
            }
        }
        finally {
            AssetRegistry.ASSET_LOCK.writeLock().unlock();
        }
        final IEventDispatcher<RegisterAssetStoreEvent, RegisterAssetStoreEvent> dispatch = assetStore.getEventBus().dispatchFor((Class<? super RegisterAssetStoreEvent>)RegisterAssetStoreEvent.class);
        if (dispatch.hasListener()) {
            dispatch.dispatch(new RegisterAssetStoreEvent(assetStore));
        }
        return assetStore;
    }
    
    public static <K, T extends JsonAssetWithMap<K, M>, M extends AssetMap<K, T>, S extends AssetStore<K, T, M>> void unregister(@Nonnull final S assetStore) {
        AssetRegistry.ASSET_LOCK.writeLock().lock();
        try {
            AssetRegistry.storeMap.remove(assetStore.getAssetClass());
        }
        finally {
            AssetRegistry.ASSET_LOCK.writeLock().unlock();
        }
        final IEventDispatcher<RemoveAssetStoreEvent, RemoveAssetStoreEvent> dispatch = assetStore.getEventBus().dispatchFor((Class<? super RemoveAssetStoreEvent>)RemoveAssetStoreEvent.class);
        if (dispatch.hasListener()) {
            dispatch.dispatch(new RemoveAssetStoreEvent(assetStore));
        }
    }
    
    public static int getTagIndex(@Nonnull final String tag) {
        if (tag == null) {
            throw new IllegalArgumentException("tag can't be null!");
        }
        final long stamp = AssetRegistry.TAG_LOCK.readLock();
        try {
            return AssetRegistry.TAG_MAP.getInt(tag);
        }
        finally {
            AssetRegistry.TAG_LOCK.unlockRead(stamp);
        }
    }
    
    public static int getOrCreateTagIndex(@Nonnull final String tag) {
        if (tag == null) {
            throw new IllegalArgumentException("tag can't be null!");
        }
        final long stamp = AssetRegistry.TAG_LOCK.writeLock();
        try {
            return AssetRegistry.TAG_MAP.computeIfAbsent(tag.intern(), k -> AssetRegistry.NEXT_TAG_INDEX.getAndIncrement());
        }
        finally {
            AssetRegistry.TAG_LOCK.unlockWrite(stamp);
        }
    }
    
    public static boolean registerClientTag(@Nonnull final String tag) {
        if (tag == null) {
            throw new IllegalArgumentException("tag can't be null!");
        }
        final long stamp = AssetRegistry.TAG_LOCK.writeLock();
        try {
            return AssetRegistry.CLIENT_TAG_MAP.put(tag, AssetRegistry.TAG_MAP.computeIfAbsent(tag, k -> AssetRegistry.NEXT_TAG_INDEX.getAndIncrement())) == Integer.MIN_VALUE;
        }
        finally {
            AssetRegistry.TAG_LOCK.unlockWrite(stamp);
        }
    }
    
    @Nonnull
    public static Object2IntMap<String> getClientTags() {
        final long stamp = AssetRegistry.TAG_LOCK.readLock();
        try {
            return new Object2IntOpenHashMap<String>(AssetRegistry.CLIENT_TAG_MAP);
        }
        finally {
            AssetRegistry.TAG_LOCK.unlockRead(stamp);
        }
    }
    
    static {
        ASSET_LOCK = new ReentrantReadWriteLock();
        AssetRegistry.HAS_INIT = false;
        storeMap = new HashMap<Class<? extends JsonAssetWithMap>, AssetStore<?, ?, ?>>();
        storeMapUnmodifiable = Collections.unmodifiableMap((Map<? extends Class<? extends JsonAssetWithMap>, ? extends AssetStore<?, ?, ?>>)AssetRegistry.storeMap);
        NEXT_TAG_INDEX = new AtomicInteger();
        TAG_LOCK = new StampedLock();
        TAG_MAP = new Object2IntOpenHashMap<String>();
        CLIENT_TAG_MAP = new Object2IntOpenHashMap<String>();
        AssetRegistry.TAG_MAP.defaultReturnValue(Integer.MIN_VALUE);
        AssetRegistry.CLIENT_TAG_MAP.defaultReturnValue(Integer.MIN_VALUE);
    }
}
