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

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

import com.hypixel.hytale.builtin.hytalegenerator.props.ScanResult;
import org.checkerframework.checker.nullness.compatqual.NonNullDecl;
import com.hypixel.hytale.builtin.hytalegenerator.newsystem.TerrainDensityProvider;
import java.util.ArrayDeque;
import com.hypixel.hytale.builtin.hytalegenerator.datastructures.voxelspace.ArrayVoxelSpace;
import java.util.Iterator;
import java.util.List;
import java.util.Collection;
import java.util.ArrayList;
import com.hypixel.hytale.builtin.hytalegenerator.threadindexer.WorkerIndexer;
import com.hypixel.hytale.builtin.hytalegenerator.datastructures.voxelspace.VoxelSpace;
import com.hypixel.hytale.builtin.hytalegenerator.bounds.SpaceSize;
import javax.annotation.Nonnull;
import com.hypixel.hytale.builtin.hytalegenerator.bounds.Bounds3i;
import com.hypixel.hytale.builtin.hytalegenerator.conveyor.stagedconveyor.ContextDependency;
import com.hypixel.hytale.builtin.hytalegenerator.patterns.Pattern;
import com.hypixel.hytale.builtin.hytalegenerator.scanners.Scanner;
import com.hypixel.hytale.builtin.hytalegenerator.MaterialSet;
import com.hypixel.hytale.builtin.hytalegenerator.material.Material;
import com.hypixel.hytale.builtin.hytalegenerator.materialproviders.MaterialProvider;
import com.hypixel.hytale.math.vector.Vector3i;
import com.hypixel.hytale.builtin.hytalegenerator.props.Prop;

public class PondFillerProp extends Prop
{
    private static final int TRAVERSED = 1;
    private static final int LEAKS = 16;
    private static final int SOLID = 256;
    private static final int STACKED = 4096;
    private final Vector3i boundingMin;
    private final Vector3i boundingMax;
    private final MaterialProvider<Material> filledMaterialProvider;
    private final MaterialSet solidSet;
    private final Scanner scanner;
    private final Pattern pattern;
    private final ContextDependency contextDependency;
    private final Bounds3i readBounds_voxelGrid;
    private final Bounds3i writeBounds_voxelGrid;
    
    public PondFillerProp(@Nonnull final Vector3i boundingMin, @Nonnull final Vector3i boundingMax, @Nonnull final MaterialSet solidSet, @Nonnull final MaterialProvider<Material> filledMaterialProvider, @Nonnull final Scanner scanner, @Nonnull final Pattern pattern) {
        this.boundingMin = boundingMin.clone();
        this.boundingMax = boundingMax.clone();
        this.solidSet = solidSet;
        this.filledMaterialProvider = filledMaterialProvider;
        this.scanner = scanner;
        this.pattern = pattern;
        SpaceSize boundingSpace = new SpaceSize(boundingMin, boundingMax);
        boundingSpace = SpaceSize.stack(boundingSpace, scanner.readSpaceWith(pattern));
        SpaceSize.stack(scanner.readSpaceWith(pattern), boundingSpace);
        final Vector3i range = boundingSpace.getRange();
        this.contextDependency = new ContextDependency(range, range);
        this.readBounds_voxelGrid = this.contextDependency.getReadBounds_voxelGrid();
        this.writeBounds_voxelGrid = this.contextDependency.getWriteBounds_voxelGrid();
    }
    
    @Override
    public FillerPropScanResult scan(@Nonnull final Vector3i position, @Nonnull final VoxelSpace<Material> materialSpace, @Nonnull final WorkerIndexer.Id id) {
        final Scanner.Context scannerContext = new Scanner.Context(position, this.pattern, materialSpace, id);
        final List<Vector3i> scanResults = this.scanner.scan(scannerContext);
        if (scanResults.size() == 1) {
            final List<Vector3i> resultList = this.renderFluidBlocks(scanResults.getFirst(), materialSpace);
            return new FillerPropScanResult(resultList);
        }
        final ArrayList<Vector3i> resultList2 = new ArrayList<Vector3i>();
        for (final Vector3i scanPosition : scanResults) {
            final List<Vector3i> renderResult = this.renderFluidBlocks(scanPosition, materialSpace);
            resultList2.addAll(renderResult);
        }
        return new FillerPropScanResult(resultList2);
    }
    
