@Override
	public Calendar plan(ArrayList<Calendar> calendars, TaskList tasklist, String calendarName) throws PlanningException {

		ZonedDateTime last = tasklist.getLastDeadline();
		ZonedDateTime now = ZonedDateTime.now();
		Calendar merged = PlanningUtil.mergeCalendars(ApplicationSettings.getInstance().getLocalizedMessage("strat.merge") + ": " + calendarName, calendars, now, last);
		Calendar plannedCalendar = new Calendar(calendarName, null);
		TaskList fail = new TaskList(calendarName + ApplicationSettings.getInstance().getLocalizedMessage("strat.fail"));
		ArrayList<FreeTimeContainer> freeTime = PlanningUtil.manageFTCExceptions(PlanningUtil.getPossibleTimeSlots(merged, tasklist));

		initStats(tasklist);

		Comparator<Task> comp = new Comparator<Task>() {
			public int compare(Task t, Task s) {
				int c = s.getDuration().compareTo(t.getDuration());

				if (c != 0) {
					return c;
				} else {
					Integer tp = t.getPriority();
					Integer sp = s.getPriority();
					return tp.compareTo(sp);
				}

			}
		};

		tasklist.sort(comp);

		for (int i = 0; i < tasklist.getSize(); i++) {
			Task toPlan = tasklist.getTask(i);

			Predicate<FreeTimeContainer> deadlineOK = p -> p.getEndZDT().isBefore(toPlan.getDeadline()) && p.getBeginZDT().isBefore(toPlan.getDeadline());
			ArrayList<FreeTimeContainer> filteredCopy = (ArrayList<FreeTimeContainer>) freeTime.stream().filter(deadlineOK)

			.sorted((l1, l2) -> {
				return l1.getDurationLeft().compareTo(l2.getDurationLeft());
			})

			.collect(Collectors.toList());

			try {
				FreeTimeContainer best = getBestContainer(toPlan, filteredCopy);
				best.addTask(toPlan);
				log.info("Planned " + best);
			} catch (PlanningException pe) {
				fail.addTask(toPlan);
				errorOccured = true;
				totalFailed++;
				failmessage = pe.getMessage();
			}
			totalFinished++;
		}

		if (errorOccured) {
			planAllTimeSlots(plannedCalendar, freeTime);
			isDone = true;
			throw new PlanningException(plannedCalendar, fail, failmessage);
		}

		planAllTimeSlots(plannedCalendar, freeTime);
		isDone = true;
		return plannedCalendar;
	}