maze-generator/src/main/java/ch/fritteli/maze/generator/renderer/textfile/TextFileRenderer.java

113 lines
4.1 KiB
Java

package ch.fritteli.maze.generator.renderer.textfile;
import ch.fritteli.maze.generator.model.Maze;
import ch.fritteli.maze.generator.renderer.Renderer;
import ch.fritteli.maze.generator.renderer.text.TextRenderer;
import io.vavr.collection.List;
import io.vavr.control.Option;
import io.vavr.control.Try;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.NoSuchElementException;
@Slf4j
public class TextFileRenderer implements Renderer<List<Path>> {
@NonNull
private static final TextRenderer TEXT_RENDERER = TextRenderer.newInstance();
@NonNull
private Option<Path> targetMazeFile;
@NonNull
private Option<Path> targetSolutionFile;
private TextFileRenderer() {
this.targetMazeFile = Try
.of(() -> Files.createTempFile("maze_", ".txt"))
.onFailure(ex -> log.error("Unable to set default target file", ex))
.toOption();
this.targetSolutionFile = this.targetMazeFile.toTry()
.map(Path::getParent)
.flatMap(parent -> this.targetMazeFile.toTry()
.map(Path::getFileName)
.map(Path::toString)
.map(a -> a.replace(".txt", "-solution.txt"))
.map(parent::resolve))
.onFailure(ex -> log.error("Unable to set default solution target file", ex))
.toOption();
}
@NonNull
public static TextFileRenderer newInstance() {
return new TextFileRenderer();
}
public boolean isTargetMazeFileDefinedAndWritable() {
return this.targetMazeFile
.map(Path::toFile)
.exists(File::canWrite);
}
public boolean isTargetSolutionFileDefinedAndWritable() {
return this.targetSolutionFile
.map(Path::toFile)
.exists(File::canWrite);
}
@NonNull
public TextFileRenderer setTargetMazeFile(@NonNull final Path targetMazeFile) {
this.targetMazeFile = Option.of(targetMazeFile);
return this;
}
@NonNull
public TextFileRenderer setTargetSolutionFile(@NonNull final Path targetSolutionFile) {
this.targetSolutionFile = Option.of(targetSolutionFile);
return this;
}
@NonNull
@Override
public List<Path> render(@NonNull final Maze maze) {
if (!this.isTargetMazeFileDefinedAndWritable()) {
try {
Files.createFile(this.targetMazeFile.get());
} catch (IOException | NoSuchElementException e) {
log.error("Cannot write to target maze file.", e);
throw new IllegalArgumentException("Cannot write to target maze file.", e);
}
}
if (!this.isTargetSolutionFileDefinedAndWritable()) {
try {
Files.createFile(this.targetSolutionFile.get());
} catch (IOException | NoSuchElementException e) {
throw new IllegalArgumentException("Cannot write to target solution file.", e);
}
}
final String text;
final String solution;
synchronized (TEXT_RENDERER) {
text = TEXT_RENDERER.setRenderSolution(false).render(maze).strip();
solution = TEXT_RENDERER.setRenderSolution(true).render(maze).strip();
}
final Path targetMazeFile = this.targetMazeFile.get();
final Path targetSolutionFile = this.targetSolutionFile.get();
try {
Files.write(targetMazeFile, text.getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
log.error("Failed writing to file " + targetMazeFile.normalize(), e);
}
try {
Files.write(targetSolutionFile, solution.getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
log.error("Failed writing to file " + targetSolutionFile.normalize());
}
return List.of(targetMazeFile, targetSolutionFile);
}
}