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

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

import org.checkerframework.checker.nullness.compatqual.NonNullDecl;
import com.hypixel.hytale.server.core.prefab.PrefabRotation;
import java.util.Iterator;
import com.hypixel.hytale.builtin.hytalegenerator.props.directionality.RotatedPositionsScanResult;
import com.hypixel.hytale.builtin.hytalegenerator.props.directionality.RotatedPosition;
import java.util.ArrayList;
import com.hypixel.hytale.builtin.hytalegenerator.patterns.Pattern;
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 com.hypixel.hytale.math.vector.Vector3i;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.Rotation;
import com.hypixel.hytale.builtin.hytalegenerator.material.MaterialCache;
import java.util.List;
import javax.annotation.Nonnull;
import com.hypixel.hytale.builtin.hytalegenerator.bounds.Bounds3i;
import com.hypixel.hytale.builtin.hytalegenerator.props.directionality.Directionality;
import com.hypixel.hytale.builtin.hytalegenerator.conveyor.stagedconveyor.ContextDependency;
import com.hypixel.hytale.builtin.hytalegenerator.scanners.Scanner;
import com.hypixel.hytale.builtin.hytalegenerator.BlockMask;
import com.hypixel.hytale.builtin.hytalegenerator.material.Material;

public class ColumnProp extends Prop
{
    private final int[] yPositions;
    private final Material[] blocks0;
    private final Material[] blocks90;
    private final Material[] blocks180;
    private final Material[] blocks270;
    private final BlockMask blockMask;
    private final Scanner scanner;
    private final ContextDependency contextDependency;
    private final Directionality directionality;
    @Nonnull
    private final Bounds3i readBounds_voxelGrid;
    @Nonnull
    private final Bounds3i writeBounds_voxelGrid;
    
    public ColumnProp(@Nonnull final List<Integer> propYPositions, @Nonnull final List<Material> blocks, @Nonnull final BlockMask blockMask, @Nonnull final Scanner scanner, @Nonnull final Directionality directionality, @Nonnull final MaterialCache materialCache) {
        if (propYPositions.size() != blocks.size()) {
            throw new IllegalArgumentException("blocks and positions sizes don't match");
        }
        this.blockMask = blockMask;
        this.yPositions = new int[propYPositions.size()];
        this.blocks0 = new Material[blocks.size()];
        this.blocks90 = new Material[blocks.size()];
        this.blocks180 = new Material[blocks.size()];
        this.blocks270 = new Material[blocks.size()];
        for (int i = 0; i < this.yPositions.length; ++i) {
            this.yPositions[i] = propYPositions.get(i);
            this.blocks0[i] = blocks.get(i);
            this.blocks90[i] = new Material(materialCache.getSolidMaterialRotatedY(blocks.get(i).solid(), Rotation.Ninety), blocks.get(i).fluid());
            this.blocks180[i] = new Material(materialCache.getSolidMaterialRotatedY(blocks.get(i).solid(), Rotation.OneEighty), blocks.get(i).fluid());
            this.blocks270[i] = new Material(materialCache.getSolidMaterialRotatedY(blocks.get(i).solid(), Rotation.TwoSeventy), blocks.get(i).fluid());
        }
        this.scanner = scanner;
        this.directionality = directionality;
        SpaceSize writeSpace = new SpaceSize(new Vector3i(0, 0, 0), new Vector3i(1, 0, 1));
        writeSpace = SpaceSize.stack(writeSpace, scanner.readSpaceWith(directionality.getGeneralPattern()));
        final Vector3i writeRange = writeSpace.getRange();
        final Vector3i readRange = directionality.getReadRangeWith(scanner);
        this.contextDependency = new ContextDependency(readRange, writeRange);
        this.readBounds_voxelGrid = this.contextDependency.getReadBounds_voxelGrid();
        this.writeBounds_voxelGrid = this.contextDependency.getWriteBounds_voxelGrid();
    }
    
    @Override
    public ScanResult scan(@Nonnull final Vector3i position, @Nonnull final VoxelSpace<Material> materialSpace, @Nonnull final WorkerIndexer.Id id) {
        final Scanner.Context scannerContext = new Scanner.Context(position, this.directionality.getGeneralPattern(), materialSpace, id);
        final List<Vector3i> validPositions = this.scanner.scan(scannerContext);
        final Vector3i patternPosition = new Vector3i();
        final Pattern.Context patternContext = new Pattern.Context(patternPosition, materialSpace, id);
        final RotatedPositionsScanResult scanResult = new RotatedPositionsScanResult(new ArrayList<RotatedPosition>());
        for (final Vector3i validPosition : validPositions) {
            patternPosition.assign(validPosition);
            final PrefabRotation rotation = this.directionality.getRotationAt(patternContext);
            if (rotation == null) {
                continue;
            }
            scanResult.positions.add(new RotatedPosition(validPosition.x, validPosition.y, validPosition.z, rotation));
        }
        return scanResult;
    }
    
    @Override
    public void place(@Nonnull final Context context) {
        final List<RotatedPosition> positions = RotatedPositionsScanResult.cast(context.scanResult).positions;
        for (final RotatedPosition position : positions) {
            this.place(position, context.materialSpace);
        }
    }
    
    private void place(@Nonnull final RotatedPosition position, @Nonnull final VoxelSpace<Material> materialSpace) {
        final PrefabRotation rotation = position.rotation;
        final Material[] blocks = switch (rotation) {
            default -> throw new MatchException(null, null);
            case ROTATION_0 -> this.blocks0;
            case ROTATION_90 -> this.blocks90;
            case ROTATION_180 -> this.blocks180;
            case ROTATION_270 -> this.blocks270;
        };
        for (int i = 0; i < this.yPositions.length; ++i) {
            final int y = this.yPositions[i] + position.y;
            final Material propBlock = blocks[i];
            if (materialSpace.isInsideSpace(position.x, y, position.z)) {
                if (this.blockMask.canPlace(propBlock)) {
                    final Material worldMaterial = materialSpace.getContent(position.x, y, position.z);
                    assert worldMaterial != null;
                    final int worldMaterialHash = worldMaterial.hashMaterialIds();
                    if (this.blockMask.canReplace(propBlock.hashMaterialIds(), worldMaterialHash)) {
                        materialSpace.set(propBlock, position.x, 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;
    }
}
