package org.artisanlogiciel.games.minetest;

import com.github.luben.zstd.Zstd;
import org.artisanlogiciel.games.minetest.core.Constant;
import org.artisanlogiciel.games.minetest.core.PacketException;
import org.artisanlogiciel.games.minetest.core.Serialize;

import java.nio.ByteBuffer;
import java.util.ArrayList;

/**
 * A block of nodes of MAP_BLOCKSIZE in any x,y,z direction
 */
public class MapBlock {

    final static int nodecount = Constant.MAP_BLOCKSIZE * Constant.MAP_BLOCKSIZE * Constant.MAP_BLOCKSIZE;

    int m_lighting_complete;

    ArrayList<MapNode> nodes;

    ArrayList<MapNode> getNodes()
    {
        if ( nodes == null )
        {
            nodes = new ArrayList<>(nodecount);
        }
        return nodes;
    }

    // in memory case
    public void deSerialize(ByteBuffer buffer, int version)
            throws PacketException
    {

        int flags = 0;
        int content_width = 0;
        int params_width = 0;

        if ( version >= 29) {
            // ByteBuffer byteBuffer = ByteBuffer.wrap(networkPacket.getBuffer(),offset,networkPacket.getLength() - offset);

    /*
            // force to have a direct buffer.
            ByteBuffer byteBuffer = ByteBuffer.allocateDirect(networkPacket.getLength());
            byteBuffer.put(networkPacket.getBuffer());
            byteBuffer.position(networkPacket.getOffset());

            //System.arraycopy(networkPacket.getBuffer(), 0, byteBuffer.array(), 0, length);
            // zstd compression
            // FIXME, can we know original size ? somehow related to BLOCKSIZE³
            long originalSizeMax = Zstd.decompressedSize(byteBuffer);
            System.out.println(String.format("originalSizeMax=%d", originalSizeMax));
            ByteBuffer decompressed = Zstd.decompress(byteBuffer,(int) originalSizeMax);
            */
            byte out[] = new byte[16386];
            long outLength = Zstd.decompressByteArray(out, 0, out.length, buffer.array(), buffer.arrayOffset(), buffer.limit());

            // Should be a MapBlock
            MapBlock block = new MapBlock();
            ByteBuffer decompressed = ByteBuffer.wrap(out, 0, (int) outLength);
            buffer = decompressed;
        }

        flags = Serialize.readU8(buffer);

        if ( version >= 27 ) {
            m_lighting_complete = Serialize.readU16(buffer);
        }

        content_width = Serialize.readU8(buffer);
        params_width = Serialize.readU8(buffer);

        System.out.println(String.format(" flags %x  lightning_complete %d content_witd %d params_width %d ",flags, m_lighting_complete, content_width, params_width));

        if (( version < 29 ) && ( version >= 11 ))
        {
            // ZLib decompression
            try {
                byte decompressed[] = Serialize.decompress(buffer);
                buffer = ByteBuffer.wrap(decompressed);
            }
            catch ( Exception e)
            {
                // TODO
                System.err.println(e);
                e.printStackTrace(System.err);
                return;
            }
        }

        nodes = getNodes();
        MapNode.deSerializeBulk(buffer,version, nodes,nodecount,content_width,params_width);

        //m_node_metadata.deSerialize(is, m_gamedef->idef());
    }
}
