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

package com.hypixel.hytale.server.core.asset.common;

import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.ConcurrentHashMap;
import com.hypixel.hytale.assetstore.AssetPack;
import javax.annotation.Nullable;
import com.hypixel.hytale.common.util.PatternUtil;
import it.unimi.dsi.fastutil.booleans.BooleanObjectPair;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.annotation.Nonnull;
import java.util.Iterator;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import java.util.Collection;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.List;
import java.util.Map;

public class CommonAssetRegistry
{
    private static final Map<String, List<PackAsset>> assetByNameMap;
    private static final Map<String, List<PackAsset>> assetByHashMap;
    private static final AtomicInteger duplicateAssetCount;
    private static final Collection<List<PackAsset>> unmodifiableAssetByNameMapValues;
    
    public static int getDuplicateAssetCount() {
        return CommonAssetRegistry.duplicateAssetCount.get();
    }
    
    @Nonnull
    public static Map<String, List<PackAsset>> getDuplicatedAssets() {
        final Map<String, List<PackAsset>> duplicates = new Object2ObjectOpenHashMap<String, List<PackAsset>>();
        for (final Map.Entry<String, List<PackAsset>> entry : CommonAssetRegistry.assetByHashMap.entrySet()) {
            if (entry.getValue().size() > 1) {
                duplicates.put(entry.getKey(), new ObjectArrayList<PackAsset>(entry.getValue()));
            }
        }
        return duplicates;
    }
    
    @Nonnull
    public static Collection<List<PackAsset>> getAllAssets() {
        return CommonAssetRegistry.unmodifiableAssetByNameMapValues;
    }
    
    public static void clearAllAssets() {
        CommonAssetRegistry.assetByNameMap.clear();
        CommonAssetRegistry.assetByHashMap.clear();
    }
    
    @Nonnull
    public static AddCommonAssetResult addCommonAsset(final String pack, @Nonnull final CommonAsset asset) {
        final AddCommonAssetResult result = new AddCommonAssetResult();
        result.newPackAsset = new PackAsset(pack, asset);
        final List<PackAsset> list = CommonAssetRegistry.assetByNameMap.computeIfAbsent(asset.getName(), v -> new CopyOnWriteArrayList());
        boolean added = false;
        boolean addHash = true;
        for (int i = 0; i < list.size(); ++i) {
            final PackAsset e = list.get(i);
            if (e.pack().equals(pack)) {
                result.previousNameAsset = e;
                if (i == list.size() - 1) {
                    CommonAssetRegistry.assetByHashMap.get(e.asset.getHash()).remove(e);
                    CommonAssetRegistry.assetByHashMap.compute(e.asset.getHash(), (k, v) -> (v == null || v.isEmpty()) ? null : v);
                }
                else {
                    addHash = false;
                }
                list.set(i, result.newPackAsset);
                added = true;
                break;
            }
        }
        if (!added) {
            if (!list.isEmpty()) {
                final PackAsset e2 = list.getLast();
                CommonAssetRegistry.assetByHashMap.get(e2.asset.getHash()).remove(e2);
                CommonAssetRegistry.assetByHashMap.compute(e2.asset.getHash(), (k, v) -> (v == null || v.isEmpty()) ? null : v);
                result.previousNameAsset = e2;
            }
            list.add(result.newPackAsset);
        }
        if (addHash) {
            final List<PackAsset> commonAssets = CommonAssetRegistry.assetByHashMap.computeIfAbsent(asset.getHash(), k -> new CopyOnWriteArrayList());
            if (!commonAssets.isEmpty()) {
                result.previousHashAssets = commonAssets.toArray(PackAsset[]::new);
            }
            commonAssets.add(result.newPackAsset);
        }
        if (result.previousHashAssets != null || result.previousNameAsset != null) {
            result.duplicateAssetId = CommonAssetRegistry.duplicateAssetCount.getAndIncrement();
        }
        result.activeAsset = list.getLast();
        return result;
    }
    
    @Nullable
    public static BooleanObjectPair<PackAsset> removeCommonAssetByName(final String pack, String name) {
        name = PatternUtil.replaceBackslashWithForwardSlash(name);
        final List<PackAsset> oldAssets = CommonAssetRegistry.assetByNameMap.get(name);
        if (oldAssets == null) {
            return null;
        }
        final PackAsset previousCurrent = oldAssets.getLast();
        oldAssets.removeIf(v -> v.pack().equals(pack));
        CommonAssetRegistry.assetByNameMap.compute(name, (k, v) -> (v == null || v.isEmpty()) ? null : v);
        if (oldAssets.isEmpty()) {
            removeCommonAssetByHash0(previousCurrent);
            return BooleanObjectPair.of(false, previousCurrent);
        }
        final PackAsset newCurrent = oldAssets.getLast();
        if (newCurrent.equals(previousCurrent)) {
            return null;
        }
        removeCommonAssetByHash0(previousCurrent);
        CommonAssetRegistry.assetByHashMap.computeIfAbsent(newCurrent.asset.getHash(), v -> new CopyOnWriteArrayList()).add(newCurrent);
        return BooleanObjectPair.of(true, newCurrent);
    }
    
