##############################################################################
#============================================================================
#  Framework to find microbial signatures of Pulmonary Exacerbation in CF
#============================================================================
#
# R codes to find shifts in relative abundance of keystone taxa that
# correspond to changes in patient health.
#
# Manuscript: Microbiome Networks and Change-Point Analysis Reveal Key
# Community Changes Associated with Cystic Fibrosis Pulmonary Exacerbations
#
# Journal: npj Biofilms and Microbiomes
#
# Author: Mehdi Layeghifard et al.
#
# Date: November/2018
#
##### Install Required packages
# install.packages("igraph")
# install.packages("qgraph")
# install.packages("changepoint")
#
# Also requires function in the utils.R file
#
##### Input data
# A comma-separated OTU table (.csv file) for each patient with rows and
# columns representing taxa and samples, respectively.
#
# A comma-separated metadata file (.csv) containing data on clinical state
# of each sample for each patient. Rows and columns represent samples and
# patients, respectively.
# 
##### Disclaimer
# This code is supplied without any warranty or guaranteed support whatsoever. 
# Authors are not responsible for its use, misuse, or functionality.
#
#============================================================================
#    Contact: Mehdi Layeghifard (mehdi.layeghifard@utoronto.ca)
#============================================================================
##############################################################################

# Load libraries
library(igraph)
library(qgraph)
library(changepoint)

# Load custom functions needed to run the framework
source("utils.R")

options(warn=-1)

##### Define parameters
# Path to data folder
data_path <- "data"
# Number of desired keystone taxa
top <- 5
# The hub detection method: pagerank (default) or hubscore
hub_metric <- "pagerank"
# FDR network metric: see qgraph manual for more detail
fdrm <- "pval"

# Define containers for keystone taxa
chpt_bugs <- list()
hubs_bugs <- list()
abun_bugs <- list()
prev_bugs <- list()

# Define containers for covariance measures
chpt_covs <- list()
hubs_covs <- list()
abun_covs <- list()
prev_covs <- list()

# Get the list of otu files
files <- list.files(path = data_path, pattern = "_otu.csv")
# Order file names
files <- files[order(nchar(files), files)]

# Read metadata (clinical states)
metadata <- read.table(paste(data_path, "clinical_states.csv", sep="/"),
                       header=TRUE, sep=",")

