public void Add(PrecursorSchedule schedule)
 {
     TransitionCount += schedule.TransitionCount;
     _precursorSchedules.Add(schedule);
 }
        private void ExportScheduledBuckets(FileIterator fileIterator)
        {
            if (!MaxTransitions.HasValue)
            {
                throw new InvalidOperationException(Resources.AbstractMassListExporter_ExportScheduledBuckets_Maximum_transitions_per_file_required);
            }

            bool singleWindow = ExportInstrumentType.IsSingleWindowInstrumentType(InstrumentType);

            var predict            = Document.Settings.PeptideSettings.Prediction;
            int?maxInstrumentTrans = null;

            if (!IsPrecursorLimited)
            {
                maxInstrumentTrans = Document.Settings.TransitionSettings.Instrument.MaxTransitions;
            }
            var listSchedules   = new List <PeptideSchedule>();
            var listRequired    = new List <PeptideSchedule>();
            var listUnscheduled = new List <PeptideSchedule>();

            foreach (PeptideGroupDocNode nodePepGroup in Document.MoleculeGroups)
            {
                foreach (PeptideDocNode nodePep in nodePepGroup.Children)
                {
                    var peptideSchedule = new PeptideSchedule(nodePep, maxInstrumentTrans);
                    foreach (TransitionGroupDocNode nodeTranGroup in nodePep.Children)
                    {
                        double timeWindow;
                        double retentionTime = predict.PredictRetentionTime(Document, nodePep, nodeTranGroup, SchedulingReplicateIndex,
                                                                            SchedulingAlgorithm, singleWindow, out timeWindow) ?? 0;
                        var nodeTranGroupPrimary = PrimaryTransitionCount > 0
                                                   ? nodePep.GetPrimaryResultsGroup(nodeTranGroup)
                                                   : null;

                        var ps = new PrecursorSchedule(nodePepGroup,
                                                       nodePep,
                                                       nodeTranGroup,
                                                       nodeTranGroupPrimary,
                                                       retentionTime,
                                                       timeWindow,
                                                       IsPrecursorLimited,
                                                       SchedulingReplicateIndex,
                                                       PrimaryTransitionCount,
                                                       OptimizeStepCount);
                        peptideSchedule.Add(ps);
                    }
                    if (RequiredPeptides.IsRequired(nodePep))
                    {
                        if (!peptideSchedule.CanSchedule)
                        {
                            throw new IOException(string.Format(Resources.AbstractMassListExporter_ExportScheduledBuckets_The_required_peptide__0__cannot_be_scheduled,
                                                                Document.Settings.GetDisplayName(nodePep)));
                        }
                        listRequired.Add(peptideSchedule);
                    }
                    else if (peptideSchedule.CanSchedule)
                    {
                        listSchedules.Add(peptideSchedule);
                    }
                    else
                    {
                        listUnscheduled.Add(peptideSchedule);
                    }
                }
            }

            int totalScheduled      = 0;
            var listScheduleBuckets = new List <PeptideScheduleBucket>();

            while (!PeptideSchedule.IsListScheduled(listSchedules))
            {
                var listScheduleNext = new PeptideScheduleBucket();
                // First add all required transitions
                foreach (var schedule in listRequired)
                {
                    schedule.Schedule(listScheduleNext, MaxTransitions.Value);
                }
                // Then try to add from the scheduling list
                foreach (var schedule in listSchedules)
                {
                    schedule.Schedule(listScheduleNext, MaxTransitions.Value);
                }
                // Throw an error if nothing beyond the required transitions could be added
                if (listScheduleNext.TransitionCount == RequiredPeptides.TransitionCount)
                {
                    string itemName = IsPrecursorLimited
                                          ? Resources.AbstractMassListExporter_ExportScheduledBuckets_precursors
                                          : Resources.AbstractMassListExporter_ExportScheduledBuckets_transitions;
                    var sb = new StringBuilder();
                    foreach (var peptideSchedule in listSchedules)
                    {
                        if (peptideSchedule.TransitionCount > MaxTransitions.Value)
                        {
                            sb.AppendLine(string.Format("{0} - {1} {2}", // Not L10N
                                                        peptideSchedule.Peptide.Peptide,
                                                        peptideSchedule.TransitionCount,
                                                        itemName));
                        }
                    }

                    var message = new StringBuilder(Resources.AbstractMassListExporter_ExportScheduledBuckets_Failed_to_schedule_the_following_peptides_with_the_current_settings);
                    message.AppendLine().AppendLine().AppendLine(sb.ToString());
                    if (OptimizeStepCount == 0)
                    {
                        message.AppendLine().AppendLine(string.Format(Resources.AbstractMassListExporter_ExportScheduledBuckets_Check_max_concurrent__0__count, itemName));
                    }
                    else
                    {
                        message.Append(string.Format(Resources.AbstractMassListExporter_ExportScheduledBuckets_Check_max_concurrent__0__count_and_optimization_step_count, itemName));
                    }
                    throw new IOException(message.ToString());
                }
                listScheduleBuckets.Add(listScheduleNext);
                totalScheduled += listScheduleNext.TransitionCount;
            }

            int countScheduleGroups = listScheduleBuckets.Count;

            if (countScheduleGroups > 1)
            {
                // Balance the scheduling buckets to counteract the tendancy for each
                // successive bucket to have fewer transitions than the previous.
                // CONSIDER: O(n^2) but number of groups should never get that large
                int balanceCount = totalScheduled / countScheduleGroups;

                for (int i = 0; i < countScheduleGroups; i++)
                {
                    var bucketUnder = listScheduleBuckets[i];
                    if (bucketUnder.TransitionCount >= balanceCount)
                    {
                        continue;
                    }

                    // It should not be possible to borrow from scheduling lists
                    // after the current list, since the reason they are there is
                    // that they had too much overlap to be included in any of the
                    // preceding buckets.
                    for (int j = 0; j < i; j++)
                    {
                        var bucketOver = listScheduleBuckets[j];
                        if (bucketOver.TransitionCount <= balanceCount)
                        {
                            continue;
                        }
                        BorrowTransitions(bucketUnder, bucketOver, balanceCount);
                        // If the under bucket ever goes over balance, then quit.
                        if (bucketUnder.Count > balanceCount)
                        {
                            break;
                        }
                    }
                }
            }

            foreach (var listScheduleNext in listScheduleBuckets)
            {
                WriteScheduledList(fileIterator, listScheduleNext);
            }
            WriteScheduledList(fileIterator, listUnscheduled);
        }