package org.apollo.game.scheduling.impl;

import java.util.Comparator;
import java.util.Deque;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Random;

import org.apollo.game.model.Position;
import org.apollo.game.model.entity.Npc;
import org.apollo.game.model.entity.WalkingQueue;
import org.apollo.game.model.entity.path.SimplePathfindingAlgorithm;
import org.apollo.game.scheduling.ScheduledTask;

import com.google.common.base.Preconditions;

/**
 * A {@link ScheduledTask} that causes {@link Npc}s to randomly walk around in their boundary.
 *
 * @author Major
 */
public final class NpcMovementTask extends ScheduledTask {

	/**
	 * The delay between executions of this task, in pulses.
	 */
	private static final int DELAY = 5;

	/**
	 * The random number generator used to calculate how many Npcs should be moved per execution.
	 */
	private static final Random RANDOM = new Random();

	/**
	 * The comparator used to sort the Npcs in the PriorityQueue.
	 */
	private static final Comparator<Npc> RANDOM_COMPARATOR = (first, second) -> RANDOM.nextInt(2) - 1;

	/**
	 * The PathfindingAlgorithm used by this Task.
	 */
	private final SimplePathfindingAlgorithm algorithm = new SimplePathfindingAlgorithm();

	/**
	 * The Queue of Npcs.
	 */
	private final Queue<Npc> npcs = new PriorityQueue<>(RANDOM_COMPARATOR);

	/**
	 * Creates the NpcMovementTask.
	 */
	public NpcMovementTask() {
		super(DELAY, false);
	}

	/**
	 * Adds the {@link Npc} to this {@link ScheduledTask}.
	 * 
	 * @param npc The Npc to add.
	 */
	public void addNpc(Npc npc) {
		Preconditions.checkArgument(npc.hasBoundaries(), "Cannot add an npc with no boundaries to the NpcMovementTask.");
		npcs.offer(npc);
		System.out.println("Adding npc to movement task: " + npc.getId());
	}

	@Override
	public void execute() {
		int count = RANDOM.nextInt(npcs.size() / 50 + 5);
		for (int iterations = 0; iterations < count; iterations++) {
			Npc npc = npcs.poll();
			if (npc == null) {
				break;
			}

			Position[] boundary = npc.getBoundaries().get();
			Position current = npc.getPosition();
			Position min = boundary[0], max = boundary[1];
			int currentX = current.getX(), currentY = current.getY();

			boolean negativeX = RANDOM.nextBoolean(), negativeY = RANDOM.nextBoolean();
			int x = RANDOM.nextInt(negativeX ? (currentX - min.getX()) : (max.getX() - currentX));
			int y = RANDOM.nextInt(negativeY ? (currentY - min.getY()) : (max.getY() - currentY));

			int dx = negativeX ? -x : x;
			int dy = negativeY ? -y : y;
			Position next = new Position(currentX + dx, currentY + dy);

			Deque<Position> positions = algorithm.find(current, next, boundary);
			WalkingQueue queue = npc.getWalkingQueue();

			Position first = positions.pollFirst();
			if (first != null && queue.addFirstStep(first)) {
				positions.forEach(npc.getWalkingQueue()::addStep);
			}

			npcs.offer(npc);
		}
	}

}
@@ -1710,77 +1710,8 @@
 c);%0A
-%09%09System.out.println(%22Adding npc to movement task: %22 + npc.getId());%0A
 %09%7D%0A%0A

Remove debug message from NpcMovementTask.