/*
* 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.targets.io;
import java.io.File;
import java.io.InputStream;
import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.shootoff.gui.targets.TargetView;
import com.shootoff.gui.controller.TargetEditorController;
import com.shootoff.targets.EllipseRegion;
import com.shootoff.targets.ImageRegion;
import com.shootoff.targets.PolygonRegion;
import com.shootoff.targets.RectangleRegion;
import com.shootoff.targets.RegionType;
import com.shootoff.targets.TargetRegion;
import javafx.geometry.Point2D;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.paint.Color;
public class TargetIO {
private static final Logger logger = LoggerFactory.getLogger(TargetIO.class);
public static final double DEFAULT_OPACITY = 0.5;
public static class TargetComponents {
private final Group targetGroup;
private final Map<String, String> targetTags;
public TargetComponents(Group targetGroup, Map<String, String> targetTags) {
this.targetGroup = targetGroup;
this.targetTags = targetTags;
}
public Group getTargetGroup() {
return targetGroup;
}
public Map<String, String> getTargetTags() {
return targetTags;
}
}
public static void saveTarget(final Map<String, String> targetTags, final List<Node> regions,
final File targetFile) {
RegionVisitor visitor;
if (targetFile.getName().endsWith("target")) {
visitor = new XMLTargetWriter(targetFile);
} else {
logger.error("Unknown target file type.");
return;
}
final URI baseURI = new File(System.getProperty("user.dir")).toURI();
for (final Node node : regions) {
final TargetRegion region = (TargetRegion) node;
switch (region.getType()) {
case IMAGE: {
final ImageRegion img = (ImageRegion) node;
// Make image path relative to cwd so that image files can be
// found on different machines
final URI imgURI = new File(img.getImageFile().getAbsolutePath()).toURI();
final File relativeImageFile = new File(baseURI.relativize(imgURI).getPath());
visitor.visitImageRegion(img.getBoundsInParent().getMinX(), img.getBoundsInParent().getMinY(),
relativeImageFile, img.getAllTags());
}
break;
case RECTANGLE: {
final RectangleRegion rec = (RectangleRegion) node;
visitor.visitRectangleRegion(rec.getBoundsInParent().getMinX(), rec.getBoundsInParent().getMinY(),
rec.getWidth(), rec.getHeight(), TargetEditorController.getColorName((Color) rec.getFill()),
rec.getAllTags());
}
break;
case ELLIPSE: {
final EllipseRegion ell = (EllipseRegion) node;
final double absoluteCenterX = ell.getBoundsInParent().getMinX() + ell.getRadiusX();
final double absoluteCenterY = ell.getBoundsInParent().getMinY() + ell.getRadiusY();
visitor.visitEllipse(absoluteCenterX, absoluteCenterY, ell.getRadiusX(), ell.getRadiusY(),
TargetEditorController.getColorName((Color) ell.getFill()), ell.getAllTags());
}
break;
case POLYGON: {
final PolygonRegion pol = (PolygonRegion) node;
final Double[] points = new Double[pol.getPoints().size()];
for (int i = 0; i < pol.getPoints().size(); i += 2) {
final Point2D p = pol.localToParent(pol.getPoints().get(i), pol.getPoints().get(i + 1));
points[i] = p.getX();
points[i + 1] = p.getY();
}
visitor.visitPolygonRegion(points, TargetEditorController.getColorName((Color) pol.getFill()),
pol.getAllTags());
}
break;
}
}
visitor.visitEnd(targetTags);
}
public static Optional<TargetComponents> loadTarget(final File targetFile) {
return loadTarget(targetFile, true);
}
// Used for loading targets from resource files for modular exercises
public static Optional<TargetComponents> loadTarget(final InputStream targetStream, final ClassLoader loader) {
return loadTarget(targetStream, true, loader);
}
public static Optional<TargetComponents> loadTarget(final File targetFile, boolean playAnimations) {
final TargetReader reader;
if (targetFile.getName().endsWith("target")) {
reader = new XMLTargetReader(targetFile, playAnimations);
} else {
logger.error("Unknown target file type.");
return Optional.empty();
}
return Optional.of(new TargetComponents(processVisualTags(reader.getTargetNodes()), reader.getTargetTags()));
}
// Used for loading targets from resource files for modular exercises
public static Optional<TargetComponents> loadTarget(final InputStream targetStream, boolean playAnimations,
final ClassLoader loader) {
final TargetReader reader = new XMLTargetReader(targetStream, playAnimations, loader);
return Optional.of(new TargetComponents(processVisualTags(reader.getTargetNodes()), reader.getTargetTags()));
}
private static Group processVisualTags(List<Node> regions) {
final Group targetGroup = new Group();
for (final Node node : regions) {
final TargetRegion region = (TargetRegion) node;
if (region.tagExists(TargetView.TAG_VISIBLE)
&& !Boolean.parseBoolean(region.getTag(TargetView.TAG_VISIBLE))) {
node.setVisible(false);
}
if (region.getType() != RegionType.IMAGE) {
if (region.tagExists(TargetView.TAG_OPACITY)) {
node.setOpacity(Double.parseDouble(region.getTag(TargetView.TAG_OPACITY)));
} else {
node.setOpacity(DEFAULT_OPACITY);
}
}
targetGroup.getChildren().add(node);
}
return targetGroup;
}
}