#1: replacing previous import 'graph::union' by 'igraph::union' when loading 'BiocFHIR' 
#2: replacing previous import 'graph::edges' by 'igraph::edges' when loading 'BiocFHIR' 
#3: replacing previous import 'graph::intersection' by 'igraph::intersection' when loading 'BiocFHIR' 
#4: replacing previous import 'graph::degree' by 'igraph::degree' when loading 'BiocFHIR' 


#' get human name from a BiocFHIR.Patient instance
#' @importFrom methods new
#' @rawNamespace import("graph", except=c("union", "edges", "intersection", "degree"))
#' @param Patient BiocFHIR.Patient instance
#' @return string with name components concatenated
#' @examples
#' testf <- system.file("json/Vince741_Rogahn59_6fa3d4ab-c0b6-424a-89d8-7d9105129296.json",
#'    package="BiocFHIR")
#' tbun <- process_fhir_bundle(testf)
#' getHumanName(tbun$Patient)
#' @export
getHumanName <- function(Patient) { 
   stopifnot(inherits(Patient, "BiocFHIR.Patient"))
   ul <- unlist(Patient);   # unpleasant to avoid "process_Patient" but simpler?
   if (!is.na(ul["name.family1"]))
     return(paste0(ul["name.family1"], ul["name.family2"]))
   else  return(paste0(ul["name.given"], ul["name.family"]))
}

#' create graph with links from patients to conditions
#' @param listOfProcessedBundles list with elements generated by `process_fhir_bundle`
#' @param keep_with_condition_only logical(1) omit bundles that lack a "Condition" element, defaults to TRUE
#' @return instance of BiocFHIR.FHIRgraph
#' @examples
#' data("allin")
#' make_condition_graph(allin, TRUE)
#' @export
make_condition_graph <- function(listOfProcessedBundles, keep_with_condition_only=TRUE) {

 patients <- vapply(listOfProcessedBundles, function(x) getHumanName(x$Patient), character(1))
 condg <- new("graphNEL", nodes=patients)
 condg@graphData <- list(edgemode="directed")

 if (keep_with_condition_only) {
   alln = lapply(listOfProcessedBundles, names)
   hascond = vapply(alln, function(x) "Condition" %in% x, logical(1))
   if (!all(hascond)) listOfProcessedBundles = listOfProcessedBundles[which(hascond)]
   }

 nn <- lapply( listOfProcessedBundles, function(x) {
    curn <- getHumanName(x$Patient)
    curconds <- try(process_Condition(x$Condition),silent=TRUE) #$code.coding.display)
    if (inherits(curconds, "try-error")) return(curconds)
    curconds <- curconds$code.coding.display
#    if (!is.null(curconds)) {
    newnodes <- setdiff(curconds, nodes(condg))
    if (length(newnodes)>0) {
      condg <- addNode(newnodes, condg)
      }
   condg <<- addEdge( curn, curconds, condg)  # must use current conditions
   condg
#    }
    })
 errs <- vapply(nn, function(x) inherits(x, "try-error"), logical(1))
 haserr <- sum(errs)
 if (haserr > 0) message("...some bundles had no Condition component")
 conditions <- setdiff(nodes(condg), patients) # hokey
 ans <- list(graph=condg, patients=patients, conditions=conditions)
 class(ans) <- "BiocFHIR.FHIRgraph"
 ans
}

#' show a combination of graph and patient attributes
#' @param x instance of BiocFHIR.FHIRgraph
#' @param \dots not used
#' @return print method
#' @examples
#' data("allin")
#' make_condition_graph(allin)
#' @export
print.BiocFHIR.FHIRgraph <- function(x, ...) {
 cat("BiocFHIR.FHIRgraph instance.\n")
 print(x$graph)
 cat(sprintf(" %d patients, %d conditions\n", length(x$patients), length(x$conditions)))
}


#' update a fhir graph on patients and conditions with procedures
#' @param fhirgraph instance of BiocFHIR.FHIRgraph
#' @param listOfProcessedBundles list
#' @return instance of BiocFHIR.FHIRgraph
#' @examples
#' data("allin")
#' g <- make_condition_graph(allin)
#' g <- add_procedures(g, allin)
#' g
#' @export
add_procedures <- function(fhirgraph, listOfProcessedBundles) {
 stopifnot(inherits(fhirgraph, "BiocFHIR.FHIRgraph"))
 curg <- fhirgraph$graph
 nn <- lapply( listOfProcessedBundles, function(x) {
    curn <- getHumanName(x$Patient)
    curprocs <- try(process_Procedure(x$Procedure),silent=TRUE) # $code.display)
    if (inherits(curprocs, "try-error")) return(curprocs)
    curprocs <- curprocs$code.display
    newnodes <- setdiff(curprocs, nodes(curg))
    if (length(newnodes)>0) {
        curg <- addNode(newnodes, curg)
        }
   curg <<- addEdge( curn, curprocs, curg)
    curg
    })
 errs <- vapply(nn, function(x) inherits(x, "try-error"), logical(1))
 haserr <- sum(errs)
 if (haserr > 0) message("...some bundles had no Procedure component")
 fhirgraph$procedures <- setdiff(nodes(curg), nodes(fhirgraph$graph))
 fhirgraph$graph <- curg
 fhirgraph
}

#library(BiocFHIR)
#library(graph)
#library(parallel)
#library(igraph)
#options(mc.cores=4)
##allin <- mclapply(dir(pattern="json$"), process_fhir_bundle)
#load("allin.rda")
#condg <- make_condition_graph( allin )
#condg <- add_procedures( condg, allin )
#condg
#
#ii <- igraph.from.graphNEL(condg$graph)



#' build graph with patients, conditions and procedures
#' @param listOfBundles list of processed FHIR bundles, processed with `process_fhir_bundle`
#' @return instance of visIgraph from visNetworks
#' @examples
#' data("allin")
#' build_proccond_igraph( allin )
#' @export
build_proccond_igraph <- function( listOfBundles ) {
 condg <- make_condition_graph( listOfBundles )
 condg <- add_procedures( condg, listOfBundles )
 ii <- igraph::igraph.from.graphNEL( condg$graph )
 igraph::V(ii)$color[ names(igraph::V(ii)) %in% condg$conditions ] <- "red"
 igraph::V(ii)$color[ names(igraph::V(ii)) %in% condg$procedures ] <- "green"
 igraph::V(ii)$color[ names(igraph::V(ii)) %in% condg$patients ] <- "blue"
 ii
}

#' make network visualization
#' @importFrom visNetwork visIgraph
#' @param igraph instance of igraph produced by `build_procond_igraph`
#' @return visIGraph instance
#' @examples
#' data("allin")
#' g <- build_proccond_igraph( allin ) 
#' if (interactive()) {
#'  display_proccond_igraph( g )
#' }
#' @export
display_proccond_igraph <- function( igraph ) {
 visIgraph( igraph )
}
