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

package com.hypixel.hytale.builtin.buildertools.scriptedbrushes;

import java.util.function.Function;
import java.util.function.BiConsumer;
import com.hypixel.hytale.math.util.MathUtil;
import com.hypixel.hytale.builtin.buildertools.utils.FluidPatternHelper;
import com.hypixel.hytale.builtin.buildertools.utils.Material;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.prefab.selection.mask.BlockMask;
import com.hypixel.hytale.server.core.prefab.selection.mask.BlockPattern;
import com.hypixel.hytale.protocol.packets.buildertools.BrushShape;
import com.hypixel.hytale.math.vector.Vector3i;
import javax.annotation.Nullable;
import com.hypixel.hytale.protocol.InteractionType;
import java.util.Random;

public class BrushConfig
{
    private static final Random random;
    @Nullable
    private InteractionType interactionType;
    private boolean isHoldDownInteraction;
    private Vector3i origin;
    private boolean isCurrentlyExecuting;
    private boolean hasExecutionContextEncounteredError;
    @Nullable
    private String executionErrorMessage;
    private Vector3i originOffset;
    @Nullable
    private Vector3i originAfterOffset;
    private BrushShape shape;
    private int shapeWidth;
    private int shapeHeight;
    private int shapeThickness;
    private boolean capped;
    private BlockPattern pattern;
    private int density;
    private boolean enableBrushMask;
    private BlockMask brushMask;
    private boolean enableOperationMask;
    private BlockMask operationMask;
    private BlockMask combinedMasks;
    private HistoryMask historyMask;
    
    public BrushConfig() {
        this.originOffset = new Vector3i(0, 0, 0);
        this.resetToDefaultValues();
    }
    
    public BrushConfig(@Nonnull final BrushConfig other) {
        this.originOffset = new Vector3i(0, 0, 0);
        this.interactionType = other.interactionType;
        this.origin = other.origin;
        this.isCurrentlyExecuting = other.isCurrentlyExecuting;
        this.hasExecutionContextEncounteredError = other.hasExecutionContextEncounteredError;
        this.executionErrorMessage = other.executionErrorMessage;
        this.originOffset = other.originOffset.clone();
        this.originAfterOffset = other.originAfterOffset.clone();
        this.shape = other.shape;
        this.shapeWidth = other.shapeWidth;
        this.shapeHeight = other.shapeHeight;
        this.shapeThickness = other.shapeThickness;
        this.capped = other.capped;
        this.pattern = other.pattern;
        this.density = other.density;
        this.enableBrushMask = other.enableBrushMask;
        this.brushMask = other.brushMask;
        this.enableOperationMask = other.enableOperationMask;
        this.operationMask = other.operationMask;
        this.combinedMasks = other.combinedMasks;
        this.historyMask = other.historyMask;
        this.isHoldDownInteraction = other.isHoldDownInteraction;
    }
    
    public void beginExecution(final Vector3i origin, final boolean isHoldDownInteraction, final InteractionType interactionType) {
        this.isCurrentlyExecuting = true;
        this.origin = origin;
        this.isHoldDownInteraction = isHoldDownInteraction;
        this.interactionType = interactionType;
        this.updateOriginWithOffsets();
    }
    
    public void endExecution() {
        this.resetToDefaultValues();
    }
    
    public void resetToDefaultValues() {
        this.interactionType = null;
        this.origin = new Vector3i(0, 0, 0);
        this.isCurrentlyExecuting = false;
        this.hasExecutionContextEncounteredError = false;
        this.executionErrorMessage = null;
        this.originOffset = new Vector3i(0, 0, 0);
        this.originAfterOffset = null;
        this.shape = BrushShape.Cube;
        this.shapeWidth = 5;
        this.shapeHeight = 5;
        this.shapeThickness = 0;
        this.capped = false;
        this.pattern = BlockPattern.parse("Rock_Stone");
        this.density = 100;
        this.enableBrushMask = true;
        this.brushMask = BlockMask.EMPTY;
        this.enableOperationMask = true;
        this.operationMask = BlockMask.EMPTY;
        this.combinedMasks = BlockMask.EMPTY;
        this.historyMask = HistoryMask.None;
    }
    
    public boolean isHoldDownInteraction() {
        return this.isHoldDownInteraction;
    }
    
    public boolean isCurrentlyExecuting() {
        return this.isCurrentlyExecuting;
    }
    
    @Nullable
    public InteractionType getInteractionType() {
        return this.interactionType;
    }
    
    @Nullable
    public Vector3i getOrigin() {
        return this.originAfterOffset;
    }
    
    @Nonnull
    public Vector3i getOriginOffset() {
        return this.originOffset.clone();
    }
    
    public void setOriginOffset(final Vector3i originOffset) {
        this.originOffset = originOffset;
        this.updateOriginWithOffsets();
    }
    
    public void modifyOriginOffset(@Nonnull final Vector3i originOffsetOffset) {
        this.originOffset = this.originOffset.add(originOffsetOffset);
        this.updateOriginWithOffsets();
    }
    
