///|
/// The Syndication namespace.
pub const SYNDICATION_NAMESPACE : String = "http://purl.org/rss/1.0/modules/syndication/"

///|
/// The update period of a syndicated feed.
pub(all) enum UpdatePeriod {
  Hourly
  Daily
  Weekly
  Monthly
  Yearly
} derive(Debug, Eq)

///|
pub impl Show for UpdatePeriod with fn output(self, logger) -> Unit {
  let s = match self {
    Hourly => "hourly"
    Daily => "daily"
    Weekly => "weekly"
    Monthly => "monthly"
    Yearly => "yearly"
  }
  logger.write_string(s)
}

///|
fn UpdatePeriod::parse(s : String) -> UpdatePeriod? {
  if s is "hourly" {
    Some(Hourly)
  } else if s is "daily" {
    Some(Daily)
  } else if s is "weekly" {
    Some(Weekly)
  } else if s is "monthly" {
    Some(Monthly)
  } else if s is "yearly" {
    Some(Yearly)
  } else {
    None
  }
}

///|
/// Syndication metadata extracted from a channel
/// (when to refresh, how often, and relative to which base time).
pub(all) struct SyndicationExtension {
  /// The update period. Defaults to [UpdatePeriod::Daily].
  period : UpdatePeriod
  /// The update frequency relative to the period. Defaults to `1`.
  frequency : Int
  /// The base time for recalculation. Defaults to `"1970-01-01T00:00:00Z"`.
  base : String
} derive(Debug, Eq)

///|
/// Parse a positive integer, defaulting to `1` on malformed input.
fn parse_positive_int(s : String) -> Int {
  let mut v = 0
  let mut any = false
  for c in s {
    if c >= '0' && c <= '9' {
      v = v * 10 + (c.to_int() - '0'.to_int())
      any = true
    } else {
      return 1
    }
  }
  if any && v > 0 {
    v
  } else {
    1
  }
}

///|
/// Build a syndication extension from parsed generic extensions,
/// mirroring `SyndicationExtension::from_map`.
pub fn SyndicationExtension::from_map(
  map : Map[String, Array[Extension]],
) -> SyndicationExtension {
  fn value(key : String) -> String? {
    match map.get(key) {
      Some(list) => if list.length() > 0 { list[0].value } else { None }
      None => None
    }
  }

  let period = match value("updatePeriod") {
    Some(period) => UpdatePeriod::parse(period).unwrap_or(Daily)
    None => Daily
  }
  let frequency = match value("updateFrequency") {
    Some(freq) => parse_positive_int(freq)
    None => 1
  }
  {
    period,
    frequency,
    base: value("updateBase").unwrap_or("1970-01-01T00:00:00Z"),
  }
}