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

package com.hypixel.hytale.server.core.meta;

import java.util.Arrays;
import javax.annotation.Nullable;
import javax.annotation.Nonnull;
import com.hypixel.hytale.common.util.ArrayUtil;

public class ArrayMetaStore<K> extends AbstractMetaStore<K>
{
    private static final Object NO_ENTRY;
    private Object[] array;
    
    public ArrayMetaStore(final K parent, final IMetaRegistry<K> registry) {
        this(parent, (IMetaRegistry<Object>)registry, false);
    }
    
    public ArrayMetaStore(final K parent, final IMetaRegistry<K> registry, final boolean bypassEncodedCache) {
        super(parent, registry, bypassEncodedCache);
        this.array = ArrayUtil.emptyArray();
    }
    
    @Override
    protected <T> T get0(@Nonnull final MetaKey<T> key) {
        return (T)this.array[key.getId()];
    }
    
    @Override
    public <T> T getMetaObject(@Nonnull final MetaKey<T> key) {
        final int id = key.getId();
        if (id >= this.array.length) {
            final T obj = this.decodeOrNewMetaObject(key);
            this.resizeArray(obj, id);
            return obj;
        }
        T obj = (T)this.get0((MetaKey<Object>)key);
        if (obj == ArrayMetaStore.NO_ENTRY) {
            obj = (T)(this.array[id] = this.decodeOrNewMetaObject(key));
        }
        return obj;
    }
    
    @Nullable
    @Override
    public <T> T getIfPresentMetaObject(@Nonnull final MetaKey<T> key) {
        if (key.getId() >= this.array.length) {
            return null;
        }
        final T oldObj = (T)this.get0((MetaKey<Object>)key);
        return (oldObj != ArrayMetaStore.NO_ENTRY) ? oldObj : null;
    }
    
    @Nullable
    @Override
    public <T> T putMetaObject(@Nonnull final MetaKey<T> key, final T obj) {
        this.markMetaStoreDirty();
        final int id = key.getId();
        if (id >= this.array.length) {
            this.resizeArray(obj, id);
            return null;
        }
        final T oldObj = (T)this.array[id];
        this.array[id] = obj;
        return (oldObj != ArrayMetaStore.NO_ENTRY) ? oldObj : null;
    }
    
    @Nullable
    @Override
    public <T> T removeMetaObject(@Nonnull final MetaKey<T> key) {
        if (key.getId() >= this.array.length) {
            return null;
        }
        this.markMetaStoreDirty();
        final T oldObj = (T)this.array[key.getId()];
        this.array[key.getId()] = ArrayMetaStore.NO_ENTRY;
        return (oldObj != ArrayMetaStore.NO_ENTRY) ? oldObj : null;
    }
    
    @Nullable
    @Override
    public <T> T removeSerializedMetaObject(@Nonnull final MetaKey<T> key) {
        if (key.getId() >= this.array.length && key instanceof PersistentMetaKey) {
            this.tryDecodeUnknownKey((PersistentMetaKey<Object>)(PersistentMetaKey)key);
        }
        return (T)this.removeMetaObject((MetaKey<Object>)key);
    }
    
    @Override
    public boolean hasMetaObject(@Nonnull final MetaKey<?> key) {
        final int id = key.getId();
        return id < this.array.length && this.array[id] != ArrayMetaStore.NO_ENTRY;
    }
    
    @Override
    public void forEachMetaObject(@Nonnull final IMetaStore.MetaEntryConsumer consumer) {
        for (int i = 0; i < this.array.length; ++i) {
            final Object o = this.array[i];
            if (o != ArrayMetaStore.NO_ENTRY) {
                consumer.accept(i, o);
            }
        }
    }
    
    private <T> void resizeArray(final T obj, final int id) {
        final Object[] arr = new Object[id + 1];
        Arrays.fill(arr, this.array.length, arr.length, ArrayMetaStore.NO_ENTRY);
        System.arraycopy(this.array, 0, arr, 0, this.array.length);
        arr[id] = obj;
        this.array = arr;
    }
    
    static {
        NO_ENTRY = new Object();
    }
}