    @Nonnull
    public static List<CommonAsset> getCommonAssetsStartingWith(final String pack, final String name) {
        final List<CommonAsset> oldAssets = new ObjectArrayList<CommonAsset>();
        for (final List<PackAsset> assets : CommonAssetRegistry.assetByNameMap.values()) {
            for (final PackAsset asset : assets) {
                if (asset.asset().getName().startsWith(name) && asset.pack().equals(pack)) {
                    oldAssets.add(asset.asset());
                }
            }
        }
        return oldAssets;
    }
    
    public static boolean hasCommonAsset(final String name) {
        return CommonAssetRegistry.assetByNameMap.containsKey(name);
    }
    
    public static boolean hasCommonAsset(final AssetPack pack, final String name) {
        final List<PackAsset> packAssets = CommonAssetRegistry.assetByNameMap.get(name);
        if (packAssets != null) {
            for (final PackAsset packAsset : packAssets) {
                if (packAsset.pack.equals(pack.getName())) {
                    return true;
                }
            }
        }
        return false;
    }
    
    @Nullable
    public static CommonAsset getByName(String name) {
        name = PatternUtil.replaceBackslashWithForwardSlash(name);
        final List<PackAsset> asset = CommonAssetRegistry.assetByNameMap.get(name);
        return (asset == null) ? null : asset.getLast().asset();
    }
    
    @Nullable
    public static CommonAsset getByHash(@Nonnull final String hash) {
        final List<PackAsset> assets = CommonAssetRegistry.assetByHashMap.get(hash.toLowerCase());
        return (assets != null && !assets.isEmpty()) ? assets.getFirst().asset() : null;
    }
    
    private static void removeCommonAssetByHash0(@Nonnull final PackAsset oldAsset) {
        final List<PackAsset> commonAssets = CommonAssetRegistry.assetByHashMap.get(oldAsset.asset().getHash());
        if (commonAssets != null && commonAssets.remove(oldAsset) && commonAssets.isEmpty()) {
            CommonAssetRegistry.assetByHashMap.compute(oldAsset.asset().getHash(), (key, assets) -> {
                if (assets == null || assets.isEmpty()) {
                    return null;
                }
                else {
                    return (List<PackAsset>)(List<PackAsset>)assets;
                }
            });
        }
    }
    
    static {
        assetByNameMap = new ConcurrentHashMap<String, List<PackAsset>>();
        assetByHashMap = new ConcurrentHashMap<String, List<PackAsset>>();
        duplicateAssetCount = new AtomicInteger();
        unmodifiableAssetByNameMapValues = Collections.unmodifiableCollection((Collection<? extends List<PackAsset>>)CommonAssetRegistry.assetByNameMap.values());
    }
    
    public static class AddCommonAssetResult
    {
        private PackAsset newPackAsset;
        private PackAsset previousNameAsset;
        private PackAsset activeAsset;
        private PackAsset[] previousHashAssets;
        private int duplicateAssetId;
        
        public PackAsset getNewPackAsset() {
            return this.newPackAsset;
        }
        
        public PackAsset getPreviousNameAsset() {
            return this.previousNameAsset;
        }
        
        public PackAsset getActiveAsset() {
            return this.activeAsset;
        }
        
        public PackAsset[] getPreviousHashAssets() {
            return this.previousHashAssets;
        }
        
        public int getDuplicateAssetId() {
            return this.duplicateAssetId;
        }
        
        @Nonnull
        @Override
        public String toString() {
            return "AddCommonAssetResult{previousNameAsset=" + String.valueOf(this.previousNameAsset) + ", previousHashAssets=" + Arrays.toString(this.previousHashAssets) + ", duplicateAssetId=" + this.duplicateAssetId;
        }
    }
    
    record PackAsset(String pack, CommonAsset asset) {
        @Override
        public boolean equals(@Nullable final Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || this.getClass() != o.getClass()) {
                return false;
            }
            final PackAsset packAsset = (PackAsset)o;
            return this.pack.equals(packAsset.pack) && this.asset.equals(packAsset.asset);
        }
        
        @Nonnull
        @Override
        public String toString() {
            return "PackAsset{pack='" + this.pack + "', asset=" + String.valueOf(this.asset);
        }
    }
}
