///|
pub(all) enum ByteOrder {
  Motorola
  Intel
} derive(Eq, Debug)

///|
pub(all) enum SignalValueType {
  Unsigned
  Signed
} derive(Eq, Debug)

///|
pub struct DbcNode {
  name_value : String
} derive(Eq, Debug)

///|
pub struct DbcValueDescription {
  raw_value : Int
  label_value : String
} derive(Eq, Debug)

///|
pub struct DbcSignal {
  name_value : String
  start_bit_value : Int
  bit_length_value : Int
  byte_order_value : ByteOrder
  value_type_value : SignalValueType
  factor_value : Double
  offset_value : Double
  minimum_value : Double
  maximum_value : Double
  unit_value : String
  receivers_value : Array[String]
  values_value : Array[DbcValueDescription]
  comment_value : String
  source_line_value : Int
} derive(Eq, Debug)

///|
pub struct DbcMessage {
  id_value : Int
  name_value : String
  size_value : Int
  transmitter_value : String
  signals_value : Array[DbcSignal]
  comment_value : String
  source_line_value : Int
} derive(Eq, Debug)

///|
pub struct DbcDatabase {
  version_value : String
  nodes_value : Array[DbcNode]
  messages_value : Array[DbcMessage]
  ignored_statement_count_value : Int
} derive(Eq, Debug)

///|
pub fn DbcNode::new(name : String) -> DbcNode {
  { name_value: name }
}

///|
pub fn DbcNode::name(self : DbcNode) -> String {
  self.name_value
}

///|
pub fn DbcValueDescription::new(
  raw : Int,
  label : String,
) -> DbcValueDescription {
  { raw_value: raw, label_value: label }
}

///|
pub fn DbcValueDescription::raw(self : DbcValueDescription) -> Int {
  self.raw_value
}

///|
pub fn DbcValueDescription::label(self : DbcValueDescription) -> String {
  self.label_value
}

///|
pub fn DbcSignal::new(
  name : String,
  start_bit : Int,
  bit_length : Int,
  byte_order : ByteOrder,
  value_type : SignalValueType,
  factor : Double,
  offset : Double,
  minimum : Double,
  maximum : Double,
  unit : String,
  receivers : Array[String],
  source_line? : Int = 0,
) -> DbcSignal {
  {
    name_value: name,
    start_bit_value: start_bit,
    bit_length_value: bit_length,
    byte_order_value: byte_order,
    value_type_value: value_type,
    factor_value: factor,
    offset_value: offset,
    minimum_value: minimum,
    maximum_value: maximum,
    unit_value: unit,
    receivers_value: receivers,
    values_value: [],
    comment_value: "",
    source_line_value: source_line,
  }
}

///|
pub fn DbcSignal::name(self : DbcSignal) -> String {
  self.name_value
}

///|
pub fn DbcSignal::start_bit(self : DbcSignal) -> Int {
  self.start_bit_value
}

///|
pub fn DbcSignal::bit_length(self : DbcSignal) -> Int {
  self.bit_length_value
}

///|
pub fn DbcSignal::byte_order(self : DbcSignal) -> ByteOrder {
  self.byte_order_value
}

///|
pub fn DbcSignal::value_type(self : DbcSignal) -> SignalValueType {
  self.value_type_value
}

///|
pub fn DbcSignal::factor(self : DbcSignal) -> Double {
  self.factor_value
}

///|
pub fn DbcSignal::offset(self : DbcSignal) -> Double {
  self.offset_value
}

///|
pub fn DbcSignal::minimum(self : DbcSignal) -> Double {
  self.minimum_value
}

///|
pub fn DbcSignal::maximum(self : DbcSignal) -> Double {
  self.maximum_value
}

///|
pub fn DbcSignal::unit(self : DbcSignal) -> String {
  self.unit_value
}

///|
pub fn DbcSignal::receivers(self : DbcSignal) -> Array[String] {
  self.receivers_value.copy()
}

///|
pub fn DbcSignal::values(self : DbcSignal) -> Array[DbcValueDescription] {
  self.values_value.copy()
}

///|
pub fn DbcSignal::comment(self : DbcSignal) -> String {
  self.comment_value
}

///|
pub fn DbcSignal::source_line(self : DbcSignal) -> Int {
  self.source_line_value
}

///|
pub fn DbcSignal::with_values(
  self : DbcSignal,
  values : Array[DbcValueDescription],
) -> DbcSignal {
  { ..self, values_value: values.copy() }
}

