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

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

import com.hypixel.hytale.server.core.inventory.container.filter.SlotFilter;
import com.hypixel.hytale.server.core.inventory.container.filter.FilterActionType;
import com.hypixel.hytale.server.core.inventory.container.filter.FilterType;
import java.util.Objects;
import com.hypixel.hytale.server.core.inventory.transaction.Transaction;
import com.hypixel.hytale.event.IBaseEvent;
import com.hypixel.hytale.event.EventRegistration;
import java.util.function.Consumer;
import com.hypixel.hytale.server.core.inventory.ItemStack;
import com.hypixel.hytale.server.core.inventory.transaction.ClearTransaction;
import java.util.function.Function;
import javax.annotation.Nonnull;
import java.util.function.Supplier;
import javax.annotation.Nullable;

public class CombinedItemContainer extends ItemContainer
{
    protected final ItemContainer[] containers;
    
    public CombinedItemContainer(final ItemContainer... containers) {
        this.containers = containers;
    }
    
    public ItemContainer getContainer(final int index) {
        return this.containers[index];
    }
    
    public int getContainersSize() {
        return this.containers.length;
    }
    
    @Nullable
    public ItemContainer getContainerForSlot(short slot) {
        for (final ItemContainer container : this.containers) {
            final short capacity = container.getCapacity();
            if (slot < capacity) {
                return container;
            }
            slot -= capacity;
        }
        return null;
    }
    
    @Override
    protected <V> V readAction(@Nonnull final Supplier<V> action) {
        return this.readAction0(0, action);
    }
    
    private <V> V readAction0(final int i, @Nonnull final Supplier<V> action) {
        if (i >= this.containers.length) {
            return action.get();
        }
        return this.containers[i].readAction(() -> this.readAction0(i + 1, (Supplier<Object>)action));
    }
    
    @Override
    protected <X, V> V readAction(@Nonnull final Function<X, V> action, final X x) {
        return this.readAction0(0, action, x);
    }
    
    private <X, V> V readAction0(final int i, @Nonnull final Function<X, V> action, final X x) {
        if (i >= this.containers.length) {
            return action.apply(x);
        }
        return this.containers[i].readAction(() -> this.readAction0(i + 1, (Function<Object, Object>)action, x));
    }
    
    @Override
    protected <V> V writeAction(@Nonnull final Supplier<V> action) {
        return this.writeAction0(0, action);
    }
    
    private <V> V writeAction0(final int i, @Nonnull final Supplier<V> action) {
        if (i >= this.containers.length) {
            return action.get();
        }
        return this.containers[i].writeAction(() -> this.writeAction0(i + 1, (Supplier<Object>)action));
    }
    
    @Override
    protected <X, V> V writeAction(@Nonnull final Function<X, V> action, final X x) {
        return this.writeAction0(0, action, x);
    }
    
    private <X, V> V writeAction0(final int i, @Nonnull final Function<X, V> action, final X x) {
        if (i >= this.containers.length) {
            return action.apply(x);
        }
        return this.containers[i].writeAction(() -> this.writeAction0(i + 1, (Function<Object, Object>)action, x));
    }
    
    @Nonnull
    @Override
    protected ClearTransaction internal_clear() {
        final ItemStack[] itemStacks = new ItemStack[this.getCapacity()];
        short start = 0;
        for (final ItemContainer container : this.containers) {
            final ClearTransaction clear = container.internal_clear();
            final ItemStack[] items = clear.getItems();
            for (short slot = 0; slot < itemStacks.length; ++slot) {
                itemStacks[(short)(start + slot)] = items[slot];
            }
            start += container.getCapacity();
        }
        return new ClearTransaction(true, (short)0, itemStacks);
    }
    
    @Nullable
    @Override
    protected ItemStack internal_getSlot(short slot) {
        for (final ItemContainer container : this.containers) {
            final short capacity = container.getCapacity();
            if (slot < capacity) {
                return container.internal_getSlot(slot);
            }
            slot -= capacity;
        }
        return null;
    }
    
    @Nullable
    @Override
    protected ItemStack internal_setSlot(short slot, final ItemStack itemStack) {
        if (ItemStack.isEmpty(itemStack)) {
            return this.internal_removeSlot(slot);
        }
        for (final ItemContainer container : this.containers) {
            final short capacity = container.getCapacity();
            if (slot < capacity) {
                return container.internal_setSlot(slot, itemStack);
            }
            slot -= capacity;
        }
        return null;
    }
    
    @Nullable
    @Override
    protected ItemStack internal_removeSlot(short slot) {
        for (final ItemContainer container : this.containers) {
            final short capacity = container.getCapacity();
            if (slot < capacity) {
                return container.internal_removeSlot(slot);
            }
            slot -= capacity;
        }
        return null;
    }
    