    public void updateOriginWithOffsets() {
        if (this.origin != null) {
            this.originAfterOffset = this.origin.clone().add(this.originOffset);
        }
    }
    
    @Nonnull
    public Random getRandom() {
        return BrushConfig.random;
    }
    
    public int getNextBlock() {
        return this.pattern.nextBlock(BrushConfig.random);
    }
    
    @Nonnull
    public Material getNextMaterial() {
        final BlockPattern.BlockEntry blockEntry = this.pattern.nextBlockTypeKey(BrushConfig.random);
        if (blockEntry != null) {
            final FluidPatternHelper.FluidInfo fluidInfo = FluidPatternHelper.getFluidInfo(blockEntry.blockTypeKey());
            if (fluidInfo != null) {
                return Material.fluid(fluidInfo.fluidId(), fluidInfo.fluidLevel());
            }
        }
        return Material.block(this.pattern.nextBlock(BrushConfig.random));
    }
    
    public BlockMask getBlockMask() {
        return this.combinedMasks;
    }
    
    public void setOperationMask(final BlockMask mask) {
        this.operationMask = mask;
        this.refreshCombinedMasks();
    }
    
    public void appendOperationMask(final BlockMask mask) {
        this.operationMask = BlockMask.combine(mask, this.operationMask);
        this.refreshCombinedMasks();
    }
    
    public void clearOperationMask() {
        this.operationMask = BlockMask.EMPTY;
        this.refreshCombinedMasks();
    }
    
    public void setUseBrushMask(final boolean useBrushMask) {
        this.enableBrushMask = useBrushMask;
        this.refreshCombinedMasks();
    }
    
    public void setUseOperationMask(final boolean useOperationMask) {
        this.enableOperationMask = useOperationMask;
        this.refreshCombinedMasks();
    }
    
    public void setBrushMask(final BlockMask mask) {
        this.brushMask = mask;
        this.refreshCombinedMasks();
    }
    
    private void refreshCombinedMasks() {
        if (this.enableBrushMask && this.enableOperationMask) {
            this.combinedMasks = BlockMask.combine(this.brushMask, this.operationMask);
        }
        else if (this.enableBrushMask) {
            this.combinedMasks = this.brushMask;
        }
        else if (this.enableOperationMask) {
            this.combinedMasks = this.operationMask;
        }
    }
    
    public int getDensity() {
        return this.density;
    }
    
    public void setDensity(final int density) {
        this.density = MathUtil.clamp(density, 1, 100);
    }
    
    public HistoryMask getHistoryMask() {
        return this.historyMask;
    }
    
    public void setHistoryMask(final HistoryMask historyMask) {
        this.historyMask = historyMask;
    }
    
    public int getShapeWidth() {
        return this.shapeWidth;
    }
    
    public void setShapeWidth(final int shapeWidth) {
        if (shapeWidth <= 0) {
            this.setErrorFlag("You cannot set shape width to be less than or equal to zero. Width: " + shapeWidth);
            return;
        }
        this.shapeWidth = shapeWidth;
    }
    
    public int getShapeHeight() {
        return this.shapeHeight;
    }
    
    public void setShapeHeight(final int shapeHeight) {
        if (shapeHeight <= 0) {
            this.setErrorFlag("You cannot set shape height to be less than or equal to zero. Height: " + shapeHeight);
            return;
        }
        this.shapeHeight = shapeHeight;
    }
    
    public int getShapeThickness() {
        return this.shapeThickness;
    }
    
    public void setShapeThickness(final int shapeThickness) {
        this.shapeThickness = shapeThickness;
    }
    
    public boolean isCapped() {
        return this.capped;
    }
    
    public void setCapped(final boolean capped) {
        this.capped = capped;
    }
    
    public BrushShape getShape() {
        return this.shape;
    }
    
    public void setShape(final BrushShape shape) {
        this.shape = shape;
    }
    
    public BlockPattern getPattern() {
        return this.pattern;
    }
    
    public void setPattern(final BlockPattern pattern) {
        this.pattern = pattern;
    }
    
    public void setErrorFlag(final String errorMessage) {
        this.hasExecutionContextEncounteredError = true;
        this.executionErrorMessage = errorMessage;
    }
    
    public void clearError() {
        this.hasExecutionContextEncounteredError = false;
        this.executionErrorMessage = null;
    }
    
    public boolean isHasExecutionContextEncounteredError() {
        return this.hasExecutionContextEncounteredError;
    }
    
    @Nullable
    public String getExecutionErrorMessage() {
        return this.executionErrorMessage;
    }
    
    @Nullable
    public Vector3i getOriginAfterOffset() {
        return this.originAfterOffset;
    }
    
