skeleton <- function(x, mapping = NULL, fill = NULL, space = FALSE) {
  if ((!is.character(x)) | length(x) > 1) {
    stop("The parameter x must be a character vector of length 1.")
  }

  if (is.null(mapping)) {
    path    <- system.file("extdata", "etcsl_mapping.txt", package = "sumer")
    mapping <- read.csv2(path, sep = ";", na.strings = "")
  }

  "get_equation" <- function(x) {
    x   <- info(x, mapping = mapping)
    res <- paste0(c(paste0(x$reading, collapse = "-"),
                    paste0(x$name, collapse = "."),
                    paste0(x$sign, collapse = "")), collapse = "=")
    return(res)
  }

  # Convert to cuneiform and extract tokens
  x     <- as.cuneiform(x, mapping = mapping)
  token <- split_sumerian(x)$signs
  N     <- length(token)

  # Validate fill if provided
  if (!is.null(fill)) {
    fill_tokens <- split_sumerian(fill$expr[1])$signs
    if (!identical(fill_tokens, token) || nrow(fill) != N * (N + 1) / 2) {
      stop("The parameter fill does not match x.")
    }
  }

  # Normalize brackets and extract hierarchical structure
  x_marked <- mark_skeleton_entries(x)
  df       <- extract_skeleton_entries(x_marked)
  n_entries <- nrow(df)

  # Add column with indices into the fill data frame
  df$fill_idx <- substr_position(df$start, df$n_tokens, N)

  # Pre-compute type and translation columns from fill
  if (!is.null(fill)) {
    df$type        <- fill$type[df$fill_idx]
    df$translation <- fill$translation[df$fill_idx]
  } else {
    df$type        <- ""
    df$translation <- ""
  }

  df$type <- str_replace_all(df$type, "x","\u2612")
  df$type <- str_replace_all(df$type, "->","\u2192")

  # Replace operator "S☒→V" with "Vt"
  df$type[df$type == paste0("S\u2612\u2192V")] <- "Vt"

  # Build header line from root row (row 1, depth 0)
  if (N == 1) {
    header <- get_equation(x_marked)
  } else {
    header <- paste0(info(x_marked, mapping = mapping)$reading, collapse = "-")
  }
  result <- paste0("|", header, ": ", df$type[1], ": ", df$translation[1])

  # Build entry lines (rows 2..n, depth >= 1)
  if (n_entries >= 2) for (i in 2:n_entries) {
    # Insert blank line before depth-1 entries
    if (space && df$depth[i] == 1) {
      result <- c(result, "")
    }

    eq <- get_equation(df$expr[i])

    result <- c(result, paste0("|", strrep("\t", df$depth[i] - 1),
                                eq, ": ", df$type[i], ": ", df$translation[i]))
  }

  result <- c(paste0("Structure: ", str_trim(x)),"",result)
  class(result) <- c("skeleton", "character")
  result
}


print.skeleton <- function(x, ...) {
  cat(x, sep = "\n")
}
