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

package com.hypixel.hytale.server.core.inventory.container;

import java.util.Iterator;
import com.hypixel.hytale.server.core.inventory.transaction.Transaction;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import com.hypixel.hytale.server.core.inventory.transaction.ListTransaction;
import javax.annotation.Nullable;
import java.util.List;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.Collections;
import com.hypixel.hytale.server.core.inventory.transaction.ActionType;
import com.hypixel.hytale.server.core.inventory.transaction.MaterialTransaction;
import com.hypixel.hytale.server.core.inventory.transaction.ResourceSlotTransaction;
import com.hypixel.hytale.server.core.inventory.transaction.TagSlotTransaction;
import com.hypixel.hytale.server.core.inventory.transaction.ItemStackSlotTransaction;
import com.hypixel.hytale.server.core.inventory.transaction.SlotTransaction;
import com.hypixel.hytale.server.core.inventory.ItemStack;
import com.hypixel.hytale.server.core.inventory.transaction.MaterialSlotTransaction;
import com.hypixel.hytale.server.core.inventory.MaterialQuantity;
import javax.annotation.Nonnull;

public class InternalContainerUtilMaterial
{
    @Nonnull
    protected static MaterialSlotTransaction internal_removeMaterialFromSlot(@Nonnull final ItemContainer itemContainer, final short slot, @Nonnull final MaterialQuantity material, final boolean allOrNothing, final boolean filter) {
        ItemContainer.validateSlotIndex(slot, itemContainer.getCapacity());
        ItemContainer.validateQuantity(material.getQuantity());
        if (material.getItemId() != null) {
            final ItemStackSlotTransaction slotTransaction = InternalContainerUtilItemStack.internal_removeItemStackFromSlot(itemContainer, slot, material.toItemStack(), material.getQuantity(), allOrNothing, filter, (a, b) -> ItemStack.isEquivalentType(a, b));
            return new MaterialSlotTransaction(material, (slotTransaction.getRemainder() != null) ? slotTransaction.getRemainder().getQuantity() : 0, slotTransaction);
        }
        if (material.getTagIndex() != Integer.MIN_VALUE) {
            final TagSlotTransaction tagTransaction = InternalContainerUtilTag.internal_removeTagFromSlot(itemContainer, slot, material.getTagIndex(), material.getQuantity(), allOrNothing, filter);
            return new MaterialSlotTransaction(material, tagTransaction.getRemainder(), tagTransaction);
        }
        final ResourceSlotTransaction resourceTransaction = InternalContainerUtilResource.internal_removeResourceFromSlot(itemContainer, slot, material.toResource(), allOrNothing, filter);
        return new MaterialSlotTransaction(material, resourceTransaction.getRemainder(), resourceTransaction);
    }
    
    protected static MaterialTransaction internal_removeMaterial(@Nonnull final ItemContainer itemContainer, @Nonnull final MaterialQuantity material, final boolean allOrNothing, final boolean exactAmount, final boolean filter) {
        return itemContainer.writeAction(() -> {
            if (allOrNothing || exactAmount) {
                final int testQuantityRemaining = testRemoveMaterialFromItems(itemContainer, material, material.getQuantity(), filter);
                if (testQuantityRemaining > 0) {
                    return new MaterialTransaction(false, ActionType.REMOVE, material, material.getQuantity(), allOrNothing, exactAmount, filter, Collections.emptyList());
                }
                else if (exactAmount && testQuantityRemaining < 0) {
                    return new MaterialTransaction(false, ActionType.REMOVE, material, material.getQuantity(), allOrNothing, exactAmount, filter, Collections.emptyList());
                }
            }
            final ObjectArrayList<MaterialSlotTransaction> list = new ObjectArrayList<MaterialSlotTransaction>();
            int quantityRemaining = material.getQuantity();
            for (short i = 0; i < itemContainer.getCapacity() && quantityRemaining > 0; ++i) {
                final MaterialQuantity clone = material.clone(quantityRemaining);
                final MaterialSlotTransaction transaction = internal_removeMaterialFromSlot(itemContainer, i, clone, false, filter);
                if (transaction.succeeded()) {
                    list.add(transaction);
                    quantityRemaining = transaction.getRemainder();
                }
            }
            new MaterialTransaction(quantityRemaining != material.getQuantity(), ActionType.REMOVE, material, material.getQuantity(), allOrNothing, exactAmount, filter, list);
            return;
        });
    }
    
    protected static ListTransaction<MaterialTransaction> internal_removeMaterials(@Nonnull final ItemContainer itemContainer, @Nullable final List<MaterialQuantity> materials, final boolean allOrNothing, final boolean exactAmount, final boolean filter) {
        if (materials == null || materials.isEmpty()) {
            return ListTransaction.getEmptyTransaction(true);
        }
        return itemContainer.writeAction(() -> {
            if (allOrNothing || exactAmount) {
                for (final MaterialQuantity material : materials) {
                    final int testQuantityRemaining = testRemoveMaterialFromItems(itemContainer, material, material.getQuantity(), filter);
                    if (testQuantityRemaining > 0) {
                        return new ListTransaction(false, (List<Transaction>)materials.stream().map(remainder -> new MaterialTransaction(false, ActionType.REMOVE, material, material.getQuantity(), allOrNothing, exactAmount, filter, Collections.emptyList())).collect(Collectors.toList()));
                    }
                    else if (exactAmount && testQuantityRemaining < 0) {
                        return new ListTransaction(false, (List<Transaction>)materials.stream().map(remainder -> new MaterialTransaction(false, ActionType.REMOVE, material, material.getQuantity(), allOrNothing, exactAmount, filter, Collections.emptyList())).collect(Collectors.toList()));
                    }
                    else {
                        continue;
                    }
                }
            }
            final List<MaterialTransaction> transactions = new ObjectArrayList<MaterialTransaction>();
            for (final MaterialQuantity material2 : materials) {
                transactions.add(internal_removeMaterial(itemContainer, material2, allOrNothing, exactAmount, filter));
            }
            return new ListTransaction(true, (List<Transaction>)transactions);
        });
    }
    
