///|
/// Standard causes of transmission used by IEC 104 application services.
pub enum Cause {
  Periodic
  Background
  Spontaneous
  Initialised
  Request
  Activation
  ActivationConfirmation
  ActivationTermination
  Unknown(Int)
} derive(Eq, Debug)

///|
pub fn Cause::number(self : Cause) -> Int {
  match self {
    Periodic => 1
    Background => 2
    Spontaneous => 3
    Initialised => 4
    Request => 5
    Activation => 6
    ActivationConfirmation => 7
    ActivationTermination => 10
    Unknown(value) => value
  }
}

///|
pub fn cause(value : Int) -> Cause {
  match value {
    1 => Periodic
    2 => Background
    3 => Spontaneous
    4 => Initialised
    5 => Request
    6 => Activation
    7 => ActivationConfirmation
    10 => ActivationTermination
    value => Unknown(value)
  }
}

///|
/// A total interrogation request, suitable for a master command queue.
pub struct InterrogationRequest {
  common_address : Int
  qualifier : Int
} derive(Eq, Debug)

///|
pub fn InterrogationRequest::new(
  common_address : Int,
  qualifier? : Int = 20,
) -> InterrogationRequest {
  { common_address, qualifier }
}

///|
/// Phases emitted by an interrogation transaction.
pub enum InterrogationPhase {
  Idle
  Activated
  Sending
  Terminated
} derive(Eq, Debug)

///|
/// Small deterministic transaction tracker; data transport remains caller-owned.
pub struct Interrogation {
  request : InterrogationRequest
  mut phase : InterrogationPhase
  mut objects_sent : Int
}

///|
pub fn Interrogation::new(request : InterrogationRequest) -> Interrogation {
  { request, phase: Idle, objects_sent: 0 }
}

///|
pub fn Interrogation::activate(self : Interrogation) -> Int {
  self.phase = Activated
  Cause::Activation.number()
}

///|
pub fn Interrogation::record(
  self : Interrogation,
  count : Int,
) -> Result[Unit, String] {
  if self.phase != Activated && self.phase != Sending {
    return Err("interrogation is not active")
  }
  self.phase = Sending
  self.objects_sent += if count < 0 { 0 } else { count }
  Ok(())
}

///|
pub fn Interrogation::finish(self : Interrogation) -> Int {
  self.phase = Terminated
  Cause::ActivationTermination.number()
}

///|
/// An immutable snapshot of values that can be used to build a response ASDU.
pub struct PointSnapshot {
  ioa : Int
  value : InformationObject
}

///|
pub fn Outstation::snapshot_single(self : Outstation) -> Array[PointSnapshot] {
  let result : Array[PointSnapshot] = []
  for ioa, value in self.single_points {
    result.push({ ioa, value: Single(value, 0) })
  }
  result
}

///|
pub fn Outstation::snapshot_normalized(
  self : Outstation,
) -> Array[PointSnapshot] {
  let result : Array[PointSnapshot] = []
  for ioa, value in self.normalized_values {
    result.push({ ioa, value: Normalized(value, 0) })
  }
  result
}