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

package com.hypixel.hytale.builtin.hytalegenerator.props;

import org.checkerframework.checker.nullness.compatqual.NonNullDecl;
import java.util.Random;
import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer;
import com.hypixel.hytale.builtin.hytalegenerator.material.Material;
import com.hypixel.hytale.builtin.hytalegenerator.datastructures.voxelspace.VoxelSpace;
import java.util.Iterator;
import com.hypixel.hytale.math.vector.Vector3i;
import com.hypixel.hytale.builtin.hytalegenerator.framework.math.SeedGenerator;
import com.hypixel.hytale.builtin.hytalegenerator.bounds.Bounds3i;
import com.hypixel.hytale.builtin.hytalegenerator.conveyor.stagedconveyor.ContextDependency;
import javax.annotation.Nonnull;
import com.hypixel.hytale.builtin.hytalegenerator.datastructures.WeightedMap;

public class WeightedProp extends Prop
{
    @Nonnull
    private final WeightedMap<Prop> props;
    @Nonnull
    private final ContextDependency contextDependency;
    @Nonnull
    private final Bounds3i readBounds_voxelGrid;
    @Nonnull
    private final Bounds3i writeBounds_voxelGrid;
    @Nonnull
    private final SeedGenerator seedGenerator;
    
    public WeightedProp(@Nonnull final WeightedMap<Prop> props, final int seed) {
        this.props = new WeightedMap<Prop>(props);
        this.readBounds_voxelGrid = new Bounds3i();
        this.writeBounds_voxelGrid = new Bounds3i();
        this.seedGenerator = new SeedGenerator(seed);
        Vector3i writeRange = new Vector3i();
        Vector3i readRange = new Vector3i();
        for (final Prop prop : this.props.allElements()) {
            writeRange = Vector3i.max(writeRange, prop.getContextDependency().getWriteRange());
            readRange = Vector3i.max(readRange, prop.getContextDependency().getReadRange());
            this.readBounds_voxelGrid.encompass(prop.getReadBounds_voxelGrid());
            this.writeBounds_voxelGrid.encompass(prop.getWriteBounds_voxelGrid());
        }
        this.contextDependency = new ContextDependency(readRange, writeRange);
    }
    
    @Nonnull
    @Override
    public ScanResult scan(@Nonnull final Vector3i position, @Nonnull final VoxelSpace<Material> materialSpace, @Nonnull final WorkerIndexer.Id id) {
        if (this.props.size() == 0) {
            return new PickedScanResult();
        }
        final Random rand = new Random(this.seedGenerator.seedAt(position.x, position.y, position.z));
        final Prop pickedProp = this.props.pick(rand);
        final ScanResult scanResult = pickedProp.scan(position, materialSpace, id);
        final PickedScanResult pickedScanResult = new PickedScanResult();
        pickedScanResult.prop = pickedProp;
        pickedScanResult.scanResult = scanResult;
        return pickedScanResult;
    }
    
    @Override
    public void place(@Nonnull final Context context) {
        if (context.scanResult.isNegative()) {
            return;
        }
        final PickedScanResult pickedScanResult = PickedScanResult.cast(context.scanResult);
        final Context childContext = new Context(context);
        childContext.scanResult = pickedScanResult.scanResult;
        pickedScanResult.prop.place(childContext);
    }
    
    @Nonnull
    @Override
    public ContextDependency getContextDependency() {
        return this.contextDependency.clone();
    }
    
    @NonNullDecl
    @Override
    public Bounds3i getReadBounds_voxelGrid() {
        return this.readBounds_voxelGrid;
    }
    
    @Nonnull
    @Override
    public Bounds3i getWriteBounds_voxelGrid() {
        return this.writeBounds_voxelGrid;
    }
    
    private static class PickedScanResult implements ScanResult
    {
        ScanResult scanResult;
        Prop prop;
        
        @Nonnull
        public static PickedScanResult cast(final ScanResult scanResult) {
            if (!(scanResult instanceof PickedScanResult)) {
                throw new IllegalArgumentException("The provided ScanResult isn't compatible with this prop.");
            }
            return (PickedScanResult)scanResult;
        }
        
        @Override
        public boolean isNegative() {
            return this.scanResult == null || this.scanResult.isNegative();
        }
    }
}
