package de.factoryfx.server;

import java.time.LocalDateTime;
import java.util.Collection;
import java.util.function.Function;

import de.factoryfx.data.merge.DataMerger;
import de.factoryfx.data.merge.MergeDiffInfo;
import de.factoryfx.factory.FactoryBase;
import de.factoryfx.factory.FactoryManager;
import de.factoryfx.factory.datastorage.FactoryAndStorageMetadata;
import de.factoryfx.factory.datastorage.FactoryStorage;
import de.factoryfx.factory.datastorage.StoredFactoryMetadata;
import de.factoryfx.factory.log.FactoryUpdateLog;

public class ApplicationServer<L,V,T extends FactoryBase<L,V>> {
    private final FactoryManager<L,V,T> factoryManager;
    private final FactoryStorage<L,V,T> factoryStorage;

    public ApplicationServer(FactoryManager<L,V,T> factoryManager, FactoryStorage<L,V,T> factoryStorage) {
        this.factoryManager = factoryManager;
        this.factoryStorage = factoryStorage;
    }

    public MergeDiffInfo getDiffToPreviousVersion(StoredFactoryMetadata storedFactoryMetadata) {
        T historyFactory = getHistoryFactory(storedFactoryMetadata.id);
        T historyFactoryPrevious = getPreviousHistoryFactory(storedFactoryMetadata.id);
        return new DataMerger(historyFactoryPrevious,historyFactoryPrevious,historyFactory).createMergeResult((permission)->true);
    }

    public /*FactoryUpdateLog*/ void revertTo(StoredFactoryMetadata storedFactoryMetadata) {
        T historyFactory = getHistoryFactory(storedFactoryMetadata.id);

        factoryManager.stop();
        factoryManager.start(historyFactory);

        FactoryAndStorageMetadata<T> prepareNewFactory = factoryStorage.getPrepareNewFactory();
        prepareNewFactory= new FactoryAndStorageMetadata<>(historyFactory.internal().copy(),prepareNewFactory.metadata);
        factoryStorage.updateCurrentFactory(prepareNewFactory);
    }

    public FactoryUpdateLog updateCurrentFactory(FactoryAndStorageMetadata<T> update, Function<String,Boolean> permissionChecker) {
        prepareFactory(update.root);
        T commonVersion = factoryStorage.getHistoryFactory(update.metadata.baseVersionId);
        FactoryUpdateLog factoryLog = factoryManager.update(commonVersion, update.root, permissionChecker);
        if (factoryLog.mergeDiffInfo.successfullyMerged()){
            update.metadata.creationTime= LocalDateTime.now();
            FactoryAndStorageMetadata<T> copy = new FactoryAndStorageMetadata<>(factoryManager.getCurrentFactory().internal().copy(),update.metadata);
            factoryStorage.updateCurrentFactory(copy);
        }
        return factoryLog;
    }

    public MergeDiffInfo simulateUpdateCurrentFactory(FactoryAndStorageMetadata<T> possibleUpdate,  Function<String, Boolean> permissionChecker){
        T commonVersion = factoryStorage.getHistoryFactory(possibleUpdate.metadata.baseVersionId);
        return factoryManager.simulateUpdate(commonVersion , possibleUpdate.root, permissionChecker);
    }

    /** creates a new factory update which is ready for editing mainly assign the right ids*/
    public FactoryAndStorageMetadata<T> prepareNewFactory() {
        return factoryStorage.getPrepareNewFactory();
    }

    public T getHistoryFactory(String id) {
        return factoryStorage.getHistoryFactory(id);
    }

    public T getPreviousHistoryFactory(String id) {
        T historyFactory = factoryStorage.getPreviousHistoryFactory(id);
        return historyFactory;
    }

    public Collection<StoredFactoryMetadata> getHistoryFactoryList() {
        return factoryStorage.getHistoryFactoryList();
    }

    public void start() {
        factoryStorage.loadInitialFactory();
        final FactoryAndStorageMetadata<T> currentFactory = factoryStorage.getCurrentFactory();
        prepareFactory(currentFactory.root);
        factoryManager.start(currentFactory.root);
    }

    @SuppressWarnings("unchecked")
    void prepareFactory(T root){
        root.internal().collectChildrenDeep().forEach(data -> {
            if (data instanceof ApplicationServerAwareFactory){
                ((ApplicationServerAwareFactory<V,L,T,?>)data).applicationServer.set(this);
            }
        });
    }

    public void stop() {
        factoryManager.stop();
    }

    public V query(V visitor) {
        return factoryManager.query(visitor);
    }
}

@@ -1512,167 +1512,56 @@
 );%0D%0A
-%0D%0A        factoryManager.stop();%0D%0A        factoryManager.start(historyFactory);%0D%0A%0D%0A        FactoryAndStorageMetadata%3CT%3E prepareNewFactory = factoryStorage.getP
+        FactoryAndStorageMetadata%3CT%3E current = p
 repa
@@ -1585,33 +1585,24 @@
         
-prepareNewFactory
+current 
 = new Fa
@@ -1625,16 +1625,17 @@
 etadata%3C
+T
 %3E(histor
@@ -1646,44 +1646,16 @@
 tory
-.internal().copy(),prepareNewFactory
+,current
 .met
@@ -1667,39 +1667,24 @@
 );%0D%0A        
-factoryStorage.
 updateCurren
@@ -1692,33 +1692,31 @@
 Factory(
-prepareNewFactory
+current,s-%3Etrue
 );%0D%0A    

revert revert