lav_step00_parameters <- function(matchcall = NULL,
                                  syscall = NULL,
                                  dotdotdot = NULL) {
  # 1. resolve a problem where parameter 'cl' is matched to 'cluster'
  #    and shouldn't
  # 2. apply default options for cfa/sem/growth functions
  # 3. if dotdotdot$control present, copy to dotdotdot$... for
  #   optim.method,
  #   optim.force.converged,
  #   gradient -> optim.gradient !!! overwritten by dotdotdot$gradient
  #     if present
  #   init_nelder_mead -> optim.init_nelder_mead

  mc <- matchcall
  sc <- syscall
  ddd <- dotdotdot

  # catch partial matching of 'cl' (expanded to cluster)
  if (!is.null(sc[["cl"]]) &&
    is.null(sc[["cluster"]]) &&
    !is.null(mc[["cluster"]])) {
    mc[["cl"]] <- mc[["cluster"]]
    mc[["cluster"]] <- NULL
    ddd$cl <- sc[["cl"]]
  }
  if (!is.null(mc$cluster)) mc$cluster <- eval(mc$cluster, parent.frame(2))

  # default options
  if (any(ddd$model.type == c("sem", "cfa", "growth"))) {
    # default options for sem/cfa or growth
    defaults <- list(
      int.ov.free     = ddd$model.type != "growth",
      int.lv.free     = ddd$model.type == "growth",
      auto.fix.first  = TRUE, # (re)set in lav_options_set
      auto.fix.single = TRUE,
      auto.var        = TRUE,
      auto.cov.lv.x   = TRUE,
      auto.cov.y      = TRUE,
      auto.th         = TRUE,
      auto.delta      = TRUE,
      auto.efa        = TRUE
    )
    for (dflt_i in seq_along(defaults)) {
      argname <- names(defaults)[dflt_i]
      if (is.null(mc[[argname]])) {
        mc[[argname]] <- defaults[[dflt_i]]
        ddd[[argname]] <- defaults[[dflt_i]]
      }
    }
  }

  # backwards compatibility, control= argument (<0.5-23)
  if (!is.null(ddd$control)) {
    # optim.method
    if (!is.null(ddd$control$optim.method)) {
      ddd$optim.method <- ddd$control$optim.method
    }
    # cor.optim.method
    if (!is.null(ddd$control$cor.optim.method)) {
      # ignore it silently
    }
    # control$optim.force.converged
    if (!is.null(ddd$control$optim.force.converged)) {
      ddd$optim.force.converged <- ddd$control$optim.force.converged
    }
    # gradient
    if (!is.null(ddd$control$gradient)) {
      ddd$optim.gradient <- ddd$control$gradient
    }
    if (!is.null(ddd$gradient)) {
      ddd$optim.gradient <- ddd$gradient
    }
    # init_nelder_mead
    if (!is.null(ddd$control$init_nelder_mead)) {
      ddd$optim.init_nelder_mead <- ddd$control$init_nelder_mead
    }
  }

  list(mc = mc, dotdotdot = ddd)
}

lav_step00_checkdata <- function(data = NULL,
                                        dotdotdot = NULL,
                                        sample_cov = NULL,
                                        sample_nobs = NULL,
                                        sample_mean = NULL,
                                        sample_th = NULL,
                                        nacov = NULL,
                                        wls_v = NULL,
                                        ov_order = NULL) {
  # if data not NULL:
  #   if it is an 'enriched' data.frame (e.g. a tibble), simplify to an
  #   ordinary data.frame
  #   if class is 'lavMoments':
  #         check if it contains sample.cov and sample.nobs (***error*** if not)
  #         if sample.mean, sample.th, NACOV and/or WLS.V present,
  #                   copy to corresponding arguments of the function
  #         if lavOptions present in data, copy those that are not provided
  #         in the function call to dotdotdot$...
  #             set data to NULL
  #   if it is a function --> ***error***
  #   TODO: other tests are present in lav_lavdata(), should we copy them here?
  # if nacov or wls_v not NULL, set ov_order to "data"

  if (!is.null(data)) {
    if (inherits(data, "data.frame")) {
      # just in case it is not a traditional data.frame
      data <- as.data.frame(data)
    } else if (inherits(data, "lavMoments")) {
      # This object must contain summary statistics
      # e.g., created by lavaan.mi::poolSat

      # set required-data arguments
      if ("sample.cov" %in% names(data)) {
        sample_cov <- data$sample.cov
      } else {
        lav_msg_stop(gettext(
          "When data= is of class lavMoments, it must contain sample.cov"))
      }

      if ("sample.nobs" %in% names(data)) {
        sample_nobs <- data$sample.nobs
      } else {
        lav_msg_stop(gettext(
          "When data= is of class lavMoments, it must contain sample.nobs"))
      }

      # check for optional-data arguments
      if ("sample.mean" %in% names(data)) sample_mean <- data$sample.mean
      if ("sample.th" %in% names(data)) sample_th <- data$sample.th
      if ("NACOV" %in% names(data)) nacov <- data$NACOV
      if ("WLS.V" %in% names(data)) wls_v <- data$WLS.V

      # set other args not included in dotdotdot
      if (length(data$lavOptions)) {
        newdots <- setdiff(names(data$lavOptions), names(dotdotdot))
        if (length(newdots)) {
          for (dd in newdots) dotdotdot[[dd]] <- data$lavOptions[[dd]]
        }
      }

      # FIXME: Should WLS.V be an I(dentity) matrix when ULS is requested?
      #       Unused for point estimates, but still used to scale/shift test
      # if (!is.null(dotdotdot$estimator)) {
      #   if (grepl(pattern = "ULS", x = toupper(dotdotdot$estimator[1L])) &&
      #       !is.null(WLS.V)) {
      #     #  set to diagonal
      #     if (is.list(WLS.V)) {
      #       WLS.V <- lapply(WLS.V, function(w) {diag(w) <- 1 ; return(w) })
      #     } else diag(WLS.V) <- 1
      #   }
      # }

      # get rid of data= argument
      data <- NULL
    }

    if (is.function(data)) {
      lav_msg_stop(gettext("data is a function; it should be a data.frame"))
    }
  }
  # new in 0.6-14: if NACOV and/or WLS.V are provided, we force
  # ov_order="data" for now
  # until we have reliable code to re-arrange/select col/rows for
  # of NACOV/WLS.V based on the model-based ov.names
  if (!is.null(nacov) || !is.null(wls_v)) {
    if (ov_order != "force.model") { # used by sam()
      ov_order <- "data"
    } else {
      ov_order <- "model"
    }
  }

  list(
    data = data, dotdotdot = dotdotdot, sample_cov = sample_cov,
    sample_nobs = sample_nobs, sample_mean = sample_mean,
    sample_th = sample_th, nacov = nacov, wls_v = wls_v, ov_order = ov_order
  )
}
