///|
pub fn parse_alarm_action(value : String) -> AlarmAction {
  let normalized = ascii_upper(trim_ascii(value))
  if normalized == "AUDIO" {
    Audio
  } else if normalized == "DISPLAY" {
    Display
  } else if normalized == "EMAIL" {
    Email
  } else {
    UnknownAction(normalized)
  }
}

///|
pub fn summarize_alarm(alarm : Component) -> AlarmSummary {
  let action = parse_alarm_action(alarm.get("ACTION").unwrap_or(""))
  {
    action,
    trigger: alarm.get("TRIGGER").unwrap_or(""),
    description: alarm.get("DESCRIPTION"),
    summary: alarm.get("SUMMARY"),
    attendee_count: alarm.count("ATTENDEE"),
  }
}

///|
pub fn alarm_action_name(alarm : Component) -> String {
  summarize_alarm(alarm).action.name()
}

///|
pub fn alarm_trigger_value(alarm : Component) -> String {
  summarize_alarm(alarm).trigger
}

///|
pub fn alarm_trigger_kind(alarm : Component) -> String {
  trigger_kind(alarm_trigger_value(alarm))
}

///|
pub fn alarm_has_relative_trigger(alarm : Component) -> Bool {
  trigger_is_relative(alarm_trigger_value(alarm))
}

///|
pub fn alarm_has_absolute_trigger(alarm : Component) -> Bool {
  trigger_is_absolute(alarm_trigger_value(alarm))
}

///|
pub fn alarm_has_negative_lead(alarm : Component) -> Bool {
  match parse_duration(alarm_trigger_value(alarm)) {
    Ok(value) => value.is_negative()
    Err(_) => false
  }
}

///|
pub fn alarm_has_positive_offset(alarm : Component) -> Bool {
  match parse_duration(alarm_trigger_value(alarm)) {
    Ok(value) => value.is_positive()
    Err(_) => false
  }
}

///|
pub fn alarm_lead_seconds_abs(alarm : Component) -> Int? {
  match parse_duration(alarm_trigger_value(alarm)) {
    Ok(value) => Some(value.total_seconds_abs())
    Err(_) => None
  }
}

///|
pub fn alarm_is_short_notice(alarm : Component) -> Bool {
  match parse_duration(alarm_trigger_value(alarm)) {
    Ok(value) => value.is_short_alarm_lead()
    Err(_) => false
  }
}

///|
pub fn alarm_is_long_notice(alarm : Component) -> Bool {
  match parse_duration(alarm_trigger_value(alarm)) {
    Ok(value) => value.is_long_alarm_lead()
    Err(_) => false
  }
}

///|
pub fn alarm_requires_description(action : AlarmAction) -> Bool {
  match action {
    Display => true
    Email => true
    Audio => false
    UnknownAction(_) => false
  }
}

///|
pub fn alarm_requires_summary(action : AlarmAction) -> Bool {
  match action {
    Email => true
    _ => false
  }
}

///|
pub fn alarm_requires_attendee(action : AlarmAction) -> Bool {
  match action {
    Email => true
    _ => false
  }
}

///|
pub fn alarm_is_action_supported(action : AlarmAction) -> Bool {
  match action {
    Audio => true
    Display => true
    Email => true
    UnknownAction(_) => false
  }
}

///|
pub fn alarm_is_complete(alarm : Component) -> Bool {
  let summary = summarize_alarm(alarm)
  if summary.trigger.length() == 0 {
    return false
  }
  if !alarm_is_action_supported(summary.action) {
    return false
  }
  if alarm_requires_description(summary.action) && summary.description is None {
    return false
  }
  if alarm_requires_summary(summary.action) && summary.summary is None {
    return false
  }
  if alarm_requires_attendee(summary.action) && summary.attendee_count == 0 {
    return false
  }
  true
}

///|
pub fn event_alarm_count(event : Component) -> Int {
  event.alarms().length()
}

///|
pub fn event_has_alarms(event : Component) -> Bool {
  event_alarm_count(event) > 0
}

///|
pub fn event_has_email_alarm(event : Component) -> Bool {
  for alarm in event.alarms() {
    if summarize_alarm(alarm).action is Email {
      return true
    }
  }
  false
}

