## ERE / H_m Estimation and confidence intervals
#' @import stats
#' @importFrom survival coxph
mod_est <- function(X, y, var_id, Mbeta, family,
                    conf.level = 0.95, CI.type = c("two.sided","one.sided"),
                    CI = TRUE){
  n = nrow(X)
  # xname = paste("x",var_id, sep = ".")
  if(length(var_id)==0){
    return(list(num.nonzeros=0,Th=0,CI=c(NA,NA)))
  }
  num.nonzeros = length(var_id) - length(var_id[var_id %in% Mbeta])
  if(num.nonzeros==0){
    return(list(num.nonzeros=0,Th=0,CI=c(NA,NA)))
  }

  ## fit the full model
  xf = X[,var_id]
  ## fit the reduced model
  if(length(var_id[var_id %in% Mbeta])!=0){
    xr = X[,var_id[var_id %in% Mbeta]]
    }


  if(family == 'gaussian'){
    fit_full = lm(y~xf)
    if(length(var_id[var_id %in% Mbeta])==0){fit_reduced = lm(y~1)}
    else{
      fit_reduced = lm(y~xr)
    }
    # estimation using log likelihood
    Th = as.numeric((logLik(fit_full)-logLik(fit_reduced))/n)
  }
  if(family == 'binomial'){
    fit_full = glm(y~xf, family = 'binomial')
    if(length(var_id[var_id %in% Mbeta])==0){fit_reduced = glm(y~1, family = 'binomial')}
    else{
      fit_reduced = glm(y~xr, family = 'binomial')
    }
    Th = -(fit_full$deviance - fit_reduced$deviance) / (2*n)
  }
  if(family == 'cox'){
    ## y is a 'Surv' object; Th is the per-observation gain in the Cox partial
    ## log-likelihood contributed by the modality-specific features.
    fit_full = coxph(y ~ as.matrix(xf))
    if(length(var_id[var_id %in% Mbeta])==0){
      ## reduced model has no covariates: use the null partial log-likelihood
      ll_reduced = fit_full$loglik[1]
    }else{
      fit_reduced = coxph(y ~ as.matrix(xr))
      ll_reduced = as.numeric(logLik(fit_reduced))
    }
    Th = (as.numeric(logLik(fit_full)) - ll_reduced) / n
  }

  # Calculating Confidence Interval
  if(!isTRUE(CI)){
    return(list(num.nonzeros=num.nonzeros,Th=Th,CI=c(NA,NA)))
  }
  if(n*Th < 0.0001){
    return(list(num.nonzeros=num.nonzeros,Th=Th,CI=c(NA,NA)))
  }

  if(family == 'cox'){
    ## Cox partial-likelihood ratio: noncentrality = n * Th, scale = n
    if(CI.type == "two.sided"){
      CI = unlist(conf.limits.nc.chisq(Chi.Square=2*n*Th, conf.level=conf.level,
                                       df=num.nonzeros)[c(1,3)])/(2*n)
    }
    else if(CI.type == "one.sided"){
      CI_L = unlist(conf.limits.nc.chisq(Chi.Square=2*n*Th, alpha.lower=1-conf.level,
                                         alpha.upper=0, conf.level=NULL,
                                         df=num.nonzeros)[2])/(2*n)
      CI = c(CI_L,Inf)
    }
  }else{
    ## Gaussian / Binomial deviance ratio: noncentrality = 2 * n * Th, scale = 2 * n
    if(CI.type == "two.sided"){
      CI = unlist(conf.limits.nc.chisq(Chi.Square=2*n*Th, conf.level=conf.level,
                                       df=num.nonzeros)[c(1,3)])/(2*n)
    }
    else if(CI.type == "one.sided"){
      CI_L = unlist(conf.limits.nc.chisq(Chi.Square=2*n*Th,
                                         alpha.lower=1-conf.level, alpha.upper=0,
                                         conf.level=NULL, df=num.nonzeros)[2])/(2*n)
      CI = c(CI_L,Inf)
    }
  }

  return(list(num.nonzeros=num.nonzeros,Th=Th,CI=CI))
}



