/**
* Copyright [2014] [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.category;
import de.ks.BaseController;
import de.ks.activity.executor.ActivityExecutor;
import de.ks.application.fxml.DefaultLoader;
import de.ks.idnadrev.entity.Category;
import de.ks.persistence.PersistentWork;
import javafx.beans.property.SimpleObjectProperty;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.layout.FlowPane;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import java.util.concurrent.*;
import java.util.stream.Collectors;
public class CategoryBrowser extends BaseController<Object> {
private static final Logger log = LoggerFactory.getLogger(CategoryBrowser.class);
@FXML
protected FlowPane categoryPane;
protected final List<CategoryItemController> itemControllers = new ArrayList<>();
protected final SimpleObjectProperty<Category> selectedCategory = new SimpleObjectProperty<>();
@Override
public void initialize(URL location, ResourceBundle resources) {
}
@Override
public void onStart() {
onResume();
}
@Override
public void onResume() {
CompletableFuture.supplyAsync(this::readCategories, controller.getExecutorService())//
.thenApply(this::loadCategoryItemControllers)//
.thenAcceptAsync(controllers -> {
controllers.forEach(c -> categoryPane.getChildren().add(c.getPane()));
}, controller.getJavaFXExecutor());
}
protected List<Category> readCategories() {
List<Category> from = PersistentWork.from(Category.class);
log.debug("Found {} categories", from.size());
return from;
}
public void reload() {
categoryPane.getChildren().clear();
itemControllers.clear();
onResume();
}
protected List<CategoryItemController> loadCategoryItemControllers(List<Category> allCategories) {
List<Category> categories = new ArrayList<>(allCategories);
List<Category> alreadyLoadedCategories = itemControllers.stream().map(ic -> ic.getCategory()).collect(Collectors.toList());
log.debug("Found {} already loaded categories", alreadyLoadedCategories.size());
categories.removeAll(alreadyLoadedCategories);
log.debug("Found {} additional categories", categories.size());
List<Category> removedCategories = alreadyLoadedCategories.stream().filter(cat -> !allCategories.contains(cat)).collect(Collectors.toList());
log.debug("Found {} removed categories", removedCategories.size());
List<CategoryItemController> removed = itemControllers.stream().filter(ic -> removedCategories.contains(ic.getCategory())).collect(Collectors.toList());
itemControllers.removeAll(removed);
Future<?> submit = controller.getJavaFXExecutor().submit(() -> removed.forEach(ic -> categoryPane.getChildren().remove(ic.getPane())));
try {
submit.get();
} catch (Exception e) {
log.error("Could not execute fx executor runnable", e);
}
ActivityExecutor executorService = controller.getExecutorService();
List<Future<CategoryItemController>> futures = categories.stream().map(category -> executorService.submit(() -> loadSingleItemController(category))).collect(Collectors.toList());
List<CategoryItemController> categoryItemControllers = futures.stream().map(f -> {
try {
CategoryItemController itemController = f.get(5, TimeUnit.SECONDS);
return itemController;
} catch (InterruptedException e) {
return null;
} catch (ExecutionException e) {
log.error("Could not load {}", CategoryItemController.class.getName(), e);
return null;
} catch (TimeoutException e) {
throw new RuntimeException(e);
}
}).collect(Collectors.toList());
itemControllers.addAll(categoryItemControllers);
return categoryItemControllers;
}
protected CategoryItemController loadSingleItemController(Category category) {
try {
DefaultLoader<Node, CategoryItemController> loader = new DefaultLoader<Node, CategoryItemController>(CategoryItemController.class);
CategoryItemController categoryItemController = loader.getController();
categoryItemController.setCategory(category);
categoryItemController.setSelectionProperty(selectedCategory);
return categoryItemController;
} catch (Exception e) {
log.error("Could not load {}", CategoryItemController.class.getName(), e);
return null;
}
}
public FlowPane getCategoryPane() {
return categoryPane;
}
public Category getSelectedCategory() {
return selectedCategory.get();
}
public SimpleObjectProperty<Category> selectedCategoryProperty() {
return selectedCategory;
}
public void setSelectedCategory(Category selectedCategory) {
this.selectedCategory.set(selectedCategory);
}
}