#' Remove TCR and BCR genes from variable gene results
#'
#' Most single-cell workflows use highly-expressed and highly-variable
#' genes for the initial calculation of PCA and subsequent dimensional
#' reduction. This function will remove the TCR and/or BCR genes from the
#' variable features in a Seurat object or from a vector (potentially
#' generated by the Bioconductor scran workflow).
#'
#' @examples
#' example <- quietVDJgenes(scRep_example)
#' scRep <- quietTCRgenes(scRep_example)
#' ibex_example <- quietBCRgenes(scRep_example)
#'
#' @param input.data Single-cell object in Seurat format or vector of variable genes
#' to use in reduction
#' @param assay The Seurat assay slot to use to remove immune receptor genes
#' from, NULL value will default to the default assay
#' @param ... Reserved for future arguments
#'
#' @export
#' @return Seurat object or vector list with TCR genes removed.
quietVDJgenes <- function(input.data, ...) {
    quietTCRgenes(quietBCRgenes(input.data, ...), ...)
}

#' @rdname quietVDJgenes
#' @export
#' @author Nicky de Vrij, Nikolaj Pagh, Nick Borcherding, Qile Yang
quietTCRgenes <- function(input.data, ...) {
    UseMethod("quietTCRgenes")
}

#' @rdname quietVDJgenes
#' @method quietTCRgenes default
#' @export
quietTCRgenes.default <- function(input.data, ...) {
    input.data[!shouldQuietTcrGene(input.data)]
}

shouldQuietTcrGene <- function(genes) {
    grepl("^TR[ABDG][VDJ][^D]", genes, ignore.case = TRUE)
}

#' @rdname quietVDJgenes
#' @method quietTCRgenes Seurat
#' @export
quietTCRgenes.Seurat <- function(input.data, assay = NULL, ...) {
    if (is.null(assay)) {
        assay <- SeuratObject::DefaultAssay(input.data)
    }
    SeuratObject::VariableFeatures(input.data, assay = assay) <-
        quietTCRgenes.default(SeuratObject::VariableFeatures(input.data, assay = assay))
    input.data
}

#' @rdname quietVDJgenes
#' @export
quietBCRgenes <- function(input.data, ...) {
    UseMethod("quietBCRgenes")
}

#' @rdname quietVDJgenes
#' @method quietBCRgenes default
#' @export
quietBCRgenes.default <- function(input.data, ...) {
    input.data[!shouldQuietBcrGene(input.data)]
}

shouldQuietBcrGene <- function(genes) {
    grepl("^IG[HLK][VDJCAGM]", genes, ignore.case = TRUE) &
    !genes %in% c(getHumanIgPseudoGenes(), getMouseIgPseudoGenes()) |
    toupper(genes) == "JCHAIN"
}

#' @rdname quietVDJgenes
#' @method quietBCRgenes Seurat
#' @export
quietBCRgenes.Seurat <- function(input.data, assay = NULL, ...) {
    if (is.null(assay)) {
        assay <- SeuratObject::DefaultAssay(input.data)
    }
    SeuratObject::VariableFeatures(input.data, assay = assay) <-
        quietBCRgenes.default(SeuratObject::VariableFeatures(input.data, assay = assay))
    input.data
}