///|
pub fn event_has_display_alarm(event : Component) -> Bool {
  for alarm in event.alarms() {
    if summarize_alarm(alarm).action is Display {
      return true
    }
  }
  false
}

///|
pub fn event_has_audio_alarm(event : Component) -> Bool {
  for alarm in event.alarms() {
    if summarize_alarm(alarm).action is Audio {
      return true
    }
  }
  false
}

///|
pub fn event_has_relative_alarm(event : Component) -> Bool {
  for alarm in event.alarms() {
    if alarm_has_relative_trigger(alarm) {
      return true
    }
  }
  false
}

///|
pub fn event_has_absolute_alarm(event : Component) -> Bool {
  for alarm in event.alarms() {
    if alarm_has_absolute_trigger(alarm) {
      return true
    }
  }
  false
}

///|
pub fn render_alarm_summary(alarm : Component) -> String {
  let summary = summarize_alarm(alarm)
  let b = StringBuilder::new()
  b.write_string(summary.action.name())
  b.write_string(" ")
  b.write_string(summary.trigger)
  match summary.description {
    Some(description) =>
      if description.length() > 0 {
        b.write_string(" description=")
        b.write_string(unescape_text(description))
      }
    None => ()
  }
  match summary.summary {
    Some(subject) =>
      if subject.length() > 0 {
        b.write_string(" summary=")
        b.write_string(unescape_text(subject))
      }
    None => ()
  }
  if summary.attendee_count > 0 {
    b.write_string(" attendees=")
    b.write_string(summary.attendee_count.to_string())
  }
  b.to_string()
}

///|
pub fn render_event_alarms(event : Component) -> String {
  let b = StringBuilder::new()
  let alarms = event.alarms()
  if alarms.length() == 0 {
    b.write_string("No alarms")
    return b.to_string()
  }
  let mut i = 0
  while i < alarms.length() {
    if i > 0 {
      b.write_string("\n")
    }
    b.write_string("- ")
    b.write_string(render_alarm_summary(alarms[i]))
    i += 1
  }
  b.to_string()
}

///|
pub fn alarm_fingerprint(alarm : Component) -> String {
  let summary = summarize_alarm(alarm)
  let b = StringBuilder::new()
  b.write_string(summary.action.name())
  b.write_string("|")
  b.write_string(summary.trigger)
  b.write_string("|")
  b.write_string(summary.description.unwrap_or(""))
  b.write_string("|")
  b.write_string(summary.summary.unwrap_or(""))
  b.write_string("|")
  b.write_string(summary.attendee_count.to_string())
  b.to_string()
}

///|
pub fn event_alarm_fingerprint(event : Component) -> String {
  let b = StringBuilder::new()
  let alarms = event.alarms()
  let mut i = 0
  while i < alarms.length() {
    if i > 0 {
      b.write_string(";")
    }
    b.write_string(alarm_fingerprint(alarms[i]))
    i += 1
  }
  b.to_string()
}

///|
pub fn create_display_alarm(
  trigger : String,
  description : String,
) -> Component {
  {
    name: "VALARM",
    properties: [
      { name: "ACTION", params: [], value: "DISPLAY", line: 0 },
      { name: "TRIGGER", params: [], value: trigger, line: 0 },
      { name: "DESCRIPTION", params: [], value: description, line: 0 },
    ],
    components: [],
    line: 0,
  }
}

///|
pub fn create_audio_alarm(trigger : String) -> Component {
  {
    name: "VALARM",
    properties: [
      { name: "ACTION", params: [], value: "AUDIO", line: 0 },
      { name: "TRIGGER", params: [], value: trigger, line: 0 },
    ],
    components: [],
    line: 0,
  }
}

///|
pub fn create_email_alarm(
  trigger : String,
  summary : String,
  description : String,
  attendee : String,
) -> Component {
  {
    name: "VALARM",
    properties: [
      { name: "ACTION", params: [], value: "EMAIL", line: 0 },
      { name: "TRIGGER", params: [], value: trigger, line: 0 },
      { name: "SUMMARY", params: [], value: summary, line: 0 },
      { name: "DESCRIPTION", params: [], value: description, line: 0 },
      { name: "ATTENDEE", params: [], value: attendee, line: 0 },
    ],
    components: [],
    line: 0,
  }
}