/*
* Copyright [2014] [Christian Loehnert, krampenschiesser@gmail.com]
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.ks.idnadrev.review.planweek;
import de.ks.BaseController;
import de.ks.activity.ActivityHint;
import de.ks.fxcontrols.weekview.AppointmentResolver;
import de.ks.fxcontrols.weekview.WeekHelper;
import de.ks.fxcontrols.weekview.WeekView;
import de.ks.fxcontrols.weekview.WeekViewAppointment;
import de.ks.i18n.Localized;
import de.ks.idnadrev.entity.Task;
import de.ks.idnadrev.task.create.CreateTaskActivity;
import de.ks.idnadrev.task.finish.FinishTaskActivity;
import de.ks.idnadrev.task.view.ViewTasksMaster;
import de.ks.persistence.PersistentWork;
import de.ks.scheduler.Schedule;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.layout.StackPane;
import org.controlsfx.dialog.Dialogs;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URL;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
public class PlanWeek extends BaseController<List<Task>> implements AppointmentResolver<Task> {
private static final Logger log = LoggerFactory.getLogger(PlanWeek.class);
@FXML
protected ViewTasksMaster viewController;
@FXML
protected StackPane weekViewContainer;
@FXML
protected Button edit;
@FXML
protected Button finish;
@FXML
protected Button delete;
protected WeekView<Task> weekView;
protected final List<Task> tasks = new LinkedList<>();
protected final SimpleBooleanProperty disable = new SimpleBooleanProperty(true);
@Override
public void initialize(URL location, ResourceBundle resources) {
weekView = new WeekView<>(Localized.get("today"));
weekView.setPrefSize(300, 300);
weekViewContainer.getChildren().add(weekView);
weekView.setAppointmentResolver(this);
viewController.getTasksView().getSelectionModel().selectedItemProperty().addListener((p, o, n) -> {
if (n != null) {
Task task = n.getValue();
WeekViewAppointment<Task> appointment = createAppointment(task);
appointment.getControl().setVisible(false);
if (!weekView.getEntries().contains(appointment)) {
weekView.getEntries().add(appointment);
}
}
});
viewController.getTasksView().setOnMouseClicked(e -> {
onEdit();
});
viewController.getTasksView().setOnDragDetected(e -> {
TreeItem<Task> selectedItem = viewController.getTasksView().getSelectionModel().getSelectedItem();
if (selectedItem == null) {
return;
}
Task task = selectedItem.getValue();
WeekViewAppointment<Task> appointment = createAppointment(task);
weekView.startAppointmentDrag(appointment);
log.debug("Detected drag gesture, selected item={}", task.getName());
e.consume();
});
viewController.getTasksView().getSelectionModel().selectedItemProperty().addListener((p, o, n) -> {
if (n != null && n.getValue() != null && n.getValue().getId() >= 0) {
disable.set(false);
} else {
disable.set(true);
}
});
finish.disableProperty().bind(disable);
edit.disableProperty().bind(disable);
delete.disableProperty().bind(disable);
}
protected WeekViewAppointment<Task> createAppointment(Task task) {
WeekViewAppointment<Task> appointment = new WeekViewAppointment<>(task.getName(), weekView.getFirstDayOfWeek(), task.getEstimatedTime());
Schedule taskSchedule = task.getSchedule();
if (taskSchedule != null) {
if (taskSchedule.getDuration() != null) {
appointment.setDuration(taskSchedule.getDuration());
}
if (taskSchedule.getScheduledDate() != null) {
appointment.setStart(taskSchedule.getScheduledDate(), taskSchedule.getScheduledTime());
} else if (taskSchedule.getProposedWeek() != 0) {
LocalDate start = new WeekHelper().getFirstDayOfWeek(taskSchedule.getProposedYear(), taskSchedule.getProposedWeek());
if (taskSchedule.getProposedWeekDay() != null) {
start = start.plusDays(taskSchedule.getProposedWeekDay().getValue() - 1);
}
appointment.setStart(start, null);
}
}
appointment.setUserData(task);
appointment.setChangeStartCallback((date, time) -> {
controller.getExecutorService().submit(() -> changeSchedule(appointment, date, time));
});
appointment.setNewTimePossiblePredicate((date, time) -> true);
appointment.setEnhancer(btn -> {
MenuItem item = new MenuItem(Localized.get("change.duration"));
item.setOnAction(e -> changeDuration(appointment, task));
ContextMenu menu = new ContextMenu(item);
btn.setContextMenu(menu);
});
appointment.setAction((btn, t) -> {
edit(() -> t);
});
return appointment;
}
protected void changeDuration(WeekViewAppointment<Task> appointment, Task task) {
Optional<String> optional = Dialogs.create().title(Localized.get("enter.time.minutes")).showTextInput(String.valueOf(appointment.getDuration().toMinutes()));
if (optional.isPresent()) {
String input = optional.get();
try {
long duration = Long.parseLong(input);
Duration minutes = Duration.ofMinutes(duration);
appointment.setDuration(minutes);
PersistentWork.wrap(() -> {
Task reloaded = PersistentWork.reload(appointment.getUserData());
reloaded.getSchedule().setDuration(minutes);
});
weekView.recreateEntries();
} catch (NumberFormatException e) {
log.warn("Could not parse input {}", input);
}
}
}
protected void changeSchedule(WeekViewAppointment<Task> appointment, LocalDate date, LocalTime time) {
PersistentWork.wrap(() -> {
Task reloaded = PersistentWork.reload(appointment.getUserData());
Schedule schedule = reloaded.getSchedule();
if (schedule == null) {
schedule = new Schedule();
reloaded.setSchedule(schedule);
}
if (time == null) {
int week = new WeekHelper().getWeek(date);
schedule.setProposedWeek(week);
schedule.setProposedWeekDay(date.getDayOfWeek());
schedule.setScheduledDate(null);
schedule.setScheduledTime(null);
} else {
schedule.setScheduledDate(date);
schedule.setScheduledTime(time);
schedule.setProposedWeek(0);
schedule.setProposedYear(0);
schedule.setProposedWeekDay(null);
}
log.info("{} now starting at {} {}", reloaded.getName(), date, time);
});
}
@Override
public void resolve(LocalDate begin, LocalDate end, Consumer<List<WeekViewAppointment<Task>>> callback) {
WeekHelper weekHelper = new WeekHelper();
List<Task> reloaded = PersistentWork.read(em -> tasks.stream().map(t -> PersistentWork.reload(t)).collect(Collectors.toList()));
List<Task> tasksWithScheduledDate = reloaded.stream().filter(t -> t.getSchedule() != null)//
.filter(t -> t.getSchedule().getScheduledDate() != null)//
.filter(t -> t.getSchedule().getScheduledDate().isAfter(begin.minusDays(1)))//
.filter(t -> t.getSchedule().getScheduledDate().isBefore(end.plusDays(1)))//
.collect(Collectors.toList());
log.info("found {} tasks with scheduled date in range {} - {}", tasksWithScheduledDate.size(), begin, end);
List<Task> tasksWithProposedDate = reloaded.stream().filter(t -> t.getSchedule() != null)//
.filter(t -> t.getSchedule().getProposedWeek() != 0)//
.filter(t -> weekHelper.getFirstDayOfWeek(t.getSchedule().getProposedYear(), t.getSchedule().getProposedWeek()).isAfter(begin.minusDays(1)))//
.filter(t -> weekHelper.getLastDayOfWeek(t.getSchedule().getProposedYear(), t.getSchedule().getProposedWeek()).isBefore(end.plusDays(1)))//
.collect(Collectors.toList());
log.info("found {} tasks with prosoded date in range {} - {}", tasksWithProposedDate.size(), begin, end);
HashSet<Task> all = new HashSet<>();
all.addAll(tasksWithProposedDate);
all.addAll(tasksWithScheduledDate);
List<WeekViewAppointment<Task>> appointments = all.stream().map(t -> createAppointment(t)).collect(Collectors.toList());
callback.accept(appointments);
}
@Override
protected void onRefresh(List<Task> model) {
this.tasks.clear();
this.tasks.addAll(model);
weekView.recreateEntries();
}
@FXML
protected void onEdit() {
TreeTableView<Task> tasksView = viewController.getTasksView();
Supplier<Task> supplier = () -> tasksView.getSelectionModel().getSelectedItem().getValue();
edit(supplier);
}
protected void edit(Supplier<Task> supplier) {
ActivityHint hint = new ActivityHint(CreateTaskActivity.class);
hint.setReturnToActivity(controller.getCurrentActivityId());
hint.setReturnToDatasourceHint(supplier);
hint.setDataSourceHint(supplier);
controller.startOrResume(hint);
}
@FXML
protected void onFinish() {
TreeTableView<Task> tasksView = viewController.getTasksView();
ActivityHint activityHint = new ActivityHint(FinishTaskActivity.class, controller.getCurrentActivityId());
activityHint.setDataSourceHint(() -> tasksView.getSelectionModel().getSelectedItem().getValue());
controller.startOrResume(activityHint);
}
@FXML
protected void onDelete() {
TreeTableView<Task> tasksView = viewController.getTasksView();
PersistentWork.run(em -> {
Task task = tasksView.getSelectionModel().getSelectedItem().getValue();
em.remove(PersistentWork.reload(task));
});
controller.reload();
}
}