    @Override
    protected boolean cantAddToSlot(short slot, final ItemStack itemStack, final ItemStack slotItemStack) {
        for (final ItemContainer container : this.containers) {
            final short capacity = container.getCapacity();
            if (slot < capacity) {
                return container.cantAddToSlot(slot, itemStack, slotItemStack);
            }
            slot -= capacity;
        }
        return true;
    }
    
    @Override
    protected boolean cantRemoveFromSlot(short slot) {
        for (final ItemContainer container : this.containers) {
            final short capacity = container.getCapacity();
            if (slot < capacity) {
                return container.cantRemoveFromSlot(slot);
            }
            slot -= capacity;
        }
        return true;
    }
    
    @Override
    protected boolean cantDropFromSlot(short slot) {
        for (final ItemContainer container : this.containers) {
            final short capacity = container.getCapacity();
            if (slot < capacity) {
                return container.cantDropFromSlot(slot);
            }
            slot -= capacity;
        }
        return true;
    }
    
    @Override
    protected boolean cantMoveToSlot(final ItemContainer fromContainer, final short slotFrom) {
        for (final ItemContainer container : this.containers) {
            final boolean cantMoveToSlot = container.cantMoveToSlot(fromContainer, slotFrom);
            if (cantMoveToSlot) {
                return true;
            }
        }
        return false;
    }
    
    @Override
    public short getCapacity() {
        short capacity = 0;
        for (final ItemContainer container : this.containers) {
            capacity += container.getCapacity();
        }
        return capacity;
    }
    
    @Override
    public CombinedItemContainer clone() {
        throw new UnsupportedOperationException("clone() is not supported for CombinedItemContainer");
    }
    
    @Nonnull
    @Override
    public EventRegistration registerChangeEvent(final short priority, @Nonnull final Consumer<ItemContainerChangeEvent> consumer) {
        final EventRegistration thisRegistration = super.registerChangeEvent(priority, consumer);
        final EventRegistration[] containerRegistrations = new EventRegistration[this.containers.length];
        short start = 0;
        for (int i = 0; i < this.containers.length; ++i) {
            final ItemContainer container = this.containers[i];
            final short finalStart = start;
            containerRegistrations[i] = container.internalChangeEventRegistry.register(priority, null, event -> consumer.accept(new ItemContainerChangeEvent(this, event.transaction().toParent(this, finalStart, container))));
            start += container.getCapacity();
        }
        return EventRegistration.combine(thisRegistration, (EventRegistration<Object, IBaseEvent>[])containerRegistrations);
    }
    
    @Override
    protected void sendUpdate(@Nonnull final Transaction transaction) {
        if (!transaction.succeeded()) {
            return;
        }
        super.sendUpdate(transaction);
        short start = 0;
        for (final ItemContainer container : this.containers) {
            final Transaction containerTransaction = transaction.fromParent(this, start, container);
            Label_0097: {
                if (containerTransaction != null) {
                    if (!containerTransaction.succeeded()) {
                        start += container.getCapacity();
                        break Label_0097;
                    }
                    container.sendUpdate(containerTransaction);
                }
                start += container.getCapacity();
            }
        }
    }
    
    @Override
    public boolean containsContainer(final ItemContainer itemContainer) {
        if (itemContainer == this) {
            return true;
        }
        for (final ItemContainer container : this.containers) {
            if (container.containsContainer(itemContainer)) {
                return true;
            }
        }
        return false;
    }
    
    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        }
        if (o instanceof final CombinedItemContainer that) {
            final short capacity = this.getCapacity();
            return capacity == that.getCapacity() && this.readAction(_that -> _that.readAction(_that2 -> {
                short i = 0;
                while (i < capacity) {
                    if (!Objects.equals(this.internal_getSlot(i), _that2.internal_getSlot(i))) {
                        return false;
                    }
                    else {
                        ++i;
                    }
                }
                return true;
            }, _that), that);
        }
        return false;
    }
    
    @Override
    public int hashCode() {
        final short capacity = this.getCapacity();
        int result = this.readAction(() -> {
            int hash = 0;
            for (short i = 0; i < capacity; ++i) {
                final ItemStack itemStack = this.internal_getSlot(i);
                hash = 31 * hash + ((itemStack != null) ? itemStack.hashCode() : 0);
            }
            return hash;
        });
        result = 31 * result + capacity;
        return result;
    }
    
    @Override
    public void setGlobalFilter(final FilterType globalFilter) {
        throw new UnsupportedOperationException("setGlobalFilter(FilterType) is not supported in CombinedItemContainer");
    }
    
    @Override
    public void setSlotFilter(final FilterActionType actionType, short slot, final SlotFilter filter) {
        for (final ItemContainer container : this.containers) {
            final short capacity = container.getCapacity();
            if (slot < capacity) {
                container.setSlotFilter(actionType, slot, filter);
                return;
            }
            slot -= capacity;
        }
    }
}