///|
pub fn DbcSignal::with_comment(self : DbcSignal, comment : String) -> DbcSignal {
  { ..self, comment_value: comment }
}

///|
fn DbcSignal::with_name(self : DbcSignal, name : String) -> DbcSignal {
  { ..self, name_value: name }
}

///|
fn DbcSignal::with_receivers(
  self : DbcSignal,
  receivers : Array[String],
) -> DbcSignal {
  { ..self, receivers_value: receivers.copy() }
}

///|
pub fn DbcSignal::physical_from_raw(self : DbcSignal, raw : Double) -> Double {
  raw * self.factor_value + self.offset_value
}

///|
pub fn DbcSignal::raw_from_physical(
  self : DbcSignal,
  physical : Double,
) -> Double {
  (physical - self.offset_value) / self.factor_value
}

///|
pub fn DbcSignal::value_label(self : DbcSignal, raw : Int) -> String? {
  for value in self.values_value {
    if value.raw() == raw {
      return Some(value.label())
    }
  }
  None
}

///|
pub fn DbcMessage::new(
  id : Int,
  name : String,
  size : Int,
  transmitter : String,
  signals : Array[DbcSignal],
  source_line? : Int = 0,
) -> DbcMessage {
  {
    id_value: id,
    name_value: name,
    size_value: size,
    transmitter_value: transmitter,
    signals_value: signals.copy(),
    comment_value: "",
    source_line_value: source_line,
  }
}

///|
pub fn DbcMessage::id(self : DbcMessage) -> Int {
  self.id_value
}

///|
pub fn DbcMessage::name(self : DbcMessage) -> String {
  self.name_value
}

///|
pub fn DbcMessage::size(self : DbcMessage) -> Int {
  self.size_value
}

///|
pub fn DbcMessage::transmitter(self : DbcMessage) -> String {
  self.transmitter_value
}

///|
pub fn DbcMessage::signals(self : DbcMessage) -> Array[DbcSignal] {
  self.signals_value.copy()
}

///|
pub fn DbcMessage::comment(self : DbcMessage) -> String {
  self.comment_value
}

///|
pub fn DbcMessage::source_line(self : DbcMessage) -> Int {
  self.source_line_value
}

///|
pub fn DbcMessage::with_signals(
  self : DbcMessage,
  signals : Array[DbcSignal],
) -> DbcMessage {
  { ..self, signals_value: signals.copy() }
}

///|
pub fn DbcMessage::with_comment(
  self : DbcMessage,
  comment : String,
) -> DbcMessage {
  { ..self, comment_value: comment }
}

///|
fn DbcMessage::with_name(self : DbcMessage, name : String) -> DbcMessage {
  { ..self, name_value: name }
}

///|
fn DbcMessage::with_transmitter(
  self : DbcMessage,
  transmitter : String,
) -> DbcMessage {
  { ..self, transmitter_value: transmitter }
}

///|
pub fn DbcMessage::find_signal(self : DbcMessage, name : String) -> DbcSignal? {
  for signal in self.signals_value {
    if signal.name() == name {
      return Some(signal)
    }
  }
  None
}

///|
pub fn DbcDatabase::new(
  version : String,
  nodes : Array[DbcNode],
  messages : Array[DbcMessage],
  ignored_statement_count? : Int = 0,
) -> DbcDatabase {
  {
    version_value: version,
    nodes_value: nodes.copy(),
    messages_value: messages.copy(),
    ignored_statement_count_value: ignored_statement_count,
  }
}

///|
pub fn DbcDatabase::version(self : DbcDatabase) -> String {
  self.version_value
}

///|
pub fn DbcDatabase::nodes(self : DbcDatabase) -> Array[DbcNode] {
  self.nodes_value.copy()
}

///|
pub fn DbcDatabase::messages(self : DbcDatabase) -> Array[DbcMessage] {
  self.messages_value.copy()
}

///|
pub fn DbcDatabase::message_count(self : DbcDatabase) -> Int {
  self.messages_value.length()
}

///|
pub fn DbcDatabase::ignored_statement_count(self : DbcDatabase) -> Int {
  self.ignored_statement_count_value
}

///|
pub fn DbcDatabase::find_message_by_id(
  self : DbcDatabase,
  id : Int,
) -> DbcMessage? {
  for message in self.messages_value {
    if message.id() == id {
      return Some(message)
    }
  }
  None
}

///|
pub fn DbcDatabase::find_message_by_name(
  self : DbcDatabase,
  name : String,
) -> DbcMessage? {
  for message in self.messages_value {
    if message.name() == name {
      return Some(message)
    }
  }
  None
}