/// <summary>
        /// Apply the appropriate layout to the specified cluster and its children (bottom up)
        /// </summary>
        /// <param name="cluster">the root of the cluster hierarchy to lay out</param>
        /// <returns>list of edges external to the cluster</returns>
        void LayoutCluster(Cluster cluster) {
            if (cluster.IsCollapsed)
                return;

            LayoutAlgorithmSettings settings = clusterSettings(cluster);
            cluster.UnsetInitialLayoutState();
            if (runInParallel && cluster.Clusters.Count() > 1)
                Parallel.ForEach(cluster.Clusters, parallelOptions, LayoutCluster);
            else
                foreach (var cl in cluster.Clusters)
                    LayoutCluster(cl);

            List<GeometryGraph> components = (List<GeometryGraph>) GetComponents(cluster);

            //currentComponentFraction = (1.0 / clusterCount) / components.Count;

//            if (runInParallel)
//                Parallel.ForEach(components, parallelOptions, comp => LayoutComponent(settings, comp));
//            else // debug!!!!!!
                components.ForEach(c => LayoutComponent(settings, c));

            var bounds = MdsGraphLayout.PackGraphs(components, settings);

            foreach (var g in components)
                FixOriginalGraph(g, true);

            cluster.UpdateBoundary(bounds);

            cluster.SetInitialLayoutState(settings.ClusterMargin);
            cluster.RaiseLayoutDoneEvent();

//            var l = new List<DebugCurve>();
//            foreach (var node in cluster.Nodes) {
//                l.Add(new DebugCurve(node.BoundaryCurve));
//            }
//            foreach (var cl in cluster.AllClustersDepthFirstExcludingSelf()) {
//                l.Add(new DebugCurve(cl.BoundaryCurve));
//                l.AddRange(cl.Nodes.Select(n=>new DebugCurve(n.BoundaryCurve)));
//            }
//            LayoutAlgorithmSettings.ShowDebugCurves(l.ToArray());
        }
        /// <summary>
        /// Apply the appropriate layout to the specified cluster
        /// </summary>
        /// <param name="cluster">the root of the cluster hierarchy to lay out</param>
        /// <returns>list of edges external to the cluster</returns>
        void LayoutCluster(Cluster cluster) {
            ProgressStep();
            cluster.UnsetInitialLayoutState();
            FastIncrementalLayoutSettings settings = null;
            LayoutAlgorithmSettings s = clusterSettings(cluster);
            Directions layoutDirection = Directions.None;
            if (s is SugiyamaLayoutSettings) {
                var ss = s as SugiyamaLayoutSettings;
                settings = ss.FallbackLayoutSettings != null
                    ? new FastIncrementalLayoutSettings((FastIncrementalLayoutSettings) ss.FallbackLayoutSettings)
                    : new FastIncrementalLayoutSettings();
                layoutDirection = LayeredLayoutEngine.GetLayoutDirection(ss);
            }
            else {
                settings = new FastIncrementalLayoutSettings((FastIncrementalLayoutSettings) s);
            }

            settings.ApplyForces = true;
            settings.MinorIterations = 10;
            settings.AvoidOverlaps = true;
            settings.InterComponentForces = false;
            settings.IdealEdgeLength = new IdealEdgeLengthSettings {
                EdgeDirectionConstraints = layoutDirection,
                ConstrainedEdgeSeparation = 30
            };
            settings.EdgeRoutingSettings.EdgeRoutingMode = EdgeRoutingMode.Spline;

            HashSet<Node> addedNodes;
           
            if (addedNodesByCluster.TryGetValue(cluster, out addedNodes)) {
                // if the structure of the cluster has changed then we apply unconstrained layout first,
                // then introduce structural constraints, and then all constraints
                settings.MinConstraintLevel = 0;
                settings.MaxConstraintLevel = 2;
            }
            else
                settings.MinConstraintLevel = 2;

            GeometryGraph newGraph = GetShallowCopyGraphUnderCluster(cluster);
            LayoutAlgorithmHelpers.ComputeDesiredEdgeLengths(settings.IdealEdgeLength, newGraph);

            // orthogonal ordering constraints preserve the left-of, above-of relationships between existing nodes
            // (we do not apply these to the newly added nodes)
            GenerateOrthogonalOrderingConstraints(
                newGraph.Nodes.Where(v => !addedNodes.Contains(v.UserData as Node)).ToList(), settings);

            LayoutComponent(newGraph, settings);
            //LayoutAlgorithmSettings.ShowGraph(newGraph);
            InitialLayoutByCluster.FixOriginalGraph(newGraph, true);

            cluster.UpdateBoundary(newGraph.BoundingBox);
        }