/*
 * Copyright 2017 BTC Business Technology AG
 *
 * 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 com.btc.redg.extractor;

import com.btc.redg.extractor.model.EntityModel;

import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class EntityModelSorter {

    public static List<EntityModel> sortEntityModels(List<EntityModel> entities) {
        Map<EntityModel, Integer> depths = new DepthCalculator().calculateDepths(entities);
        return entities.stream()
                .sorted(Comparator.comparing(depths::get))
                .collect(Collectors.toList());
    }

    private static class DepthCalculator {
        Map<EntityModel, Integer> depths;

        Map<EntityModel, Integer> calculateDepths(List<EntityModel> entities) {
            depths = new HashMap<>();
            entities.forEach(this::calculateDepth);
            return depths;
        }

        private int calculateDepth(EntityModel entity) {
            return depths.computeIfAbsent(entity, e -> e.getAllRefs().stream()
                    .map(this::calculateDepth)
                    .max(Comparator.comparingInt(d -> d))
                    .map(depth -> depth + 1)
                    .orElse(0)
            );
        }
    }
}

@@ -659,60 +659,8 @@
 %0D%0A%0D%0A
-import com.btc.redg.extractor.model.EntityModel;%0D%0A%0D%0A
 impo
@@ -685,16 +685,16 @@
 rator;%0D%0A
+
 import j
@@ -798,16 +798,68 @@
 ors;%0D%0A%0D%0A
+import com.btc.redg.extractor.model.EntityModel;%0D%0A%0D%0A
 public c
@@ -1579,32 +1579,834 @@
  %7B%0D%0A            
+// Get depth if already calculated%0D%0A            if (this.depths.containsKey(entity)) %7B%0D%0A                return this.depths.get(entity);%0D%0A            %7D%0D%0A            // No depth if no dependencies%0D%0A            if (entity.getAllRefs() == null %7C%7C entity.getAllRefs().size() == 0) %7B%0D%0A                this.depths.put(entity, 0);%0D%0A                return 0;%0D%0A            %7D%0D%0A%0D%0A            // otherwise, find max%0D%0A            int maxDepth = 0;%0D%0A            for (final EntityModel childEntity : entity.getAllRefs()) %7B%0D%0A                maxDepth = Math.max(maxDepth, this.calculateDepth(childEntity));%0D%0A            %7D%0D%0A            // one higher than before%0D%0A            maxDepth++;%0D%0A            // save it for the future%0D%0A            this.depths.put(entity, maxDepth);%0D%0A            return maxDepth;%0D%0A%0D%0A            /*
 return depths.co
@@ -2642,16 +2642,16 @@
 lse(0)%0D%0A
-
         
@@ -2656,16 +2656,18 @@
       );
+*/
 %0D%0A      

Fix ConcurrentModificationException in EntityModelSorter