private List <WixActionSymbol> ScheduleActions(Dictionary <string, WixActionSymbol> requiredActionSymbols) { var scheduledActionSymbols = new List <WixActionSymbol>(); // Process each sequence table individually. foreach (SequenceTable sequenceTable in Enum.GetValues(typeof(SequenceTable))) { // Create a collection of just the action symbols in this sequence var sequenceActionSymbols = requiredActionSymbols.Values.Where(a => a.SequenceTable == sequenceTable).ToList(); // Schedule the absolutely scheduled actions (by sorting them by their sequence numbers). var absoluteActionSymbols = new List <WixActionSymbol>(); foreach (var actionSymbol in sequenceActionSymbols) { if (actionSymbol.Sequence.HasValue) { // Look for sequence number collisions foreach (var sequenceScheduledActionSymbol in absoluteActionSymbols) { if (sequenceScheduledActionSymbol.Sequence == actionSymbol.Sequence) { this.Messaging.Write(WarningMessages.ActionSequenceCollision(actionSymbol.SourceLineNumbers, actionSymbol.SequenceTable.ToString(), actionSymbol.Action, sequenceScheduledActionSymbol.Action, actionSymbol.Sequence ?? 0)); if (null != sequenceScheduledActionSymbol.SourceLineNumbers) { this.Messaging.Write(WarningMessages.ActionSequenceCollision2(sequenceScheduledActionSymbol.SourceLineNumbers)); } } } absoluteActionSymbols.Add(actionSymbol); } } absoluteActionSymbols.Sort((x, y) => (x.Sequence ?? 0).CompareTo(y.Sequence ?? 0)); // Schedule the relatively scheduled actions (by resolving the dependency trees). var previousUsedSequence = 0; var relativeActionSymbols = new List <WixActionSymbol>(); for (int j = 0; j < absoluteActionSymbols.Count; j++) { var absoluteActionSymbol = absoluteActionSymbols[j]; // Get all the relatively scheduled action symbols occuring before and after this absolutely scheduled action symbol. var relativeActions = this.GetAllRelativeActionsForSequenceType(sequenceTable, absoluteActionSymbol); // Check for relatively scheduled actions occuring before/after a special action // (those actions with a negative sequence number). if (absoluteActionSymbol.Sequence < 0 && (relativeActions.PreviousActions.Any() || relativeActions.NextActions.Any())) { // Create errors for all the before actions. foreach (var actionSymbol in relativeActions.PreviousActions) { this.Messaging.Write(ErrorMessages.ActionScheduledRelativeToTerminationAction(actionSymbol.SourceLineNumbers, actionSymbol.SequenceTable.ToString(), actionSymbol.Action, absoluteActionSymbol.Action)); } // Create errors for all the after actions. foreach (var actionSymbol in relativeActions.NextActions) { this.Messaging.Write(ErrorMessages.ActionScheduledRelativeToTerminationAction(actionSymbol.SourceLineNumbers, actionSymbol.SequenceTable.ToString(), actionSymbol.Action, absoluteActionSymbol.Action)); } // If there is source line information for the absolutely scheduled action display it if (absoluteActionSymbol.SourceLineNumbers != null) { this.Messaging.Write(ErrorMessages.ActionScheduledRelativeToTerminationAction2(absoluteActionSymbol.SourceLineNumbers)); } continue; } // Schedule the action symbols before this one. var unusedSequence = absoluteActionSymbol.Sequence - 1; for (var i = relativeActions.PreviousActions.Count - 1; i >= 0; i--) { var relativeActionSymbol = relativeActions.PreviousActions[i]; // look for collisions if (unusedSequence == previousUsedSequence) { this.Messaging.Write(ErrorMessages.NoUniqueActionSequenceNumber(relativeActionSymbol.SourceLineNumbers, relativeActionSymbol.SequenceTable.ToString(), relativeActionSymbol.Action, absoluteActionSymbol.Action)); if (absoluteActionSymbol.SourceLineNumbers != null) { this.Messaging.Write(ErrorMessages.NoUniqueActionSequenceNumber2(absoluteActionSymbol.SourceLineNumbers)); } unusedSequence++; } relativeActionSymbol.Sequence = unusedSequence; relativeActionSymbols.Add(relativeActionSymbol); unusedSequence--; } // Determine the next used action sequence number. var nextUsedSequence = Int16.MaxValue + 1; if (absoluteActionSymbols.Count > j + 1) { nextUsedSequence = absoluteActionSymbols[j + 1].Sequence ?? 0; } // Schedule the action symbols after this one. unusedSequence = absoluteActionSymbol.Sequence + 1; for (var i = 0; i < relativeActions.NextActions.Count; i++) { var relativeActionSymbol = relativeActions.NextActions[i]; if (unusedSequence == nextUsedSequence) { this.Messaging.Write(ErrorMessages.NoUniqueActionSequenceNumber(relativeActionSymbol.SourceLineNumbers, relativeActionSymbol.SequenceTable.ToString(), relativeActionSymbol.Action, absoluteActionSymbol.Action)); if (absoluteActionSymbol.SourceLineNumbers != null) { this.Messaging.Write(ErrorMessages.NoUniqueActionSequenceNumber2(absoluteActionSymbol.SourceLineNumbers)); } unusedSequence--; } relativeActionSymbol.Sequence = unusedSequence; relativeActionSymbols.Add(relativeActionSymbol); unusedSequence++; } // keep track of this sequence number as the previous used sequence number for the next iteration previousUsedSequence = absoluteActionSymbol.Sequence ?? 0; } // add the absolutely and relatively scheduled actions to the list of scheduled actions scheduledActionSymbols.AddRange(absoluteActionSymbols); scheduledActionSymbols.AddRange(relativeActionSymbols); } return(scheduledActionSymbols); }