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

package com.hypixel.hytale.builtin.hytalegenerator.materialproviders.spaceanddepth;

import com.hypixel.hytale.codec.codecs.EnumCodec;
import com.hypixel.hytale.codec.Codec;
import javax.annotation.Nullable;
import com.hypixel.hytale.builtin.hytalegenerator.LoggerUtil;
import java.util.List;
import javax.annotation.Nonnull;
import com.hypixel.hytale.builtin.hytalegenerator.materialproviders.MaterialProvider;

public class SpaceAndDepthMaterialProvider<V> extends MaterialProvider<V>
{
    @Nonnull
    private final LayerContextType layerContextType;
    @Nonnull
    private final Layer<V>[] layers;
    @Nonnull
    private final Condition condition;
    private final int maxDistance;
    
    public SpaceAndDepthMaterialProvider(@Nonnull final LayerContextType layerContextType, @Nonnull final List<Layer<V>> layers, @Nonnull final Condition condition, final int maxDistance) {
        this.layerContextType = layerContextType;
        this.maxDistance = maxDistance;
        this.layers = new Layer[layers.size()];
        for (int i = 0; i < layers.size(); ++i) {
            final Layer<V> l = layers.get(i);
            if (l == null) {
                LoggerUtil.getLogger().warning("Couldn't retrieve layer with index " + i);
            }
            else {
                this.layers[i] = l;
            }
        }
        this.condition = condition;
    }
    
    @Nullable
    @Override
    public V getVoxelTypeAt(@Nonnull final Context context) {
        final int distance = switch (this.layerContextType.ordinal()) {
            default -> throw new MatchException(null, null);
            case 0 -> context.depthIntoFloor;
            case 1 -> context.depthIntoCeiling;
        };
        if (distance > this.maxDistance) {
            return null;
        }
        if (!this.condition.qualifies(context.position.x, context.position.y, context.position.z, context.depthIntoFloor, context.depthIntoCeiling, context.spaceAboveFloor, context.spaceBelowCeiling)) {
            return null;
        }
        MaterialProvider<V> material = null;
        int depthAccumulator = 0;
        for (final Layer<V> l : this.layers) {
            final int layerDepth = l.getThicknessAt(context.position.x, context.position.y, context.position.z, context.depthIntoFloor, context.depthIntoCeiling, context.spaceAboveFloor, context.spaceBelowCeiling, context.distanceToBiomeEdge);
            final int nextDepthAccumulator = depthAccumulator + layerDepth;
            if (distance > depthAccumulator && distance <= nextDepthAccumulator) {
                material = l.getMaterialProvider();
                break;
            }
            depthAccumulator = nextDepthAccumulator;
        }
        if (material == null) {
            return null;
        }
        return material.getVoxelTypeAt(context);
    }
    
    public enum LayerContextType
    {
        DEPTH_INTO_FLOOR, 
        DEPTH_INTO_CEILING;
        
        public static final Codec<LayerContextType> CODEC;
        
        static {
            CODEC = new EnumCodec<LayerContextType>(LayerContextType.class, EnumCodec.EnumStyle.LEGACY);
        }
    }
    
    public abstract static class Layer<V>
    {
        public abstract int getThicknessAt(final int p0, final int p1, final int p2, final int p3, final int p4, final int p5, final int p6, final double p7);
        
        @Nullable
        public abstract MaterialProvider<V> getMaterialProvider();
    }
    
    public interface Condition
    {
        boolean qualifies(final int p0, final int p1, final int p2, final int p3, final int p4, final int p5, final int p6);
    }
}
