///|
/// An ordered collection of named configuration layers.
///
/// Layers are merged from first to last, so later layers have higher
/// precedence.
pub struct LayeredConfig {
  layers : Array[ConfigLayer]
} derive(Eq, Debug)

///|
/// Create an ordered configuration from the supplied layers.
///
/// The input array is copied, so later changes to the caller's array do not
/// change the layer ordering stored by this value.
pub fn LayeredConfig::new(layers : Array[ConfigLayer]) -> LayeredConfig {
  { layers: layers.copy() }
}

///|
/// Return an empty ordered configuration.
pub fn LayeredConfig::empty() -> LayeredConfig {
  { layers: [] }
}

///|
/// Return the number of layers in this configuration.
pub fn LayeredConfig::length(self : LayeredConfig) -> Int {
  self.layers.length()
}

///|
/// Return one layer by position, or `None` when the index is out of bounds.
pub fn LayeredConfig::layer(self : LayeredConfig, index : Int) -> ConfigLayer? {
  self.layers.get(index)
}

///|
/// Merge all layers from first to last and report structural conflicts.
///
/// An empty configuration has no value to merge and returns `None`.
pub fn LayeredConfig::merge_with_report(self : LayeredConfig) -> MergeResult? {
  let first = self.layers.get(0)
  match first {
    None => None
    Some(first_layer) => {
      let mut value = first_layer.value()
      let conflicts : Array[ConfigConflict] = []
      let mut index = 1
      while index < self.layers.length() {
        let layer = self.layers.get(index).unwrap()
        let result = value.deep_merge_with_report(layer.value())
        value = result.value()
        result.conflicts.each(conflict => conflicts.push(conflict))
        index = index + 1
      }
      Some({ value, conflicts })
    }
  }
}

///|
/// Merge all layers from first to last, or return `None` for no layers.
pub fn LayeredConfig::merge(self : LayeredConfig) -> ConfigValue? {
  match self.merge_with_report() {
    None => None
    Some(result) => Some(result.value())
  }
}