package net.minecraft.data.models.blockstates;

import java.util.function.BiFunction;
import java.util.Collections;
import com.google.common.collect.ImmutableList;
import java.util.Iterator;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.function.Function;
import net.minecraft.world.level.block.state.properties.Property;
import java.util.stream.Stream;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import java.util.List;
import java.util.Map;

public abstract class PropertyDispatch {
    private final Map<Selector, List<Variant>> values;
    
    public PropertyDispatch() {
        this.values = Maps.newHashMap();
    }
    
    protected void putValue(final Selector ip, final List<Variant> list) {
        final List<Variant> list2 = this.values.put(ip, list);
        if (list2 != null) {
            throw new IllegalStateException("Value " + ip + " is already defined");
        }
    }
    
    Map<Selector, List<Variant>> getEntries() {
        this.verifyComplete();
        return ImmutableMap.copyOf(this.values);
    }
    
    private void verifyComplete() {
        final List<Property<?>> list2 = this.getDefinedProperties();
        Stream<Selector> stream3 = Stream.<Selector>of(Selector.empty());
        for (final Property<?> cgl5 : list2) {
            stream3 = stream3.<Selector>flatMap(ip -> cgl5.getAllValues().map(ip::extend));
        }
        final List<Selector> list3 = stream3.filter(ip -> !this.values.containsKey(ip)).collect(Collectors.toList());
        if (!list3.isEmpty()) {
            throw new IllegalStateException("Missing definition for properties: " + list3);
        }
    }
    
    abstract List<Property<?>> getDefinedProperties();
    
    public static <T1 extends Comparable<T1>> C1<T1> property(final Property<T1> cgl) {
        return new C1<T1>((Property)cgl);
    }
    
    public static <T1 extends Comparable<T1>, T2 extends Comparable<T2>> C2<T1, T2> properties(final Property<T1> cgl1, final Property<T2> cgl2) {
        return new C2<T1, T2>((Property)cgl1, (Property)cgl2);
    }
    
    public static <T1 extends Comparable<T1>, T2 extends Comparable<T2>, T3 extends Comparable<T3>> C3<T1, T2, T3> properties(final Property<T1> cgl1, final Property<T2> cgl2, final Property<T3> cgl3) {
        return new C3<T1, T2, T3>((Property)cgl1, (Property)cgl2, (Property)cgl3);
    }
    
    public static <T1 extends Comparable<T1>, T2 extends Comparable<T2>, T3 extends Comparable<T3>, T4 extends Comparable<T4>> C4<T1, T2, T3, T4> properties(final Property<T1> cgl1, final Property<T2> cgl2, final Property<T3> cgl3, final Property<T4> cgl4) {
        return new C4<T1, T2, T3, T4>((Property)cgl1, (Property)cgl2, (Property)cgl3, (Property)cgl4);
    }
    
    public static <T1 extends Comparable<T1>, T2 extends Comparable<T2>, T3 extends Comparable<T3>, T4 extends Comparable<T4>, T5 extends Comparable<T5>> C5<T1, T2, T3, T4, T5> properties(final Property<T1> cgl1, final Property<T2> cgl2, final Property<T3> cgl3, final Property<T4> cgl4, final Property<T5> cgl5) {
        return new C5<T1, T2, T3, T4, T5>((Property)cgl1, (Property)cgl2, (Property)cgl3, (Property)cgl4, (Property)cgl5);
    }
    
    public static class C1<T1 extends Comparable<T1>> extends PropertyDispatch {
        private final Property<T1> property1;
        
        private C1(final Property<T1> cgl) {
            this.property1 = cgl;
        }
        
        public List<Property<?>> getDefinedProperties() {
            return ImmutableList.of(this.property1);
        }
        
        public C1<T1> select(final T1 comparable, final List<Variant> list) {
            final Selector ip4 = Selector.of(this.property1.value(comparable));
            this.putValue(ip4, list);
            return this;
        }
        
        public C1<T1> select(final T1 comparable, final Variant iq) {
            return this.select(comparable, Collections.<Variant>singletonList(iq));
        }
        
        public PropertyDispatch generate(final Function<T1, Variant> function) {
            this.property1.getPossibleValues().forEach(comparable -> this.select((T1)comparable, function.apply((T1)comparable)));
            return this;
        }
    }
    
    public static class C2<T1 extends Comparable<T1>, T2 extends Comparable<T2>> extends PropertyDispatch {
        private final Property<T1> property1;
        private final Property<T2> property2;
        
        private C2(final Property<T1> cgl1, final Property<T2> cgl2) {
            this.property1 = cgl1;
            this.property2 = cgl2;
        }
        
        public List<Property<?>> getDefinedProperties() {
            return ImmutableList.of(this.property1, (Property<T1>)this.property2);
        }
        
        public C2<T1, T2> select(final T1 comparable1, final T2 comparable2, final List<Variant> list) {
            final Selector ip5 = Selector.of(this.property1.value(comparable1), this.property2.value(comparable2));
            this.putValue(ip5, list);
            return this;
        }
        
        public C2<T1, T2> select(final T1 comparable1, final T2 comparable2, final Variant iq) {
            return this.select(comparable1, comparable2, Collections.<Variant>singletonList(iq));
        }
        
        public PropertyDispatch generate(final BiFunction<T1, T2, Variant> biFunction) {
            this.property1.getPossibleValues().forEach(comparable -> this.property2.getPossibleValues().forEach(comparable3 -> this.select((T1)comparable, (T2)comparable3, biFunction.apply((T1)comparable, (T2)comparable3))));
            return this;
        }
        
