package com.zivilon.cindercore.util;

import java.lang.reflect.Method;
import java.lang.reflect.Field;

import java.util.Vector;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import net.minecraft.world.chunk.NibbleArray;
import net.minecraft.world.chunk.Chunk;

import java.util.Arrays;

import com.zivilon.cindercore.mixins.MixinExtendedBlockStorage;
import com.zivilon.cindercore.mixins.MixinNibbleArray;

public class ChunkDeepCopy {
    public static Chunk deepCopyChunk(Chunk original) {
        Chunk copy = new Chunk(original.worldObj, original.xPosition, original.zPosition);
        copy.isLit = original.isLit;
        copy.setBiomeArray(original.getBiomeArray());
        copy.precipitationHeightMap = original.precipitationHeightMap;
        copy.updateSkylightColumns = original.updateSkylightColumns;
        copy.isChunkLoaded = original.isChunkLoaded;
        copy.heightMap = original.heightMap;
        copy.chunkTileEntityMap = original.chunkTileEntityMap;
        copy.entityLists = original.entityLists;
        copy.isTerrainPopulated = original.isTerrainPopulated;
        copy.isLightPopulated = original.isLightPopulated;
        copy.field_150815_m = original.field_150815_m;
        copy.isModified = original.isModified;
        copy.hasEntities = original.hasEntities;
        copy.lastSaveTime = original.lastSaveTime;
        copy.sendUpdates = original.sendUpdates;
        copy.heightMapMinimum = original.heightMapMinimum;
        copy.inhabitedTime = original.inhabitedTime;

        // Deep copy ExtendedBlockStorages
        ExtendedBlockStorage[] original_arrays = original.getBlockStorageArray();
        ExtendedBlockStorage[] copy_arrays = copy.getBlockStorageArray();

        for (int i = 0; i < original_arrays.length; i++) {
            if (original_arrays[i] != null) {
                copy_arrays[i] = deepCopyExtendedBlockStorage(original_arrays[i]);
            }
        }

        return copy;
    }

    public static ExtendedBlockStorage deepCopyExtendedBlockStorage(ExtendedBlockStorage original) {
        ExtendedBlockStorage copy = new ExtendedBlockStorage(original.getYLocation(), false);

        // Copies of primitives
        ((MixinExtendedBlockStorage)copy).setBlockRefCount(((MixinExtendedBlockStorage)original).getBlockRefCount());
        ((MixinExtendedBlockStorage)copy).setTickRefCount(((MixinExtendedBlockStorage)original).getTickRefCount());
        copy.setBlockLSBArray(Arrays.copyOf(original.getBlockLSBArray(), original.getBlockLSBArray().length));

        // NibbleArrays. Needs deep copy for each!
        if (original.getBlockMSBArray() != null) {
            copy.setBlockMSBArray(deepCopyNibbleArray(original.getBlockMSBArray()));
        }
        if (original.getBlocklightArray() != null) {
            copy.setBlocklightArray(deepCopyNibbleArray(original.getBlocklightArray()));
        }
        if (original.getSkylightArray() != null) {
            copy.setSkylightArray(deepCopyNibbleArray(original.getSkylightArray()));
        }
        if (original.getMetadataArray() != null) {
            copy.setBlockMetadataArray(deepCopyNibbleArray(original.getMetadataArray()));
        }
        return copy;
    }

    public static NibbleArray deepCopyNibbleArray(NibbleArray original) {
        int depthBits = ((MixinNibbleArray)original).getDepthBits();
        byte[] data;

        if (original.data == null) {
            data = new byte[(1 << depthBits) * 2];
            return new NibbleArray(data, depthBits);
        } else {
            data = Arrays.copyOf(original.data, original.data.length);
        }
        return new NibbleArray(data, depthBits);            
    }
}
