/*
* Copyright (c) 2015 tothm.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* tothm - initial API and implementation and/or initial documentation
*/
package airportsimulation.schedule;
import airportsimulation.airplane.Airplane;
import airportsimulation.event.StatusControllerSelector;
import airportsimulation.event.handler.EventHandler;
import airportsimulation.gui.CLIViewer;
import airportsimulation.utils.Builder;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
*
* @author tothm
*/
public class Scheduler {
private final Map<String, Queue<Schedule>> schedules;
private final Map<String, ScheduleController> scheduleControllers;
private final Map<String, Future> scheduleStateFutures;
private final ExecutorService executorService;
public Scheduler(Builder<Airplane> airplaneBuilder, Builder<Schedule> scheduleReader) {
schedules = new HashMap<>();
scheduleControllers = new HashMap<>();
scheduleStateFutures = new HashMap<>();
executorService = Executors.newScheduledThreadPool(4);
queueSchedules(scheduleReader);
createControllers(airplaneBuilder);
}
private void queueSchedules(Builder<Schedule> scheduleReader) {
while (scheduleReader.hasNext()) {
Schedule s = scheduleReader.getNext();
final String airplaneId = s.getAirplaneId();
if (!schedules.containsKey(airplaneId)) {
schedules.put(airplaneId, new LinkedList<Schedule>());
}
schedules.get(airplaneId).add(s);
}
}
private void createControllers(Builder<Airplane> airplaneBuilder) {
while (airplaneBuilder.hasNext()) {
Airplane airplane = airplaneBuilder.getNext();
StatusControllerSelector statusController = new StatusControllerSelector(airplane, executorService);
statusController.attach(new CLIViewer());
final String airplaneId = airplane.getId();
if (!schedules.containsKey(airplaneId)) {
continue;
}
ScheduleController scheduleController = new ScheduleController(
statusController, schedules.get(airplaneId));
scheduleControllers.put(airplaneId, scheduleController);
scheduleStateFutures.put(airplaneId, null);
}
}
public void startSchedules() {
Set<String> scheduleInProgressIdSet = new HashSet<>();
while (true) {
submitNextTask(scheduleInProgressIdSet);
final int endedScheduleCount = checkTaskFinished(scheduleInProgressIdSet);
if (endedScheduleCount == scheduleStateFutures.size()) {
break;
}
}
executorService.shutdown();
}
private int checkTaskFinished(Set<String> scheduleInProgressIdSet) {
int endedScheduleCnt = 0;
for (String airplaneId : scheduleStateFutures.keySet()) {
Future<StateFlag> scheduleStateFuture = scheduleStateFutures.get(airplaneId);
if (scheduleStateFuture == null) {
scheduleInProgressIdSet.remove(airplaneId);
++endedScheduleCnt;
continue;
}
try {
StateFlag stateFlag = scheduleStateFuture.get(
EventHandler.EVENT_LOOP_LENGTH_IN_MILISECONDS, TimeUnit.MILLISECONDS);
if (stateFlag.equals(StateFlag.ENDED)) {
++endedScheduleCnt;
} else {
scheduleInProgressIdSet.remove(airplaneId);
}
} catch (InterruptedException | ExecutionException ex) {
System.err.println("Cannot get schedule state future value due to:\n" + ex);
} catch (TimeoutException ex) {
}
}
return endedScheduleCnt;
}
private void submitNextTask(Set<String> scheduleInProgressIdSet) {
for (String airplaneId : scheduleControllers.keySet()) {
if (scheduleInProgressIdSet.contains(airplaneId)) {
continue;
}
ScheduleController controller = scheduleControllers.get(airplaneId);
scheduleStateFutures.remove(airplaneId);
scheduleStateFutures.put(airplaneId, executorService.submit(controller));
scheduleInProgressIdSet.add(airplaneId);
}
}
}