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

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

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 javax.annotation.Nullable;
import com.hypixel.hytale.server.core.inventory.ItemStack;
import com.hypixel.hytale.server.core.inventory.transaction.ClearTransaction;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.inventory.container.filter.FilterType;
import com.hypixel.hytale.server.core.inventory.container.filter.SlotFilter;
import com.hypixel.fastutil.ints.Int2ObjectConcurrentHashMap;
import com.hypixel.hytale.server.core.inventory.container.filter.FilterActionType;
import java.util.Map;

public class DelegateItemContainer<T extends ItemContainer> extends ItemContainer
{
    private T delegate;
    private final Map<FilterActionType, Int2ObjectConcurrentHashMap<SlotFilter>> slotFilters;
    @Nonnull
    private FilterType globalFilter;
    
    public DelegateItemContainer(final T delegate) {
        this.slotFilters = new ConcurrentHashMap<FilterActionType, Int2ObjectConcurrentHashMap<SlotFilter>>();
        this.globalFilter = FilterType.ALLOW_ALL;
        Objects.requireNonNull(delegate, "Delegate can't be null!");
        this.delegate = delegate;
    }
    
    public T getDelegate() {
        return this.delegate;
    }
    
    @Override
    protected <V> V readAction(final Supplier<V> action) {
        return this.delegate.readAction(action);
    }
    
    @Override
    protected <X, V> V readAction(final Function<X, V> action, final X x) {
        return this.delegate.readAction(action, x);
    }
    
    @Override
    protected <V> V writeAction(final Supplier<V> action) {
        return this.delegate.writeAction(action);
    }
    
    @Override
    protected <X, V> V writeAction(final Function<X, V> action, final X x) {
        return this.delegate.writeAction(action, x);
    }
    
    @Override
    protected ClearTransaction internal_clear() {
        return this.delegate.internal_clear();
    }
    
    @Override
    protected ItemStack internal_getSlot(final short slot) {
        return this.delegate.internal_getSlot(slot);
    }
    
    @Override
    protected ItemStack internal_setSlot(final short slot, final ItemStack itemStack) {
        return this.delegate.internal_setSlot(slot, itemStack);
    }
    
    @Override
    protected ItemStack internal_removeSlot(final short slot) {
        return this.delegate.internal_removeSlot(slot);
    }
    
    @Override
    protected boolean cantAddToSlot(final short slot, final ItemStack itemStack, final ItemStack slotItemStack) {
        return !this.globalFilter.allowInput() || this.testFilter(FilterActionType.ADD, slot, itemStack) || this.delegate.cantAddToSlot(slot, itemStack, slotItemStack);
    }
    
    @Override
    protected boolean cantRemoveFromSlot(final short slot) {
        return !this.globalFilter.allowOutput() || this.testFilter(FilterActionType.REMOVE, slot, null) || this.delegate.cantRemoveFromSlot(slot);
    }
    
    @Override
    protected boolean cantDropFromSlot(final short slot) {
        return this.testFilter(FilterActionType.DROP, slot, null) || this.delegate.cantDropFromSlot(slot);
    }
    
    @Override
    protected boolean cantMoveToSlot(final ItemContainer fromContainer, final short slotFrom) {
        return this.delegate.cantMoveToSlot(fromContainer, slotFrom);
    }
    
    private boolean testFilter(final FilterActionType actionType, final short slot, final ItemStack itemStack) {
        final Int2ObjectConcurrentHashMap<SlotFilter> map = this.slotFilters.get(actionType);
        if (map == null) {
            return false;
        }
        final SlotFilter filter = map.get(slot);
        return filter != null && !filter.test(actionType, this, slot, itemStack);
    }
    
    @Override
    public short getCapacity() {
        return this.delegate.getCapacity();
    }
    
    @Override
    public ClearTransaction clear() {
        return this.delegate.clear();
    }
    
    @Nonnull
    @Override
    public DelegateItemContainer<T> clone() {
        return new DelegateItemContainer<T>(this.delegate);
    }
    
    @Override
    public boolean isEmpty() {
        return this.delegate.isEmpty();
    }
    
    @Override
    public void setGlobalFilter(@Nonnull final FilterType globalFilter) {
        this.globalFilter = Objects.requireNonNull(globalFilter);
    }
    
    @Override
    public void setSlotFilter(final FilterActionType actionType, final short slot, @Nullable final SlotFilter filter) {
        ItemContainer.validateSlotIndex(slot, this.getCapacity());
        if (filter != null) {
            this.slotFilters.computeIfAbsent(actionType, k -> new Int2ObjectConcurrentHashMap()).put(slot, filter);
        }
        else {
            this.slotFilters.computeIfPresent(actionType, (k, map) -> {
                map.remove(slot);
                return map.isEmpty() ? null : map;
            });
        }
    }
    
    @Nonnull
    @Override
    public EventRegistration registerChangeEvent(final short priority, @Nonnull final Consumer<ItemContainerChangeEvent> consumer) {
        final EventRegistration thisRegistration = super.registerChangeEvent(priority, consumer);
        final EventRegistration[] delegateRegistration = { this.delegate.internalChangeEventRegistry.register(priority, null, event -> consumer.accept(new ItemContainerChangeEvent(this, event.transaction().toParent(this, (short)0, this.delegate)))) };
        return EventRegistration.combine(thisRegistration, (EventRegistration<Object, IBaseEvent>[])delegateRegistration);
    }
    
    @Override
    protected void sendUpdate(@Nonnull final Transaction transaction) {
        if (!transaction.succeeded()) {
            return;
        }
        super.sendUpdate(transaction);
        this.delegate.externalChangeEventRegistry.dispatchFor(null).dispatch(new ItemContainerChangeEvent(this.delegate, transaction));
    }
    
    @Override
    public boolean equals(@Nullable final Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || this.getClass() != o.getClass()) {
            return false;
        }
        final DelegateItemContainer<?> that = (DelegateItemContainer<?>)o;
        Label_0062: {
            if (this.delegate != null) {
                if (this.delegate.equals(that.delegate)) {
                    break Label_0062;
                }
            }
            else if (that.delegate == null) {
                break Label_0062;
            }
            return false;
        }
        if (this.slotFilters != null) {
            if (this.slotFilters.equals(that.slotFilters)) {
                return this.globalFilter == that.globalFilter;
            }
        }
        else if (that.slotFilters == null) {
            return this.globalFilter == that.globalFilter;
        }
        return false;
    }
    
    @Override
    public int hashCode() {
        int result = (this.delegate != null) ? this.delegate.hashCode() : 0;
        result = 31 * result + ((this.slotFilters != null) ? this.slotFilters.hashCode() : 0);
        result = 31 * result + ((this.globalFilter != null) ? this.globalFilter.hashCode() : 0);
        return result;
    }
}
