package org.apollo.game.sync;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Phaser;

import org.apollo.game.GameService;
import org.apollo.game.message.impl.RegionUpdateMessage;
import org.apollo.game.model.area.RegionCoordinates;
import org.apollo.game.model.entity.Npc;
import org.apollo.game.model.entity.Player;
import org.apollo.game.sync.task.NpcSynchronizationTask;
import org.apollo.game.sync.task.PhasedSynchronizationTask;
import org.apollo.game.sync.task.PlayerSynchronizationTask;
import org.apollo.game.sync.task.PostNpcSynchronizationTask;
import org.apollo.game.sync.task.PostPlayerSynchronizationTask;
import org.apollo.game.sync.task.PreNpcSynchronizationTask;
import org.apollo.game.sync.task.PrePlayerSynchronizationTask;
import org.apollo.game.sync.task.SynchronizationTask;
import org.apollo.util.MobRepository;
import org.apollo.util.ThreadUtil;

/**
 * An implementation of {@link ClientSynchronizer} which runs in a thread pool. A {@link Phaser} is used to ensure that
 * the synchronization is complete, allowing control to return to the {@link GameService} that started the
 * synchronization. This class will scale well with machines that have multiple cores/processors. The
 * {@link SequentialClientSynchronizer} will work better on machines with a single core/processor, however, both classes
 * will work.
 *
 * @author Graham
 * @author Major
 */
public final class ParallelClientSynchronizer extends ClientSynchronizer {

	/**
	 * The executor service.
	 */
	private final ExecutorService executor;

	/**
	 * The phaser.
	 */
	private final Phaser phaser = new Phaser(1);

	/**
	 * Creates the parallel client synchronizer backed by a thread pool with a number of threads equal to the number of
	 * processing cores available (this is found by the {@link ThreadUtil#AVAILABLE_PROCESSORS} method.
	 */
	public ParallelClientSynchronizer() {
		executor = Executors.newFixedThreadPool(ThreadUtil.AVAILABLE_PROCESSORS, ThreadUtil.create("ClientSynchronizer"));
	}

	@Override
	public void synchronize(MobRepository<Player> players, MobRepository<Npc> npcs) {
		int playerCount = players.size();
		int npcCount = npcs.size();

		Map<RegionCoordinates, List<RegionUpdateMessage>> updates = new HashMap<>();
		Map<RegionCoordinates, List<RegionUpdateMessage>> snapshots = new HashMap<>();

		phaser.bulkRegister(playerCount);
		for (Player player : players) {
			SynchronizationTask task = new PrePlayerSynchronizationTask(player, updates, snapshots);
			executor.submit(new PhasedSynchronizationTask(phaser, task));
		}
		phaser.arriveAndAwaitAdvance();

		phaser.bulkRegister(npcCount);
		for (Npc npc : npcs) {
			SynchronizationTask task = new PreNpcSynchronizationTask(npc);
			executor.submit(new PhasedSynchronizationTask(phaser, task));
		}
		phaser.arriveAndAwaitAdvance();

		phaser.bulkRegister(playerCount);
		for (Player player : players) {
			SynchronizationTask task = new PlayerSynchronizationTask(player);
			executor.submit(new PhasedSynchronizationTask(phaser, task));
		}
		phaser.arriveAndAwaitAdvance();

		phaser.bulkRegister(playerCount);
		for (Player player : players) {
			SynchronizationTask task = new NpcSynchronizationTask(player);
			executor.submit(new PhasedSynchronizationTask(phaser, task));
		}
		phaser.arriveAndAwaitAdvance();

		phaser.bulkRegister(playerCount);
		for (Player player : players) {
			SynchronizationTask task = new PostPlayerSynchronizationTask(player);
			executor.submit(new PhasedSynchronizationTask(phaser, task));
		}
		phaser.arriveAndAwaitAdvance();

		phaser.bulkRegister(npcCount);
		for (Npc npc : npcs) {
			SynchronizationTask task = new PostNpcSynchronizationTask(npc);
			executor.submit(new PhasedSynchronizationTask(phaser, task));
		}
		phaser.arriveAndAwaitAdvance();
	}

}
@@ -1603,18 +1603,17 @@
 The 
-e
+E
 xecutor
- s
+S
 ervi
@@ -1676,17 +1676,17 @@
 %09 * The 
-p
+P
 haser.%0A%09
@@ -1761,25 +1761,23 @@
 the 
-p
+P
 arallel
- c
+C
 lient
- s
+S
 ynch
@@ -1890,77 +1890,8 @@
 able
- (this is found by the %7B@link ThreadUtil#AVAILABLE_PROCESSORS%7D method
 .%0A%09 

Improve doc message in ParallelClientSynchronizer.