/// <summary>
        /// (1) -> [One] -> (3)-> [Three] -> (5)-> [Five] -> (6)
        /// Has a corresponding EventLog!
        /// </summary>
        /// <author>Thomas Meents</author>
        public static PetriNet OneThreeFive()
        {
            var petriNet = new PetriNet("OneThreeFive");

            var place1 = petriNet.AddPlace("1");
            var place3 = petriNet.AddPlace("3");
            var place5 = petriNet.AddPlace("5");
            var place6 = petriNet.AddPlace("6");

            petriNet.AddTransition("One", incomingPlace: place1, outgoingPlace: place3);
            petriNet.AddTransition("Three", incomingPlace: place3, outgoingPlace: place5);
            petriNet.AddTransition("Five", incomingPlace: place5, outgoingPlace: place6);

            return petriNet;
        }
        /// <summary>
        /// Adds a place and the transitions it leads to.
        /// </summary>
        /// <param name="startingTransition">>Contains the starting transition</param>
        /// <param name="followers">node.followers</param>
        /// <param name="petriNet">Contains the current petri net</param>
        /// <returns>The two transitions that are in an XOR-relation.</returns>
        /// <author>Jannik Arndt</author>
        public List<Transition> StartXOR(Transition startingTransition, List<EventNode> followers, PetriNet petriNet)
        {
            if (followers.Count > 1)
                for (var index = 0; index < followers.Count; index++)
                    _openParallelismCount.Push(Parallelism.Xor);

            var newPlace = petriNet.AddPlace();
            var listOfFollowingTransitions = new List<Transition>();
            foreach (var eventNode in followers)
            {
                if (eventNode == null)
                    break;
                /* _____________________          __________         ____________________________
                 * | startingTransition |  --->  ( NewPlace )  --->  |  NewFollowingTransition  |
                 * '''''''''''''''''''''          **********         ''''''''''''''''''''''''''''
                 */
                var newFollowingTransition = petriNet.FindTransition(eventNode.InnerEvent.Name);
                // The following transition already exists => close something
                if (newFollowingTransition != null)
                {
                    if (_openParallelismCount.Count > 0)
                        switch (_openParallelismCount.Peek())
                        {
                            // Close XOR
                            case Parallelism.Xor:
                                newFollowingTransition.IncomingPlaces.Remove(newPlace);
                                startingTransition.AddOutgoingPlace(newFollowingTransition.IncomingPlaces.First());
                                _openParallelismCount.Pop();
                                break;
                            // Close AND
                            case Parallelism.And:
                                newFollowingTransition.AddIncomingPlace(newPlace);
                                startingTransition.AddOutgoingPlace(newPlace);
                                _openParallelismCount.Pop();
                                break;
                        }
                }
                // Open XOR
                else
                {
                    newFollowingTransition = petriNet.AddTransition(eventNode.InnerEvent.Name, incomingPlace: newPlace);
                    if (newPlace.IncomingTransitions.Count == 0)
                        startingTransition.AddOutgoingPlace(newPlace);
                }

                listOfFollowingTransitions.Add(newFollowingTransition);

            }
            if (newPlace.IncomingTransitions.Count == 0 && newPlace.OutgoingTransitions.Count == 0)
                petriNet.Places.Remove(newPlace);
            return listOfFollowingTransitions;
        }
 /// <summary>
 /// Adds an optional Transition to the net, as well as the next mandatory transition.
 /// </summary>
 /// <param name="startingTransition">The existing transition</param>
 /// <param name="optionalAction">The optional transition</param>
 /// <param name="commonAction">The mandatory transition</param>
 /// <param name="petriNet"></param>
 /// <returns></returns>
 /// <author>Jannik Arndt</author>
 public List<Transition> StartOptionalTransition(Transition startingTransition, String optionalAction, String commonAction, PetriNet petriNet)
 {
     var place1 = petriNet.AddPlace();
     var place2 = petriNet.AddPlace();
     startingTransition.AddOutgoingPlace(place1);
     petriNet.AddTransition(optionalAction, incomingPlace: place1, outgoingPlace: place2);
     var commonTransition = petriNet.AddTransition(commonAction, new List<Place> { place1, place2 });
     return new List<Transition> { commonTransition };
 }
        /// <summary>
        /// Resolves a construct of three parallel events: a XOR ( b AND c )
        /// </summary>
        /// <param name="event1">Event number one</param>
        /// <param name="a">An Event node</param>
        /// <param name="b">An Event node</param>
        /// <param name="c">An Event node</param>
        /// <param name="petriNet">The current petri net</param>
        /// <returns>A list with final transition</returns>
        /// <author>Jannik Arndt</author>
        public List<Transition> StartAxor_BandC(Transition event1, EventNode a, EventNode b, EventNode c, PetriNet petriNet)
        {
            var finalTransition = petriNet.AddTransition(); // empty transition, will possibly be cleaned up
            finalTransition.Name = FindFirstCommonSuccessor(new List<EventNode> { a, b, c });

            var xorTransition = StartXOR(event1, new List<EventNode> { a }, petriNet);
            EndXOR(xorTransition, petriNet, finalTransition);

            var andSplit = petriNet.AddTransition(); // no idea where this disappears...
            andSplit.AddIncomingPlace(xorTransition[0].IncomingPlaces[0]); // XOR-Split-Place

            var andTransition = StartAND(andSplit, new List<EventNode> { b, c }, petriNet);
            var andJoin = petriNet.AddTransition("AND Join");
            andJoin.IsANDJoin = true;
            var andTransition2 = EndAND(andTransition, petriNet, andJoin);

            andTransition2[0].AddOutgoingPlace(finalTransition.IncomingPlaces.FirstOrDefault());

            return new List<Transition> { finalTransition };
        }
        /// <summary>
        /// Adds as many places as following events that each lead to a transition.
        /// </summary>
        /// <param name="startingTransition">Contains the starting transition</param>
        /// <param name="followers">node.followers</param>
        /// <param name="petriNet">Contains the current petri net</param>
        /// <returns>The transitions that are in an AND-relation.</returns>
        /// <author>Jannik Arndt</author>
        public List<Transition> StartAND(Transition startingTransition, List<EventNode> followers, PetriNet petriNet)
        {
            for (var index = 0; index < followers.Count; index++)
                _openParallelismCount.Push(Parallelism.And);
            var listOfFollowingTransitions = new List<Transition>();

            if (startingTransition.Name == "")
                startingTransition.Name = "AND Split";
            startingTransition.IsANDSplit = true;

            foreach (var node in followers)
            {
                var newPlace = petriNet.AddPlace();

                listOfFollowingTransitions.Add(petriNet.AddTransition(node.InnerEvent.Name, incomingPlace: newPlace));
                startingTransition.AddOutgoingPlace(newPlace);
            }
            return listOfFollowingTransitions;
        }
        /// <summary>
        /// Resolves a construct of three parallel events: a AND ( b XOR c )        
        /// </summary>
        /// <param name="event1">One event</param>
        /// <param name="a">An event node</param>
        /// <param name="b">An event node</param>
        /// <param name="c">An event node</param>
        /// <param name="petriNet">Current petri net</param>
        /// <returns>A list with final transitions</returns>
        /// <author>Jannik Arndt</author>
        public List<Transition> StartAand_BxorC(Transition event1, EventNode a, EventNode b, EventNode c, PetriNet petriNet)
        {
            var finalTransition = petriNet.AddTransition("AND Join");
            finalTransition.IsANDJoin = true;

            var andTransition = StartAND(event1, new List<EventNode> { a }, petriNet);
            EndAND(andTransition, petriNet, finalTransition);

            var xorTransition = StartXOR(event1, new List<EventNode> { b, c }, petriNet);
            EndXOR(xorTransition, petriNet, finalTransition);

            return new List<Transition> { finalTransition };
        }
 /// <summary>
 /// Connects all open endings to one end-place. This is useful for multiple processmodels in one net or for loops at the end of the net.
 /// </summary>
 /// <param name="petriNet">A petrinet with possible open endings</param>
 /// <returns>The given PetriNet with a fixed ending</returns>
 /// <author>Jannik Arndt</author>
 public PetriNet FixEnding(PetriNet petriNet)
 {
     if (petriNet.GetTransitionsWithoutFollowersIgnoreLoops().Count > 0)
     {
         var endingPlace = petriNet.AddPlace("End");
         foreach (var transition in petriNet.GetTransitionsWithoutFollowersIgnoreLoops())
         {
             if (transition.OutgoingPlaces.Count > 0)
             {
                 var temporaryTransition = petriNet.AddTransition();
                 transition.OutgoingPlaces[0].AppendOutgoingTransition(temporaryTransition);
                 temporaryTransition.AddIncomingPlace(transition.OutgoingPlaces[0]);
                 temporaryTransition.AddOutgoingPlace(endingPlace);
             }
             else
                 transition.AddOutgoingPlace(endingPlace);
         }
     }
     return petriNet;
 }
        /// <summary>
        /// Adds a place and connects the open transitions to it. Then puts the given transition behind that whole thing.
        /// </summary>
        /// <param name="startingTransition">The starting transition</param>
        /// <param name="petriNet">The current petri net</param>
        /// <param name="endingTransition">The ending transition, if it exists already. Otherwise a new one is created.</param>
        /// <returns>The empty transition after the place that combines to XOR.</returns>
        /// <author>Jannik Arndt</author>
        public List<Transition> EndXOR(List<Transition> startingTransition, PetriNet petriNet, Transition endingTransition = null)
        {
            if (endingTransition == null)
                endingTransition = petriNet.AddTransition();

            if (_openParallelismCount.Count > 0)
                _openParallelismCount.Pop();

            var newPlace = petriNet.AddPlace();
            foreach (var transition in startingTransition)
                transition.AddOutgoingPlace(newPlace);
            endingTransition.AddIncomingPlace(newPlace);
            return new List<Transition> { endingTransition };
        }
        /// <summary>
        /// Adds a place for each transition, then combines these places in the given transition.
        /// </summary>
        /// <param name="startingTransition">The starting transition</param>
        /// <param name="petriNet">The current petri net</param>
        /// <param name="endingTransition">The ending transition, if it exists already. Otherwise a new one is created></param>
        /// <returns>The transition where the places after the AND-related-events are connected.</returns>
        /// <author>Jannik Arndt</author>
        public List<Transition> EndAND(List<Transition> startingTransition, PetriNet petriNet, Transition endingTransition = null)
        {
            if (endingTransition == null)
                endingTransition = petriNet.AddTransition();

            if (_openParallelismCount.Count > 0)
                _openParallelismCount.Pop();

            var listOfClosingPlaces = new List<Place>();
            foreach (var transition in startingTransition)
            {
                var newPlace = petriNet.AddPlace();
                transition.AddOutgoingPlace(newPlace);
                listOfClosingPlaces.Add(newPlace);
            }
            endingTransition.AddIncomingPlaces(listOfClosingPlaces);
            return new List<Transition> { endingTransition };
        }
        /// <summary>
        /// Goes through the dependency-graph and creates a petrinet.
        /// </summary>
        /// <param name="dependencyGraph">An EventNode from CreateDependencyGraph()</param>
        /// <param name="eventLog">The EventLog to calculate AND and XOR-relations</param>
        /// <param name="name">The name of the new PetriNet</param>
        /// <returns>A complete petrinet</returns>
        /// <author>Jannik Arndt, Bernhard Bruns</author>
        public PetriNet CreatePetriNetFromDependencyGraph(EventNode dependencyGraph, EventLog eventLog, string name)
        {
            var petriNet = new PetriNet(name);

            // 1. first event
            var startingPlace = petriNet.AddPlace("", 1);
            var firstEvent = petriNet.AddTransition(dependencyGraph.InnerEvent.Name, incomingPlace: startingPlace);

            // 2. Go through the net and turn Nodes into Places and Transitions, with parallel structures
            HandleNodesAndCloseParallelisms(firstEvent, dependencyGraph, eventLog, petriNet);

            // 3. handle loops
            petriNet = HandleLoops(eventLog, petriNet);

            return petriNet;
        }