///|
pub fn audit_chain() -> AuditChain {
  { events: [], digest: 0 }
}

///|
pub fn audit_chain_with_digest(chain : AuditChain, digest : Int) -> AuditChain {
  { events: chain.events, digest }
}

///|
fn audit_event_digest(event : AuditEvent) -> Int {
  event.sequence * 31 +
  event.code.length() * 17 +
  event.detail.length() * 13 +
  event.amount.cents
}

///|
fn audit_digest_step(previous : Int, event : AuditEvent) -> Int {
  previous * 31 + audit_event_digest(event)
}

///|
pub fn append_audit_event(chain : AuditChain, event : AuditEvent) -> AuditChain {
  let events = chain.events.copy()
  events.push(event)
  { events, digest: audit_digest_step(chain.digest, event) }
}

///|
pub fn audit_chain_is_consistent(chain : AuditChain) -> Bool {
  let mut digest = 0
  for event in chain.events {
    digest = audit_digest_step(digest, event)
  }
  digest == chain.digest
}

///|
pub fn AuditChain::length(self : AuditChain) -> Int {
  self.events.length()
}

///|
pub fn AuditChain::last_sequence(self : AuditChain) -> Int {
  match self.events.last() {
    None => 0
    Some(event) => event.sequence
  }
}

///|
pub fn AuditChain::is_monotonic(self : AuditChain) -> Bool {
  let mut previous = -1
  for event in self.events {
    if event.sequence <= previous {
      return false
    }
    previous = event.sequence
  }
  true
}