// 
// 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.ResourceTransaction;
import com.hypixel.hytale.protocol.ItemResourceType;
import com.hypixel.hytale.server.core.asset.type.item.config.Item;
import com.hypixel.hytale.math.util.MathUtil;
import com.hypixel.hytale.server.core.inventory.ItemStack;
import com.hypixel.hytale.server.core.inventory.transaction.ActionType;
import com.hypixel.hytale.server.core.inventory.transaction.ResourceSlotTransaction;
import com.hypixel.hytale.server.core.inventory.ResourceQuantity;
import javax.annotation.Nonnull;

public class InternalContainerUtilResource
{
    protected static ResourceSlotTransaction internal_removeResourceFromSlot(@Nonnull final ItemContainer itemContainer, final short slot, @Nonnull final ResourceQuantity resource, final boolean allOrNothing, final boolean filter) {
        ItemContainer.validateSlotIndex(slot, itemContainer.getCapacity());
        ItemContainer.validateQuantity(resource.getQuantity());
        return itemContainer.writeAction(() -> {
            if (filter && itemContainer.cantRemoveFromSlot(slot)) {
                final ItemStack itemStack = itemContainer.internal_getSlot(slot);
                return new ResourceSlotTransaction(false, ActionType.REMOVE, slot, itemStack, itemStack, null, allOrNothing, false, filter, resource, resource.getQuantity(), 0);
            }
            else {
                final ItemStack slotItemStack = itemContainer.internal_getSlot(slot);
                if (slotItemStack == null) {
                    return new ResourceSlotTransaction(false, ActionType.REMOVE, slot, null, null, null, allOrNothing, false, filter, resource, resource.getQuantity(), 0);
                }
                else {
                    final Item slotItem = slotItemStack.getItem();
                    final int quantityInItems = slotItemStack.getQuantity();
                    final ItemResourceType resourceType = resource.getResourceType(slotItem);
                    if (resourceType == null) {
                        return new ResourceSlotTransaction(false, ActionType.REMOVE, slot, slotItemStack, slotItemStack, null, allOrNothing, false, filter, resource, resource.getQuantity(), 0);
                    }
                    else {
                        final int resourceTypeQuantity = resourceType.quantity;
                        final int quantityRemaining = resource.getQuantity();
                        final int quantityInItemsRemaining = MathUtil.ceil(quantityRemaining / (double)resourceTypeQuantity);
                        final int quantityInItemsAdjustment = Math.min(quantityInItems, quantityInItemsRemaining);
                        final int newItemStackQuantity = Math.max(quantityInItems - quantityInItemsAdjustment, 0);
                        final int quantityAdjustment = quantityInItemsAdjustment * resourceTypeQuantity;
                        final int quantityRemaining2 = quantityRemaining - quantityAdjustment;
                        if (allOrNothing && quantityRemaining2 > 0) {
                            return new ResourceSlotTransaction(false, ActionType.REMOVE, slot, slotItemStack, slotItemStack, null, allOrNothing, false, filter, resource, resource.getQuantity(), 0);
                        }
                        else if (quantityAdjustment <= 0) {
                            return new ResourceSlotTransaction(false, ActionType.REMOVE, slot, slotItemStack, slotItemStack, null, allOrNothing, false, filter, resource, resource.getQuantity(), 0);
                        }
                        else {
                            final ItemStack slotNewItemStack = slotItemStack.withQuantity(newItemStackQuantity);
                            itemContainer.internal_setSlot(slot, slotNewItemStack);
                            final ItemStack newStack = slotItemStack.withQuantity(quantityInItemsAdjustment);
                            return new ResourceSlotTransaction(true, ActionType.REMOVE, slot, slotItemStack, slotNewItemStack, newStack, allOrNothing, false, filter, resource, quantityRemaining2, quantityAdjustment);
                        }
                    }
                }
            }
        });
    }
    
    protected static ResourceTransaction internal_removeResource(@Nonnull final ItemContainer itemContainer, @Nonnull final ResourceQuantity resource, final boolean allOrNothing, final boolean exactAmount, final boolean filter) {
        return itemContainer.writeAction(() -> {
            if (allOrNothing || exactAmount) {
                final int testQuantityRemaining = testRemoveResourceFromItems(itemContainer, resource, resource.getQuantity(), filter);
                if (testQuantityRemaining > 0) {
                    return new ResourceTransaction(false, ActionType.REMOVE, resource, resource.getQuantity(), 0, allOrNothing, exactAmount, filter, Collections.emptyList());
                }
                else if (exactAmount && testQuantityRemaining < 0) {
                    return new ResourceTransaction(false, ActionType.REMOVE, resource, resource.getQuantity(), 0, allOrNothing, exactAmount, filter, Collections.emptyList());
                }
            }
            final ObjectArrayList<ResourceSlotTransaction> list = new ObjectArrayList<ResourceSlotTransaction>();
            int consumed = 0;
            int quantityRemaining = resource.getQuantity();
            for (short i = 0; i < itemContainer.getCapacity() && quantityRemaining > 0; ++i) {
                final ResourceQuantity clone = resource.clone(quantityRemaining);
                final ResourceSlotTransaction transaction = internal_removeResourceFromSlot(itemContainer, i, clone, false, filter);
                if (transaction.succeeded()) {
                    list.add(transaction);
                    quantityRemaining = transaction.getRemainder();
                    consumed += transaction.getConsumed();
                }
            }
            new ResourceTransaction(quantityRemaining != resource.getQuantity(), ActionType.REMOVE, resource, quantityRemaining, consumed, allOrNothing, exactAmount, filter, list);
            return;
        });
    }
    
