
#' check onclick
#' @description Function to put a tickmark on click
#' @return Change value of reactive output, without return 
#' @keywords internal

check_onclick_ <- function(.menu_react, .butt_number, my_envir) {

output <- NULL

check_onclick <- function(menu_react, butt_number) {
element <- paste0("check", butt_number)
output[[element]] <- shiny::renderPrint({
    if (menu_react() == TRUE) {
        shiny::HTML(paste0("<script>
        \t\t\t\t\t   $(\"#button", 
        butt_number, " span\").addClass(\"checked\");
        \t\t\t\t\t   </script>"))
    } else {
        shiny::HTML(paste0("<script>
        \t\t\t\t\t   if($(\"#button", 
        butt_number, " span\").hasClass(\"checked\")) {
        \t\t\t\t\t   $(\"#button", 
        butt_number, " span\").removeClass(\"checked\");}
        \t\t\t\t\t   
        \t\t\t\t\t   </script>"))
    }
})
}
environment(check_onclick) <- my_envir
check_onclick(.menu_react, .butt_number)
}

#' outputClean_
#' @return Vector with chunks length and width  information 
#' @keywords internal

outputClean_ <- function(.myFile, .lengthWidthVec, my_envir) {

outputClean <- function(myFile, lengthWidthVec) {
file_length <- length(myFile)
file_width <- Biostrings::width(ShortRead::sread(myFile))
lengthWidthVec[[1]] <- sum(c(lengthWidthVec[[1]], file_length))
lengthWidthVec[[2]] <- unique(c(lengthWidthVec[[2]], file_width))
if (length(lengthWidthVec[[2]]) > 1) {
    lengthWidthVec[[2]] <- c(min(lengthWidthVec[[2]]), 
    max(lengthWidthVec[[2]]))
}
lengthWidthVec
}
environment(outputClean) <- my_envir
outputClean(.myFile, .lengthWidthVec)
}

#' messageFun_
#' @return Changes the state of reactive vector, without return 
#' @keywords internal


messageFun_ <- function(.who, .chunck, .which_read, my_envir) {
messageFun <- function(who, chunck, which_read, envir) {

readsWidth[[who]][[which_read]] <- outputClean_(chunck, 
readsWidth[[who]][[which_read]], envir)
chunck_length <- readsWidth[[who]][[which_read]][[1]]
chunck_width <- readsWidth[[who]][[which_read]][[2]]
if (length(chunck_width) > 1) {
    chunck_width <- paste0(min(chunck_width), "-", 
    max(chunck_width), " cicles")
} else {
    chunck_width <- paste0(readsWidth[[who]][[which_read]][[2]], 
    " cicles")
}
messages[[who]][which_read] <- paste0("Processed: ", chunck_length, 
                                        " reads. ", 
                                        chunck_width)
}
environment(messageFun) <- my_envir
messageFun(.who, .chunck, .which_read, my_envir)
}


#' create_cleanfunction_
#' @description Create a function to process FASTQ files in function
#' of the Shiny parameters selected by the user
#' @return Function with selected cleaning operations
#' @keywords internal

create_cleanfunction_ <- function(my_envir, 
.which_read = c("FORWARD", "REVERSE")) {
.which_read <- match.arg(.which_read)
force(my_envir)  

out <- function() {}

NCleanData <- lowComplexData <- SeqInput <- function() {}
FilterbymeanQ <- TrimCleanData <- FixedCleanData <- function() {}
SizeCleanData <- FilterbymeanQ <- TrimCleanData <- function() {}
FixedCleanData <- SizeCleanData <- DuplicCleanData <- function() {}

fun_body <- function(which_read) {

if (NCleanData()) {
    e1 <- expression(fileToProcess <- n_filter(fileToProcess,
    as.numeric(input$rm.N)), 
    messageFun_("nFilterCatch", 
    fileToProcess, read, my_envir))
} else {
    e1 <- expression()
}

if (lowComplexData()) {
    e2 <- expression(fileToProcess <- complex_filter(fileToProcess,
    input$complexThres), 
    messageFun_("lowComplexFilterCatch", 
    fileToProcess, read, my_envir))
} else {
    e2 <- expression()
}

if (SeqInput()) {
    if (which_read == "FORWARD") {
        e3 <- expression(fileToProcess <- adapter_filter(fileToProcess,
            Lpattern = input$LpatternF, 
            Rpattern = input$RpatternF,
            rc.L = input$reverseLF, 
            rc.R = input$reverseRF, 
            first = input$first_forward,
            with_indels = input$indels, 
            error_rate = input$errate, 
            anchored = input$anchored, 
            min_match_flank = input$min_match_flank, 
            checks = FALSE), 
        messageFun_("seqFilterCatch", fileToProcess, 
        .which_read = 1,  my_envir))
} else {
        e3 <- expression(fileToProcess <- adapter_filter(fileToProcess, 
            Lpattern = input$LpatternR, 
            Rpattern = input$RpatternR, 
            rc.L = input$reverseLR, 
            rc.R = input$reverseRR,
            first = input$first_reverse, 
            with_indels = input$indels, 
            error_rate = input$errate,
            anchored = input$anchored,
            min_match_flank = input$min_match_flank, 
            checks = FALSE), 
        messageFun_("seqFilterCatch", fileToProcess, 
        .which_read = 2,  my_envir))
}  # end 'REVERSE'

} else {
    e3 <- expression()
}

if (FilterbymeanQ()) {
    e4 <- expression(fileToProcess <- qmean_filter(fileToProcess,
        input$thresmeanQ, 
        q_format = my_encoding[["value"]]), 
    messageFun_("meanQFilterCatch", fileToProcess, read, my_envir))
} else {
e4 <- expression()
}

if (TrimCleanData()) {
    e5 <- expression(fileToProcess <- trim3q_filter(fileToProcess, 
        input$thresQual, 
        q_format = my_encoding[["value"]]), 
        messageFun_("trim3FilterCatch", fileToProcess, read, my_envir))
} else {
e5 <- expression()
}

if (FixedCleanData()) {
    e6 <- expression(fileToProcess <- fixed_filter(fileToProcess, input$rm3, 
    input$rm5), 
    messageFun_("fixedFilterCatch", fileToProcess, read, my_envir))
} else {
    e6 <- expression()
}

if (SizeCleanData()) {
    e7 <- expression(fileToProcess <- length_filter(fileToProcess, input$rmMin, 
    input$rmMax), 
    messageFun_("lengthFilterCatch", fileToProcess, read,  my_envir))
} else {
e7 <- expression()
}

if (DuplicCleanData()) {
    e8 <- expression(fileToProcess <- unique_filter(fileToProcess),
    messageFun_("duplicFilterCatch", fileToProcess, read, my_envir))
} else {
    e8 <- expression()
}
    e9 <- expression(fileToProcess)
    as.call(c(as.name("{"), e1, e2, e3, e4, e5, e6, e7, e8, e9))
}

environment(fun_body) <- my_envir
body(out) <- fun_body(which_read = .which_read)
formals(out) <- alist(fileToProcess = , read = , my_envir = )
environment(out) <- my_envir

out
}

#' processingFunction_
#' @description This function is the core of the application. It is used 
#' for the program to process the FASTQ file/s in the environment 
#' of the Shiny app. Note that this program makes a call to
#' create_cleanfunction
#' @return Processes the input FASTQ file, without return
#' @keywords internal


processingFunction_ <- function(my_envir) {

input <- this_envir <- filepath <- session <- NULL

create_processing_function <- function() {

if (input$fileTypeOut == "fastq") {
    compress <- FALSE
} else {
    compress <- TRUE
}


i <- 0


if (input$fileTypeIn == "SR") {
    .cleanfunction <- create_cleanfunction_(this_envir, 
    .which_read = "FORWARD")
    no_output <- as.character(body(.cleanfunction))[2] == "fileToProcess"

} else {
    .cleanfunctionF <- create_cleanfunction_(this_envir, 
    .which_read = "FORWARD")
    .cleanfunctionR <- create_cleanfunction_(this_envir,
    .which_read = "REVERSE")
    no_output <- as.character(body(.cleanfunctionF))[2] == "fileToProcess"


}


if (input$fileTypeIn == "SR" && no_output) {
    outname <- sprintf("%s_out", filepath$x)
if (file.exists(outname)) {
    file.remove(outname)
}
    file.symlink(filepath$x, outname)
}

if (input$fileTypeIn == "PE" && no_output) {

    outname1 <- sprintf("%s_out", (filepath$x)[1])
    outname2 <- sprintf("%s_out", (filepath$x)[2])

if (file.exists(outname1)) {
    file.remove(outname1)
}

if (file.exists(outname2)) {
    file.remove(outname2)
}

file.symlink((filepath$x)[1], outname1)
file.symlink((filepath$x)[2], outname2)
}


if (input$fileTypeIn == "SR" && !no_output) {


if (file.exists(sprintf("%s_out", filepath$x))) {
    file.remove(sprintf("%s_out", filepath$x))
    file.create(sprintf("%s_out", filepath$x))
}

cat("Counting lines in file ...\n")
lfile <- ShortRead::countLines(filepath$x)/4
cat(lfile, "reads found\n\n")
largo <- 0L
ancho <- c(-1L, -1L)


progress <- shiny::Progress$new(session, min = 0, max = lfile)
progress$set(message = "Processing the file",
detail = "This may take a while...")

stream <- ShortRead::FastqStreamer(filepath$x, n = input$nfile)


while (TRUE) {
    passfile <- try(ShortRead::yield(stream), silent = TRUE)
    if(length(passfile) == 0) {

    if(length(unique(ancho)) > 1) {
        cycle_info <- paste0(ancho[1], "-", ancho[2], " cycles")
    } else {
        cycle_info <- paste0(unique(ancho), " cycles")
    }

messages[["outResult"]] <- paste0(largo, " reads. ", cycle_info, 
"\n",
sprintf("%s_out", (filepath$x)))

break

} else {
progress$set(value = i)
cat(i, " reads processed", "\n")
i <- i + length(passfile)

outFile <- .cleanfunction(passfile, read = 1, this_envir)
ShortRead::writeFastq(outFile, sprintf("%s_out", 
filepath$x), mode = "a", 
compress = compress)

largo <- largo + length(outFile)
ancho <- unique(range(c(ancho[ancho != -1], Biostrings::width(outFile))))
cat(ancho, "\n")

}
}

close(stream)
progress$close()
}

if (input$fileTypeIn == "PE" && !no_output) {

    cat("Counting lines in file ...\n")
    lfile <- (ShortRead::countLines((filepath$x)[1]))/4
    cat(lfile, "reads found\n\n")

    largoL <- largoR <- 0L
    anchoL <- anchoR <- c(-1L, -1L)

    for (j in filepath$x) {
        if (file.exists(sprintf("%s_out", j))) {
        file.remove(sprintf("%s_out", j))
    }
        file.create(sprintf("%s_out", j))
    }

    progress <- shiny::Progress$new(session, min = 0, max = lfile)
    progress$set(message = "Processing the file",
    detail = "This may take a while...")

    streamL <- ShortRead::FastqStreamer((filepath$x)[1], n = input$nfile)
    streamR <- ShortRead::FastqStreamer((filepath$x)[2], n = input$nfile)

    while (TRUE) {

        passfileL <- try(ShortRead::yield(streamL), silent = TRUE)
        passfileR <- try(ShortRead::yield(streamR), silent = TRUE)

        if(length(passfileL) == 0 && length(passfileR) == 0) {

            if(length(unique(anchoL)) > 1) {
                cycle_info_L <- paste0(anchoL[1], "-", anchoL[2], " cycles")
            } else {
                cycle_info_L <- paste0(unique(anchoL), " cycles")
            }

            messages[["outResult"]][1] <- paste0(largoL, " reads. ", 
                                            cycle_info_L, "\n",
            sprintf("%s_out", (filepath$x)[1]))

            if (length(unique(anchoR)) > 1) {
                cycle_info_R <- paste0(anchoR[1], "-", anchoR[2], " cycles")
            } else {
                cycle_info_R <- paste0(unique(anchoR), " cycles")
            }

            messages[["outResult"]][2] <- paste0(largoR, " reads. ", 
                                                cycle_info_R, "\n", 
            sprintf("%s_out", (filepath$x)[2]))

            break

        } else {
        progress$set(value = i)
        cat(i, " reads processed", "\n")
        i <- i + length(passfileL)

        outFileL <- .cleanfunctionF(passfileL, read = 1, this_envir)
        outFileR <- .cleanfunctionR(passfileR, read = 2, this_envir)

        inL <- ShortRead::id(passfileL)
        outL <- ShortRead::id(outFileL)
        indexL <- as.character(inL) %in% as.character(outL)
        names(indexL) <- seq(along = indexL)
        indexL <- names(indexL[indexL])

        inR <- ShortRead::id(passfileR)
        outR <- ShortRead::id(outFileR)
        indexL <- as.character(inL) %in% as.character(outL)
        names(indexR) <- seq(along = indexR)
        indexR <- names(indexR[indexR])

        indexpairL <- indexL %in% indexR
        indexpairR <- indexR %in% indexL

        outFileL <- outFileL[indexpairL]
        outFileR <- outFileR[indexpairR]

        ShortRead::writeFastq(outFileL, sprintf("%s_out", (filepath$x)[1]), 
        mode = "a", compress = compress)

        ShortRead::writeFastq(outFileR, sprintf("%s_out", (filepath$x)[2]), 
        mode = "a", compress = compress)


        largoL <- largoL + length(outFileL)
        largoR <- largoR + length(outFileR)

        anchoL <- unique(range(c(anchoL[anchoL != -1], 
                Biostrings::width(outFileL))))
        anchoR <- unique(range(c(anchoR[anchoR != -1], 
                Biostrings::width(outFileR))))

    }
    }

        close(streamL)
        close(streamR)
        progress$close()

        }
    }

environment(create_processing_function) <- my_envir
create_processing_function()
}
