// Path: src/main/java/com/groupon/vertx/utils/util/Digraph.java
// public class Digraph<E> {
//     private Set<E> nodes;
//     private final Map<E, Set<E>> adjacent;
// 
//     public Digraph() {
//         this(0);
//     }
// 
//     public Digraph(int initialCapacity) {
//         nodes = new HashSet<>(initialCapacity);
//         adjacent = new ConcurrentHashMap<>(initialCapacity);
//     }
// 
//     public void addNode(E v) {
//         nodes.add(v);
//     }
// 
//     public void addEdge(E v, E w) {
//         if (!nodes.contains(v) || !nodes.contains(w)) {
//             throw new IllegalStateException("Both nodes must already exist in the graph prior to adding a connecting edge");
//         }
// 
//         Set<E> set = adjacent.get(v);
// 
//         if (set == null) {
//             set = Collections.synchronizedSet(new HashSet<E>());
//             adjacent.put(v, set);
//         }
// 
//         set.add(w);
//     }
// 
//     public Set<E> getNodes() {
//         return Collections.unmodifiableSet(nodes);
//     }
// 
//     public Iterable<E> getAdjacent(E v) {
//         Set<E> set = adjacent.get(v);
// 
//         if (set == null) {
//             set = Collections.emptySet();
//         }
// 
//         return Collections.unmodifiableSet(set);
//     }
// 
//     @Override
//     public String toString() {
//         StringBuilder sb = new StringBuilder("Digraph[");
//         for (Map.Entry<E, Set<E>> entry : adjacent.entrySet()) {
//             E v = entry.getKey();
//             for (E w : entry.getValue()) {
//                 sb.append("[");
//                 sb.append(v.toString());
//                 sb.append(" --> ");
//                 sb.append(w.toString());
//                 sb.append("]");
//             }
//         }
//         sb.append("]");
//         return sb.toString();
//     }
// }
// 
// Path: src/main/java/com/groupon/vertx/utils/util/TopSorter.java
// public class TopSorter<E> {
//     private final Digraph<E> digraph;
// 
//     public TopSorter(Digraph<E> digraph) {
//         this.digraph = digraph;
//     }
// 
//     public List<E> sort() {
//         Set<E> nodes = digraph.getNodes();
// 
//         List<E> result = new ArrayList<>(nodes.size());
//         Set<E> flagged = new HashSet<>(nodes.size());
//         Set<E> visited = new HashSet<>(nodes.size());
// 
//         for (E node : nodes) {
//             visit(node, result, flagged, visited);
//         }
// 
//         return result;
//     }
// 
//     private void visit(E node, List<E> result, Set<E> flagged, Set<E> visited) {
//         if (flagged.contains(node)) {
//             throw new IllegalStateException("Cycle detected; can only sort directed acyclic graphs");
//         }
// 
//         if (!visited.contains(node)) {
// 
//             flagged.add(node);
//             for (E edgeNode : digraph.getAdjacent(node)) {
//                 visit(edgeNode, result, flagged, visited);
//             }
// 
//             flagged.remove(node);
//             visited.add(node);
//             result.add(node);
//         }
//     }
// }


import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import io.vertx.core.json.JsonObject;
import com.groupon.vertx.utils.util.Digraph;
import com.groupon.vertx.utils.util.TopSorter;
/**
 * Copyright 2015 Groupon.com
 *
 * 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.groupon.vertx.utils.config;




/**
 * Deployment configuration
 *
 * @author Tristan Blease (tblease at groupon dot com)
 * @since 2.0.2
 * @version 2.0.2
 */
public class Config implements Iterable<VerticleConfig> {
    private static final String VERTICLES_FIELD = "verticles";

    private int total;
    private Map<String, VerticleConfig> verticles;
    private List<VerticleConfig> orderedVerticles;

    public Config(JsonObject config) {
        final JsonObject verticleJson = config.getJsonObject(VERTICLES_FIELD);
        if (verticleJson == null) {
            throw new IllegalStateException("Required config field `" + VERTICLES_FIELD + "` is missing");
        }

        Set<String> verticleNames = verticleJson.fieldNames();

        total = verticleNames.size();
        verticles = new ConcurrentHashMap<>(total);

        for (String verticleName : verticleNames) {
            JsonObject verticleConfig = verticleJson.getJsonObject(verticleName);
            verticles.put(verticleName, new VerticleConfig(verticleName, verticleConfig));
        }

        determineLoadOrder();
    }