    protected static ListTransaction<ResourceTransaction> internal_removeResources(@Nonnull final ItemContainer itemContainer, @Nullable final List<ResourceQuantity> resources, final boolean allOrNothing, final boolean exactAmount, final boolean filter) {
        if (resources == null || resources.isEmpty()) {
            return ListTransaction.getEmptyTransaction(true);
        }
        return itemContainer.writeAction(() -> {
            if (allOrNothing || exactAmount) {
                for (final ResourceQuantity resource : resources) {
                    final int testQuantityRemaining = testRemoveResourceFromItems(itemContainer, resource, resource.getQuantity(), filter);
                    if (testQuantityRemaining > 0) {
                        return new ListTransaction(false, (List<Transaction>)resources.stream().map(remainder -> new ResourceTransaction(false, ActionType.REMOVE, resource, resource.getQuantity(), 0, allOrNothing, exactAmount, filter, Collections.emptyList())).collect(Collectors.toList()));
                    }
                    else if (exactAmount && testQuantityRemaining < 0) {
                        return new ListTransaction(false, (List<Transaction>)resources.stream().map(remainder -> new ResourceTransaction(false, ActionType.REMOVE, resource, resource.getQuantity(), 0, allOrNothing, exactAmount, filter, Collections.emptyList())).collect(Collectors.toList()));
                    }
                    else {
                        continue;
                    }
                }
            }
            final List<ResourceTransaction> transactions = new ObjectArrayList<ResourceTransaction>();
            for (final ResourceQuantity resource2 : resources) {
                transactions.add(internal_removeResource(itemContainer, resource2, allOrNothing, exactAmount, filter));
            }
            return new ListTransaction(true, (List<Transaction>)transactions);
        });
    }
    
    public static int testRemoveResourceFromItems(@Nonnull final ItemContainer container, @Nonnull final ResourceQuantity resource, int testQuantityRemaining, final boolean filter) {
        for (short i = 0; i < container.getCapacity() && testQuantityRemaining > 0; testQuantityRemaining = testRemoveResourceFromSlot(container, i, resource, testQuantityRemaining, filter), ++i) {}
        return testQuantityRemaining;
    }
    
    public static TestRemoveItemSlotResult testRemoveResourceSlotFromItems(@Nonnull final ItemContainer container, @Nonnull final ResourceQuantity resource, final int testQuantityRemaining, final boolean filter) {
        final TestRemoveItemSlotResult result = new TestRemoveItemSlotResult(testQuantityRemaining);
        for (short i = 0; i < container.getCapacity() && result.quantityRemaining > 0; ++i) {
            final int newValue = testRemoveResourceFromSlot(container, i, resource, result.quantityRemaining, filter);
            if (newValue != result.quantityRemaining) {
                final int diff = result.quantityRemaining - newValue;
                result.quantityRemaining = newValue;
                result.picked.put(i, diff);
            }
        }
        return result;
    }
    
    public static int testRemoveResourceFromSlot(@Nonnull final ItemContainer container, final short slot, @Nonnull final ResourceQuantity resource, int testQuantityRemaining, final boolean filter) {
        if (filter && container.cantRemoveFromSlot(slot)) {
            return testQuantityRemaining;
        }
        final ItemStack slotItemStack = container.internal_getSlot(slot);
        if (ItemStack.isEmpty(slotItemStack)) {
            return testQuantityRemaining;
        }
        final Item slotItem = slotItemStack.getItem();
        final ItemResourceType resourceType = resource.getResourceType(slotItem);
        if (resourceType == null) {
            return testQuantityRemaining;
        }
        final int resourceTypeQuantity = resourceType.quantity;
        final int quantityInItemsRemaining = MathUtil.ceil(testQuantityRemaining / (double)resourceTypeQuantity);
        final int quantityInItems = slotItemStack.getQuantity();
        final int quantityInItemsAdjustment = Math.min(quantityInItems, quantityInItemsRemaining);
        final int quantityAdjustment = quantityInItemsAdjustment * resourceTypeQuantity;
        testQuantityRemaining -= quantityAdjustment;
        return testQuantityRemaining;
    }
}
