/**
* Copyright [2015] [Christian Loehnert]
*
* 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.cost.createbooking;
import de.ks.BaseController;
import de.ks.executor.group.LastTextChange;
import de.ks.idnadrev.cost.bookingview.BookingLoadingHint;
import de.ks.idnadrev.cost.pattern.view.BookingPatternParser;
import de.ks.idnadrev.entity.cost.Account;
import de.ks.idnadrev.entity.cost.Booking;
import de.ks.option.Options;
import de.ks.persistence.PersistentWork;
import de.ks.selection.CustomAutoCompletionBinding;
import de.ks.validation.validators.DoubleValidator;
import de.ks.validation.validators.NotEmptyValidator;
import de.ks.validation.validators.NotNullValidator;
import de.ks.validation.validators.TimeHHMMValidator;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.DatePicker;
import javafx.scene.control.TextField;
import org.controlsfx.control.textfield.AutoCompletionBinding;
import javax.inject.Inject;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Path;
import java.net.URL;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
public class CreateBookingController extends BaseController<Booking> {
public static final int MAX_AUTOCOMPLEITON_RESULTS = 2;//20;
@FXML
protected ComboBox<String> account;
@FXML
protected TextField category;
@FXML
protected TextField time;
@FXML
protected DatePicker date;
@FXML
protected TextField description;
@FXML
protected TextField amount;
@FXML
protected Button book;
private CustomAutoCompletionBinding categoryAutoCompletion;
private TimeHHMMValidator timeValidator;
@Inject
BookingPatternParser patternParser;
private LastTextChange lastTextChange;
@Override
public void initialize(URL location, ResourceBundle resources) {
description.textProperty().bindBidirectional(store.getBinding().getStringProperty(Booking.class, b -> b.getDescription()));
category.textProperty().bindBidirectional(store.getBinding().getStringProperty(Booking.class, b -> b.getCategory()));
timeValidator = new TimeHHMMValidator();
validationRegistry.registerValidator(time, timeValidator);
validationRegistry.registerValidator(amount, new DoubleValidator());
validationRegistry.registerValidator(amount, new NotEmptyValidator());
validationRegistry.registerValidator(date, new NotNullValidator());
book.disableProperty().bind(validationRegistry.invalidProperty());
controller.getJavaFXExecutor().submit(() -> categoryAutoCompletion = new CustomAutoCompletionBinding(category, this::supplyCategoryCompletion));
lastTextChange = new LastTextChange(description, controller.getExecutorService());
lastTextChange.registerHandler(cf -> cf.thenApply(patternParser::parseLine).thenAcceptAsync(s -> {
if (s != null) {
category.setText(s);
}
}, controller.getJavaFXExecutor()));
}
protected List<String> supplyCategoryCompletion(AutoCompletionBinding.ISuggestionRequest request) {
if (request.getUserText() == null || request.getUserText().isEmpty()) {
return Collections.emptyList();
} else {
return PersistentWork.projection(Booking.class, true, MAX_AUTOCOMPLEITON_RESULTS, b -> b.getCategory(), (root, query, builder) -> {
Path<String> categoryPath = root.get(BookingLoadingHint.KEY_CATEGORY);
Expression<String> categoryPathLower = builder.lower(categoryPath);
String pattern = request.getUserText().toLowerCase(Locale.ROOT).trim() + "%";
query.where(builder.like(categoryPathLower, pattern));
query.orderBy(builder.asc(categoryPath));
});
}
}
@FXML
protected void onBooking() {
controller.save();
controller.reload();
}
@Override
public void onStop() {
onSuspend();
}
@Override
public void onSuspend() {
Options.store(account.getValue(), CreateBookingOptions.class).getDefaultAccount();
}
@Override
public void onStart() {
onResume();
}
@Override
public void onResume() {
date.setValue(LocalDate.now());
CreateBookingOptions options = Options.get(CreateBookingOptions.class);
String defaultAccount = options.getDefaultAccount();
CompletableFuture.supplyAsync(() -> PersistentWork.from(Account.class), controller.getExecutorService())//
.thenAcceptAsync(accounts -> {
List<String> accountNames = accounts.stream().map(a -> a.getName()).collect(Collectors.toList());
account.getItems().clear();
account.getItems().addAll(accountNames);
if (!accountNames.isEmpty()) {
if (accountNames.contains(defaultAccount)) {
account.getSelectionModel().select(defaultAccount);
} else {
account.getSelectionModel().select(0);
}
}
}, controller.getJavaFXExecutor());
}
@Override
protected void onRefresh(Booking model) {
amount.setText("");
amount.requestFocus();
}
@Override
public void duringSave(Booking model) {
model.setAccount(PersistentWork.forName(Account.class, account.getValue()));
model.setAmount(Double.parseDouble(amount.getText()));
LocalTime bookingTime = timeValidator.getTime();
if (bookingTime == null) {
bookingTime = LocalTime.now();
}
LocalDate bookingDate = date.getValue();
model.setBookingTime(LocalDateTime.of(bookingDate, bookingTime));
}
}