/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Config file for defining DSL2 per module options and publishing paths
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Available keys to override module options:
        ext.args   = Additional arguments appended to command in module.
        ext.args2  = Second set of arguments appended to command in module (multi-tool modules).
        ext.args3  = Third set of arguments appended to command in module (multi-tool modules).
        ext.prefix = File name prefix for output files.
----------------------------------------------------------------------------------------
*/

//prepare reverse complement primers to remove those in PacBio, IonTorrent and Illumina read-through cutadapt steps
// Get the complement of a DNA sequence
// Complement table taken from http://arep.med.harvard.edu/labgc/adnan/projects/Utilities/revcomp.html
def make_complement(String seq) {
    def complements = [ A:'T', T:'A', U:'A', G:'C', C:'G', Y:'R', R:'Y', S:'S', W:'W', K:'M', M:'K', B:'V', D:'H', H:'D', V:'B', N:'N' ]
    comp = seq.toUpperCase().collect { base -> complements[ base ] ?: 'X' }.join()
    return comp
}
FW_primer_RevComp = make_complement ( "${params.FW_primer}".reverse() )
RV_primer_RevComp = make_complement ( "${params.RV_primer}".reverse() )

process {

    publishDir = [
        path: { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" },
        mode: params.publish_dir_mode,
        enabled: false
    ]

    withName: RENAME_RAW_DATA_FILES {
        // copy in case cutadapt is skipped, because the next step (DADA2's filterAndTrim) follows soft links and ignores renamed file names
        ext.args = params.skip_cutadapt ? 'cp' : 'ln -s'
        publishDir = [
            path: { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" },
            mode: params.publish_dir_mode,
            enabled: false
        ]
    }

    withName: FASTQC {
        ext.args = '--quiet'
        publishDir = [
            path: { "${params.outdir}/${task.process.tokenize(':')[-1].tokenize('_')[0].toLowerCase()}" },
            mode: params.publish_dir_mode,
            pattern: "*.html"
        ]
    }

    withName: CUTADAPT_BASIC {
        ext.args = [
            "--minimum-length 1",
            "-O ${params.cutadapt_min_overlap}",
            "-e ${params.cutadapt_max_error_rate}",
            params.pacbio ? "--rc -g ${params.FW_primer}...${RV_primer_RevComp}" :
                params.iontorrent ? "--rc -g ${params.FW_primer}...${RV_primer_RevComp}" :
                params.single_end ? "-g ${params.FW_primer}" :
                "-g ${params.FW_primer} -G ${params.RV_primer}",
            params.retain_untrimmed ? '' : "--discard-untrimmed"
        ].join(' ').trim()
        ext.prefix = { "${meta.id}.trimmed" }
        publishDir = [
            path: { "${params.outdir}/cutadapt" },
            mode: params.publish_dir_mode,
            pattern: "*.log"
        ]
    }

    withName: CUTADAPT_READTHROUGH {
        ext.args = [
            "--minimum-length 1",
            "-O ${params.cutadapt_min_overlap}",
            "-e ${params.cutadapt_max_error_rate}",
            "-a ${RV_primer_RevComp} -A ${FW_primer_RevComp}"
        ].join(' ').trim()
        ext.prefix = { "${meta.id}.read-through" }
        publishDir = [
            path: { "${params.outdir}/cutadapt" },
            mode: params.publish_dir_mode,
            pattern: "*.log"
        ]
    }

    withName: CUTADAPT_DOUBLEPRIMER {
        ext.args = [
            "--discard-trimmed --minimum-length 1",
            "-O ${params.cutadapt_min_overlap}",
            "-e ${params.cutadapt_max_error_rate}",
            params.pacbio ? "--rc -g ${params.FW_primer}...${RV_primer_RevComp}" :
                params.iontorrent ? "--rc -g ${params.FW_primer}...${RV_primer_RevComp}" :
                params.single_end ? "-g ${params.FW_primer}" :
                "-g ${params.FW_primer} -G ${params.RV_primer}"
        ].join(' ').trim()
        ext.prefix = { "${meta.id}.double-primer" }
        publishDir = [
            path: { "${params.outdir}/cutadapt" },
            mode: params.publish_dir_mode,
            pattern: "*.log"
        ]
    }

    withName: CUTADAPT_TAXONOMY {
        ext.args = "--discard-untrimmed --minimum-length 1 -g ${params.FW_primer}...${RV_primer_RevComp}"
        publishDir = [
            path: { "${params.outdir}/cutadapt" },
            mode: params.publish_dir_mode,
            pattern: "*.log"
        ]
    }

    withName: CUTADAPT_SUMMARY_MERGE {
        publishDir = [
            path: { "${params.outdir}/cutadapt" },
            mode: params.publish_dir_mode,
            saveAs: { filename -> filename.equals('versions.yml') ? null : filename }
        ]
    }

    withName: DADA2_QUALITY {
        ext.args = ", n = 5e+04, aggregate = TRUE"
        publishDir = [
            [
                path: { "${params.outdir}/dada2/QC" },
                mode: params.publish_dir_mode,
                pattern: "*{.pdf,plotQualityProfile.txt}"
            ],
            [
                path: { "${params.outdir}/dada2/args" },
                mode: params.publish_dir_mode,
                pattern: "*.args.txt"
            ]
        ]
    }

    withName: TRUNCLEN {
        ext.args = "${params.trunc_qmin} ${params.trunc_rmin}"
        publishDir = [
            path: { "${params.outdir}/dada2" },
            mode: params.publish_dir_mode,
            enabled: false
        ]
    }

    max_len = params.max_len ?: "Inf"
    withName: DADA2_FILTNTRIM {
        ext.args = [
            'maxN = 0, truncQ = 2, trimRight = 0, minQ = 0, rm.lowcomplex = 0, orient.fwd = NULL, matchIDs = FALSE, id.sep = "\\\\s", id.field = NULL, n = 1e+05, OMP = TRUE, qualityType = "Auto"',
            params.pacbio || params.iontorrent || params.single_end ? "maxEE = ${params.max_ee}" : "maxEE = c(${params.max_ee}, ${params.max_ee})",
            params.pacbio ? "trimLeft = 0, minLen = ${params.min_len}, maxLen = $max_len, rm.phix = FALSE" :
                params.iontorrent ? "trimLeft = 15, minLen = ${params.min_len}, maxLen = $max_len, rm.phix = TRUE" :
                params.illumina_pe_its ? "trimLeft = 0, minLen = ${params.min_len}, maxLen = $max_len, rm.phix = TRUE" :
                "trimLeft = 0, minLen = ${params.min_len}, maxLen = $max_len, rm.phix = TRUE"
        ].join(',').replaceAll('(,)*$', "")
        publishDir = [
            path: { "${params.outdir}/dada2/args" },
            mode: params.publish_dir_mode,
            pattern: "*.args.txt"
        ]
    }

    withName: DADA2_QUALITY2 {
        ext.args = ", n = 5e+04, aggregate = TRUE"
        ext.prefix = { "${meta}_preprocessed" }
        publishDir = [
            [
                path: { "${params.outdir}/dada2/QC" },
                mode: params.publish_dir_mode,
                pattern: "*{.pdf}"
            ],
            [
                path: { "${params.outdir}/dada2/args" },
                mode: params.publish_dir_mode,
                pattern: "*.args.txt"
            ]
        ]
    }

    withName: DADA2_ERR {
        ext.seed = "${params.seed}"
        ext.args = [
            'nbases = 1e8, nreads = NULL, randomize = TRUE, MAX_CONSIST = 10, OMEGA_C = 0, qualityType = "Auto"',
            params.pacbio ? "errorEstimationFunction = PacBioErrfun" : "errorEstimationFunction = loessErrfun"
        ].join(',').replaceAll('(,)*$', "")
        publishDir = [
            [
                path: { "${params.outdir}/dada2/QC" },
                mode: params.publish_dir_mode,
                pattern: "*{.pdf,convergence.txt}"
            ],
            [
            path: { "${params.outdir}/dada2/args" },
            mode: params.publish_dir_mode,
            pattern: "*.args.txt"
            ],
            [
            path: { "${params.outdir}/dada2/log" },
            mode: params.publish_dir_mode,
            pattern: "*.log"
            ]
        ]
    }

    withName: NOVASEQ_ERR {
        publishDir = [
            path: { "${params.outdir}/dada2/QC" },
            mode: params.publish_dir_mode,
            pattern: "*{.pdf,convergence.txt}"
        ]
    }

    withName: DADA2_DENOISING {
        // standard setting can be inspected with getDadaOpt(option = NULL)
        ext.args = [
            'selfConsist = FALSE, priors = character(0), DETECT_SINGLETONS = FALSE, GAPLESS = TRUE, GAP_PENALTY = -8, GREEDY = TRUE, KDIST_CUTOFF = 0.42, MATCH = 5, MAX_CLUST = 0, MAX_CONSIST = 10, MIN_ABUNDANCE = 1, MIN_FOLD = 1, MIN_HAMMING = 1, MISMATCH = -4, OMEGA_A = 1e-40, OMEGA_C = 1e-40, OMEGA_P = 1e-4, PSEUDO_ABUNDANCE = Inf, PSEUDO_PREVALENCE = 2, SSE = 2, USE_KMERS = TRUE, USE_QUALS = TRUE, VECTORIZED_ALIGNMENT = TRUE',
            params.iontorrent ? "BAND_SIZE = 32, HOMOPOLYMER_GAP_PENALTY = -1" : "BAND_SIZE = 16, HOMOPOLYMER_GAP_PENALTY = NULL",
            params.sample_inference == "pseudo" ? "pool = \"pseudo\"" :
                params.sample_inference == "pooled" ? "pool = TRUE" : "pool = FALSE"
        ].join(',').replaceAll('(,)*$', "")
        // setting from https://rdrr.io/bioc/dada2/man/mergePairs.html & https://rdrr.io/bioc/dada2/man/nwalign.html & match = getDadaOpt("MATCH"), mismatch = getDadaOpt("MISMATCH"), gap = getDadaOpt("GAP_PENALTY"), missing from the list below is: 'band = -1'
        ext.args2 = [
            'minOverlap = 12, maxMismatch = 0, returnRejects = FALSE, propagateCol = character(0), trimOverhang = FALSE, match = 1, mismatch = -64, gap = -64, homo_gap = NULL, endsfree = TRUE, vec = FALSE',
            params.concatenate_reads ? "justConcatenate = TRUE" : "justConcatenate = FALSE"
        ].join(',').replaceAll('(,)*$', "")
        publishDir = [
            [
                path: { "${params.outdir}/dada2/args" },
                mode: params.publish_dir_mode,
                pattern: "*.args.txt"
            ],
            [
                path: { "${params.outdir}/dada2/log" },
                mode: params.publish_dir_mode,
                pattern: "*.log"
            ]
        ]
    }

    withName: DADA2_RMCHIMERA {
        ext.args = 'method="consensus", minSampleFraction = 0.9, ignoreNNegatives = 1, minFoldParentOverAbundance = 2, minParentAbundance = 8, allowOneOff = FALSE, minOneOffParentDistance = 4, maxShift = 16'
        publishDir = [
            path: { "${params.outdir}/dada2/args" },
            mode: params.publish_dir_mode,
            pattern: "*.args.txt"
        ]
    }

    withName: DADA2_MERGE {
        publishDir = [
            path: { "${params.outdir}/dada2" },
            mode: params.publish_dir_mode,
            saveAs: { filename -> filename.equals('versions.yml') ? null : filename }
        ]
    }

    withName: BARRNAP {
        ext.kingdom = "bac,arc,mito,euk"
        ext.args = "--quiet --reject 0.1"
        publishDir = [
            path: { "${params.outdir}/barrnap" },
            mode: params.publish_dir_mode,
            pattern: "*.gff"
        ]
    }

    withName: FILTER_SSU {
        publishDir = [
            path: { "${params.outdir}/barrnap" },
            mode: params.publish_dir_mode,
            saveAs: { filename -> filename.equals('versions.yml') ? null : filename }
        ]
    }

    withName: FILTER_LEN_ASV {
        publishDir = [
            path: { "${params.outdir}/asv_length_filter" },
            mode: params.publish_dir_mode,
            saveAs: { filename -> filename.equals('versions.yml') ? null : filename }
        ]
    }

    withName: 'MERGE_STATS|MERGE_STATS_FILTERSSU|MERGE_STATS_FILTERTAXA' {
        publishDir = [
            path: { "${params.outdir}" },
            mode: params.publish_dir_mode,
            saveAs: { filename -> filename.equals('versions.yml') ? null : filename }
        ]
    }

    withName: ITSX_CUTASV {
        ext.args = [
            '-t all --preserve T --date F --positions F --graphical F',
            params.cut_its == "its1" ? "--save_regions ITS1" :
                params.cut_its == "its2" ? "--save_regions ITS2" : "--save_regions none",
            params.its_partial != 0 ? "--partial ${params.its_partial}" : ""
        ].join(' ').trim()
        publishDir = [
            path: { "${params.outdir}/itsx" },
            mode: params.publish_dir_mode,
            saveAs: { filename -> filename.equals('versions.yml') ? null : filename }
        ]
    }

    withName: 'FORMAT_TAXONOMY|FORMAT_TAXRESULTS' {
        publishDir = [
            path: { "${params.outdir}/dada2" },
            mode: params.publish_dir_mode,
            pattern: "{ref_taxonomy.txt,ASV_tax.tsv,ASV_tax_species.tsv}"
        ]
    }

    withName: DADA2_TAXONOMY {
        ext.seed = "${params.seed}"
        ext.args = [
            'minBoot = 50',
            params.pacbio ? "tryRC = TRUE" :
                params.iontorrent ? "tryRC = TRUE" : ""
        ].join(',').replaceAll('(,)*$', "")
        publishDir = [
            [
                path: { "${params.outdir}/dada2/args" },
                mode: params.publish_dir_mode,
                pattern: "*.args.txt"
            ],
            [
                path: { "${params.outdir}/dada2" },
                mode: params.publish_dir_mode,
                pattern: "*.tsv"
            ]
        ]
    }

    withName: DADA2_ADDSPECIES {
        ext.seed = "${params.seed}"
        ext.args = [
            'allowMultiple = FALSE, n = 1e5',
            params.pacbio ? "tryRC = TRUE" :
                params.iontorrent ? "tryRC = TRUE" : ""
        ].join(',').replaceAll('(,)*$', "")
        publishDir = [
            [
                path: { "${params.outdir}/dada2/args" },
                mode: params.publish_dir_mode,
                pattern: "*.args.txt"
            ],
            [
                path: { "${params.outdir}/dada2" },
                mode: params.publish_dir_mode,
                pattern: "*.tsv"
            ]
        ]
    }

    withName: VSEARCH_USEARCHGLOBAL {
        ext.args = '--top_hits_only --output_no_hits --maxaccepts 50 --query_cov 0.9'
        publishDir = [
            [
                path: { "${params.outdir}/assignsh" },
                mode: params.publish_dir_mode,
                pattern: "*.txt"
            ]
        ]
    }

    withName: ASSIGNSH {
        publishDir = [
            [
                path: { "${params.outdir}/assignsh" },
                mode: params.publish_dir_mode,
                pattern: "*.tsv"
            ]
        ]
    }

    withName: FORMAT_TAXONOMY_QIIME {
        publishDir = [
            path: { "${params.outdir}/qiime2/taxonomy" },
            mode: params.publish_dir_mode,
            pattern: "ref_taxonomy.txt"
        ]
    }

    withName: 'QIIME2_EXTRACT|QIIME2_TRAIN|QIIME2_CLASSIFY' {
        publishDir = [
            path: { "${params.outdir}/qiime2/taxonomy" },
            mode: params.publish_dir_mode,
            pattern: "*{-classifier.qza,.tsv}"
        ]
    }

    withName: 'QIIME2_INASV|QIIME2_INSEQ|QIIME2_INTAX' {
        publishDir = [
            path: { "${params.outdir}/qiime2/input" },
            mode: params.publish_dir_mode,
            pattern: "*.qza"
        ]
    }

    withName: QIIME2_FILTERTAXA {
        publishDir = [
            [
                path: { "${params.outdir}/qiime2/abundance_tables" },
                mode: params.publish_dir_mode,
                pattern: "*table.qza"
            ],
            [
                path: { "${params.outdir}/qiime2/representative_sequences" },
                mode: params.publish_dir_mode,
                pattern: "*sequences.qza"
            ]
        ]
    }

    withName: FILTER_STATS {
        publishDir = [
            path: { "${params.outdir}/qiime2/abundance_tables" },
            mode: params.publish_dir_mode,
            pattern: "*.tsv"
        ]
    }

    withName: QIIME2_BARPLOT {
        publishDir = [
            path: { "${params.outdir}/qiime2" },
            mode: params.publish_dir_mode,
            saveAs: { filename -> filename.equals('versions.yml') ? null : filename }
        ]
    }

    withName: QIIME2_EXPORT_ABSOLUTE {
        publishDir = [
            [
                path: { "${params.outdir}/qiime2/representative_sequences" },
                mode: params.publish_dir_mode,
                pattern: "{descriptive_stats.tsv,seven_number_summary.tsv}"
            ],
            [
                path: { "${params.outdir}/qiime2/abundance_tables" },
                mode: params.publish_dir_mode,
                pattern: "{feature-table.tsv,feature-table.biom}"
            ],
            [
                path: { "${params.outdir}/qiime2/abundance_tables" },
                mode: params.publish_dir_mode,
                pattern: "abs-abund-table-*.tsv"
            ],
            [
                path: { "${params.outdir}/qiime2/representative_sequences" },
                mode: params.publish_dir_mode,
                pattern: "*.fasta"
            ]
        ]
    }

    withName: 'QIIME2_EXPORT_RELASV|QIIME2_EXPORT_RELTAX|COMBINE_TABLE' {
        publishDir = [
            path: { "${params.outdir}/qiime2/rel_abundance_tables" },
            mode: params.publish_dir_mode,
            pattern: "*.tsv"
        ]
    }

    withName: QIIME2_TREE {
        publishDir = [
            path: { "${params.outdir}/qiime2/phylogenetic_tree" },
            mode: params.publish_dir_mode,
            saveAs: { filename -> filename.equals('versions.yml') ? null : filename }
        ]
    }

    withName: QIIME2_ALPHARAREFACTION {
        publishDir = [
            path: { "${params.outdir}/qiime2" },
            mode: params.publish_dir_mode,
            saveAs: { filename -> filename.equals('versions.yml') ? null : filename }
        ]
    }

    withName: 'QIIME2_DIVERSITY_CORE|QIIME2_DIVERSITY_ALPHA|QIIME2_DIVERSITY_BETA|QIIME2_DIVERSITY_BETAORD' {
        publishDir = [
            path: { "${params.outdir}/qiime2/diversity" },
            mode: params.publish_dir_mode,
            saveAs: { filename -> filename.equals('versions.yml') || filename.endsWith('.qza') ? null : filename }
        ]
    }

    withName: QIIME2_DIVERSITY_ADONIS {
        publishDir = [
            path: { "${params.outdir}/qiime2/diversity/beta_diversity" },
            mode: params.publish_dir_mode,
            saveAs: { filename -> filename.equals('versions.yml') ? null : filename }
        ]
    }

    withName: 'QIIME2_ANCOM_TAX|QIIME2_ANCOM_ASV' {
        publishDir = [
            path: { "${params.outdir}/qiime2" },
            mode: params.publish_dir_mode,
            saveAs: { filename -> filename.equals('versions.yml') ? null : filename }
        ]
    }

    withName: PICRUST {
        ext.args = "-t epa-ng --remove_intermediate"
        publishDir = [
            path: { "${params.outdir}/picrust" },
            mode: params.publish_dir_mode,
            saveAs: { filename -> filename.equals('versions.yml') ? null : filename }
        ]
    }

    withName: SBDIEXPORT {
        ext.args = [
            params.single_end ? 'single' : 'paired',
            "${params.FW_primer}",
            "${params.RV_primer}"
        ].join(' ').trim()
        publishDir = [
            path: { "${params.outdir}/SBDI" },
            mode: params.publish_dir_mode,
            saveAs: { filename -> filename.equals('versions.yml') ? null : filename }
        ]
    }

    withName: SBDIEXPORTREANNOTATE {
        publishDir = [
            path: { "${params.outdir}/SBDI" },
            mode: params.publish_dir_mode,
            saveAs: { filename -> filename.equals('versions.yml') ? null : filename }
        ]
    }

    withName: CUSTOM_DUMPSOFTWAREVERSIONS {
        publishDir = [
            path: { "${params.outdir}/pipeline_info" },
            mode: params.publish_dir_mode,
            pattern: '*_versions.yml'
        ]
    }

    withName: MULTIQC {
        ext.args   = params.multiqc_title ? "--title \"$params.multiqc_title\"" : ''
        publishDir = [
            path: "${params.outdir}/multiqc",
            mode: params.publish_dir_mode,
            saveAs: { filename -> filename.equals('versions.yml') ? null : filename }
        ]
    }
}