    public static int testRemoveMaterialFromItems(@Nonnull final ItemContainer container, @Nonnull final MaterialQuantity material, final int testQuantityRemaining, final boolean filter) {
        if (material.getItemId() != null) {
            return InternalContainerUtilItemStack.testRemoveItemStackFromItems(container, material.toItemStack(), testQuantityRemaining, filter);
        }
        if (material.getTagIndex() != Integer.MIN_VALUE) {
            return InternalContainerUtilTag.testRemoveTagFromItems(container, material.getTagIndex(), testQuantityRemaining, filter);
        }
        return InternalContainerUtilResource.testRemoveResourceFromItems(container, material.toResource(), testQuantityRemaining, filter);
    }
    
    public static TestRemoveItemSlotResult getTestRemoveMaterialFromItems(@Nonnull final ItemContainer container, @Nonnull final MaterialQuantity material, final int testQuantityRemaining, final boolean filter) {
        if (material.getItemId() != null) {
            return InternalContainerUtilItemStack.testRemoveItemStackSlotFromItems(container, material.toItemStack(), testQuantityRemaining, filter, (a, b) -> ItemStack.isEquivalentType(a, b));
        }
        if (material.getTagIndex() != Integer.MIN_VALUE) {
            return InternalContainerUtilTag.testRemoveTagSlotFromItems(container, material.getTagIndex(), testQuantityRemaining, filter);
        }
        return InternalContainerUtilResource.testRemoveResourceSlotFromItems(container, material.toResource(), testQuantityRemaining, filter);
    }
    
    protected static ListTransaction<MaterialSlotTransaction> internal_removeMaterialsOrdered(@Nonnull final ItemContainer itemContainer, final short offset, @Nullable final List<MaterialQuantity> materials, final boolean allOrNothing, final boolean exactAmount, final boolean filter) {
        if (materials == null || materials.isEmpty()) {
            return ListTransaction.getEmptyTransaction(true);
        }
        if (offset + materials.size() > itemContainer.getCapacity()) {
            return ListTransaction.getEmptyTransaction(false);
        }
        return itemContainer.writeAction(() -> {
            if (allOrNothing || exactAmount) {
                short i = 0;
                while (i < materials.size()) {
                    final short slot = (short)(offset + i);
                    final MaterialQuantity material = materials.get(i);
                    final int testQuantityRemaining = testRemoveMaterialFromSlot(itemContainer, slot, material, material.getQuantity(), filter);
                    if (testQuantityRemaining > 0) {
                        final List<MaterialSlotTransaction> list = new ObjectArrayList<MaterialSlotTransaction>();
                        for (short i2 = 0; i2 < materials.size(); ++i2) {
                            final short islot = (short)(offset + i2);
                            new MaterialSlotTransaction(material, material.getQuantity(), new SlotTransaction(false, ActionType.REMOVE, islot, null, null, null, allOrNothing, exactAmount, filter));
                            final MaterialSlotTransaction materialSlotTransaction;
                            final Object o;
                            ((List<MaterialSlotTransaction>)o).add(materialSlotTransaction);
                        }
                        return new ListTransaction(false, (List<Transaction>)list);
                    }
                    else if (exactAmount && testQuantityRemaining < 0) {
                        final List<MaterialSlotTransaction> list2 = new ObjectArrayList<MaterialSlotTransaction>();
                        for (short i3 = 0; i3 < materials.size(); ++i3) {
                            final short islot2 = (short)(offset + i3);
                            new MaterialSlotTransaction(material, material.getQuantity(), new SlotTransaction(false, ActionType.REMOVE, islot2, null, null, null, allOrNothing, exactAmount, filter));
                            final MaterialSlotTransaction materialSlotTransaction2;
                            final Object o2;
                            ((List<MaterialSlotTransaction>)o2).add(materialSlotTransaction2);
                        }
                        return new ListTransaction(false, (List<Transaction>)list2);
                    }
                    else {
                        ++i;
                    }
                }
            }
            final List<MaterialSlotTransaction> transactions = new ObjectArrayList<MaterialSlotTransaction>();
            for (short j = 0; j < materials.size(); ++j) {
                final short slot2 = (short)(offset + j);
                final MaterialQuantity material2 = materials.get(j);
                transactions.add(internal_removeMaterialFromSlot(itemContainer, slot2, material2, allOrNothing, filter));
            }
            return new ListTransaction(true, (List<Transaction>)transactions);
        });
    }
    
    public static int testRemoveMaterialFromSlot(@Nonnull final ItemContainer container, final short slot, @Nonnull final MaterialQuantity material, final int testQuantityRemaining, final boolean filter) {
        if (material.getItemId() != null) {
            return InternalContainerUtilItemStack.testRemoveItemStackFromSlot(container, slot, material.toItemStack(), testQuantityRemaining, filter, (a, b) -> ItemStack.isEquivalentType(a, b));
        }
        if (material.getTagIndex() != Integer.MIN_VALUE) {
            return InternalContainerUtilTag.testRemoveTagFromSlot(container, slot, material.getTagIndex(), testQuantityRemaining, filter);
        }
        return InternalContainerUtilResource.testRemoveResourceFromSlot(container, slot, material.toResource(), testQuantityRemaining, filter);
    }
}
