gt:             variants.forEach(x -> processVariant(x));
context: package com.hartwig.hmftools.pave;
  
  import static com.hartwig.hmftools.common.drivercatalog.panel.DriverGenePanelConfig.DRIVER_GENE_PANEL_OPTION;
  import static com.hartwig.hmftools.common.ensemblcache.EnsemblDataCache.ENSEMBL_DATA_DIR;
  import static com.hartwig.hmftools.common.genome.refgenome.RefGenomeSource.REF_GENOME;
  import static com.hartwig.hmftools.common.genome.refgenome.RefGenomeSource.loadRefGenome;
  import static com.hartwig.hmftools.common.utils.ConfigUtils.setLogLevel;
  import static com.hartwig.hmftools.common.utils.FileWriterUtils.closeBufferedWriter;
  import static com.hartwig.hmftools.common.utils.FileWriterUtils.createBufferedWriter;
  import static com.hartwig.hmftools.common.variant.SomaticVariantFactory.PASS_FILTER;
  import static com.hartwig.hmftools.common.variant.VariantConsequence.VARIANT_CONSEQ_DELIM;
  import static com.hartwig.hmftools.common.variant.snpeff.SnpEffUtils.SNPEFF_CANONICAL;
  import static com.hartwig.hmftools.common.variant.snpeff.SnpEffUtils.SNPEFF_WORST;
  import static com.hartwig.hmftools.pave.PaveConfig.PON_ARTEFACTS_FILE;
  import static com.hartwig.hmftools.pave.PaveConfig.PON_FILE;
  import static com.hartwig.hmftools.pave.PaveConfig.PON_FILTERS;
  import static com.hartwig.hmftools.pave.PaveConfig.PV_LOGGER;
  import static com.hartwig.hmftools.pave.PaveConstants.DELIM;
  import static com.hartwig.hmftools.pave.PaveUtils.createRightAlignedVariant;
  import static com.hartwig.hmftools.pave.VariantData.NO_LOCAL_PHASE_SET;
  import static com.hartwig.hmftools.pave.VcfWriter.PON_ARTEFACT_FILTER;
  import static com.hartwig.hmftools.pave.compare.ComparisonUtils.effectsMatch;
  import static com.hartwig.hmftools.pave.compare.ComparisonUtils.ignoreSnpEffAnnotation;
  
  import static htsjdk.tribble.AbstractFeatureReader.getFeatureReader;
  
  import java.io.BufferedWriter;
  import java.io.IOException;
  import java.util.List;
  import java.util.Map;
  import java.util.StringJoiner;
  import java.util.stream.Collectors;
  
  import com.google.common.collect.Lists;
  import com.hartwig.hmftools.common.gene.GeneData;
  import com.hartwig.hmftools.common.gene.TranscriptData;
  import com.hartwig.hmftools.common.genome.refgenome.RefGenomeInterface;
  import com.hartwig.hmftools.common.utils.version.VersionInfo;
  import com.hartwig.hmftools.common.variant.impact.VariantImpact;
  import com.hartwig.hmftools.common.variant.snpeff.SnpEffAnnotation;
  import com.hartwig.hmftools.common.variant.snpeff.SnpEffAnnotationParser;
  import com.hartwig.hmftools.pave.compare.ComparisonUtils;
  
  import org.apache.commons.cli.CommandLine;
  import org.apache.commons.cli.CommandLineParser;
  import org.apache.commons.cli.DefaultParser;
  import org.apache.commons.cli.Options;
  import org.apache.commons.cli.ParseException;
  import org.jetbrains.annotations.NotNull;
  
  import htsjdk.tribble.AbstractFeatureReader;
  import htsjdk.tribble.readers.LineIterator;
  import htsjdk.variant.variantcontext.VariantContext;
  import htsjdk.variant.vcf.VCFCodec;
  
  public class PaveApplication
  {
      private final PaveConfig mConfig;
      private final ImpactClassifier mImpactClassifier;
      private final VariantImpactBuilder mImpactBuilder;
      private final GeneDataCache mGeneDataCache;
      private final GnomadAnnotation mGnomadAnnotation;
  
      private final PonAnnotation mPon;
      private final PonAnnotation mPonArtefacts;
  
      // for comparison with SnpEff
      private int mTransEffectMatched;
      private int mTransTotalComparisons;
  
      private VcfWriter mVcfWriter;
      private BufferedWriter mCsvTranscriptWriter;
  
      public PaveApplication(final CommandLine cmd)
      {
          mConfig = new PaveConfig(cmd);
  
          mGeneDataCache = new GeneDataCache(
                  cmd.getOptionValue(ENSEMBL_DATA_DIR), mConfig.RefGenVersion,
                  cmd.getOptionValue(DRIVER_GENE_PANEL_OPTION), mConfig.CompareSnpEff, true);
  
          mGnomadAnnotation = new GnomadAnnotation(cmd);
  
          mPon = new PonAnnotation(cmd.getOptionValue(PON_FILE), true);
          mPon.loadFilters(cmd.getOptionValue(PON_FILTERS));
  
          mPonArtefacts = new PonAnnotation(cmd.getOptionValue(PON_ARTEFACTS_FILE), false);
  
          mImpactBuilder = new VariantImpactBuilder(mGeneDataCache);
  
          RefGenomeInterface refGenome = loadRefGenome(cmd.getOptionValue(REF_GENOME));
  
          mImpactClassifier = new ImpactClassifier(refGenome);
  
          mVcfWriter = null;
          initialiseVcfWriter();
  
          if(mConfig.WriteTranscriptCsv)
              initialiseTranscriptWriter();
  
          mTransEffectMatched = 0;
          mTransTotalComparisons = 0;
      }
  
      public void run()
      {
          if(!mConfig.isValid())
          {
              PV_LOGGER.error("invalid config, exiting");
              System.exit(1);
          }
  
          if(!mGeneDataCache.loadCache(mConfig.OnlyCanonical, false))
          {
              PV_LOGGER.error("Ensembl data cache loading failed, exiting");
              System.exit(1);
          }
  
          if((mPon.isEnabled() && !mPon.hasValidData()) || (mPonArtefacts.isEnabled() && !mPonArtefacts.hasValidData()))
          {
              PV_LOGGER.error("invalid PON files, exiting");
              System.exit(1);
          }
  
          processVcfFile(mConfig.SampleId);
  
          closeBufferedWriter(mCsvTranscriptWriter);
  
          PV_LOGGER.info("sample({}) annotation complete", mConfig.SampleId);
      }
  
      private void processVcfFile(final String sampleId)
      {
          PV_LOGGER.info("sample({}) reading VCF file({})", sampleId, mConfig.VcfFile);
  
          int variantCount = 0;
  
          try
          {
              final AbstractFeatureReader<VariantContext, LineIterator> reader = getFeatureReader(
                      mConfig.VcfFile, new VCFCodec(), false);
  
              for(VariantContext variantContext : reader.iterator())
              {
                  processVariant(variantContext);
                  ++variantCount;
  
                  if(variantCount > 0 && (variantCount % 10000) == 0)
                  {
                      PV_LOGGER.debug("processed {} variants", variantCount);
                  }
              }
  
              processPhasedVariants(NO_LOCAL_PHASE_SET);
          }
          catch(IOException e)
          {
              PV_LOGGER.error(" failed to read somatic VCF file({}): {}", mConfig.VcfFile, e.toString());
          }
  
          PV_LOGGER.info("sample({}) processed {} variants", sampleId, variantCount);
  
          if(mConfig.CompareSnpEff)
          {
              PV_LOGGER.info("sample({}) transcript comparison total({} matched={} diffs={})",
                      sampleId, mTransTotalComparisons, mTransEffectMatched, mTransTotalComparisons - mTransEffectMatched);
          }
  
          mVcfWriter.close();
      }
  
      private void processVariant(final VariantContext variantContext)
      {
          VariantData variant = VariantData.fromContext(variantContext);
  
          if(mConfig.FilterPass)
          {
              if(!variantContext.getFilters().isEmpty() && !variantContext.getFilters().contains(PASS_FILTER))
                  return;
          }
  
          if(!mConfig.CompareSnpEff)
          {
              if(variantContext.hasAttribute(SNPEFF_CANONICAL))
                  variantContext.getCommonInfo().removeAttribute(SNPEFF_CANONICAL);
  
              if(variantContext.hasAttribute(SNPEFF_WORST))
                  variantContext.getCommonInfo().removeAttribute(SNPEFF_WORST);
          }
  
          try
          {
              variant.setRealignedVariant(createRightAlignedVariant(variant, mImpactClassifier.refGenome()));
  
              findVariantImpacts(variant, mImpactClassifier, mGeneDataCache);
  
              processPhasedVariants(variant.localPhaseSet());
  
              if(!variant.hasLocalPhaseSet())
                  processVariant(variant);
          }
          catch(Exception e)
          {
              PV_LOGGER.error("error processing var({})", variant);
              e.printStackTrace();
          }
      }
  
      private void processPhasedVariants(int currentLocalPhaseSet)
      {
          List<VariantData> variants = mImpactClassifier.processPhasedVariants(currentLocalPhaseSet);
  
          if(variants != null)
  