bic.mixesag <- function(x, G = 5, tol = 1e-4, ncores = 1) {
  runtime <- proc.time()
  logn <- log( dim(x)[1] )  ## sample size of the data
  bic <- icl <- 1:G
  mod <- Directional::esag.mle(x)
  bic[1] <- icl[1] <-  - 2 * mod$loglik + 5 * logn  ## BIC assuming one cluster

  if ( ncores > 1 ) {
    cl <- parallel::makeCluster(ncores)
    on.exit(parallel::stopCluster(cl))
    parallel::clusterExport(cl, varlist = c("x", "tol", "logn"), envir = environment())
    parallel::clusterEvalQ(cl, library(sphereclust))

    results <- parallel::parSapply(cl, 2:G, function(vim) {
      a <- sphereclust::mixesag.mle(x, vim, tol = tol)
      nm <- min( table(a$pred) )
      d <- dim(a$param)[1]
      bic_val <-  - 2 * a$loglik + ( d - 1 + d * 5 ) * logn
      icl_val <- bic_val - 2 * sum( a$probs * log(a$probs), na.rm = TRUE )
      c( bic = bic_val, icl = icl_val, d = d, nm = nm )
    }, simplify = TRUE )                          ## 2 x (G-1) matrix

    d <- nm <- 1:G
    d[1] <- nm[1] <- dim(x)[1]
    bic[2:G] <- results["bic", ]
    icl[2:G] <- results["icl", ]
    d[2:G] <- results["d", ]
    nm[2:G] <- results["nm", ]
    ep <- which( diff(d) == 0 ) + 1
    if ( length(ep) > 0 ) {
      bic[ep] <- bic[ min(ep) - 1 ]
      icl[ep] <- icl[ min(ep) - 1 ]
    }
    ep <- which(nm < 10)
    if ( length(ep) > 0 ) {
      bic[ep] <- bic[ep - 1]
      icl[ep] <- icl[ep - 1]
    }

  } else {

    for ( vim in 2:G ) {
      a <- sphereclust::mixesag.mle(x, vim, tol = tol)  ## model based clustering for some possible clusters
      d <- dim(a$param)[1]
      nm <- min( table(a$pred) )
      if ( d == vim  &  nm > 10 ) {
        bic[vim] <-  - 2 * a$loglik + ( d - 1 + d * 5 ) * logn
        icl[vim] <- bic[vim] - 2 * sum( a$probs * log(a$probs), na.rm = TRUE )
      } else  {
        bic[vim] <- bic[vim - 1]
        icl[vim] <- icl[vim - 1]
      }
    }  ## BIC for a range of different clusters
  }

  runtime <- proc.time() - runtime
  names(bic) <- names(icl) <- paste("g=", 1:G, sep = "")
  ina <- rep(1, G)
  char <- rep(16, G)
  ina[ which.min(icl) ] <- 3  ## chosen number of clusters will appear with red on the plot
  char[ which.min(icl) ] <- 17
  plot(1:G, icl, col = ina, xlab = "Number of components", ylab = "ICL values", cex.lab = 1.3, cex.axis = 1.3)
  abline(v = 1:G, lty = 2, col = "lightgrey")
  abline(h = seq(min(icl, na.rm = FALSE), max(icl, na.rm = FALSE), length = 10), lty = 2, col = "lightgrey" )
  lines(1:G, icl, lwd = 2)
  abline(v = which.min(icl), col = 3, lwd = 2)
  points(1:G, icl, pch = char, col = ina)
  list(bic = bic, icl = icl, runtime = runtime)
}
