#==========================================================
# Internal Validation Functions
#==========================================================


#==========================================================
# Validate Data
#==========================================================

#' Validate Data
#'
#' Internal validation function used throughout DataAudit.
#'
#' @param data An object expected to be a data.frame.
#'
#' @return Invisibly returns \code{TRUE} when validation
#'   succeeds.
#'
#' @keywords internal
#' @noRd

validate_data <- function(data) {

  #---------------------------------------------
  # NULL
  #---------------------------------------------
  if (is.null(data)) {
    stop(
      "'data' cannot be NULL.",
      call. = FALSE
    )
  }

  #---------------------------------------------
  # Data frame
  #---------------------------------------------
  if (!is.data.frame(data)) {
    stop(
      "'data' must be a data.frame.",
      call. = FALSE
    )
  }

  #---------------------------------------------
  # At least one variable
  #---------------------------------------------
  if (ncol(data) == 0L) {
    stop(
      "'data' must contain at least one variable.",
      call. = FALSE
    )
  }

  invisible(TRUE)
}


#==========================================================
# Validate Column
#==========================================================

#' Validate Column
#'
#' Internal validation function for a column name.
#'
#' @param data A data.frame.
#' @param column A column name.
#'
#' @return Invisibly returns \code{TRUE} when validation
#'   succeeds.
#'
#' @keywords internal
#' @noRd

.validate_column <- function(data, column) {

  validate_data(data)

  if (
    !is.character(column) ||
    length(column) != 1L ||
    is.na(column)
  ) {
    stop(
      "'column' must be a single non-missing character string.",
      call. = FALSE
    )
  }

  if (!nzchar(column)) {
    stop(
      "'column' cannot be empty.",
      call. = FALSE
    )
  }

  if (!column %in% names(data)) {
    stop(
      sprintf(
        "Column '%s' was not found in 'data'.",
        column
      ),
      call. = FALSE
    )
  }

  invisible(TRUE)
}


#==========================================================
# Validate Numeric Scalar
#==========================================================

#' Validate Numeric Scalar
#'
#' Internal validation function for finite numeric scalar
#' arguments.
#'
#' @param x Object to validate.
#' @param name Argument name used in the error message.
#'
#' @return Invisibly returns \code{TRUE}.
#'
#' @keywords internal
#' @noRd

.validate_numeric_scalar <- function(x, name) {

  if (
    !is.numeric(x) ||
    length(x) != 1L ||
    is.na(x) ||
    !is.finite(x)
  ) {
    stop(
      sprintf(
        "'%s' must be a single finite numeric value.",
        name
      ),
      call. = FALSE
    )
  }

  invisible(TRUE)
}


#==========================================================
# Validate Logical Scalar
#==========================================================

#' Validate Logical Scalar
#'
#' @param x Object to validate.
#' @param name Argument name.
#'
#' @return Invisibly returns \code{TRUE}.
#'
#' @keywords internal
#' @noRd

.validate_logical_scalar <- function(x, name) {

  if (
    !is.logical(x) ||
    length(x) != 1L ||
    is.na(x)
  ) {
    stop(
      sprintf(
        "'%s' must be TRUE or FALSE.",
        name
      ),
      call. = FALSE
    )
  }

  invisible(TRUE)
}


#==========================================================
# Detect Blank Strings
#==========================================================

#' Detect Blank Strings
#'
#' Internal helper for identifying empty or whitespace-only
#' character values.
#'
#' @param x A vector.
#'
#' @return A logical vector.
#'
#' @keywords internal
#' @noRd

.is_blank <- function(x) {

  if (!is.character(x)) {
    return(
      rep(FALSE, length(x))
    )
  }

  !is.na(x) & trimws(x) == ""
}