    private void determineLoadOrder() {
// Path: src/main/java/com/groupon/vertx/utils/util/Digraph.java
// public class Digraph<E> {
//     private Set<E> nodes;
//     private final Map<E, Set<E>> adjacent;
// 
//     public Digraph() {
//         this(0);
//     }
// 
//     public Digraph(int initialCapacity) {
//         nodes = new HashSet<>(initialCapacity);
//         adjacent = new ConcurrentHashMap<>(initialCapacity);
//     }
// 
//     public void addNode(E v) {
//         nodes.add(v);
//     }
// 
//     public void addEdge(E v, E w) {
//         if (!nodes.contains(v) || !nodes.contains(w)) {
//             throw new IllegalStateException("Both nodes must already exist in the graph prior to adding a connecting edge");
//         }
// 
//         Set<E> set = adjacent.get(v);
// 
//         if (set == null) {
//             set = Collections.synchronizedSet(new HashSet<E>());
//             adjacent.put(v, set);
//         }
// 
//         set.add(w);
//     }
// 
//     public Set<E> getNodes() {
//         return Collections.unmodifiableSet(nodes);
//     }
// 
//     public Iterable<E> getAdjacent(E v) {
//         Set<E> set = adjacent.get(v);
// 
//         if (set == null) {
//             set = Collections.emptySet();
//         }
// 
//         return Collections.unmodifiableSet(set);
//     }
// 
//     @Override
//     public String toString() {
//         StringBuilder sb = new StringBuilder("Digraph[");
//         for (Map.Entry<E, Set<E>> entry : adjacent.entrySet()) {
//             E v = entry.getKey();
//             for (E w : entry.getValue()) {
//                 sb.append("[");
//                 sb.append(v.toString());
//                 sb.append(" --> ");
//                 sb.append(w.toString());
//                 sb.append("]");
//             }
//         }
//         sb.append("]");
//         return sb.toString();
//     }
// }
// 
// Path: src/main/java/com/groupon/vertx/utils/util/TopSorter.java
// public class TopSorter<E> {
//     private final Digraph<E> digraph;
// 
//     public TopSorter(Digraph<E> digraph) {
//         this.digraph = digraph;
//     }
// 
//     public List<E> sort() {
//         Set<E> nodes = digraph.getNodes();
// 
//         List<E> result = new ArrayList<>(nodes.size());
//         Set<E> flagged = new HashSet<>(nodes.size());
//         Set<E> visited = new HashSet<>(nodes.size());
// 
//         for (E node : nodes) {
//             visit(node, result, flagged, visited);
//         }
// 
//         return result;
//     }
// 
//     private void visit(E node, List<E> result, Set<E> flagged, Set<E> visited) {
//         if (flagged.contains(node)) {
//             throw new IllegalStateException("Cycle detected; can only sort directed acyclic graphs");
//         }
// 
//         if (!visited.contains(node)) {
// 
//             flagged.add(node);
//             for (E edgeNode : digraph.getAdjacent(node)) {
//                 visit(edgeNode, result, flagged, visited);
//             }
// 
//             flagged.remove(node);
//             visited.add(node);
//             result.add(node);
//         }
//     }
// }


// Path: src/main/java/com/groupon/vertx/utils/config/Config.java
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import io.vertx.core.json.JsonObject;
import com.groupon.vertx.utils.util.Digraph;
import com.groupon.vertx.utils.util.TopSorter;

/**
 * Copyright 2015 Groupon.com
 *
 * 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.groupon.vertx.utils.config;




/**
 * Deployment configuration
 *
 * @author Tristan Blease (tblease at groupon dot com)
 * @since 2.0.2
 * @version 2.0.2
 */
public class Config implements Iterable<VerticleConfig> {
    private static final String VERTICLES_FIELD = "verticles";

    private int total;
    private Map<String, VerticleConfig> verticles;
    private List<VerticleConfig> orderedVerticles;

    public Config(JsonObject config) {
        final JsonObject verticleJson = config.getJsonObject(VERTICLES_FIELD);
        if (verticleJson == null) {
            throw new IllegalStateException("Required config field `" + VERTICLES_FIELD + "` is missing");
        }

        Set<String> verticleNames = verticleJson.fieldNames();

        total = verticleNames.size();
        verticles = new ConcurrentHashMap<>(total);

        for (String verticleName : verticleNames) {
            JsonObject verticleConfig = verticleJson.getJsonObject(verticleName);
            verticles.put(verticleName, new VerticleConfig(verticleName, verticleConfig));
        }

        determineLoadOrder();
    }

    private void determineLoadOrder() {
        Digraph<VerticleConfig> dependencyGraph = new Digraph<>(verticles.size());