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

package com.hypixel.hytale.builtin.hytalegenerator.newsystem.bufferbundle.buffers;

import java.util.Arrays;
import com.hypixel.hytale.builtin.hytalegenerator.newsystem.performanceinstruments.MemInstrument;
import com.hypixel.hytale.builtin.hytalegenerator.ArrayUtil;
import com.hypixel.hytale.math.vector.Vector3i;
import javax.annotation.Nullable;
import javax.annotation.Nonnull;
import com.hypixel.hytale.builtin.hytalegenerator.bounds.Bounds3i;

public class NSimplePixelBuffer<T> extends NPixelBuffer<T>
{
    private static final Bounds3i bounds;
    @Nonnull
    private final Class<T> pixelType;
    @Nonnull
    private State state;
    @Nullable
    private ArrayContents<T> arrayContents;
    @Nullable
    private T singleValue;
    
    public NSimplePixelBuffer(@Nonnull final Class<T> pixelType) {
        this.pixelType = pixelType;
        this.state = State.EMPTY;
        this.arrayContents = null;
        this.singleValue = null;
    }
    
    @Nullable
    @Override
    public T getPixelContent(@Nonnull final Vector3i position) {
        assert NSimplePixelBuffer.bounds.contains(position);
        return switch (this.state.ordinal()) {
            case 1 -> this.singleValue;
            case 2 -> this.arrayContents.array[index(position)];
            default -> null;
        };
    }
    
    @Override
    public void setPixelContent(@Nonnull final Vector3i position, @Nullable final T value) {
        assert NSimplePixelBuffer.bounds.contains(position);
        switch (this.state.ordinal()) {
            case 1: {
                if (this.singleValue == value) {
                    return;
                }
                this.switchFromSingleValueToArray();
                this.setPixelContent(position, value);
                break;
            }
            case 2: {
                this.arrayContents.array[index(position)] = value;
                break;
            }
            default: {
                this.state = State.SINGLE_VALUE;
                this.singleValue = value;
                break;
            }
        }
    }
    
    @Nonnull
    @Override
    public Class<T> getPixelType() {
        return this.pixelType;
    }
    
    public void copyFrom(@Nonnull final NSimplePixelBuffer<T> sourceBuffer) {
        this.state = sourceBuffer.state;
        switch (this.state.ordinal()) {
            case 1: {
                this.singleValue = sourceBuffer.singleValue;
                break;
            }
            case 2: {
                this.arrayContents = new ArrayContents<T>();
                ArrayUtil.copy(sourceBuffer.arrayContents.array, this.arrayContents.array);
                break;
            }
            default: {}
        }
    }
    
    @Nonnull
    @Override
    public MemInstrument.Report getMemoryUsage() {
        long size_bytes = 128L;
        if (this.arrayContents != null) {
            size_bytes += this.arrayContents.getMemoryUsage().size_bytes();
        }
        return new MemInstrument.Report(size_bytes);
    }
    
    private void ensureContents() {
        if (this.arrayContents != null) {
            return;
        }
        this.arrayContents = new ArrayContents<T>();
    }
    
    private void switchFromSingleValueToArray() {
        assert this.state == State.SINGLE_VALUE;
        this.state = State.ARRAY;
        this.arrayContents = new ArrayContents<T>();
        Arrays.fill(this.arrayContents.array, this.singleValue);
        this.singleValue = null;
    }
    
    private static int index(@Nonnull final Vector3i position) {
        return position.y + position.x * NSimplePixelBuffer.SIZE.y + position.z * NSimplePixelBuffer.SIZE.y * NSimplePixelBuffer.SIZE.x;
    }
    
    static {
        bounds = new Bounds3i(Vector3i.ZERO, NSimplePixelBuffer.SIZE);
    }
    
    public static class ArrayContents<T> implements MemInstrument
    {
        private final T[] array;
        
        public ArrayContents() {
            this.array = (T[])new Object[NPixelBuffer.SIZE.x * NPixelBuffer.SIZE.y * NPixelBuffer.SIZE.z];
        }
        
        @Nonnull
        @Override
        public Report getMemoryUsage() {
            final long size_bytes = 16L + 8L * this.array.length;
            return new Report(size_bytes);
        }
    }
    
    private enum State
    {
        EMPTY, 
        SINGLE_VALUE, 
        ARRAY;
    }
}