#' Get Human Immunoglobulin pseudogenes
#'
#' This function returns a character vector of human immunoglobulin
#' pseudogenes. These are also the genes that are removed from the
#' variable gene list in [quietVDJgenes()].
#'
#' @return Character vector of human immunoglobulin pseudogenes.
#' @keywords internal
getHumanIgPseudoGenes <- function() {
    unique(c(
        "IGHJ1P", "IGHJ2P", "IGHJ3P", "IGLC4", "IGLC5", "IGHEP1", "IGHEP2",
        "IGHV1-12","IGHV1-14", "IGHV1-17", "IGHV1-67", "IGHV1-68",
        "IGHV2-10", "IGHV3-6", "IGHV3-19", "IGHV3-22", "IGHV3-25",
        "IGHV3-29", "IGHV3-32", "IGHV3-36", "IGHV3-37", "IGHV3-41",
        "IGHV3-42", "IGHV3-47", "IGHV3-50", "IGHV3-52", "IGHV3-54",
        "IGHV3-57", "IGHV3-60", "IGHV3-62", "IGHV3-63", "IGHV3-65",
        "IGHV3-71", "IGHV3-75", "IGHV3-76", "IGHV3-79", "IGHV4-55",
        "IGHV4-80", "IGHV5-78", "IGHV7-27", "IGHV7-40", "IGHV7-56",
        "IGHVIII-44", "IGHVIII-82", "IGKV1-22", "IGKV1-32", "IGKV1-35",
        "IGKV1D-22", "IGKV1D-27", "IGKV1D-32", "IGKV1D-35", "IGKVOR-2",
        "IGKVOR-3", "IGKVOR-4", "IGKV2-4", "IGKV2-10", "IGKV2-14", "IGKV2-18",
        "IGKV2-19", "IGKV2-23", "IGKV2-26", "IGKV2-36", "IGKV2-38",
        "IGKV2D-10", "IGKV2D-14", "IGKV2D-18", "IGKV2D-19", "IGKV2D-23",
        "IGKV2D-36", "IGKV2D-38", "IGKV3-25", "IGKV3-31", "IGKV3-34",
        "IGKV7-3", "IGLCOR22-1", "IGLCOR22-2", "IGLJCOR18", "IGLV1-41",
        "IGLV1-62", "IGLV2-5", "IGLV2-28", "IGLV2-34", "IGLV3-2",
        "IGLV3-4", "IGLV3-6", "IGLV3-7", "IGLV3-13", "IGLV3-15",
        "IGLV3-17", "IGLV3-24", "IGLV3-26", "IGLV3-29", "IGLV3-30",
        "IGLV3-31", "IGLV7-35", "IGLV10-67", "IGLVI-20", "IGLVI-38",
        "IGLVI-42", "IGLVI-56", "IGLVI-63", "IGLVI-68", "IGLVI-70",
        "IGLVIV-53", "IGLVIV-59", "IGLVIV-64", "IGLVIV-65", "IGLVV-58",
        "IGLVV-66", "IGHV1OR15-2", "IGHV1OR15-3", "IGHV1OR15-4", "IGHV1OR15-6",
        "IGHV1OR16-1", "IGHV1OR16-2", "IGHV1OR16-3", "IGHV1OR16-4", "IGHV3-30-2",
        "IGHV3-33-2", "IGHV3-69-1", "IGHV3OR15-7", "IGHV3OR16-6", "IGHV3OR16-7",
        "IGHV3OR16-11", "IGHV3OR16-14", "IGHV3OR16-15", "IGHV3OR16-16", "IGHV7-34-1",
        "IGHVII-1-1", "IGHVII-15-1", "IGHVII-20-1", "IGHVII-22-1", "IGHVII-26-2",
        "IGHVII-28-1", "IGHVII-30-1", "IGHVII-30-21", "IGHVII-31-1", "IGHVII-33-1",
        "IGHVII-40-1", "IGHVII-43-1", "IGHVII-44-2", "IGHVII-46-1", "IGHVII-49-1",
        "IGHVII-51-2", "IGHVII-53-1", "IGHVII-60-1", "IGHVII-62-1", "IGHVII-65-1",
        "IGHVII-67-1", "IGHVII-74-1", "IGHVII-78-1", "IGHVIII-2-1", "IGHVIII-5-1",
        "IGHVIII-5-2", "IGHVIII-11-1", "IGHVIII-13-1", "IGHVIII-16-1", "IGHVIII-22-2",
        "IGHVIII-25-1", "IGHVIII-26-1", "IGHVIII-38-1", "IGHVIII-47-1", "IGHVIII-67-2",
        "IGHVIII-67-3", "IGHVIII-67-4", "IGHVIII-76-1", "IGHVIV-44-1", "IGKV1OR1-1",
        "IGKV1OR2-1", "IGKV1OR2-2", "IGKV1OR2-3", "IGKV1OR2-6", "IGKV1OR2-9",
        "IGKV1OR2-11", "IGKV1OR2-118", "IGKV1OR9-1", "IGKV1OR9-2", "IGKV1OR10-1",
        "IGKV1OR15-118", "IGKV1OR22-1", "IGKV1OR22-5", "IGKV1ORY-1", "IGKV2OR2-1",
        "IGKV2OR2-2", "IGKV2OR2-4", "IGKV2OR2-7", "IGKV2OR2-7D", "IGKV2OR2-8",
        "IGKV2OR2-10", "IGKV2OR22-3", "IGKV2OR22-4", "IGKV3OR2-5", "IGKV3OR22-2",
        "IGKV8OR8-1", "IGLVIV-66-1", "IGLVIVOR22-1", "IGLVIVOR22-2", "IGLVVI-22-1",
        "IGLVVI-25-1", "IGLVVII-41-1"
    ))
}

