package net.minecraft.world.level.block.state;

import java.util.ArrayList;
import javax.annotation.Nullable;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.function.Function;
import com.google.common.base.MoreObjects;
import java.util.Collection;
import java.util.Iterator;
import com.google.common.collect.UnmodifiableIterator;
import com.google.common.collect.ImmutableMap;
import net.minecraft.core.MapFiller;
import java.util.List;
import java.util.stream.Stream;
import java.util.Collections;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.util.Map;
import com.google.common.collect.ImmutableList;
import net.minecraft.world.level.block.state.properties.Property;
import com.google.common.collect.ImmutableSortedMap;
import java.util.regex.Pattern;

public class StateDefinition<O, S extends StateHolder<S>> {
    private static final Pattern NAME_PATTERN;
    private final O owner;
    private final ImmutableSortedMap<String, Property<?>> propertiesByName;
    private final ImmutableList<S> states;
    
    protected <A extends AbstractStateHolder<O, S>> StateDefinition(final O object, final Factory<O, S, A> b, final Map<String, Property<?>> map) {
        this.owner = object;
        this.propertiesByName = ImmutableSortedMap.<String, Property<?>>copyOf(map);
        final Map<Map<Property<?>, Comparable<?>>, A> map2 = Maps.newLinkedHashMap();
        final List<A> list6 = Lists.newArrayList();
        Stream<List<Comparable<?>>> stream7 = Stream.<List<Comparable<?>>>of(Collections.<Comparable<?>>emptyList());
        for (final Property<?> bzm9 : this.propertiesByName.values()) {
            final List<Comparable<?>> list7;
            stream7 = stream7.<List<Comparable<?>>>flatMap(list -> bzm9.getPossibleValues().stream().map(comparable -> {
                list7 = Lists.newArrayList(list);
                list7.add(comparable);
                return list7;
            }));
        }
        final Map<Property<?>, Comparable<?>> map3;
        final AbstractStateHolder byi8;
        final Map<Map<Property<?>, Comparable<?>>, AbstractStateHolder> map4;
        final List<AbstractStateHolder> list8;
        stream7.forEach(list5 -> {
            map3 = MapFiller.<Property<?>, Comparable<?>>linkedHashMapFrom(this.propertiesByName.values(), list5);
            byi8 = b.create(object, ImmutableMap.<Property<?>, Comparable<?>>copyOf(map3));
            map4.put(map3, byi8);
            list8.add(byi8);
            return;
        });
        for (final A byi9 : list6) {
            ((AbstractStateHolder<O, S>)byi9).populateNeighbours((Map<Map<Property<?>, Comparable<?>>, S>)map2);
        }
        this.states = ImmutableList.<S>copyOf(list6);
    }
    
    public ImmutableList<S> getPossibleStates() {
        return this.states;
    }
    
    public S any() {
        return this.states.get(0);
    }
    
    public O getOwner() {
        return this.owner;
    }
    
    public Collection<Property<?>> getProperties() {
        return this.propertiesByName.values();
    }
    
    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this).add("block", this.owner).add("properties", this.propertiesByName.values().stream().map(Property::getName).collect(Collectors.toList())).toString();
    }
    
    @Nullable
    public Property<?> getProperty(final String string) {
        return this.propertiesByName.get(string);
    }
    
    static {
        NAME_PATTERN = Pattern.compile("^[a-z0-9_]+$");
    }
    
    public static class Builder<O, S extends StateHolder<S>> {
        private final O owner;
        private final Map<String, Property<?>> properties;
        
        public Builder(final O object) {
            this.properties = Maps.newHashMap();
            this.owner = object;
        }
        
        public Builder<O, S> add(final Property<?>... arr) {
            for (final Property<?> bzm6 : arr) {
                this.validateProperty(bzm6);
                this.properties.put(bzm6.getName(), bzm6);
            }
            return this;
        }
        
        private <T extends Comparable<T>> void validateProperty(final Property<T> bzm) {
            final String string3 = bzm.getName();
            if (!StateDefinition.NAME_PATTERN.matcher(string3).matches()) {
                throw new IllegalArgumentException(this.owner + " has invalidly named property: " + string3);
            }
            final Collection<T> collection4 = bzm.getPossibleValues();
            if (collection4.size() <= 1) {
                throw new IllegalArgumentException(this.owner + " attempted use property " + string3 + " with <= 1 possible values");
            }
            for (final T comparable6 : collection4) {
                final String string4 = bzm.getName(comparable6);
                if (!StateDefinition.NAME_PATTERN.matcher(string4).matches()) {
                    throw new IllegalArgumentException(this.owner + " has property: " + string3 + " with invalidly named value: " + string4);
                }
            }
            if (this.properties.containsKey(string3)) {
                throw new IllegalArgumentException(this.owner + " has duplicate property: " + string3);
            }
        }
        
        public <A extends AbstractStateHolder<O, S>> StateDefinition<O, S> create(final Factory<O, S, A> b) {
            return new StateDefinition<O, S>(this.owner, (Factory<O, S, A>)b, this.properties);
        }
    }
    
    public interface Factory<O, S extends StateHolder<S>, A extends AbstractStateHolder<O, S>> {
        A create(final O object, final ImmutableMap<Property<?>, Comparable<?>> immutableMap);
    }
}
