package com.github.semres;

import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Board {
    public Map<String, Synset> getSynsets() {
        return synsets;
    }

    private Map<String, Synset> synsets = new HashMap<>();
    private Map<String, Boolean> synsetsLoadedState = new HashMap<>();
    private Map<String, Edge> edges = new HashMap<>();

    private Map<String, Synset> newSynsets = new HashMap<>();
    private Map<String, Edge> newEdges = new HashMap<>();
    private Map<String, Synset> removedSynsets = new HashMap<>();
    private Map<String, Edge> removedEdges = new HashMap<>();

    private Database attachedDatabase;

    public Board(Database attachedDatabase) {
        this.attachedDatabase = attachedDatabase;
    }

    public List<Synset> loadSynsets(String searchPhrase) {
        List<Synset> synsetsFound = attachedDatabase.searchSynsets(searchPhrase);
        List<Synset> newSynsets = new ArrayList<>();
        for (Synset synset : synsetsFound) {
            if (synsets.get(synset.getId()) == null) {
                newSynsets.add(synset);
                synsets.put(synset.getId(), synset);
            }
        }
        return newSynsets;
    }

    public void loadEdges(String synsetId) {
        Synset synset = synsets.get(synsetId);
        if (synset != null) {
            if (synset.getOutgoingEdges().size() > 0) {
                return;
            }

            List<Edge> edges = attachedDatabase.getOutgoingEdges(synset);
            for (Edge edge : edges) {
                if (synsets.containsKey(edge.getPointedSynset().getId())) {
                    edge.setPointedSynset(synsets.get(edge.getPointedSynset().getId()));
                } else {
                    synsets.put(edge.getPointedSynset().getId(), edge.getPointedSynset());
                }
                this.edges.put(edge.getId(), edge);
                synset.addOutgoingEdge(edge);
                edge.getPointedSynset().addPointingEdge(edge);
            }
        }
    }

    public void addSynset(Synset newSynset) {
        if (newSynset.getId() == null) {
            newSynset.setId(getNewSynsetId());
        }
        synsets.put(newSynset.getId(), newSynset);
        newSynsets.put(newSynset.getId(), newSynset);
    }

    public void addEdge(Edge newEdge) {
        edges.put(newEdge.getId(), newEdge);
        newEdges.put(newEdge.getId(), newEdge);

        synsets.get(newEdge.getOriginSynset().getId()).addOutgoingEdge(newEdge);
    }

    public Synset getSynset(String id) {
        return synsets.get(id);
    }

    public List<Synset> searchLoadedSynsets(String searchPhrase) {
        List<Synset> synsetsFound = new ArrayList<>();

        for (Synset synset : synsets.values()) {
            if (synset.getRepresentation().equals(searchPhrase)) {
                synsetsFound.add(synset);
            }
        }
        return synsetsFound;
    }

    public void removeElement(String id) {
        if (synsets.containsKey(id)) {
            Synset removedSynset = synsets.get(id);
            for (Edge edge : removedSynset.getOutgoingEdges().values()) {
                edges.remove(edge.getId());
            }
            for (Edge edge : removedSynset.getPointingEdges().values()) {
                edges.remove(edge.getId());
            }
            synsets.remove(id);
            removedSynsets.put(id, removedSynset);
        } else if (edges.containsKey(id)) {
            Edge removedEdge = edges.get(id);
            removedEdge.getPointedSynset().removePointingEdge(removedEdge);
            removedEdge.getOriginSynset().removeOutgoingEdge(removedEdge);
            edges.remove(id);
            removedEdges.put(id, removedEdge);
        }
    }

    public void save() {
        for (Synset synset : newSynsets.values()) {
            attachedDatabase.addSynset(synset);
        }
        newSynsets.clear();
        for (Edge edge : newEdges.values()) {
            attachedDatabase.addEdge(edge);
        }
        newEdges.clear();
        for (Edge edge : removedEdges.values()) {
            attachedDatabase.removeEdge(edge);
        }
        removedEdges.clear();
        for (Synset synset : removedSynsets.values()) {
            attachedDatabase.removeSynset(synset);
        }
        removedSynsets.clear();
    }

    /**
     * Generate unique synset id.
     * @return Unique synset id.
     */
    private String getNewSynsetId() {
        SecureRandom random = new SecureRandom();
        String id;
        while (true) {
            id = new BigInteger(130, random).toString(32);
            if (!synsets.containsKey(id)) {
                break;
            }
        }
        return id;
    }
}

@@ -1142,24 +1142,70 @@
 .getId()) ==
+ null && removedSynsets.get(synset.getId()) ==
  null) %7B%0A   
@@ -1440,24 +1440,25 @@
 (synsetId);%0A
+%0A
         if (
@@ -1468,35 +1468,20 @@
 set 
-!
+=
 = null
-) %7B%0A            if (
+ %7C%7C !
 syns
@@ -1506,26 +1506,21 @@
 s().
-size() %3E 0) %7B%0A    
+isEmpty()) %7B%0A
     
@@ -1547,26 +1547,19 @@
     
-    %7D%0A%0A   
+%7D%0A%0A
         
  Lis
@@ -1550,25 +1550,24 @@
  %7D%0A%0A        
- 
 List%3CEdge%3E e
@@ -1616,36 +1616,32 @@
 ynset);%0A        
-    
 for (Edge edge :
@@ -1646,32 +1646,127 @@
  : edges) %7B%0A    
+        if (removedEdges.get(edge.getId()) != null) %7B%0A                continue;%0A            %7D%0A%0A
             if (
@@ -1817,28 +1817,24 @@
 getId())) %7B%0A
-    
             
@@ -1914,28 +1914,24 @@
             
-   
- 
 %7D else %7B%0A   
@@ -1927,20 +1927,16 @@
  else %7B%0A
-    
         
@@ -2022,33 +2022,26 @@
             
-    %7D%0A   
+%7D%0A
             
@@ -2036,25 +2036,24 @@
             
- 
 this.edges.p
@@ -2084,28 +2084,24 @@
             
-    
 synset.addOu
@@ -2126,28 +2126,24 @@
             
- 
-   
 edge.getPoin
@@ -2177,30 +2177,16 @@
 (edge);%0A
-            %7D%0A
         

Fix synset and edge loading after removal, but before saving changes.