package com.zivilon.cindercore.mixins;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Dynamic;
import org.spongepowered.asm.mixin.Shadow;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.NibbleArray;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import net.minecraft.world.World;
import net.minecraft.block.Block;
import java.util.ArrayList;
import java.util.Iterator;
import org.apache.logging.log4j.Logger;
import java.util.List;
import java.util.Map;

import com.zivilon.cindercore.interfaces.ICustomChunk;
import com.zivilon.cindercore.util.MethodChecker;

@Mixin(Chunk.class)
public abstract class MixinChunk implements ICustomChunk {

    @Shadow public static boolean isLit;
    @Shadow private ExtendedBlockStorage[] storageArrays;
    @Shadow private byte[] blockBiomeArray;
    @Shadow public int[] precipitationHeightMap;
    @Shadow public boolean[] updateSkylightColumns;
    @Shadow public boolean isChunkLoaded;
    @Shadow public World worldObj;
    @Shadow public int[] heightMap;
    @Shadow private boolean isGapLightingUpdated;
    @Shadow public Map chunkTileEntityMap;
    @Shadow public List[] entityLists;
    @Shadow public boolean isTerrainPopulated;
    @Shadow public boolean isLightPopulated;
    @Shadow public boolean field_150815_m;
    @Shadow public boolean isModified;
    @Shadow public boolean hasEntities;
    @Shadow public long lastSaveTime;
    @Shadow public boolean sendUpdates;
    @Shadow public int heightMapMinimum;
    @Shadow public long inhabitedTime;
    @Shadow private int queuedLightChecks;

    @Shadow
    public abstract Block getBlock(final int p_150810_1_, final int p_150810_2_, final int p_150810_3_);

    @Shadow
    public abstract int getBlockMetadata(int p_76628_1_, int p_76628_2_, int p_76628_3_);

    @Shadow
    public abstract int getTopFilledSegment();

    @Shadow
    public abstract int func_150808_b(int p_150808_1_, int p_150808_2_, int p_150808_3_);

    @Dynamic
    public void fillChunk(byte[] p_76607_1_, int p_76607_2_, int p_76607_3_, boolean p_76607_4_) {
        Iterator iterator = chunkTileEntityMap.values().iterator();
        while(iterator.hasNext())
        {
            TileEntity tileEntity = (TileEntity)iterator.next();
            tileEntity.updateContainingBlockInfo();
            tileEntity.getBlockMetadata();
            tileEntity.getBlockType();
        }

        int k = 0;
        boolean flag1 = !this.worldObj.provider.hasNoSky;
        int l;

        for (l = 0; l < this.storageArrays.length; ++l)
        {
            if ((p_76607_2_ & 1 << l) != 0)
            {
                if (this.storageArrays[l] == null)
                {
                    this.storageArrays[l] = new ExtendedBlockStorage(l << 4, flag1);
                }

                byte[] abyte1 = this.storageArrays[l].getBlockLSBArray();
                System.arraycopy(p_76607_1_, k, abyte1, 0, abyte1.length);
                k += abyte1.length;
            }
            else if (p_76607_4_ && this.storageArrays[l] != null)
            {
                this.storageArrays[l] = null;
            }
        }

        NibbleArray nibblearray;

        for (l = 0; l < this.storageArrays.length; ++l)
        {
            if ((p_76607_2_ & 1 << l) != 0 && this.storageArrays[l] != null)
            {
                nibblearray = this.storageArrays[l].getMetadataArray();
                System.arraycopy(p_76607_1_, k, nibblearray.data, 0, nibblearray.data.length);
                k += nibblearray.data.length;
            }
        }

        for (l = 0; l < this.storageArrays.length; ++l)
        {
            if ((p_76607_2_ & 1 << l) != 0 && this.storageArrays[l] != null)
            {
                nibblearray = this.storageArrays[l].getBlocklightArray();
                System.arraycopy(p_76607_1_, k, nibblearray.data, 0, nibblearray.data.length);
                k += nibblearray.data.length;
            }
        }

        if (flag1)
        {
            for (l = 0; l < this.storageArrays.length; ++l)
            {
                if ((p_76607_2_ & 1 << l) != 0 && this.storageArrays[l] != null)
                {
                    nibblearray = this.storageArrays[l].getSkylightArray();
                    System.arraycopy(p_76607_1_, k, nibblearray.data, 0, nibblearray.data.length);
                    k += nibblearray.data.length;
                }
            }
        }

        for (l = 0; l < this.storageArrays.length; ++l)
        {
            if ((p_76607_3_ & 1 << l) != 0)
            {
                if (this.storageArrays[l] == null)
                {
                    k += 2048;
                }
                else
                {
                    nibblearray = this.storageArrays[l].getBlockMSBArray();

                    if (nibblearray == null)
                    {
                        nibblearray = this.storageArrays[l].createBlockMSBArray();
                    }

                    System.arraycopy(p_76607_1_, k, nibblearray.data, 0, nibblearray.data.length);
                    k += nibblearray.data.length;
                }
            }
            else if (p_76607_4_ && this.storageArrays[l] != null && this.storageArrays[l].getBlockMSBArray() != null)
            {
                this.storageArrays[l].clearMSBArray();
            }
        }

        if (p_76607_4_)
        {
            System.arraycopy(p_76607_1_, k, this.blockBiomeArray, 0, this.blockBiomeArray.length);
            int i1 = k + this.blockBiomeArray.length;
        }

        for (l = 0; l < this.storageArrays.length; ++l)
        {
            if (this.storageArrays[l] != null && (p_76607_2_ & 1 << l) != 0)
            {
                this.storageArrays[l].removeInvalidBlocks();
            }
        }

        this.isLightPopulated = true;
        this.isTerrainPopulated = true;
        this.generateHeightMap();
        List<TileEntity> invalidList = new ArrayList<TileEntity>();
        iterator = this.chunkTileEntityMap.values().iterator();

        while (iterator.hasNext())
        {
            TileEntity tileentity = (TileEntity)iterator.next();
            int x = tileentity.xCoord & 15;
            int y = tileentity.yCoord;
            int z = tileentity.zCoord & 15;
            Block block = tileentity.getBlockType();
            if ((block != getBlock(x, y, z) || tileentity.blockMetadata != this.getBlockMetadata(x, y, z)) && tileentity.shouldRefresh(block, getBlock(x, y, z), tileentity.blockMetadata, this.getBlockMetadata(x, y, z), worldObj, x, y, z))
            {
                invalidList.add(tileentity);
            }
            tileentity.updateContainingBlockInfo();
        }

        for (TileEntity te : invalidList)
        {
            te.invalidate();
        }
    }

    @Dynamic
    public void generateHeightMap()
    {
        int i = this.getTopFilledSegment();
        this.heightMapMinimum = Integer.MAX_VALUE;

        for (int j = 0; j < 16; ++j)
        {
            int k = 0;

            while (k < 16)
            {
                this.precipitationHeightMap[j + (k << 4)] = -999;
                int l = i + 16 - 1;

                while (true)
                {
                    if (l > 0)
                    {
                        Block block = this.getBlock(j, l - 1, k);

                        if (func_150808_b(j, l - 1, k) == 0)
                        {
                            --l;
                            continue;
                        }

                        this.heightMap[k << 4 | j] = l;

                        if (l < this.heightMapMinimum)
                        {
                            this.heightMapMinimum = l;
                        }
                    }

                    ++k;
                    break;
                }
            }
        }

        this.isModified = true;
    }


}