public static void main(String[] args) throws IOException {

    Modification methylH = Modification.parseModification("CH2");
    Modification methylD = Modification.parseModification("CH[2]3H-1");

    PeakProcessorChain<PeakAnnotation> ppc = new PeakProcessorChain<>();

    SpectraPairExtractor mse = new SpectraPairExtractor(methylH, methylD);

    FilenameFilter filter = new SuffixFileFilter(".mgf", IOCase.INSENSITIVE);

    File specFile = new File(args[0]);

    if (specFile.isDirectory()) {

      File[] files = specFile.listFiles(filter);

      for (File aFile : files) {

        System.out.println("Processing File:" + aFile.getName());

        mse.process(aFile.getAbsolutePath(), ppc, 6);
      }

    } else {

      System.out.println("Processing File:" + specFile.getName());

      mse.process(specFile.getAbsolutePath(), ppc, 10);
    }
  }
  public void process(String mgfFile, PeakProcessorChain<PeakAnnotation> aChain, double scoreLimit)
      throws IOException {

    MgfReader reader = new MgfReader(new File(mgfFile));

    String core = FilePathUtil.removeExtension(mgfFile);
    PrintWriter log = new PrintWriter(core + "_log.csv");
    log.println("Scan1,Mz1,Charge1,Scan2,Mz2,Charge2,DeltaCount,NewMz,PeakCount,FilterPeakCount");

    MgfWriter writer = new MgfWriter(new File(core + "_pair.mgf"));

    List<MsnSpectrum> specList = loadMgf(reader, aChain);

    PeakListExtractor extractor = new PeakListExtractor(iMs2Tol);

    HashMap<Integer, SpectrumSpectrumMatch> map = new HashMap<>();

    double labelDelta = iHeavyMod.getMolecularMass() - iLightMod.getMolecularMass();
    double maxDelta = labelDelta * iMaxModCount;

    for (int lId = 0; lId < specList.size(); lId++) {

      MsnSpectrum lSpec = specList.get(lId);
      Peak lPeak = lSpec.getPrecursor();

      for (int hId = lId + 1; hId < specList.size(); hId++) {

        MsnSpectrum hSpec = specList.get(hId);
        Peak hPeak = hSpec.getPrecursor();

        double delta = hPeak.getMass() - lPeak.getMass();

        if (iMs1Tol.check(maxDelta, delta).equals(Location.LARGER)) break;

        if (iMs1Tol.check(labelDelta, delta).equals(Location.SMALLER)) continue;

        if (iChargeTol.isPresent()) {

          int deltaE = iChargeTol.get();

          int lightE = lPeak.getCharge();
          int heavyE = hPeak.getCharge();

          if (Math.abs(lightE - heavyE) > deltaE) break;
        }

        if (iIntensityTol.isPresent()) {

          double deltaIn = iIntensityTol.get();

          double lightI = lPeak.getIntensity();
          double heavyI = hPeak.getIntensity();

          if (Math.abs(Math.log(lightI / heavyI)) > Math.log(deltaIn)) break;
        }

        if (iTimeTol.isPresent()) {

          double lightT = lSpec.getRetentionTimes().getFirst().getTime();
          double heavyT = hSpec.getRetentionTimes().getFirst().getTime();

          int deltaTime = iTimeTol.get();
          if (Math.abs(lightT - heavyT) > deltaTime) break;
        }

        for (int mCount = iMaxModCount; mCount > 0; mCount--) {

          if (!iMs1Tol.withinTolerance(mCount * labelDelta, delta)) continue;

          double lBaseIn = lSpec.getBasePeakIntensity();
          double hBaseIn = hSpec.getBasePeakIntensity();

          MsnSpectrum lFilterSpec = lSpec.copy(new ThresholdFilter<>(lBaseIn * 0.01));
          MsnSpectrum hFilterSpec = hSpec.copy(new ThresholdFilter<>(hBaseIn * 0.01));

          HashMap<Integer, Integer> filterMatch =
              extractor.getMatchPeaks(lFilterSpec, hFilterSpec, labelDelta, mCount);

          if (filterMatch.size() < scoreLimit) break;

          HashMap<Integer, Integer> pairPeaksIndex =
              extractor.getMatchPeaks(lSpec, hSpec, labelDelta, mCount);

          MsnSpectrum peaks = new MsnSpectrum();

          for (Entry<Integer, Integer> entry : pairPeaksIndex.entrySet()) {

            double lightMz = lSpec.getMz(entry.getKey());

            double heavyMz = hSpec.getMz(entry.getValue());

            double intensity = lSpec.getIntensity(entry.getKey());

            int count = (int) (FastMath.round((heavyMz - lightMz) / labelDelta));

            if (count != 0) {

              lightMz = lightMz - count * iLightMod.getMolecularMass();
            }

            peaks.add(lightMz, intensity);
          }

          double newMz = lPeak.getMz() - mCount * iLightMod.getMolecularMass() / lPeak.getCharge();

          Peak rPeak = Peak.noIntensity(newMz, lPeak.getCharge());

          peaks.setPrecursor(rPeak);

          log.print(lSpec.getScanNumbers().getFirst().getValue() + ",");
          log.print(lPeak.getMz() + ",");
          log.print(lPeak.getCharge() + ",");
          log.print(hSpec.getScanNumbers().getFirst().getValue() + ",");
          log.print(hPeak.getMz() + ",");
          log.print(hPeak.getCharge() + ",");
          log.print(mCount + ",");
          log.print(newMz + ",");
          log.print(pairPeaksIndex.size() + ",");

          log.print(filterMatch.size() + "\n");

          SpectrumSpectrumMatch aMatch =
              new SpectrumSpectrumMatch(lSpec.getComment(), hSpec.getComment());

          aMatch.setFirstPrecursorPeak(lPeak);
          aMatch.setSecondPrecursorPeak(hPeak);

          aMatch.setFirstRetentionTime(lSpec.getRetentionTimes().getFirst());
          aMatch.setSecondRetentionTime(hSpec.getRetentionTimes().getFirst());

          aMatch.setFirstScanNumber(lSpec.getScanNumbers().getFirst());
          aMatch.setSecondScanNumber(hSpec.getScanNumbers().getFirst());

          aMatch.setCommonPeaks(peaks);

          aMatch.setLabelDelta(mCount);

          aMatch.setMatchCount(peaks.size());

          if (map.containsKey(lId)) {

            SpectrumSpectrumMatch spectrumSpectrumMatch = map.get(lId);

            if (spectrumSpectrumMatch.getMatchCount() < peaks.size()) {
              map.put(lId, aMatch);
            }

          } else {
            map.put(lId, aMatch);
          }

          break;
        }
      }
    }

    for (SpectrumSpectrumMatch match : map.values()) {

      MsnSpectrum spec = match.getCommonPeaks();

      spec.setComment(String.valueOf(match.getLabelDelta().get()));

      spec.addScanNumber(match.getFirstScanNumber());
      spec.addScanNumber(match.getSecondScanNumber());

      spec.addRetentionTime(match.getFirstRetentionTime());
      spec.addRetentionTime(match.getSecondRetentionTime());

      writer.write(spec);
    }

    writer.close();
    log.close();
  }