/*
* ShootOFF - Software for Laser Dry Fire Training
* Copyright (C) 2016 phrack
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.shootoff.gui.pane;
import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.shootoff.courses.Course;
import com.shootoff.courses.io.CourseIO;
import com.shootoff.gui.targets.TargetView;
import com.shootoff.targets.Target;
import javafx.geometry.Dimension2D;
import javafx.scene.Group;
import javafx.scene.SnapshotParameters;
import javafx.scene.control.TitledPane;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
public class ArenaCoursesSlide extends Slide implements ItemSelectionListener<File> {
private static final Logger logger = LoggerFactory.getLogger(ArenaCoursesSlide.class);
private final Map<String, ItemSelectionPane<File>> categoryMap = new HashMap<>();
private final VBox coursePanes = new VBox();
private final ProjectorArenaPane arenaPane;
private final Stage shootOffStage;
private boolean choseCourse = false;
public ArenaCoursesSlide(Pane parentControls, Pane parentBody, ProjectorArenaPane arenaPane, Stage shootOffStage) {
super(parentControls, parentBody);
this.arenaPane = arenaPane;
this.shootOffStage = shootOffStage;
addSlideControlButton("Save Course", (event) -> {
saveCourse();
});
addSlideControlButton("Clear Course", (event) -> {
arenaPane.getCanvasManager().clearTargets();
});
addBodyNode(buildCoursePanes());
}
private void saveCourse() {
final File coursesDir = new File(System.getProperty("shootoff.courses"));
if (!coursesDir.exists()) {
if (!coursesDir.mkdirs()) {
logger.error("Courses folder does not exist and cannot be created: {}", coursesDir.getAbsolutePath());
}
}
final FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Save Course");
fileChooser.setInitialDirectory(coursesDir);
fileChooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("Course File (*.course)", "*.course"));
File courseFile = fileChooser.showSaveDialog(shootOffStage);
if (courseFile != null) {
String path = courseFile.getPath();
if (!path.endsWith(".course")) path += ".course";
courseFile = new File(path);
CourseIO.saveCourse(arenaPane, courseFile);
// Add the course to the list in the appropriate category
ItemSelectionPane<File> itemPane;
if (categoryMap.containsKey(courseFile.getParent())) {
itemPane = categoryMap.get(courseFile.getParent());
addCourseButton(itemPane, courseFile);
} else {
itemPane = buildCategoryPane(courseFile.getParentFile());
coursePanes.getChildren().add(new TitledPane(
courseFile.getParentFile().getName().replaceAll("_", "") + " Courses", itemPane));
categoryMap.put(courseFile.getParent(), itemPane);
}
}
}
private static final FileFilter FOLDER_FILTER = new FileFilter() {
@Override
public boolean accept(File path) {
return path.isDirectory();
}
};
private Pane buildCoursePanes() {
final File coursesDirectory = new File(System.getProperty("shootoff.courses"));
final ItemSelectionPane<File> uncategorizedPane = buildCategoryPane(coursesDirectory);
coursePanes.getChildren().add(new TitledPane("Uncategorized Courses", uncategorizedPane));
categoryMap.put(coursesDirectory.getPath(), uncategorizedPane);
final File[] courseFolders = coursesDirectory.listFiles(FOLDER_FILTER);
if (courseFolders != null) {
for (final File courseFolder : courseFolders) {
coursePanes.getChildren().add(new TitledPane(courseFolder.getName().replaceAll("_", "") + " Courses",
buildCategoryPane(courseFolder)));
}
} else {
logger.error("{} does not appear to be a valid course directory", coursesDirectory.getPath());
}
return coursePanes;
}
private static final FilenameFilter COURSE_FILTER = new FilenameFilter() {
@Override
public boolean accept(File directory, String fileName) {
return fileName.endsWith(".course");
}
};
private ItemSelectionPane<File> buildCategoryPane(File path) {
final ItemSelectionPane<File> itemPane = new ItemSelectionPane<>(false, this);
categoryMap.put(path.getPath(), itemPane);
final File[] courseFiles = path.listFiles(COURSE_FILTER);
if (courseFiles != null) {
for (final File f : courseFiles) {
addCourseButton(itemPane, f);
}
} else {
logger.error("{} doesn't appear to be a valid course-containing directory", path.getPath());
}
return itemPane;
}
private void addCourseButton(ItemSelectionPane<File> itemPane, File courseFile) {
final ImageView courseThumbnail = getCourseThumbnail(courseFile);
if (courseThumbnail == null) {
itemPane.addButton(courseFile, courseFile.getName().replace(".course", "").replaceAll("_", " "));
} else {
itemPane.addButton(courseFile, courseFile.getName().replace(".course", "").replaceAll("_", " "),
Optional.of(courseThumbnail), Optional.empty());
}
}
private ImageView getCourseThumbnail(File courseFile) {
final Optional<Course> course = CourseIO.loadCourse(arenaPane, courseFile);
if (course.isPresent()) {
final Group courseGroup = new Group();
final Course c = course.get();
if (c.getBackground().isPresent()) {
final Dimension2D courseDimensions;
if (c.getResolution().isPresent()) {
courseDimensions = c.getResolution().get();
} else {
courseDimensions = new Dimension2D(arenaPane.getWidth(), arenaPane.getWidth());
}
final ImageView backgroundImageView = new ImageView(c.getBackground().get());
backgroundImageView.setFitWidth(courseDimensions.getWidth());
backgroundImageView.setFitHeight(courseDimensions.getHeight());
backgroundImageView.setSmooth(true);
courseGroup.getChildren().add(backgroundImageView);
}
for (final Target t : c.getTargets()) {
courseGroup.getChildren().add(((TargetView) t).getTargetGroup());
}
final Image courseThumbnail = courseGroup.snapshot(new SnapshotParameters(), null);
final ImageView courseImageView = new ImageView(courseThumbnail);
courseImageView.setFitWidth(60);
courseImageView.setFitHeight(60);
courseImageView.setPreserveRatio(true);
courseImageView.setSmooth(true);
return courseImageView;
}
return null;
}
@Override
public void onItemClicked(File courseFile) {
final Optional<Course> course = CourseIO.loadCourse(arenaPane, courseFile);
if (course.isPresent()) {
arenaPane.setCourse(course.get());
}
choseCourse = true;
hide();
}
public boolean choseCourse() {
return choseCourse;
}
}