///|
pub fn EpochStaticIntMap::build(
  entries : Array[EpochFuseValue],
) -> Result[EpochStaticIntMap, FuseError] {
  if entries.length() == 0 {
    return Err(EmptyInput)
  }
  let sorted = entries.copy()
  sorted.sort_by((left, right) => {
    let order = left.epoch.compare(right.epoch)
    if order == 0 {
      left.hash.compare(right.hash)
    } else {
      order
    }
  })
  let epochs : Array[FuseMapEpoch] = []
  let mut cursor = 0
  while cursor < sorted.length() {
    let epoch = sorted[cursor].epoch
    let values : Array[FuseValue] = []
    while cursor < sorted.length() && sorted[cursor].epoch == epoch {
      values.push({ hash: sorted[cursor].hash, value: sorted[cursor].value })
      cursor = cursor + 1
    }
    match StaticIntMap::build(values) {
      Ok(map) => epochs.push({ epoch, map })
      Err(error) => return Err(error)
    }
  }
  Ok({ epochs, })
}

///|
pub fn EpochStaticIntMap::get_at(
  self : EpochStaticIntMap,
  epoch : Int,
  hash : Int,
) -> Int? {
  match self.find_epoch(epoch) {
    Some(map) => map.get(hash)
    None => None
  }
}

///|
pub fn EpochStaticIntMap::get_at_or_before(
  self : EpochStaticIntMap,
  epoch : Int,
  hash : Int,
) -> Int? {
  let mut low = 0
  let mut high = self.epochs.length()
  while low < high {
    let middle = low + (high - low) / 2
    if self.epochs[middle].epoch <= epoch {
      low = middle + 1
    } else {
      high = middle
    }
  }
  if low == 0 {
    None
  } else {
    self.epochs[low - 1].map.get(hash)
  }
}

///|
pub fn EpochStaticIntMap::epoch_count(self : EpochStaticIntMap) -> Int {
  self.epochs.length()
}

///|
pub fn EpochStaticIntMap::entry_count(self : EpochStaticIntMap) -> Int {
  let mut count = 0
  for item in self.epochs {
    count = count + item.map.len()
  }
  count
}

///|
pub fn EpochStaticIntMap::keep_from(
  self : EpochStaticIntMap,
  minimum_epoch : Int,
) -> EpochStaticIntMap {
  let epochs : Array[FuseMapEpoch] = []
  for item in self.epochs {
    if item.epoch >= minimum_epoch {
      epochs.push(item)
    }
  }
  { epochs, }
}

///|
pub fn EpochStaticIntMap::stats(self : EpochStaticIntMap) -> EpochMapStats {
  {
    epoch_count: self.epochs.length(),
    entry_count: self.entry_count(),
    first_epoch: self.epochs[0].epoch,
    last_epoch: self.epochs[self.epochs.length() - 1].epoch,
  }
}

///|
pub fn EpochStaticIntMap::validate(self : EpochStaticIntMap) -> Bool {
  if self.epochs.length() == 0 {
    return false
  }
  for index in 0.. 0 && self.epochs[index - 1].epoch >= self.epochs[index].epoch) {
      return false
    }
  }
  true
}

///|
fn EpochStaticIntMap::find_epoch(
  self : EpochStaticIntMap,
  epoch : Int,
) -> StaticIntMap? {
  let mut low = 0
  let mut high = self.epochs.length()
  while low < high {
    let middle = low + (high - low) / 2
    let candidate = self.epochs[middle]
    if candidate.epoch == epoch {
      return Some(candidate.map)
    }
    if candidate.epoch < epoch {
      low = middle + 1
    } else {
      high = middle
    }
  }
  None
}