// Path: distribution/src/main/java/nl/crowndov/displaydirect/distribution/domain/travelinfo/Line.java
// public class Line implements Serializable {
// 
//     private static final long serialVersionUID = -7614598114730697681L;
// 
//     private String code;
//     private String publicNumber;
//     private TransportType type;
// 
//     public Line(String code, String publicNumber, TransportType type) {
//         this.code = code;
//         this.publicNumber = publicNumber;
//         this.type = type;
//     }
// 
//     public String getCode() {
//         return code;
//     }
// 
//     public String getPublicNumber() {
//         return publicNumber;
//     }
// 
//     public TransportType getType() {
//         return type;
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (o == null || getClass() != o.getClass()) return false;
// 
//         Line line = (Line) o;
// 
//         if (code != null ? !code.equals(line.code) : line.code != null) return false;
//         if (publicNumber != null ? !publicNumber.equals(line.publicNumber) : line.publicNumber != null) return false;
//         return type == line.type;
//     }
// 
//     @Override
//     public int hashCode() {
//         int result = code != null ? code.hashCode() : 0;
//         result = 31 * result + (publicNumber != null ? publicNumber.hashCode() : 0);
//         result = 31 * result + (type != null ? type.hashCode() : 0);
//         return result;
//     }
// }
// 
// Path: distribution/src/main/java/nl/crowndov/displaydirect/distribution/util/AbstractService.java
// public abstract class AbstractService {
// 
//     private static final Logger LOGGER = LoggerFactory.getLogger(AbstractService.class);
//     private static final Gson GSON = JsonFile.gson();
// 
//     protected static void backup(Runnable func) {
//         func.run();
//     }
// 
//     protected static <T> Optional<T> readFile(String key, Class<T> clazz) {
//         return JsonFile.read(key).map(s1 -> (T) GSON.fromJson(s1, clazz));
//     }
// 
//     protected static <T> Optional<T> readSerializedFile(String key) {
//         Path input = getPathSerialized(key);
//         LOGGER.info("Reading from {}", input.toString());
//         if (!input.toFile().exists()) {
//             return Optional.empty();
//         }
//         try (  FileInputStream fis = new FileInputStream(input.toString());
//                ObjectInputStream ois = new ObjectInputStream(fis)) {
//             T result = (T) ois.readObject();
//             return Optional.of(result);
//         } catch (ClassNotFoundException e) {
//             LOGGER.error("Error deserializing {}", key, e);
//         } catch (Exception e) {
//             LOGGER.error("Error reading {}", key, e);
//         }
//         return Optional.empty();
//     }
// 
//     protected static <T> void writeFile(String key, T data) {
//         String dataStr = GSON.toJson(data);
//         LOGGER.info("Got serialized data {} (len {})", key, dataStr.length());
//         JsonFile.write(key, dataStr);
//     }
// 
//     protected static <T> void writeFileSerialize(String key, T data) {
//         String out = getPathSerialized(key+"-temp").toString();
//         LOGGER.info("Writing to {}", out);
//         try (FileOutputStream fos = new FileOutputStream(out, false);
//              ObjectOutputStream oos = new ObjectOutputStream(fos)) {
//             oos.writeObject(data);
//             // Once done, move to the location we read, so that in case the (long) export is interupted, we don't lose a backup
//             Files.move(getPathSerialized(key+"-temp"), getPathSerialized(key), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
//         } catch (IOException e) {
//             LOGGER.error("Error writing {}", key, e);
//         }
//     }
// 
//     private static Path getPathSerialized(String key) {
//         return Paths.get(Configuration.getFileBasePath(), key+".out");
//     }
// 
//     protected static void schedule(ScheduledExecutorService executor, String label, Runnable run, String firstTime, int hoursRepeated) {
//         long minutes = DateTimeUtil.getMinutesTill(firstTime);
//         LOGGER.info("Scheduling task {} to first run in {} minutes, every {} hours thereafter", label, minutes, hoursRepeated);
//         executor.scheduleAtFixedRate(run, minutes, hoursRepeated*60, TimeUnit.MINUTES);
//     }
// }
// 
// Path: distribution/src/main/java/nl/crowndov/displaydirect/distribution/util/Store.java
// public class Store {
// 
//     public static class StringList extends ArrayList<String> {}
// 
//     public static class ValidationTokenStore extends ConcurrentHashMap<String, ValidationToken> {}
// 
//     public static class PlanningStore extends ConcurrentHashMap<String, QuayStore> {}
// 
//     public static class LineStore extends ConcurrentHashMap<String, Line> {}
// 
//     public static class DestinationStore extends ConcurrentHashMap<String, Destination> {}
// 
//     public static class SubscriptionQuayStore extends ConcurrentHashMap<String, List<Subscription>> {}
// 
//     public static class SubscriptionStore extends ConcurrentHashMap<String, Subscription> {}
// 
//     public static class TimingPointStore extends ConcurrentHashMap<String, String> {}
// }


