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

package com.hypixel.hytale.builtin.crafting;

import java.util.Objects;
import com.hypixel.hytale.protocol.ItemResourceType;
import com.hypixel.hytale.server.core.inventory.ItemStack;
import com.hypixel.hytale.server.core.inventory.MaterialQuantity;
import javax.annotation.Nullable;
import java.util.List;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.Collection;
import com.hypixel.hytale.server.core.asset.type.item.config.CraftingRecipe;
import com.hypixel.hytale.protocol.BenchRequirement;
import java.util.Iterator;
import java.util.Collections;
import javax.annotation.Nonnull;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import java.util.Set;
import java.util.Map;

public class BenchRecipeRegistry
{
    private final String benchId;
    private final Map<String, Set<String>> categoryMap;
    private final Map<String, Set<String>> itemToIncomingRecipe;
    private final Set<String> uncategorizedRecipes;
    private final Set<String> allMaterialIds;
    private final Set<String> allMaterialResourceType;
    
    public BenchRecipeRegistry(final String benchId) {
        this.categoryMap = new Object2ObjectOpenHashMap<String, Set<String>>();
        this.itemToIncomingRecipe = new Object2ObjectOpenHashMap<String, Set<String>>();
        this.uncategorizedRecipes = new ObjectOpenHashSet<String>();
        this.allMaterialIds = new ObjectOpenHashSet<String>();
        this.allMaterialResourceType = new ObjectOpenHashSet<String>();
        this.benchId = benchId;
    }
    
    public Iterable<String> getIncomingRecipesForItem(@Nonnull final String itemId) {
        final Set<String> recipes = this.itemToIncomingRecipe.get(itemId);
        if (recipes == null) {
            return (Iterable<String>)Collections.emptySet();
        }
        return recipes;
    }
    
    public void removeRecipe(@Nonnull final String id) {
        this.uncategorizedRecipes.remove(id);
        for (final Map.Entry<String, Set<String>> entry : this.categoryMap.entrySet()) {
            entry.getValue().remove(id);
        }
    }
    
    public void addRecipe(@Nonnull final BenchRequirement benchRequirement, @Nonnull final CraftingRecipe recipe) {
        if (benchRequirement.categories == null || benchRequirement.categories.length == 0) {
            this.uncategorizedRecipes.add(recipe.getId());
        }
        else {
            for (final String category : benchRequirement.categories) {
                this.categoryMap.computeIfAbsent(category, k -> new ObjectOpenHashSet()).add(recipe.getId());
            }
        }
    }
    
    public CraftingRecipe[] getAllRecipes() {
        final Set<String> allRecipeIds = new ObjectOpenHashSet<String>(this.uncategorizedRecipes);
        for (final Set<String> recipes : this.categoryMap.values()) {
            allRecipeIds.addAll(recipes);
        }
        final List<CraftingRecipe> allRecipes = new ObjectArrayList<CraftingRecipe>(allRecipeIds.size());
        for (final String recipeId : allRecipeIds) {
            final CraftingRecipe recipe = CraftingRecipe.getAssetMap().getAsset(recipeId);
            if (recipe != null) {
                allRecipes.add(recipe);
            }
        }
        return allRecipes.toArray(CraftingRecipe[]::new);
    }
    
    @Nullable
    public Set<String> getRecipesForCategory(@Nonnull final String benchCategoryId) {
        return this.categoryMap.get(benchCategoryId);
    }
    
    public void recompute() {
        this.allMaterialIds.clear();
        this.allMaterialResourceType.clear();
        this.itemToIncomingRecipe.clear();
        for (final Set<String> recipes : this.categoryMap.values()) {
            this.extractMaterialFromRecipes(recipes);
        }
        this.extractMaterialFromRecipes(this.uncategorizedRecipes);
    }
    
    private void extractMaterialFromRecipes(final Set<String> recipes) {
        for (final String recipeId : recipes) {
            final CraftingRecipe recipe = CraftingRecipe.getAssetMap().getAsset(recipeId);
            if (recipe == null) {
                continue;
            }
            final BenchRequirement[] benchRequirements = recipe.getBenchRequirement();
            if (benchRequirements == null) {
                continue;
            }
            boolean matchesRegistry = false;
            for (final BenchRequirement requirement : benchRequirements) {
                if (requirement.id.equals(this.benchId)) {
                    matchesRegistry = true;
                    break;
                }
            }
            if (!matchesRegistry) {
                continue;
            }
            for (final MaterialQuantity material : recipe.getInput()) {
                if (material.getItemId() != null) {
                    this.allMaterialIds.add(material.getItemId());
                }
                if (material.getResourceTypeId() != null) {
                    this.allMaterialResourceType.add(material.getResourceTypeId());
                }
            }
            for (final MaterialQuantity output : recipe.getOutputs()) {
                this.itemToIncomingRecipe.computeIfAbsent(output.getItemId(), k -> new ObjectOpenHashSet()).add(recipeId);
            }
        }
    }
    
    public boolean isValidCraftingMaterial(@Nonnull final ItemStack itemStack) {
        if (this.allMaterialIds.contains(itemStack.getItemId())) {
            return true;
        }
        final ItemResourceType[] resourceTypeId = itemStack.getItem().getResourceTypes();
        if (resourceTypeId != null) {
            for (final ItemResourceType resTypeId : resourceTypeId) {
                if (this.allMaterialResourceType.contains(resTypeId.id)) {
                    return true;
                }
            }
        }
        return false;
    }
    
    @Override
    public boolean equals(final Object o) {
        if (o == null || this.getClass() != o.getClass()) {
            return false;
        }
        final BenchRecipeRegistry that = (BenchRecipeRegistry)o;
        return Objects.equals(this.benchId, that.benchId) && Objects.equals(this.categoryMap, that.categoryMap) && Objects.equals(this.uncategorizedRecipes, that.uncategorizedRecipes) && Objects.equals(this.allMaterialIds, that.allMaterialIds) && Objects.equals(this.allMaterialResourceType, that.allMaterialResourceType);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(this.benchId, this.categoryMap, this.uncategorizedRecipes, this.allMaterialIds, this.allMaterialResourceType);
    }
    
    @Override
    public String toString() {
        return "BenchRecipeRegistry{benchId='" + this.benchId + "', categoryMap=" + String.valueOf(this.categoryMap) + ", uncategorizedRecipes=" + String.valueOf(this.uncategorizedRecipes) + ", allMaterialIds=" + String.valueOf(this.allMaterialIds) + ", allMaterialResourceType=" + String.valueOf(this.allMaterialResourceType);
    }
}
