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

package com.hypixel.hytale.server.core.universe.world.chunk;

import javax.annotation.Nonnull;
import com.hypixel.hytale.component.ComponentType;
import javax.annotation.Nullable;
import java.util.Arrays;
import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.component.Component;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
import com.hypixel.hytale.component.ComponentAccessor;

public abstract class AbstractCachedAccessor
{
    protected ComponentAccessor<ChunkStore> commandBuffer;
    private int minX;
    private int minY;
    private int minZ;
    private int length;
    private Ref<ChunkStore>[] chunks;
    private Ref<ChunkStore>[] sections;
    private Component<ChunkStore>[][] sectionComponents;
    
    protected AbstractCachedAccessor(final int numComponents) {
        this.sectionComponents = new Component[numComponents][];
    }
    
    protected void init(final ComponentAccessor<ChunkStore> commandBuffer, final int cx, final int cy, final int cz, int radius) {
        this.commandBuffer = commandBuffer;
        radius = ChunkUtil.chunkCoordinate(radius) + 1;
        this.minX = cx - radius;
        this.minY = cy - radius;
        this.minZ = cz - radius;
        this.length = radius * 2 + 1;
        final int size2d = this.length * this.length;
        final int size3d = this.length * this.length * this.length;
        if (this.chunks == null || this.chunks.length < size2d) {
            this.chunks = new Ref[size2d];
        }
        else {
            Arrays.fill(this.chunks, null);
        }
        for (int i = 0; i < this.sectionComponents.length; ++i) {
            final Component<ChunkStore>[] sectionComps = this.sectionComponents[i];
            if (sectionComps == null || sectionComps.length < size3d) {
                this.sectionComponents[i] = new Component[size3d];
            }
            else {
                Arrays.fill(sectionComps, null);
            }
        }
        if (this.sections == null || this.sections.length < size3d) {
            this.sections = new Ref[size3d];
        }
        else {
            Arrays.fill(this.sections, null);
        }
    }
    
    protected void insertSection(final Ref<ChunkStore> section, final int cx, final int cy, final int cz) {
        final int x = cx - this.minX;
        final int y = cy - this.minY;
        final int z = cz - this.minZ;
        final int index3d = x + z * this.length + y * this.length * this.length;
        if (index3d >= 0 && index3d < this.sections.length) {
            this.sections[index3d] = section;
        }
    }
    
    protected void insertSectionComponent(final int index, final Component<ChunkStore> component, final int cx, final int cy, final int cz) {
        final int x = cx - this.minX;
        final int y = cy - this.minY;
        final int z = cz - this.minZ;
        final int index3d = x + z * this.length + y * this.length * this.length;
        if (index3d >= 0 && index3d < this.sectionComponents[index].length) {
            this.sectionComponents[index][index3d] = component;
        }
    }
    
    @Nullable
    public Ref<ChunkStore> getChunk(final int cx, final int cz) {
        final int x = cx - this.minX;
        final int z = cz - this.minZ;
        final int index = x + z * this.length;
        if (index >= 0 && index < this.chunks.length) {
            Ref<ChunkStore> chunk = this.chunks[index];
            if (chunk == null) {
                chunk = (this.chunks[index] = this.commandBuffer.getExternalData().getChunkReference(ChunkUtil.indexChunk(cx, cz)));
            }
            return chunk;
        }
        return this.commandBuffer.getExternalData().getChunkReference(ChunkUtil.indexChunk(cx, cz));
    }
    
    @Nullable
    public Ref<ChunkStore> getSection(final int cx, final int cy, final int cz) {
        if (cy < 0 || cy >= 10) {
            return null;
        }
        final int x = cx - this.minX;
        final int y = cy - this.minY;
        final int z = cz - this.minZ;
        final int index = x + z * this.length + y * this.length * this.length;
        if (index >= 0 && index < this.sections.length) {
            Ref<ChunkStore> section = this.sections[index];
            if (section == null) {
                section = (this.sections[index] = this.commandBuffer.getExternalData().getChunkSectionReference(this.commandBuffer, cx, cy, cz));
            }
            return section;
        }
        return this.commandBuffer.getExternalData().getChunkSectionReference(this.commandBuffer, cx, cy, cz);
    }
    
    @Nullable
    protected <T extends Component<ChunkStore>> T getComponentSection(final int cx, final int cy, final int cz, final int typeIndex, @Nonnull final ComponentType<ChunkStore, T> componentType) {
        final int x = cx - this.minX;
        final int y = cy - this.minY;
        final int z = cz - this.minZ;
        final int index = x + z * this.length + y * this.length * this.length;
        if (index >= 0 && index < this.sections.length) {
            T comp = (T)this.sectionComponents[typeIndex][index];
            if (comp == null) {
                final Ref<ChunkStore> section = this.getSection(cx, cy, cz);
                if (section == null) {
                    return null;
                }
                comp = (T)(this.sectionComponents[typeIndex][index] = this.commandBuffer.getComponent(section, componentType));
            }
            return comp;
        }
        final Ref<ChunkStore> section2 = this.getSection(cx, cy, cz);
        if (section2 == null) {
            return null;
        }
        return this.commandBuffer.getComponent(section2, componentType);
    }
}