getMouseIgPseudoGenes <- function() {
  unique(c(
    "Ighv1-1", "Ighv1-2", "Ighv1-3", "Ighv1-6", "Ighv1-8",
    "Ighv1-10", "Ighv1-13", "Ighv1-14", "Ighv1-17", "Ighv1-17-1",
    "Ighv1-18-1", "Ighv1-18-3", "Ighv1-18-5", "Ighv1-18-6", "Ighv1-18-8",
    "Ighv1-18-9", "Ighv1-18-10", "Ighv1-18-12", "Ighv1-18-15", "Ighv1-18-16",
    "Ighv1-18-18", "Ighv1-18-20", "Ighv1-18-21", "Ighv1-18-24", "Ighv1-18-25",
    "Ighv1-18-27", "Ighv1-18-29", "Ighv1-18-30", "Ighv1-18-31", "Ighv1-18-33",
    "Ighv1-18-34", "Ighv1-18-35", "Ighv1-18-38", "Ighv1-18-42", "Ighv1-18-43",
    "Ighv1-18-44", "Ighv1-18-46", "Ighv1-18-47", "Ighv1-18-48", "Ighv1-18-49",
    "Ighv1-18-51", "Ighv1-18-52", "Ighv1-18-54", "Ighv1-18-57", "Ighv1-18-59",
    "Ighv1-18-61", "Ighv1-18-61d", "Ighv1-18-63", "Ighv1-18-67", "Ighv1-18-70",
    "Ighv1-18-71", "Ighv1-18-72", "Ighv1-18-76", "Ighv1-18-77", "Ighv1-18-79",
    "Ighv1-18-83", "Ighv1-18-85", "Ighv1-18-87", "Ighv1-18-88", "Ighv1-18-90",
    "Ighv1-18-91", "Ighv1-18-93", "Ighv1-18-94", "Ighv1-18-95", "Ighv1-18-96",
    "Ighv1-18-97", "Ighv1-19-1", "Ighv1-21", "Ighv1-21-1", "Ighv1-25",
    "Ighv1-27", "Ighv1-28", "Ighv1-29", "Ighv1-30", "Ighv1-32",
    "Ighv1-33", "Ighv1-34", "Ighv1-35", "Ighv1-38", "Ighv1-40",
    "Ighv1-41", "Ighv1-42", "Ighv1-43", "Ighv1-44", "Ighv1-45",
    "Ighv1-46", "Ighv1-47-4", "Ighv1-47-12", "Ighv1-47-15", "Ighv1-47-16",
    "Ighv1-47-19", "Ighv1-47-21", "Ighv1-47-25", "Ighv1-47-38", "Ighv1-47-42",
    "Ighv1-47-49", "Ighv1-47-50", "Ighv1-47-54", "Ighv1-47-55", "Ighv1-47-57",
    "Ighv1-48", "Ighv1-51", "Ighv1-57", "Ighv1-58", "Ighv1-60",
    "Ighv1-62", "Ighv1-65", "Ighv1-67", "Ighv1-68", "Ighv1-70",
    "Ighv1-71-7", "Ighv1-71-13", "Ighv1-71-14", "Ighv1-73", "Ighv1-79",
    "Ighv1-83", "Ighv1-86", "Ighv1s9", "Ighv1s10", "Ighv1s11",
    "Ighv1s15", "Ighv1s16", "Ighv1s17", "Ighv1s18", "Ighv1s19",
    "Ighv1s28", "Ighv1s30", "Ighv1s51", "Ighv1s57", "Ighv1s65",
    "Ighv1s74", "Ighv1s84", "Ighv1s88", "Ighv1s101", "Ighv1s110",
    "Ighv1s112", "Ighv1s124", "Ighv2-1", "Ighv2-2-1", "Ighv2-7",
    "Ighv2-8", "Ighv3-2", "Ighv3-3", "Ighv3-3-1", "Ighv3-7",
    "Ighv4-2", "Ighv5-1", "Ighv5-3", "Ighv5-5", "Ighv5-5-1",
    "Ighv5-5-3", "Ighv5-7", "Ighv5-7-1", "Ighv5-7-2", "Ighv5-7-3",
    "Ighv5-7-4", "Ighv5-7-5", "Ighv5-7-6", "Ighv5-8", "Ighv5-8-1",
    "Ighv5-8-2", "Ighv5-8-3", "Ighv5-8-4", "Ighv5-10", "Ighv5-10-1",
    "Ighv5-10-2", "Ighv5-11", "Ighv5-11-1", "Ighv5-11-2", "Ighv5-11-3",
    "Ighv5-11d", "Ighv5-12-3", "Ighv5-13", "Ighv5-13-1", "Ighv5-18",
    "Ighv5-19", "Ighv5-21", "Ighv6-1", "Ighv6-1-1", "Ighv6-2",
    "Ighv6-2d", "Ighv7-2", "Ighv7-4", "Ighv8-1", "Ighv8-3",
    "Ighv8-4-1", "Ighv8-4-3", "Ighv8-4-5", "Ighv8-4-9", "Ighv8-4-10",
    "Ighv8-4-11", "Ighv8-4-20", "Ighv8-7", "Ighv8-8-1", "Ighv8-9",
    "Ighv8-10", "Ighv8-13", "Ighv8-13-1", "Ighv8-13-2", "Ighv8-13-5",
    "Ighv8-13-6", "Ighv8-13-7", "Ighv8-13-9", "Ighv8-14", "Ighv8-15",
    "Ighv8-16", "Ighv8-17", "Ighv8-18", "Ighv8s1", "Ighv8s6",
    "Ighv9-2-3", "Ighv10-1-1", "Ighv10-1-3", "Ighv10-1-5", "Ighv10-1-7",
    "Ighv10-2", "Ighv10-4", "Ighv10s5", "Ighv11-2-1", "Ighv12-1",
    "Ighv12-1-2", "Ighv12-1-3", "Ighv12-1-6", "Ighv12-1-7", "Ighv12-1-8",
    "Ighv12-2", "Ighv12s2", "Ighv13-1", "Ighv14-2", "Ighv15-1",
    "Ighv15-1-1", "Ighv16-1-1"
  ))
}