## Iterative Dimension reduction procedure
# @import stats
# ISIS_mglm <- function(X, y, family, iter , tune = tune, iter.max = 20){
#   p = ncol(X)
#   n = nrow(X)
#
#   ix0 = c()
#   iterind = 0
#
#   ## Variable Selection through SIS
#   nseq = seq(12, ceiling(n/(log(n))),by = 1)
#   tune_stat = 10000
#   tune_value = rep(0,length(nseq))
#   var_id0 = c()
#
#   for (k in 1:length(nseq)){
#     model = SIS(X, y, family=family, tune=tune,nsis = nseq[k],iter = FALSE)
#     xf = X[,model$sis.ix0]
#     fit0 = glm(y~xf-1, family = family)
#     tune_value[k] = switch(tune, bic = BIC(fit0),
#                            ebic = BIC(fit0) + log(choose(p,k)),
#                            aic = AIC(fit0) )
#     if(tune_value[k] < tune_stat){
#       var_id0_min = model$sis.ix0
#       tune_stat = tune_value[k]
#     }
#   }
#   k = min(which(tune_value < min(tune_value) + sd(tune_value)/length(nseq) ))
#   model = SIS(X, y, family=family, tune=tune,nsis = nseq[k],iter = FALSE)
#   ix0 = model$sis.ix0
#
#   if(iter == FALSE){
#     ## SIS procedure
#     iterind = 1
#     cat("Iter", iterind, ", selection: ", c(ix0), "\n")
#   }else{
#     iterind = 1
#     cat("Iter", iterind, ", selection: ", c(ix0), "\n")
#     repeat{ ## Iterative screening procedure
#       iterind = iterind + 1
#       new.ind = 0
#       nsis = max(ceiling(n/(log(n)))-length(ix0),2)
#       nseq = seq(1, nsis,by = 1)
#       tune_value = rep(0,length(nseq))
#       candind = setdiff(1:p, ix0)
#
#       condcoef = margcoef(X, y, ix0, family = family, null.model = FALSE, iterind = iterind)
#       rankcoef = sort(condcoef, decreasing = TRUE, index.return = TRUE)
#       var_id_iter = ix0
#
#       for (k in 1:length(nseq)){
#         newix = candind[rankcoef$ix[1:nseq[k]]]
#         xf = X[,c(ix0,newix)]
#         fit0 = glm(y~xf-1, family = family)
#         tune_value[k] = switch(tune, bic = BIC(fit0),
#                                ebic = BIC(fit0) + log(choose(p,k)),
#                                aic = AIC(fit0) )
#         if(tune_value[k] < tune_stat){
#           new.ind = 1
#           var_id0_min = model$sis.ix0
#           tune_stat = tune_value[k]
#         }
#       }
#
#       if(new.ind==1){
#         k = min(which(tune_value < min(tune_value) + sd(tune_value)/length(nseq) ))
#         if(k==1) newix = c() else{
#           newix = candind[rankcoef$ix[1:nseq[k-1]]]
#         }
#         tune_stat = tune_value[k]
#       }else{
#         newix=c()
#       }
#       ix_iter = sort(c(ix0,newix))
#
#       cat("Iter", iterind, ", selection: ", ix_iter, "\n")
#       if (length(newix) >= nsis || iterind >= iter.max) {
#         ix0 = ix_iter
#         if (length(newix) >= nsis)
#           cat("Maximum number of variables selected \n")
#         if (iterind >= iter.max)
#           cat("Maximum number of iterations reached \n")
#         break
#       }
#       ix0 = ix_iter
#       if (iterind > 1 & length(newix) == 0) {
#         cat("Model already selected \n")
#         break
#       }
#     }
#   }
#   return(ix0)
# }