    private List<Vector3i> renderFluidBlocks(@Nonnull final Vector3i origin, @Nonnull final VoxelSpace<Material> materialSpace) {
        Vector3i min = this.boundingMin.clone().add(origin);
        Vector3i max = this.boundingMax.clone().add(origin);
        min = Vector3i.max(min, new Vector3i(materialSpace.minX(), materialSpace.minY(), materialSpace.minZ()));
        max = Vector3i.min(max, new Vector3i(materialSpace.maxX(), materialSpace.maxY(), materialSpace.maxZ()));
        final ArrayVoxelSpace<Integer> mask = new ArrayVoxelSpace<Integer>(max.x - min.x, max.y - min.y, max.z - min.z);
        mask.setOrigin(-min.x, -min.y, -min.z);
        mask.set(0);
        int y = min.y;
        for (int x = min.x; x < max.x; ++x) {
            for (int z = min.z; z < max.z; ++z) {
                final Material material = materialSpace.getContent(x, y, z);
                final int contextMaterialHash = material.hashMaterialIds();
                int maskValue = 1;
                if (this.solidSet.test(contextMaterialHash)) {
                    maskValue |= 0x100;
                    mask.set(maskValue, x, y, z);
                }
                else {
                    maskValue |= 0x10;
                    mask.set(maskValue, x, y, z);
                }
            }
        }
        for (y = min.y + 1; y < max.y; ++y) {
            final int underY = y - 1;
            for (int x2 = min.x; x2 < max.x; ++x2) {
                for (int z2 = min.z; z2 < max.z; ++z2) {
                    if (!isTraversed(mask.getContent(x2, y, z2))) {
                        final int maskValueUnder = mask.getContent(x2, underY, z2);
                        Material material = materialSpace.getContent(x2, y, z2);
                        int contextMaterialHash = material.hashMaterialIds();
                        if (this.solidSet.test(contextMaterialHash)) {
                            int maskValue2 = 0;
                            maskValue2 |= 0x1;
                            maskValue2 |= 0x100;
                            mask.set(maskValue2, x2, y, z2);
                        }
                        else if (isLeaks(maskValueUnder) || x2 == min.x || x2 == max.x - 1 || z2 == min.z || z2 == max.z - 1) {
                            final ArrayDeque<Vector3i> stack = new ArrayDeque<Vector3i>();
                            stack.push(new Vector3i(x2, y, z2));
                            mask.set(4096, x2, y, z2);
                            while (!stack.isEmpty()) {
                                final Vector3i poppedPos = stack.pop();
                                int maskValue3 = mask.getContent(poppedPos.x, poppedPos.y, poppedPos.z);
                                maskValue3 |= 0x10;
                                mask.set(maskValue3, poppedPos.x, poppedPos.y, poppedPos.z);
                                final Vector3i vector3i = poppedPos;
                                --vector3i.x;
                                if (mask.isInsideSpace(poppedPos.x, poppedPos.y, poppedPos.z)) {
                                    final int poppedMaskValue = mask.getContent(poppedPos.x, poppedPos.y, poppedPos.z);
                                    if (!isStacked(poppedMaskValue)) {
                                        material = materialSpace.getContent(poppedPos.x, poppedPos.y, poppedPos.z);
                                        contextMaterialHash = material.hashMaterialIds();
                                        if (!this.solidSet.test(contextMaterialHash)) {
                                            stack.push(poppedPos.clone());
                                            mask.set(0x1000 | poppedMaskValue, poppedPos.x, poppedPos.y, poppedPos.z);
                                        }
                                    }
                                }
                                final Vector3i vector3i2 = poppedPos;
                                vector3i2.x += 2;
                                if (mask.isInsideSpace(poppedPos.x, poppedPos.y, poppedPos.z)) {
                                    final int poppedMaskValue = mask.getContent(poppedPos.x, poppedPos.y, poppedPos.z);
                                    if (!isStacked(poppedMaskValue)) {
                                        material = materialSpace.getContent(poppedPos.x, poppedPos.y, poppedPos.z);
                                        contextMaterialHash = material.hashMaterialIds();
                                        if (!this.solidSet.test(contextMaterialHash)) {
                                            stack.push(poppedPos.clone());
                                            mask.set(0x1000 | poppedMaskValue, poppedPos.x, poppedPos.y, poppedPos.z);
                                        }
                                    }
                                }
                                final Vector3i vector3i3 = poppedPos;
                                --vector3i3.x;
                                final Vector3i vector3i4 = poppedPos;
                                --vector3i4.z;
                                if (mask.isInsideSpace(poppedPos.x, poppedPos.y, poppedPos.z)) {
                                    final int poppedMaskValue = mask.getContent(poppedPos.x, poppedPos.y, poppedPos.z);
                                    if (!isStacked(poppedMaskValue)) {
                                        material = materialSpace.getContent(poppedPos.x, y, poppedPos.z);
                                        contextMaterialHash = material.hashMaterialIds();
                                        if (!this.solidSet.test(contextMaterialHash)) {
                                            stack.push(poppedPos.clone());
                                            mask.set(0x1000 | poppedMaskValue, poppedPos.x, poppedPos.y, poppedPos.z);
                                        }
                                    }
                                }
                                final Vector3i vector3i5 = poppedPos;
                                vector3i5.z += 2;
                                if (mask.isInsideSpace(poppedPos.x, poppedPos.y, poppedPos.z)) {
                                    final int poppedMaskValue = mask.getContent(poppedPos.x, poppedPos.y, poppedPos.z);
                                    if (!isStacked(poppedMaskValue)) {
                                        material = materialSpace.getContent(poppedPos.x, poppedPos.y, poppedPos.z);
                                        contextMaterialHash = material.hashMaterialIds();
                                        if (!this.solidSet.test(contextMaterialHash)) {
                                            stack.push(poppedPos.clone());
                                            mask.set(0x1000 | poppedMaskValue, poppedPos.x, poppedPos.y, poppedPos.z);
                                        }
                                    }
                                }
                                final Vector3i vector3i6 = poppedPos;
                                --vector3i6.z;
                            }
                        }
                    }
                }
            }
        }
        final ArrayList<Vector3i> fluidBlocks = new ArrayList<Vector3i>();
        for (y = mask.minY() + 1; y < mask.maxY(); ++y) {
            for (int x2 = mask.minX() + 1; x2 < mask.maxX() - 1; ++x2) {
                for (int z2 = mask.minZ() + 1; z2 < mask.maxZ() - 1; ++z2) {
                    final int maskValue4 = mask.getContent(x2, y, z2);
                    if (!isSolid(maskValue4) && !isLeaks(maskValue4)) {
                        fluidBlocks.add(new Vector3i(x2, y, z2));
                    }
                }
            }
        }
        return fluidBlocks;
    }
    
    @Override
    public void place(@Nonnull final Context context) {
        final List<Vector3i> fluidBlocks = FillerPropScanResult.cast(context.scanResult).getFluidBlocks();
        if (fluidBlocks == null) {
            return;
        }
        for (final Vector3i position : fluidBlocks) {
            if (!context.materialSpace.isInsideSpace(position.x, position.y, position.z)) {
                continue;
            }
            final MaterialProvider.Context materialsContext = new MaterialProvider.Context(position, 0.0, 0, 0, 0, 0, context.workerId, null, context.distanceFromBiomeEdge);
            final Material material = this.filledMaterialProvider.getVoxelTypeAt(materialsContext);
            if (material == null) {
                continue;
            }
            context.materialSpace.set(material, position.x, position.y, position.z);
        }
    }
    
    @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 boolean isTraversed(final int maskValue) {
        return (maskValue & 0x1) == 0x1;
    }
    
    private static boolean isLeaks(final int maskValue) {
        return (maskValue & 0x10) == 0x10;
    }
    
    private static boolean isSolid(final int maskValue) {
        return (maskValue & 0x100) == 0x100;
    }
    
    private static boolean isStacked(final int maskValue) {
        return (maskValue & 0x1000) == 0x1000;
    }
}
