/**
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package edu.berkeley.ground.model.versions;

import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class VersionHistoryDag<T extends Version> {
  // the id of the Version that's at the rootId of this DAG
  private final long itemId;

  // list of VersionSuccessors that make up this DAG
  private final List<Long> edgeIds;

  // map of parents to children
  private final Map<Long, List<Long>> parentChildMap;

  /**
   * Create a new version history DAG.
   *
   * @param itemId the id of the item of this DAG
   * @param edges the version successors in this DAG
   */
  public VersionHistoryDag(long itemId, List<VersionSuccessor<T>> edges) {
    this.itemId = itemId;
    this.edgeIds = new ArrayList<>();
    this.parentChildMap = new HashMap<>();

    for (VersionSuccessor<T> edge : edges) {
      edgeIds.add(edge.getId());

      this.addToParentChildMap(edge.getFromId(), edge.getToId());
    }
  }

  @JsonProperty
  public long getItemId() {
    return this.itemId;
  }

  @JsonProperty
  public List<Long> getEdgeIds() {
    return this.edgeIds;
  }

  /**
   * Checks if a given ID is in the DAG.
   *
   * @param id the ID to be checked
   * @return true if id is in the DAG, false otherwise
   */
  public boolean checkItemInDag(long id) {
    return this.parentChildMap.keySet().contains(id) || this.getLeaves().contains(id);
  }

  /**
   * Adds an edge to this DAG.
   *
   * @param parentId the id of the "from" of the edge
   * @param childId the id of the "to" of the edge
   */
  public void addEdge(long parentId, long childId, long successorId) {
    edgeIds.add(successorId);
    this.addToParentChildMap(parentId, childId);
  }

  /**
   * Return the parent(s) of a particular version.
   *
   * @param childId the query id
   * @return the list of parent version(s)
   */
  public List<Long> getParent(long childId) {
    List<Long> result = new ArrayList<>();

    for (long parentId : parentChildMap.keySet()) {
      if (parentChildMap.get(parentId).contains(childId)) {
        result.add(parentId);
      }
    }

    return result;
  }

  /**
   * Returns the leaves of the DAG (i.e., any version id that is not a parent of another version
   * id).
   *
   * @return the list of the IDs of the leaves of this DAG
   */
  public List<Long> getLeaves() {
    List<Long> leaves = new ArrayList<>();
    for (List<Long> values : parentChildMap.values()) {
      leaves.addAll(values);
    }

    leaves.removeAll(this.parentChildMap.keySet());

    Set<Long> leafSet = new HashSet<>(leaves);
    List<Long> result = new ArrayList<>();
    result.addAll(leafSet);

    return result;
  }

  private void addToParentChildMap(long parent, long child) {
    List<Long> childList = this.parentChildMap.get(parent);
    if (childList == null) {
      childList = new ArrayList<>();
    }

    childList.add(child);
    this.parentChildMap.put(parent, childList);
  }
}

@@ -802,16 +802,52 @@
 til.Set;
+%0Aimport java.util.stream.Collectors;
 %0A%0Apublic
@@ -1438,32 +1438,96 @@
 geIds = 
-new Array
+edges.stream().map(VersionSuccessor::getId)%0A        .collect(Collectors.to
 List
-%3C%3E
 (
+)
 );%0A    t
@@ -1573,88 +1573,29 @@
     
-for (VersionSuccessor%3CT%3E edge : edges) %7B%0A      edgeIds.add(edge.getId());%0A%0A     
+edges.forEach(edge -%3E
  thi
@@ -1649,23 +1649,18 @@
 tToId())
+)
 ;
-%0A    %7D
 %0A  %7D%0A%0A  
@@ -2319,24 +2319,29 @@
 orId) %7B%0A    
+this.
 edgeIds.add(
@@ -2606,73 +2606,20 @@
     
-List%3CLong%3E result = new ArrayList%3C%3E();%0A%0A    for (long parentId : 
+return this.
 pare
@@ -2633,57 +2633,68 @@
 Map.
-k
 e
+ntr
 ySet()
-) %7B%0A      if (parentChildMap.get(parentId
+.stream()%0A        .filter(entry -%3E entry.getValue(
 ).co
@@ -2709,18 +2709,16 @@
 hildId))
- %7B
 %0A       
@@ -2722,62 +2722,69 @@
     
-result.add(parentId);%0A      %7D%0A    %7D%0A%0A    return result
+.map(Map.Entry::getKey)%0A        .collect(Collectors.toList())
 ;%0A  
@@ -2999,35 +2999,34 @@
 tLeaves() %7B%0A    
-Lis
+Se
 t%3CLong%3E leaves =
@@ -3026,32 +3026,30 @@
 eaves = new 
-ArrayLis
+HashSe
 t%3C%3E();%0A    f
@@ -3051,33 +3051,13 @@
     
-for (List%3CLong%3E values : 
+this.
 pare
@@ -3079,47 +3079,33 @@
 es()
-) %7B%0A      
+.forEach(
 leaves
-.
+::
 addAll
-(values);%0A    %7D%0A
+);
 %0A   
@@ -3162,140 +3162,38 @@
     
-Set%3CLong%3E leafSet = new HashSet%3C%3E(leaves);%0A    List%3CLong%3E result = new ArrayList%3C%3E();%0A    result.addAll(leafSet);%0A%0A    return result
+return new ArrayList%3C%3E(leaves)
 ;%0A  
@@ -3308,18 +3308,30 @@
 Map.
-ge
+computeIfAbsen
 t(parent
 );%0A 
@@ -3330,57 +3330,24 @@
 rent
-);
+,
 %0A    
-if (childList == null) %7B%0A      childList =
+    key -%3E
  new
@@ -3364,17 +3364,11 @@
 %3C%3E()
+)
 ;%0A
-    %7D%0A%0A
     
@@ -3393,56 +3393,8 @@
 d);%0A
-    this.parentChildMap.put(parent, childList);%0A
   %7D%0A

Simplify collections code