/FileExtraction/Java_unseen/Wind-Development_WindSpigot/WindSpigot-Server/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java
package org.bukkit.craftbukkit.chunkio;

import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;

import org.bukkit.Server;
import org.bukkit.craftbukkit.util.AsynchronousExecutor;
import org.bukkit.craftbukkit.util.LongHash;

import net.minecraft.server.Chunk;
import net.minecraft.server.ChunkRegionLoader;
import net.minecraft.server.NBTTagCompound;

class ChunkIOProvider implements AsynchronousExecutor.CallBackProvider<QueuedChunk, Chunk, Runnable, RuntimeException> {
	private final AtomicInteger threadNumber = new AtomicInteger(1);

	// async stuff
	@Override
	public Chunk callStage1(QueuedChunk queuedChunk) throws RuntimeException {
		try {
			ChunkRegionLoader loader = queuedChunk.loader;
			Object[] data = loader.loadChunk(queuedChunk.world, queuedChunk.x, queuedChunk.z);

			if (data != null) {
				queuedChunk.compound = (NBTTagCompound) data[1];
				return (Chunk) data[0];
			}

			return null;
		} catch (IOException ex) {
			throw new RuntimeException(ex);
		}
	}

	// sync stuff
	@Override
	public void callStage2(QueuedChunk queuedChunk, Chunk chunk) throws RuntimeException {
		if (chunk == null) {
			// If the chunk loading failed just do it synchronously (may generate)
			queuedChunk.provider.originalGetChunkAt(queuedChunk.x, queuedChunk.z);
			return;
		}

		queuedChunk.loader.loadEntities(chunk, queuedChunk.compound.getCompound("Level"), queuedChunk.world);
		chunk.setLastSaved(queuedChunk.provider.world.getTime());
		queuedChunk.provider.chunks.put(LongHash.toLong(queuedChunk.x, queuedChunk.z), chunk);
		chunk.addEntities();

		if (queuedChunk.provider.chunkProvider != null) {
			queuedChunk.provider.world.timings.syncChunkLoadStructuresTimer.startTiming(); // Spigot
			queuedChunk.provider.chunkProvider.recreateStructures(chunk, queuedChunk.x, queuedChunk.z);
			queuedChunk.provider.world.timings.syncChunkLoadStructuresTimer.stopTiming(); // Spigot
		}

		Server server = queuedChunk.provider.world.getServer();
		if (server != null) {
			server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(chunk.bukkitChunk, false));
		}

		// Update neighbor counts
		for (int x = -2; x < 3; x++) {
			for (int z = -2; z < 3; z++) {
				if (x == 0 && z == 0) {
					continue;
				}

				Chunk neighbor = queuedChunk.provider.getChunkIfLoaded(chunk.locX + x, chunk.locZ + z);
				if (neighbor != null) {
					neighbor.setNeighborLoaded(-x, -z);
					chunk.setNeighborLoaded(x, z);
				}
			}
		}

		chunk.loadNearby(queuedChunk.provider, queuedChunk.provider, queuedChunk.x, queuedChunk.z);
	}

	@Override
	public void callStage3(QueuedChunk queuedChunk, Chunk chunk, Runnable runnable) throws RuntimeException {
		runnable.run();
	}

	@Override
	public Thread newThread(Runnable runnable) {
		Thread thread = new Thread(runnable, "Chunk I/O Executor Thread-" + threadNumber.getAndIncrement());
		thread.setDaemon(true);
		return thread;
	}
}
