package net.minecraft.data.models.blockstates;

import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.google.common.collect.Maps;
import net.minecraft.world.level.block.state.properties.Property;
import java.util.Map;
import com.google.gson.JsonObject;
import java.util.function.Consumer;
import java.util.function.Function;
import com.google.gson.JsonArray;
import java.util.List;
import java.util.Arrays;
import net.minecraft.world.level.block.state.StateDefinition;
import com.google.gson.JsonElement;
import java.util.function.Supplier;

public interface Condition extends Supplier<JsonElement> {
    void validate(final StateDefinition<?, ?> cfk);
    
    default TerminalCondition condition() {
        return new TerminalCondition();
    }
    
    default Condition or(final Condition... arr) {
        return new CompositeCondition(Operation.OR, (List)Arrays.<Condition>asList(arr));
    }
    
    public enum Operation {
        AND("AND"), 
        OR("OR");
        
        private final String id;
        
        private Operation(final String string3) {
            this.id = string3;
        }
    }
    
    public static class CompositeCondition implements Condition {
        private final Operation operation;
        private final List<Condition> subconditions;
        
        private CompositeCondition(final Operation b, final List<Condition> list) {
            this.operation = b;
            this.subconditions = list;
        }
        
        @Override
        public void validate(final StateDefinition<?, ?> cfk) {
            this.subconditions.forEach(il -> il.validate(cfk));
        }
        
        @Override
        public JsonElement get() {
            final JsonArray jsonArray2 = new JsonArray();
            this.subconditions.stream().map(Supplier::get).forEach(jsonArray2::add);
            final JsonObject jsonObject3 = new JsonObject();
            jsonObject3.add(this.operation.id, jsonArray2);
            return jsonObject3;
        }
    }
    
    public static class TerminalCondition implements Condition {
        private final Map<Property<?>, String> terms;
        
        public TerminalCondition() {
            this.terms = Maps.newHashMap();
        }
        
        private static <T extends Comparable<T>> String joinValues(final Property<T> cgl, final Stream<T> stream) {
            return stream.map(cgl::getName).collect(Collectors.joining("|"));
        }
        
        private static <T extends Comparable<T>> String getTerm(final Property<T> cgl, final T comparable, final T[] arr) {
            return TerminalCondition.<T>joinValues(cgl, Stream.<T>concat(Stream.of((T)comparable), Stream.of((T[])arr)));
        }
        
        private <T extends Comparable<T>> void putValue(final Property<T> cgl, final String string) {
            final String string2 = this.terms.put(cgl, string);
            if (string2 != null) {
                throw new IllegalStateException("Tried to replace " + cgl + " value from " + string2 + " to " + string);
            }
        }
        
        public final <T extends Comparable<T>> TerminalCondition term(final Property<T> cgl, final T comparable) {
            this.<T>putValue(cgl, cgl.getName(comparable));
            return this;
        }
        
        @SafeVarargs
        public final <T extends Comparable<T>> TerminalCondition term(final Property<T> cgl, final T comparable, final T... arr) {
            this.<T>putValue(cgl, TerminalCondition.<T>getTerm(cgl, comparable, arr));
            return this;
        }
        
        @Override
        public JsonElement get() {
            final JsonObject jsonObject2 = new JsonObject();
            this.terms.forEach((cgl, string) -> jsonObject2.addProperty(cgl.getName(), string));
            return jsonObject2;
        }
        
        @Override
        public void validate(final StateDefinition<?, ?> cfk) {
            final List<Property<?>> list3 = this.terms.keySet().stream().filter(cgl -> cfk.getProperty(cgl.getName()) != cgl).collect(Collectors.toList());
            if (!list3.isEmpty()) {
                throw new IllegalStateException("Properties " + list3 + " are missing from " + cfk);
            }
        }
    }
}
