///|
/// 表示一个有界的命令历史记录集合。
///
/// `History` 是可复制的共享 handle。不同副本共享记录和容量,不会复制底层资源。
///
/// **Construction:**
///
/// 请使用 `History::new` 构造。
///
/// **Lifecycle:**
///
/// 最后一个引用消失后,底层资源会被自动释放;调用者不需要也不能显式关闭。
pub struct History {
  priv owner : HistoryOwner
}

///|
fn history_owner_with_capacity(
  capacity : Int,
) -> HistoryOwner raise ReadlineError {
  guard capacity > 0 else { raise InvalidHistoryCapacity(capacity) }
  let owner = HistoryOwner::new(capacity)
  match owner.status() {
    0 => owner
    1 => raise InitializationFailed
    _ => raise HistoryUpdateFailed
  }
}

///|
fn history_error_code(owner : HistoryOwner) -> Int? {
  match owner.last_errno() {
    0 => None
    code => Some(code)
  }
}

///|
/// 创建一个空的、有界的 History。
///
/// **Parameters:**
///
/// - `capacity`:最多保留的记录条数,必须大于零,默认为 1000。
///
/// **Errors:**
///
/// - `capacity` 不大于零时抛出 `InvalidHistoryCapacity`。
/// - 无法创建底层资源时抛出 `InitializationFailed`。
/// - 无法设置容量时抛出 `HistoryUpdateFailed`。
///
/// **Lifecycle:**
///
/// 返回值的所有副本共享同一个私有 owner,并由 finalizer 自动释放底层资源。
///
/// **Examples:**
///
/// ```mbt check
/// test {
///   let history = History::new(capacity=100)
///   inspect(history.length(), content="0")
/// }
/// ```
pub fn History::new(capacity? : Int = 1000) -> History raise ReadlineError {
  { owner: history_owner_with_capacity(capacity) }
}

///|
/// 原样添加一条记录。
///
/// 空字符串和重复记录都会被保留;此操作不会 trim 或去重。超过容量时会自动丢弃最旧的
/// 记录。
///
/// **Errors:**
///
/// - `line` 包含 NUL 时抛出 `EmbeddedNul`。
/// - 无法更新 History 时抛出 `HistoryUpdateFailed`。
/// - 当前 History 正被行读取使用时抛出 `Busy`。
pub fn History::add(
  self : History,
  line : StringView,
) -> Unit raise ReadlineError {
  match self.owner.add(@utf8.encode(line)) {
    0 => ()
    1 => raise EmbeddedNul
    3 => raise Busy
    _ => raise HistoryUpdateFailed
  }
}

///|
/// 清空当前 History 中的全部记录。
///
/// **Errors:**
///
/// 当前 History 正被行读取使用时抛出 `Busy`。
pub fn History::clear(self : History) -> Unit raise ReadlineError {
  guard self.owner.clear() != 3 else { raise Busy }
}

///|
/// 返回当前保存的记录条数。
///
/// **Errors:**
///
/// - 无法查询底层 History 状态时抛出 `HistoryUpdateFailed`。
/// - 当前 History 正被行读取使用时抛出 `Busy`。
pub fn History::length(self : History) -> Int raise ReadlineError {
  let length = self.owner.length()
  guard length != -2 else { raise Busy }
  guard length >= 0 else { raise HistoryUpdateFailed }
  length
}

///|
/// 创建一个新的 History,并从文件加载记录。
///
/// 加载成功后,超过容量的旧记录不会被保留。加载失败时不会返回半初始化对象,也不会
/// 修改任何已有 History。
///
/// **Parameters:**
///
/// - `path`:要读取的 History 文件路径。
/// - `capacity`:最多保留的记录条数,必须大于零,默认为 1000。
///
/// **Errors:**
///
/// - `capacity` 不大于零时抛出 `InvalidHistoryCapacity`。
/// - `path` 包含 NUL 时抛出 `EmbeddedNul`。
/// - 无法创建或配置底层资源时抛出 `InitializationFailed` 或
///   `HistoryUpdateFailed`。
/// - 无法读取或解析文件时抛出 `HistoryLoadFailed`;错误中包含路径,以及底层能够可靠
///   提供时的 OS error code。
///
/// **Side effects:**
///
/// 此操作会读取 `path` 指向的文件。
pub fn History::load(
  path : StringView,
  capacity? : Int = 1000,
) -> History raise ReadlineError {
  let owned_path = path.to_owned()
  let owner = history_owner_with_capacity(capacity)
  match owner.load(@utf8.encode(owned_path)) {
    0 => { owner, }
    1 => raise EmbeddedNul
    _ => raise HistoryLoadFailed(owned_path, history_error_code(owner))
  }
}

///|
/// 将当前全部记录保存到文件,并覆盖目标文件原有内容。
///
/// 保存失败不会改变内存中的 History,但目标文件可能已经被创建或截断。
///
/// **Parameters:**
///
/// - `path`:要覆盖写入的文件路径。
///
/// **Errors:**
///
/// - `path` 包含 NUL 时抛出 `EmbeddedNul`。
/// - 无法写入文件时抛出 `HistorySaveFailed`;错误中包含路径,以及底层能够可靠提供时的
///   OS error code。
/// - 当前 History 正被行读取使用时抛出 `Busy`。
///
/// **Side effects:**
///
/// 此操作会创建或覆盖 `path` 指向的文件。
pub fn History::save(
  self : History,
  path : StringView,
) -> Unit raise ReadlineError {
  let owned_path = path.to_owned()
  match self.owner.save(@utf8.encode(owned_path)) {
    0 => ()
    1 => raise EmbeddedNul
    3 => raise Busy
    _ => raise HistorySaveFailed(owned_path, history_error_code(self.owner))
  }
}