.any_na <- function(x) {
  if (inherits(x,"dist"))
    x <- as.matrix(x)
  rowSums(is.na(x)) > 0
}

#' Handle Missing Values in \code{procmod_frame}.
#'
#' These S3 methods are useful for dealing with NAs in e.g., \code{procmod_frame}.
#'
#' na.fail returns the object if it does not contain any missing values,
#' and signals an error otherwise.
#'
#' na.omit returns the object with incomplete cases removed.
#'
#' na.pass returns the object unchanged.
#'
#' @param object a \code{procmod_frame} object
#' @param ... further arguments special methods could require.
#'
#' @examples
#' A <- simulate_matrix(20, 5)
#' B <- simulate_correlation(A, 10, r2 = 0.4)
#' C <- simulate_correlation(A, 15, r2 = 0.6)
#' D <- dist(A)
#' A[3, 2] <- NA
#'
#' pf <- procmod_frame(A = A, B = B, C = C, D = D)
#'
#' na.omit(pf)
#' na.exclude(pf)
#'
#' @seealso \link[stats]{na.fail}
#' @author Eric Coissac
#' @author Christelle Gonindard-Melodelima
#' @export
na.omit.procmod_frame <- function(object, ...) {
  omit <- rowSums(sapply(object,.any_na)) > 0

  if (any(omit)) {
    xx <- object[!omit, , drop = FALSE]
    attr(xx, "row_names") <- attr(object, "row_names")[!omit]

    if (any(omit > 0L)) {
      temp <- setNames(seq(omit)[omit], attr(object, "row.names")[omit])
      attr(temp, "class") <- "omit"
      attr(xx, "na.action") <- temp
    }
  }
  else
    xx <- object

  xx
}

#' @rdname na.omit.procmod_frame
#' @export
na.exclude.procmod_frame <- function(object, ...) {
  xx <- na.omit.procmod_frame(object, ...)
  na.action <- attr(xx, "na.action")
  if (!is.null(na.action)) {
    class(na.action) <- "exclude"
    attr(xx, "na.action") <- na.action
  }

  xx
}


#' @rdname na.omit.procmod_frame
#' @export
na.fail.procmod_frame <- function(object, ...) {
  omit <- rowSums(sapply(object,.any_na)) > 0

  if (any(omit))
    stop("missing values in object")

  object
}
