package think.webglmap.bukkit;

import io.netty.buffer.ByteBuf;
import org.bukkit.ChunkSnapshot;
import org.bukkit.World;

import java.util.concurrent.*;

public class ChunkManager {

    private final WebglMapPlugin plugin;
    private final World world;
    private final IOThread ioThread;

    public ChunkManager(WebglMapPlugin plugin, World world) {
        this.plugin = plugin;
        this.world = world;
        ioThread = new IOThread();
        ioThread.start();
    }

    private static long chunkKey(int x, int z) {
        return ((long) x << 32) | z & 0xFFFFFFFL;
    }

    public void cleanup() {
        try {
            ioThread.stopping = true;
            ioThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public boolean getChunkBytes(final int x, final int z, ByteBuf out) {
        ChunkSnapshot chunk = null;
        try {
            chunk = plugin.getServer().getScheduler().callSyncMethod(plugin, new Callable<ChunkSnapshot>() {
                @Override
                public ChunkSnapshot call() throws Exception {
                    return world.getChunkAt(x, z).getChunkSnapshot(false, true, false);
                }
            }).get();
        } catch (InterruptedException e) {
            Thread.interrupted();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        if (chunk == null) {
            return false;
        }
        int mask = 0;
        for (int i = 0; i < 16; i++) {
            if (!chunk.isSectionEmpty(i))
                mask |= 1 << i;
        }
        out.writeInt(x);
        out.writeInt(z);
        out.writeShort(mask);
        for (int i = 0; i < 16; i++) {
            if (!chunk.isSectionEmpty(i)) {
                for (int oy = 0; oy < 16; oy++) {
                    for (int oz = 0; oz < 16; oz++) {
                        for (int ox = 0; ox < 16; ox++) {
                            out.writeShort(chunk.getBlockTypeId(ox, oy + i * 16, oz));
                            out.writeByte(chunk.getBlockData(ox, oy + i * 16, oz));
                            out.writeByte(chunk.getBlockEmittedLight(ox, oy + i * 16, oz));
                            out.writeByte(chunk.getBlockSkyLight(ox, oy + i * 16, oz));
                        }
                    }
                }
            }
        }
        return true;
    }

    private class IOThread extends Thread {
        public volatile boolean stopping = false;

        private final BlockingQueue<Runnable> tasks = new LinkedBlockingQueue<Runnable>();

        public void saveChunk(ChunkSnapshot chunk) {
            tasks.add(new Runnable() {
                @Override
                public void run() {
                    //TODO: Saving
                }
            });
        }

        @Override
        public void run() {
            try {
                while (true) {
                    Runnable task;
                    if (stopping) {
                        task = tasks.poll();
                        if (task == null) {
                            return;
                        }
                    } else {
                        task = tasks.poll(2, TimeUnit.SECONDS);
                        if (task == null) {
                            if (stopping) {
                                return;
                            } else {
                                continue;
                            }
                        }

                    }
                    task.run();
                }
            } catch (InterruptedException e) {
                interrupt();
            }
        }
    }
}

@@ -252,45 +252,8 @@
 rld;
-%0A    private final IOThread ioThread;
 %0A%0A  
@@ -374,69 +374,8 @@
 ld;%0A
-        ioThread = new IOThread();%0A        ioThread.start();%0A
     
@@ -515,175 +515,8 @@
 ) %7B%0A
-        try %7B%0A            ioThread.stopping = true;%0A            ioThread.join();%0A        %7D catch (InterruptedException e) %7B%0A            e.printStackTrace();%0A        %7D%0A
     
@@ -2097,32 +2097,32 @@
     %7D%0A        %7D%0A
+
         return t
@@ -2135,1281 +2135,7 @@
    %7D
-%0A%0A    private class IOThread extends Thread %7B%0A        public volatile boolean stopping = false;%0A%0A        private final BlockingQueue%3CRunnable%3E tasks = new LinkedBlockingQueue%3CRunnable%3E();%0A%0A        public void saveChunk(ChunkSnapshot chunk) %7B%0A            tasks.add(new Runnable() %7B%0A                @Override%0A                public void run() %7B%0A                    //TODO: Saving%0A                %7D%0A            %7D);%0A        %7D%0A%0A        @Override%0A        public void run() %7B%0A            try %7B%0A                while (true) %7B%0A                    Runnable task;%0A                    if (stopping) %7B%0A                        task = tasks.poll();%0A                        if (task == null) %7B%0A                            return;%0A                        %7D%0A                    %7D else %7B%0A                        task = tasks.poll(2, TimeUnit.SECONDS);%0A                        if (task == null) %7B%0A                            if (stopping) %7B%0A                                return;%0A                            %7D else %7B%0A                                continue;%0A                            %7D%0A                        %7D%0A%0A                    %7D%0A                    task.run();%0A                %7D%0A            %7D catch (InterruptedException e) %7B%0A                interrupt();%0A            %7D%0A        %7D%0A    %7D
 %0A%7D%0A

Remove unused thread