package com.github.prologdb.runtime.playground.jvm.persistence;

import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
import java.util.Optional;

/**
 * Implements {@link PlaygroundStatePersistenceService} by writing the state as
 * JSON to a file specified when the service is constructed
 */
public class JsonFilePlaygroundStatePersistenceService implements PlaygroundStatePersistenceService {
    /** The file to persist to */
    private Path filePath;

    private ObjectMapper objectMapper;

    public JsonFilePlaygroundStatePersistenceService(Path filePath, ObjectMapper om) {
        this.filePath = Objects.requireNonNull(filePath);
        this.objectMapper = Objects.requireNonNull(om);
    }

    public JsonFilePlaygroundStatePersistenceService(Path filePath) {
        this(filePath, new ObjectMapper());
    }

    @Override
    public Optional<PlaygroundState> read() throws IOException {
        if (Files.exists(filePath)) {
            if (Files.isRegularFile(filePath)) {
                return Optional.of(objectMapper.readValue(filePath.toFile(), PlaygroundState.class));
            } else {
                throw new IOException(filePath.toString() + " is a directory, expected file");
            }
        } else {
            return Optional.empty();
        }
    }

    @Override
    public void write(PlaygroundState state) throws IOException {
        if (!Files.exists(filePath)) {
            Files.createFile(filePath);
        }

        if (!Files.isRegularFile(filePath)) {
            throw new IOException(filePath.toString() + " is a directory, expected file");
        }

        objectMapper.writeValue(filePath.toFile(), state);
    }
}

@@ -505,16 +505,23 @@
 %0A    /**
+%0A     *
  The fil
@@ -535,16 +535,21 @@
 rsist to
+%0A    
  */%0A    
@@ -572,16 +572,46 @@
 ePath;%0A%0A
+    private Path backupPath;%0A%0A
     priv
@@ -726,16 +726,20 @@
 pper om)
+%0A   
  %7B%0A     
@@ -783,32 +783,127 @@
 Null(filePath);%0A
+        this.backupPath = filePath.resolveSibling(filePath.getFileName().toString() + %22.bak%22);%0A
         this.obj
@@ -1138,35 +1138,190 @@
 rows IOException
+%0A   
  %7B%0A
+        if (Files.exists(backupPath)) %7B%0A            return Optional.of(objectMapper.readValue(backupPath.toFile(), PlaygroundState.class));%0A        %7D%0A%0A
         if (File
@@ -1771,16 +1771,20 @@
 xception
+%0A   
  %7B%0A     
@@ -1786,25 +1786,24 @@
         if (
-!
 Files.exists
@@ -1816,75 +1816,188 @@
 ath)
-) %7B%0A            Files.createFile(filePath);%0A        %7D%0A%0A        if (
+ && !Files.isRegularFile(filePath)) %7B%0A            throw new IOException(filePath.toString() + %22 is a directory, expected file%22);%0A        %7D%0A%0A        if (Files.exists(backupPath) && 
 !Fil
@@ -2005,36 +2005,38 @@
 s.isRegularFile(
-file
+backup
 Path)) %7B%0A       
@@ -2054,36 +2054,38 @@
 new IOException(
-file
+backup
 Path.toString() 
@@ -2124,32 +2124,116 @@
 e%22);%0A        %7D%0A%0A
+        Files.deleteIfExists(backupPath);%0A        Files.move(filePath, backupPath);%0A
         objectMa
@@ -2275,16 +2275,58 @@
 state);%0A
+        Files.deleteIfExists(backupPath);%0A
     %7D%0A%7D%0A

use two-phase commit for storing the state as to not loose it when the process is killed at the wrong time