        public PropertyDispatch generateList(final BiFunction<T1, T2, List<Variant>> biFunction) {
            this.property1.getPossibleValues().forEach(comparable -> this.property2.getPossibleValues().forEach(comparable3 -> this.select((T1)comparable, (T2)comparable3, biFunction.apply((T1)comparable, (T2)comparable3))));
            return this;
        }
    }
    
    public static class C3<T1 extends Comparable<T1>, T2 extends Comparable<T2>, T3 extends Comparable<T3>> extends PropertyDispatch {
        private final Property<T1> property1;
        private final Property<T2> property2;
        private final Property<T3> property3;
        
        private C3(final Property<T1> cgl1, final Property<T2> cgl2, final Property<T3> cgl3) {
            this.property1 = cgl1;
            this.property2 = cgl2;
            this.property3 = cgl3;
        }
        
        public List<Property<?>> getDefinedProperties() {
            return ImmutableList.of(this.property1, (Property<T1>)this.property2, (Property<T1>)this.property3);
        }
        
        public C3<T1, T2, T3> select(final T1 comparable1, final T2 comparable2, final T3 comparable3, final List<Variant> list) {
            final Selector ip6 = Selector.of(this.property1.value(comparable1), this.property2.value(comparable2), this.property3.value(comparable3));
            this.putValue(ip6, list);
            return this;
        }
        
        public C3<T1, T2, T3> select(final T1 comparable1, final T2 comparable2, final T3 comparable3, final Variant iq) {
            return this.select(comparable1, comparable2, comparable3, Collections.<Variant>singletonList(iq));
        }
        
        public PropertyDispatch generate(final TriFunction<T1, T2, T3, Variant> h) {
            this.property1.getPossibleValues().forEach(comparable -> this.property2.getPossibleValues().forEach(comparable3 -> this.property3.getPossibleValues().forEach(comparable4 -> this.select((T1)comparable, (T2)comparable3, (T3)comparable4, h.apply((T1)comparable, (T2)comparable3, (T3)comparable4)))));
            return this;
        }
    }
    
    public static class C4<T1 extends Comparable<T1>, T2 extends Comparable<T2>, T3 extends Comparable<T3>, T4 extends Comparable<T4>> extends PropertyDispatch {
        private final Property<T1> property1;
        private final Property<T2> property2;
        private final Property<T3> property3;
        private final Property<T4> property4;
        
        private C4(final Property<T1> cgl1, final Property<T2> cgl2, final Property<T3> cgl3, final Property<T4> cgl4) {
            this.property1 = cgl1;
            this.property2 = cgl2;
            this.property3 = cgl3;
            this.property4 = cgl4;
        }
        
        public List<Property<?>> getDefinedProperties() {
            return ImmutableList.of(this.property1, (Property<T1>)this.property2, (Property<T1>)this.property3, (Property<T1>)this.property4);
        }
        
        public C4<T1, T2, T3, T4> select(final T1 comparable1, final T2 comparable2, final T3 comparable3, final T4 comparable4, final List<Variant> list) {
            final Selector ip7 = Selector.of(this.property1.value(comparable1), this.property2.value(comparable2), this.property3.value(comparable3), this.property4.value(comparable4));
            this.putValue(ip7, list);
            return this;
        }
        
        public C4<T1, T2, T3, T4> select(final T1 comparable1, final T2 comparable2, final T3 comparable3, final T4 comparable4, final Variant iq) {
            return this.select(comparable1, comparable2, comparable3, comparable4, Collections.<Variant>singletonList(iq));
        }
    }
    
    public static class C5<T1 extends Comparable<T1>, T2 extends Comparable<T2>, T3 extends Comparable<T3>, T4 extends Comparable<T4>, T5 extends Comparable<T5>> extends PropertyDispatch {
        private final Property<T1> property1;
        private final Property<T2> property2;
        private final Property<T3> property3;
        private final Property<T4> property4;
        private final Property<T5> property5;
        
        private C5(final Property<T1> cgl1, final Property<T2> cgl2, final Property<T3> cgl3, final Property<T4> cgl4, final Property<T5> cgl5) {
            this.property1 = cgl1;
            this.property2 = cgl2;
            this.property3 = cgl3;
            this.property4 = cgl4;
            this.property5 = cgl5;
        }
        
        public List<Property<?>> getDefinedProperties() {
            return ImmutableList.of(this.property1, (Property<T1>)this.property2, (Property<T1>)this.property3, (Property<T1>)this.property4, (Property<T1>)this.property5);
        }
        
        public C5<T1, T2, T3, T4, T5> select(final T1 comparable1, final T2 comparable2, final T3 comparable3, final T4 comparable4, final T5 comparable5, final List<Variant> list) {
            final Selector ip8 = Selector.of(this.property1.value(comparable1), this.property2.value(comparable2), this.property3.value(comparable3), this.property4.value(comparable4), this.property5.value(comparable5));
            this.putValue(ip8, list);
            return this;
        }
        
        public C5<T1, T2, T3, T4, T5> select(final T1 comparable1, final T2 comparable2, final T3 comparable3, final T4 comparable4, final T5 comparable5, final Variant iq) {
            return this.select(comparable1, comparable2, comparable3, comparable4, comparable5, Collections.<Variant>singletonList(iq));
        }
    }
    
    @FunctionalInterface
    public interface TriFunction<P1, P2, P3, R> {
        R apply(final P1 object1, final P2 object2, final P3 object3);
    }
}
