private MassSpectrumCollection NMerge(IEnumerable <MassSpectrum> spectra)
        {
            List <double> lowers = new List <double> {
                this.seg1Low.Value, this.seg2Low.Value, this.seg3Low.Value
            };
            List <double> uppers = new List <double> {
                this.seg1Upp.Value, this.seg2Upp.Value, this.seg3Upp.Value
            };

            int nSpecs = spectra.Aggregate(0, (x, y) => x + 1);

            int count = 0;
            int segs  = this.nSegs.Value;

            lowers = lowers.GetRange(0, segs);
            uppers = uppers.GetRange(0, segs);


            // Find if offset needed
            double[] overlaps = new double[nSegs.Value];
            foreach (int i in Enumerable.Range(0, segs))
            {
                overlaps[i] = Math.Min(spectra.ElementAt(0).Header.HighPosition, uppers[i]) -
                              Math.Max(spectra.ElementAt(0).Header.LowPosition, lowers[i]);
            }
            int offset = overlaps.ToList().IndexOf(overlaps.Max());

            MassSpectrumCollection massSpectrumCollection = new MassSpectrumCollection((int)(nSpecs / (double)segs));

            int nCentsY = 0;
            int nCentsN = 0;

            int nCentsYtot = 0;
            int nCentsNtot = 0;
            int nSpecStart = nSpecs;

            base.WriteLogMessage(MessageLevel.Info, "Starting - Number of Specs: {0}", nSpecs);
            MassSpectrum buildingSpec = null;

            foreach (MassSpectrum spec in spectra)
            {
                // base.WriteLogMessage(MessageLevel.Info, "Mahieu.NMerge - Header. {0} - {1} - {2} - {3}", spec.Header.ScanRange, spec.Header.MasterScanRange, spec.Header.ScanNumbers, spec.Header.MasterScanNumbers);
                // base.WriteLogMessage(MessageLevel.Info, "Mahieu.NMerge - {0} - {1} - {2} - {3}", spec.ScanEvent.IsolationOffset, spec.Header.MasterScanRange, spec.Header.ScanNumbers, spec.Header.MasterScanNumbers);


                int currentSeg       = (int)(count % segs);
                int currentSegBounds = (int)((count + offset) % segs);

                if (count > 0 & currentSeg == 0)
                {
                    //buildingSpec.Header.HighPosition = buildingSpec.PeakCentroids.FindClosestPeak(10000).Position;
                    //buildingSpec.Header.LowPosition = buildingSpec.PeakCentroids.FindClosestPeak(0).Position;

                    buildingSpec.Header.HighPosition = uppers.Max();
                    buildingSpec.Header.LowPosition  = lowers.Min();

                    buildingSpec.Header.BasePeakIntensity = buildingSpec.PeakCentroids.FindMostIntensePeak().Intensity;
                    buildingSpec.Header.BasePeakPosition  = buildingSpec.PeakCentroids.FindMostIntensePeak().Position;
                    buildingSpec.Header.TotalIntensity    = buildingSpec.PeakCentroids.Aggregate(0.0, (x, y) => x + y.Intensity);

                    // fake it. important?
                    buildingSpec.ScanEvent.IsolationMass  = (uppers.Max() + lowers.Min()) / 2;
                    buildingSpec.ScanEvent.IsolationWidth = (uppers.Max() - lowers.Min());

                    if (!buildingSpec.IsValid)
                    {
                        base.WriteLogMessage(MessageLevel.Info, "Building Spec Invalid");
                    }

                    // spec.Precursor.IsolationMass, spec.Precursor.IonInjectTime, spec.Precursor.IsolationWindow = 0; spec.Precursor.MeasuredMonoisotopicPeakCentroids is empty.
                    // spec.Traits mostly mass accuracy, should be invariant
                    // spec.ScanEvent Isolation mass and such could be important
                    // spec.Header - appears to be important.

                    // Every nSegs specs add the merged spec to the collection and start a new one.
                    massSpectrumCollection.Add(buildingSpec);

                    nCentsY    = buildingSpec.PeakCentroids.Aggregate(0, (x, y) => x + 1);
                    nCentsYtot = nCentsYtot + nCentsY;

                    if (nCentsY < nCentsN)
                    {
                        base.WriteLogMessage(MessageLevel.Warn, "Number of centroids kept ({0}) is smaller than number of centroids discarded ({1}). Are scan segments defined appropriately?", nCentsY, nCentsN);
                    }

                    if ((double)count % (nSpecs / 4) == 0)
                    {
                        base.WriteLogMessage(MessageLevel.Info, "Spot Check - Centroids kept: {0}; Centroids discarded {1}.", nCentsY, nCentsN);
                    }
                    nCentsNtot = nCentsNtot + nCentsN;
                    nCentsY    = 0;
                    nCentsN    = 0;
                }
                if (currentSeg == 0)
                {
                    buildingSpec           = new MassSpectrum();
                    buildingSpec.Header    = spec.Header;
                    buildingSpec.ScanEvent = spec.ScanEvent;
                    buildingSpec.Precursor = spec.Precursor;

                    int ncents = buildingSpec.PeakCentroids.Aggregate(0, (x, y) => x + 1);
                    int nprofs = buildingSpec.ProfilePoints.Aggregate(0, (x, y) => x + 1);

                    buildingSpec.PeakCentroids = new MassCentroidCollection(ncents * 4);
                    buildingSpec.ProfilePoints = new SpectrumPointCollection(nprofs * 4);

                    // buildingSpec = spec;
                }

                // Merge current scan with buildingSpec
                //base.WriteLogMessage(MessageLevel.Info, "Mahieu.NMerge - Current Segment {0}.", currentSeg);

                // base.WriteLogMessage(MessageLevel.Info, "Mahieu.NMerge - Precursor Info. {0}", spec.Precursor.MeasuredMonoisotopicPeakCentroids.Max(t => t.Position));
                // base.WriteLogMessage(MessageLevel.Info, "Mahieu.NMerge - Precursor Info. {0} - {1} - {2}", spec.ScanEvent.IsolationWidth, spec.ScanEvent.IsolationMass, spec.ScanEvent.IsolationWindow);

                foreach (MassCentroid m in spec.PeakCentroids)
                {
                    if ((m.Position >= lowers[currentSegBounds]) && (m.Position < uppers[currentSegBounds]))
                    {
                        buildingSpec.PeakCentroids.Add(m);
                    }
                    else
                    {
                        nCentsN = nCentsN + 1;
                        // base.WriteLogMessage(MessageLevel.Info, "Mahieu.NMerge - Discarded Centroid.");
                    }
                }

                foreach (SpectrumPoint m in spec.ProfilePoints)
                {
                    if ((m.Position >= lowers[currentSegBounds]) && (m.Position < uppers[currentSegBounds]))
                    {
                        buildingSpec.ProfilePoints.Add(m);
                    }
                    else
                    {
                        // counter
                    }
                }

                count += 1;
            }



            int nSpecs2 = massSpectrumCollection.Aggregate(0, (x, y) => x + 1);

            SendAndLogMessage("Mahieu NMerge Completed - Specs Remaining: {0}/{1} - Centroids remaining: {3}/{4} - Fraction: {2}", nSpecs2, nSpecStart, (double)nCentsYtot / ((double)nCentsNtot + (double)nCentsYtot), nCentsNtot, nCentsYtot);

            if ((double)nCentsYtot / ((double)nCentsNtot + (double)nCentsYtot) < 0.98)
            {
                SendAndLogWarningMessage("Mahieu NMerge Reported >2% centroids discarded. Are scan segments set appropriately?");
            }

            return(massSpectrumCollection);
        }
 /// <summary>
 /// REPLACE THIS
 ///
 /// Assumes scan segment order does not vary.  Not sure if this is a fair assumption.
 /// </returns>
 protected override MassSpectrumCollection ProcessSpectra(MassSpectrumCollection spectra)
 {
     return(NMerge(spectra));
 }