import nl.crowndov.displaydirect.distribution.domain.travelinfo.Line;
import nl.crowndov.displaydirect.distribution.util.AbstractService;
import nl.crowndov.displaydirect.distribution.util.Store;
import java.util.List;
import java.util.Map;
package nl.crowndov.displaydirect.distribution.input;



/**
 * Copyright 2017 CROW-NDOV
 *
 * This file is subject to the terms and conditions defined in file 'LICENSE.txt', which is part of this source code package.
 */
public class LineProvider extends AbstractService {

    private static final Store.LineStore lines = new Store.LineStore();

    public static void start() {
        readFile("lines", Store.LineStore.class).ifPresent(lines::putAll);
    }

    public static void stop() {
        backup();
    }

    public static void backup() {
        writeFile("lines", lines);
    }

// Path: distribution/src/main/java/nl/crowndov/displaydirect/distribution/domain/travelinfo/Line.java
// public class Line implements Serializable {
// 
//     private static final long serialVersionUID = -7614598114730697681L;
// 
//     private String code;
//     private String publicNumber;
//     private TransportType type;
// 
//     public Line(String code, String publicNumber, TransportType type) {
//         this.code = code;
//         this.publicNumber = publicNumber;
//         this.type = type;
//     }
// 
//     public String getCode() {
//         return code;
//     }
// 
//     public String getPublicNumber() {
//         return publicNumber;
//     }
// 
//     public TransportType getType() {
//         return type;
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (o == null || getClass() != o.getClass()) return false;
// 
//         Line line = (Line) o;
// 
//         if (code != null ? !code.equals(line.code) : line.code != null) return false;
//         if (publicNumber != null ? !publicNumber.equals(line.publicNumber) : line.publicNumber != null) return false;
//         return type == line.type;
//     }
// 
//     @Override
//     public int hashCode() {
//         int result = code != null ? code.hashCode() : 0;
//         result = 31 * result + (publicNumber != null ? publicNumber.hashCode() : 0);
//         result = 31 * result + (type != null ? type.hashCode() : 0);
//         return result;
//     }
// }
// 
// Path: distribution/src/main/java/nl/crowndov/displaydirect/distribution/util/AbstractService.java
// public abstract class AbstractService {
// 
//     private static final Logger LOGGER = LoggerFactory.getLogger(AbstractService.class);
//     private static final Gson GSON = JsonFile.gson();
// 
//     protected static void backup(Runnable func) {
//         func.run();
//     }
// 
//     protected static <T> Optional<T> readFile(String key, Class<T> clazz) {
//         return JsonFile.read(key).map(s1 -> (T) GSON.fromJson(s1, clazz));
//     }
// 
//     protected static <T> Optional<T> readSerializedFile(String key) {
//         Path input = getPathSerialized(key);
//         LOGGER.info("Reading from {}", input.toString());
//         if (!input.toFile().exists()) {
//             return Optional.empty();
//         }
//         try (  FileInputStream fis = new FileInputStream(input.toString());
//                ObjectInputStream ois = new ObjectInputStream(fis)) {
//             T result = (T) ois.readObject();
//             return Optional.of(result);
//         } catch (ClassNotFoundException e) {
//             LOGGER.error("Error deserializing {}", key, e);
//         } catch (Exception e) {
//             LOGGER.error("Error reading {}", key, e);
//         }
//         return Optional.empty();
//     }
// 
//     protected static <T> void writeFile(String key, T data) {
//         String dataStr = GSON.toJson(data);
//         LOGGER.info("Got serialized data {} (len {})", key, dataStr.length());
//         JsonFile.write(key, dataStr);
//     }
// 
//     protected static <T> void writeFileSerialize(String key, T data) {
//         String out = getPathSerialized(key+"-temp").toString();
//         LOGGER.info("Writing to {}", out);
//         try (FileOutputStream fos = new FileOutputStream(out, false);
//              ObjectOutputStream oos = new ObjectOutputStream(fos)) {
//             oos.writeObject(data);
//             // Once done, move to the location we read, so that in case the (long) export is interupted, we don't lose a backup
//             Files.move(getPathSerialized(key+"-temp"), getPathSerialized(key), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
//         } catch (IOException e) {
//             LOGGER.error("Error writing {}", key, e);
//         }
//     }
// 
//     private static Path getPathSerialized(String key) {
//         return Paths.get(Configuration.getFileBasePath(), key+".out");
//     }
// 
//     protected static void schedule(ScheduledExecutorService executor, String label, Runnable run, String firstTime, int hoursRepeated) {
//         long minutes = DateTimeUtil.getMinutesTill(firstTime);
//         LOGGER.info("Scheduling task {} to first run in {} minutes, every {} hours thereafter", label, minutes, hoursRepeated);
//         executor.scheduleAtFixedRate(run, minutes, hoursRepeated*60, TimeUnit.MINUTES);
//     }
// }
// 
// Path: distribution/src/main/java/nl/crowndov/displaydirect/distribution/util/Store.java
// public class Store {
// 
//     public static class StringList extends ArrayList<String> {}
// 
//     public static class ValidationTokenStore extends ConcurrentHashMap<String, ValidationToken> {}
// 
//     public static class PlanningStore extends ConcurrentHashMap<String, QuayStore> {}
// 
//     public static class LineStore extends ConcurrentHashMap<String, Line> {}
// 
//     public static class DestinationStore extends ConcurrentHashMap<String, Destination> {}
// 
//     public static class SubscriptionQuayStore extends ConcurrentHashMap<String, List<Subscription>> {}
// 
//     public static class SubscriptionStore extends ConcurrentHashMap<String, Subscription> {}
// 
//     public static class TimingPointStore extends ConcurrentHashMap<String, String> {}
// }


// Path: distribution/src/main/java/nl/crowndov/displaydirect/distribution/input/LineProvider.java
import nl.crowndov.displaydirect.distribution.domain.travelinfo.Line;
import nl.crowndov.displaydirect.distribution.util.AbstractService;
import nl.crowndov.displaydirect.distribution.util.Store;
import java.util.List;
import java.util.Map;

package nl.crowndov.displaydirect.distribution.input;



/**
 * Copyright 2017 CROW-NDOV
 *
 * This file is subject to the terms and conditions defined in file 'LICENSE.txt', which is part of this source code package.
 */
public class LineProvider extends AbstractService {

    private static final Store.LineStore lines = new Store.LineStore();

    public static void start() {
        readFile("lines", Store.LineStore.class).ifPresent(lines::putAll);
    }

    public static void stop() {
        backup();
    }

    public static void backup() {
        writeFile("lines", lines);
    }

    public static void updateLines(List<Line> input) {