public int ComparePeakLists(PeptideChromDataPeakList p1, PeptideChromDataPeakList p2)
        {
            // TODO: Do we want to keep this?
            // All identified peaks come first
            if (p1.IsIdentified != p2.IsIdentified)
            {
                return(p1.IsIdentified ? -1 : 1);
            }

            // Then order by CombinedScore descending
            return(Comparer <double> .Default.Compare(p2.CombinedScore, p1.CombinedScore));
        }
        /// <summary>
        /// Given a high scoring peak precursor peak group, find other lower scoring precursor peak
        /// groups from different precursors for the same peptide, which overlap in time with the
        /// high scoring peak.
        /// </summary>
        /// <param name="dataSets">Chromatogram data sets from which to create peptide peaks</param>
        /// <param name="dataPeakMax">High scoring precursor peak group</param>
        /// <param name="allPeakGroups">List of all lower scoring precursor peak groups for the same peptide</param>
        /// <returns>A list of coeluting precursor peak groups for this peptide</returns>
        private PeptideChromDataPeakList FindCoelutingPeptidePeaks(IEnumerable <ChromDataSet> dataSets,
                                                                   PeptideChromDataPeak dataPeakMax,
                                                                   IList <PeptideChromDataPeak> allPeakGroups)
        {
            TransitionGroupDocNode nodeGroupMax = dataPeakMax.Data.NodeGroup;
            int startMax = dataPeakMax.StartIndex;
            int endMax   = dataPeakMax.EndIndex;
            int timeMax  = dataPeakMax.TimeIndex;

            // Initialize the collection of peaks with this peak
            var listPeaks = new PeptideChromDataPeakList(NodePep, FileInfo, dataPeakMax);

            // Enumerate the precursors for this peptide
            foreach (var chromData in dataSets)
            {
                // Skip the precursor for the max peak itself
                if (ReferenceEquals(chromData, dataPeakMax.Data))
                {
                    continue;
                }

                int    iPeakBest   = -1;
                double bestProduct = 0;

                // Find nearest peak in remaining set that is less than 1/4 length
                // from the primary peak's center
                for (int i = 0, len = allPeakGroups.Count; i < len; i++)
                {
                    var peakGroup = allPeakGroups[i];
                    // Consider only peaks for the current precursor
                    if (!ReferenceEquals(peakGroup.Data, chromData))
                    {
                        continue;
                    }

                    // Exclude peaks that do not overlap with the maximum peak
                    TransitionGroupDocNode nodeGroup = peakGroup.Data.NodeGroup;
                    int startPeak = peakGroup.StartIndex;
                    int endPeak   = peakGroup.EndIndex;
                    if (Math.Min(endPeak, endMax) - Math.Max(startPeak, startMax) <= 0)
                    {
                        continue;
                    }

                    int timeIndex = peakGroup.TimeIndex;
                    if ((nodeGroup.RelativeRT == RelativeRT.Matching && nodeGroupMax.RelativeRT == RelativeRT.Matching) ||
                        // Matching label types (i.e. different charge states of same label type should always match)
                        ReferenceEquals(nodeGroup.TransitionGroup.LabelType, nodeGroupMax.TransitionGroup.LabelType))
                    {
                        // If the peaks are supposed to have the same elution time,
                        // then be more strict about how they overlap
                        if (startMax >= timeIndex || timeIndex >= endMax)
                        {
                            continue;
                        }
                    }
                    else if (nodeGroup.RelativeRT == RelativeRT.Matching && nodeGroupMax.RelativeRT == RelativeRT.Preceding)
                    {
                        // If the maximum is supposed to precede this, look for any
                        // indication that this relationship holds, by testing the peak apex
                        // and the peak center.
                        if (timeIndex < timeMax && (startPeak + endPeak) / 2 < (startMax + endMax) / 2)
                        {
                            continue;
                        }
                    }
                    else if (nodeGroup.RelativeRT == RelativeRT.Preceding && nodeGroupMax.RelativeRT == RelativeRT.Matching)
                    {
                        // If this peak is supposed to precede the maximum, look for any
                        // indication that this relationship holds, by testing the peak apex
                        // and the peak center.
                        if (timeIndex > timeMax && (startPeak + endPeak) / 2 > (startMax + endMax) / 2)
                        {
                            continue;
                        }
                    }

                    // Choose the next best peak that overlaps
                    if (peakGroup.PeakGroup.CombinedScore > bestProduct)
                    {
                        iPeakBest   = i;
                        bestProduct = peakGroup.PeakGroup.CombinedScore;
                    }
                }

                // If no coeluting peaks found, add an empty peak group
                if (iPeakBest == -1)
                {
                    listPeaks.Add(new PeptideChromDataPeak(chromData, null));
                }
                // Otherwise, add the found coeluting peak group, and remove it from the full list
                else
                {
                    listPeaks.Add(new PeptideChromDataPeak(chromData, allPeakGroups[iPeakBest].PeakGroup));
                    allPeakGroups.RemoveAt(iPeakBest);
                }
            }
            return(listPeaks);
        }