    @Nonnull
    @Override
    public String toString() {
        return "BrushConfig{, interactionType=" + String.valueOf(this.interactionType) + ", origin=" + String.valueOf(this.origin) + ", originOffset=" + String.valueOf(this.originOffset) + ", originAfterOffset=" + String.valueOf(this.originAfterOffset) + ", shapeWidth=" + this.shapeWidth + ", shapeHeight=" + this.shapeHeight + ", shapeThickness=" + this.shapeThickness + ", capped=" + this.capped + ", density=" + this.density + ", shape=" + String.valueOf(this.shape) + ", pattern=" + String.valueOf(this.pattern) + ", historyMask=" + String.valueOf(this.historyMask) + ", brushMask=" + String.valueOf(this.brushMask) + ", operationMask=" + String.valueOf(this.operationMask) + ", combinedMasks=" + String.valueOf(this.combinedMasks) + ", enableOperationMask=" + this.enableOperationMask + ", enableBrushMask=" + this.enableBrushMask + ", random=" + String.valueOf(BrushConfig.random) + ", isCurrentlyExecuting=" + this.isCurrentlyExecuting;
    }
    
    @Nonnull
    public String getInfo() {
        final StringBuilder builder = new StringBuilder("Brush Config Information:");
        builder.append("\nOrigin with Offset: {");
        if (this.originAfterOffset == null) {
            builder.append("Not currently executing, so no origin");
        }
        else {
            builder.append(this.originAfterOffset.x).append(", ").append(this.originAfterOffset.y).append(", ").append(this.originAfterOffset.z);
        }
        builder.append("}");
        builder.append("\nOffset: {").append(this.originOffset.x).append(", ").append(this.originOffset.y).append(", ").append(this.originOffset.z).append("}");
        builder.append("\nDimensions: {Width: ").append(this.shapeWidth).append(", Height: ").append(this.shapeHeight).append("}");
        builder.append("\nShape Properties: {Shape: ").append(this.shape.name()).append(", Thickness: ").append(this.shapeThickness).append(", Capped: ").append(this.capped).append("}");
        builder.append("\nPattern: ").append(this.pattern.toString());
        builder.append("\nMasks: {HistoryMask: ").append(this.historyMask.name()).append(", EnableOperationMask: ").append(this.enableOperationMask).append(", EnableBrushMask: ").append(this.enableBrushMask).append(", CombinedMasks: ").append(this.combinedMasks.informativeToString()).append("}");
        builder.append("\nIs Currently Executing: ").append(this.isCurrentlyExecuting);
        return builder.toString();
    }
    
    static {
        random = new Random();
    }
    
    public enum HistoryMask
    {
        None, 
        Only, 
        Not;
    }
    
    public enum BCExecutionStatus
    {
        Continue, 
        Error, 
        Complete;
    }
    
    public enum DataSettingFlags
    {
        Offset((copyTo, copyFrom) -> copyTo.setOriginOffset(copyFrom.getOriginOffset())), 
        Shape((copyTo, copyFrom) -> copyTo.setShape(copyFrom.getShape())), 
        Dimensions((copyTo, copyFrom) -> {
            copyTo.setShapeWidth(copyFrom.getShapeWidth());
            copyTo.setShapeHeight(copyFrom.getShapeHeight());
            return;
        }), 
        Thickness((copyTo, copyFrom) -> copyTo.setShapeThickness(copyFrom.getShapeThickness())), 
        Capped((copyTo, copyFrom) -> copyTo.setCapped(copyFrom.isCapped())), 
        Pattern((copyTo, copyFrom) -> copyTo.setPattern(copyFrom.getPattern())), 
        Density((copyTo, copyFrom) -> copyTo.setDensity(copyFrom.getDensity())), 
        BrushMask((copyTo, copyFrom) -> {
            copyTo.setBrushMask(copyFrom.brushMask);
            copyTo.setUseBrushMask(copyFrom.enableBrushMask);
            return;
        }), 
        OperationMask((copyTo, copyFrom) -> {
            copyTo.setOperationMask(copyFrom.operationMask);
            copyTo.setUseOperationMask(copyFrom.enableOperationMask);
            return;
        }), 
        HistoryMask((copyTo, copyFrom) -> copyTo.setHistoryMask(copyFrom.getHistoryMask()));
        
        private final BiConsumer<BrushConfig, BrushConfig> stateLoader;
        
        private DataSettingFlags(final BiConsumer<BrushConfig, BrushConfig> stateLoader) {
            this.stateLoader = stateLoader;
        }
        
        public void loadData(final BrushConfig copyTo, final BrushConfig copyFrom) {
            this.stateLoader.accept(copyTo, copyFrom);
        }
    }
    
    public enum DataGettingFlags
    {
        OffsetX(brushConfig -> brushConfig.getOriginOffset().x), 
        OffsetY(brushConfig -> brushConfig.getOriginOffset().y), 
        OffsetZ(brushConfig -> brushConfig.getOriginOffset().z), 
        Height(brushConfig -> brushConfig.getShapeHeight()), 
        Width(brushConfig -> brushConfig.getShapeWidth()), 
        Density(brushConfig -> brushConfig.getDensity());
        
        private final Function<BrushConfig, Integer> valueGetter;
        
        private DataGettingFlags(final Function<BrushConfig, Integer> valueGetter) {
            this.valueGetter = valueGetter;
        }
        
        public int getValue(final BrushConfig brushConfig) {
            return this.valueGetter.apply(brushConfig);
        }
    }
}