# Compute changepoints and covariances for each otu table
for (fname in files) {
    patient_id <- strsplit(fname, "_")[[1]][1]
    writeLines(paste("Processing: ", patient_id))
    
    # Read the otu file
    infile <- paste(data_path, fname, sep="/")
    MB <- read.table(infile, header=TRUE, sep=",")
    
    num_taxa <- dim(MB)[1]
    num_samples <- dim(MB)[2]
    
    # Create the FDR network using qgraph package
    CorMat <- cor_auto(t(MB), verbose = FALSE)
    PCorMat_FDR <- FDRnetwork(CorMat, cutoff = 0.01, method = fdrm)
    FDRnet <- qgraph(PCorMat_FDR, DoNotPlot = TRUE)
    net <- q2igraph(FDRnet)
    
    # Find changepoints in clinical states
    clin_state <- metadata[[patient_id]]
    clin_state <- clin_state[!is.na(clin_state)]
    cp1 <- cpt.meanvar(clin_state, method="PELT")
    cs_vec1 <- as.vector(matrix(0, nrow=dim(MB)[2])) #######
    j <- 1
    for (i in 1:length(cp1@cpts)) {
        cs_vec1[j:cp1@cpts[i]] <- i
        j <- cp1@cpts[i] + 1
    }

    # Find keystone taxa
    abun <- names(head(sort(rowSums(MB), decreasing=TRUE), top))
    prev <- names(head(sort(rowSums(MB != 0), decreasing=TRUE), top))
    hubs <- find_hubs(net, hub_metric="pagerank")

    # Extract relative abundance of keystone taxa from otu table
    abun_mat <- MB[abun, ]
    prev_mat <- MB[prev, ]
    hubs_mat <- MB[hubs, ]

    # Define containers to store covariance measures for each otu
    chpt_res <- array(0, dim=c(3, num_taxa))
    colnames(chpt_res) <- rownames(MB)
    abun_res <- array(0, dim=c(3, top))
    prev_res <- array(0, dim=c(3, top))
    hubs_res <- array(0, dim=c(3, top))

    # Find changepoint covariances for all taxa
    for (i in 1:num_taxa) {
        chpt_cpt <- cpt.meanvar(as.numeric(MB[i,]), method="PELT")
        chpt_vec <- cpt_conv(chpt_cpt, num_samples)
        chpt_ccf <- ccf(chpt_vec,
                        cs_vec1,
                        lag.max = 1,
                        type="covariance",
                        plot=F)
        chpt_res[, i] <- chpt_ccf$acf
    }
    # Select the top taxa
    chpt_res <- chpt_res[, order(chpt_res[2,], decreasing=T)]
    chpt_res <- chpt_res[, 1:top]

    # Find changepoint covariance for keystone taxa
    for (i in 1:top) {
        abun_cpt <- cpt.meanvar(as.numeric(abun_mat[i,]), method="PELT")
        prev_cpt <- cpt.meanvar(as.numeric(prev_mat[i,]), method="PELT")
        hubs_cpt <- cpt.meanvar(as.numeric(hubs_mat[i,]), method="PELT")

        abun_vec <- cpt_conv(abun_cpt, num_samples)
        prev_vec <- cpt_conv(prev_cpt, num_samples)
        hubs_vec <- cpt_conv(hubs_cpt, num_samples)

        abun_ccf <- ccf(abun_vec,
                        cs_vec1,
                        lag.max = 1,
                        type="covariance",
                        plot=F)
        prev_ccf <- ccf(prev_vec,
                        cs_vec1,
                        lag.max = 1,
                        type="covariance",
                        plot=F)
        hubs_ccf <- ccf(hubs_vec,
                        cs_vec1,
                        lag.max = 1,
                        type="covariance",
                        plot=F)

        abun_res[, i] <- abun_ccf$acf
        prev_res[, i] <- prev_ccf$acf
        hubs_res[, i] <- hubs_ccf$acf
    }

    # Store keystone taxa found for this otu
    chpt_bugs[[patient_id]] <- colnames(chpt_res)
    hubs_bugs[[patient_id]] <- hubs
    abun_bugs[[patient_id]] <- abun
    prev_bugs[[patient_id]] <- prev

    # Store covariances of keystone taxa found for this otu
    chpt_covs[[patient_id]] <- cumsum(abs(chpt_res[2,]))
    hubs_covs[[patient_id]] <- cumsum(abs(hubs_res[2,]))
    abun_covs[[patient_id]] <- cumsum(abs(abun_res[2,]))
    prev_covs[[patient_id]] <- cumsum(abs(prev_res[2,]))
    
}

# Convert lists of keystone taxa to dataframes
chpt_df <- data.frame(chpt_bugs)
abun_df <- data.frame(abun_bugs)
prev_df <- data.frame(prev_bugs)
hubs_df <- data.frame(hubs_bugs)

# Add row names
rownames(chpt_df) <- paste0("top.", c(1:top))
rownames(abun_df) <- paste0("top.", c(1:top))
rownames(prev_df) <- paste0("top.", c(1:top))
rownames(hubs_df) <- paste0("top.", c(1:top))

# Convert lists of covariance measures to matrices
chpt_covs <- as.matrix(data.frame(chpt_covs))
hubs_covs <- as.matrix(data.frame(hubs_covs))
abun_covs <- as.matrix(data.frame(abun_covs))
prev_covs <- as.matrix(data.frame(prev_covs))

# Combine all covariance measures into one data frame
all_covs <- cbind(abun_covs, prev_covs, hubs_covs)

# Siginificance test 
significance_res <- wilcoxtest(all_covs, top)
writeLines("\n\nResults of the significance test:\n")
print(significance_res)

#### Write the results to files
# Write keystone taxa
write.table(chpt_df, "keystone_changepoint.csv", sep=",")
write.table(abun_df, "keystone_abundance.csv", sep=",")
write.table(prev_df, "keystone_prevalence.csv", sep=",")
write.table(hubs_df, "keystone_hubs.csv", sep=",")

# Write covariance measures
write.table(chpt_covs, "covariances_changepoint.csv", sep=",")
write.table(abun_covs, "covariances_abundance.csv", sep=",")
write.table(prev_covs, "covariances_prevalence.csv", sep=",")
write.table(hubs_covs, "covariances_hubs.csv", sep=",")

# Write significance test results
write.table(significance_res, "significance_results.csv", sep=",")
