public static List <Tuple <Node, int, int> > SccOrdering(StrongComponent component)
        {
            if (component.nodes.Count <= 1)
            {
                return(component.nodes.Select(nd => new Tuple <Node, int, int>(nd, 0, 1)).ToList());
            }
            var ordering = SccBfsOrdering(component);
            var s        = ordering.First().Item2;
            var t        = ordering
                           .Aggregate(ordering.First().Item2, (res, cur) => res > cur.Item2 ? res : cur.Item2);
            var left     = ordering.Skip(1).TakeWhile(a => a.Item2 < t).ToList();
            var right    = ordering.SkipWhile(a => a.Item2 < t).Skip(1).ToList();
            var addition = 0;

            if (right.Count < 0 || right.Last().Item2 < 1)
            {
                addition = -right.Last().Item2 + 1;
            }

            var first = right
                        .Select(a => new Tuple <Node, int, int>(a.Item1, a.Item2 + addition, 2))
                        .Concat(left.Select(a => new Tuple <Node, int, int>(a.Item1, a.Item2, right.Count > 0 ? 0 : 1)));
            var second = first.Append(ordering.Take(1).Select(a => new Tuple <Node, int, int>(a.Item1, a.Item2, 1)).First());
            var third  = second.Append(ordering.SkipWhile(a => a.Item2 < t).Take(1)
                                       .Select(a => new Tuple <Node, int, int>(a.Item1, a.Item2, 1)).First());

            return(third.OrderBy(a => a.Item2).ToList());
        }
        private static List <System.Tuple <Node, int> > SccBfsOrdering(StrongComponent component)
        {
            //! only 1 outgoing, only 1 ingoing
            //! in general extremely bad approach causing many bugs => t doesnt have to be the only node on its layer found by bfs

            var s       = component.incoming.Count == 0 ? component.nodes.First() : component.incoming.First(); //!assuming they are already sorted (p0 < p1 < p2 < ...), and well, assuming there is only 1
            var t       = component.outgoing.Count == 0 ? component.nodes.Last() : component.outgoing.Last();
            var visited = component.nodes.ToDictionary(c => c, v => false);

            visited[s] = true;
            var order = new List <System.Tuple <Node, int> > {
                new System.Tuple <Node, int>(s, 0)
            };
            var queue = new Queue <System.Tuple <Node, int> >();

            queue.Enqueue(new System.Tuple <Node, int>(s, 0));
            while (queue.Count > 0)
            {
                var(node, ord) = queue.Dequeue();
                if (component.outgoing.Contains(node))
                {
                    continue;
                }

                foreach (var succ in node.succs
                         .Where(nd => component.nodes.Contains(nd.Item1))
                         .Select(tup => tup.Item1).Where(nd => !visited[nd]))
                {
                    order.Add(new System.Tuple <Node, int>(succ, ord + 1));
                    queue.Enqueue(order.Last());
                    visited[succ] = true;
                }
            }
            queue.Enqueue(order.Find(o => o.Item1.Equals(t)));
            while (queue.Count > 0)
            {
                var(node, ord) = queue.Dequeue();
                foreach (var succ in node.succs
                         .Where(nd => component.nodes.Contains(nd.Item1))
                         .Select(tup => tup.Item1).Where(nd => !visited[nd]))
                {
                    order.Add(new System.Tuple <Node, int>(succ, ord - 1));
                    queue.Enqueue(order.Last());
                    visited[succ] = true;
                }
            }

            return(order);
        }
        private static void TopoOnPetriGraph(Stack <StrongComponent> stack, StrongComponent component, int depth)
        {
            component.flag  = true;
            component.depth = depth;
            if (component.outside != null)
            {
                foreach (var outside in component.outside
                         .Where(outside => !outside.flag || outside.depth < depth + 1))
                {
                    TopoOnPetriGraph(stack, outside, depth + 1);
                }
            }

            stack.Push(component);
        }
        private static void FindInAndOut(StrongComponent c, List <Node> nodes)
        {
            var res  = new List <Node>();
            var res2 = new List <Node>();

            foreach (var cNode in c.nodes)
            {
                if (nodes.Exists(node => node.succs.Exists(nd => nd.Item1.Equals(cNode))))
                {
                    res.Add(cNode);
                }

                if (cNode.succs.Exists(nd => nodes.Exists(node => node.Equals(nd.Item1))))
                {
                    res2.Add(cNode);
                }
            }

            c.incoming = res.Count > 0 ? res : null;
            c.outgoing = res2.Count > 0 ? res2 : null;
        }