package net.minecraft.world.level.block;

import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.entity.BlockEntity;
import java.util.function.BiPredicate;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.state.BlockState;
import java.util.function.Function;
import net.minecraft.world.level.block.entity.BlockEntityType;

public class DoubleBlockCombiner {
    public static <S extends BlockEntity> NeighborCombineResult<S> combineWithNeigbour(final BlockEntityType<S> cdm, final Function<BlockState, BlockType> function2, final Function<BlockState, Direction> function3, final DirectionProperty cgd, final BlockState cfj, final LevelAccessor bqc, final BlockPos fu, final BiPredicate<LevelAccessor, BlockPos> biPredicate) {
        final S cdl9 = cdm.getBlockEntity(bqc, fu);
        if (cdl9 == null) {
            return Combiner::acceptNone;
        }
        if (biPredicate.test(bqc, fu)) {
            return Combiner::acceptNone;
        }
        final BlockType a10 = function2.apply(cfj);
        final boolean boolean11 = a10 == BlockType.SINGLE;
        final boolean boolean12 = a10 == BlockType.FIRST;
        if (boolean11) {
            return new NeighborCombineResult.Single<S>(cdl9);
        }
        final BlockPos fu2 = fu.relative(function3.apply(cfj));
        final BlockState cfj2 = bqc.getBlockState(fu2);
        if (cfj2.is(cfj.getBlock())) {
            final BlockType a11 = function2.apply(cfj2);
            if (a11 != BlockType.SINGLE && a10 != a11 && cfj2.<Comparable>getValue((Property<Comparable>)cgd) == cfj.<Comparable>getValue((Property<Comparable>)cgd)) {
                if (biPredicate.test(bqc, fu2)) {
                    return Combiner::acceptNone;
                }
                final S cdl10 = cdm.getBlockEntity(bqc, fu2);
                if (cdl10 != null) {
                    final S cdl11 = boolean12 ? cdl9 : cdl10;
                    final S cdl12 = boolean12 ? cdl10 : cdl9;
                    return new NeighborCombineResult.Double<S>(cdl11, cdl12);
                }
            }
        }
        return new NeighborCombineResult.Single<S>(cdl9);
    }
    
    public enum BlockType {
        SINGLE, 
        FIRST, 
        SECOND;
    }
    
    public interface NeighborCombineResult<S> {
         <T> T apply(final Combiner<? super S, T> b);
        
        public static final class Double<S> implements NeighborCombineResult<S> {
            private final S first;
            private final S second;
            
            public Double(final S object1, final S object2) {
                this.first = object1;
                this.second = object2;
            }
            
            @Override
            public <T> T apply(final Combiner<? super S, T> b) {
                return b.acceptDouble(this.first, this.second);
            }
        }
        
        public static final class Single<S> implements NeighborCombineResult<S> {
            private final S single;
            
            public Single(final S object) {
                this.single = object;
            }
            
            @Override
            public <T> T apply(final Combiner<? super S, T> b) {
                return b.acceptSingle(this.single);
            }
        }
    }
    
    public interface Combiner<S, T> {
        T acceptDouble(final S object1, final S object2);
        
        T acceptSingle(final S object);
        
        T acceptNone();
    }
}
