///|
pub(all) struct NameOfStationBlock {
  is_persistent : Bool
  value : String
} derive(Eq)

///|
pub(all) struct IPParameterBlock {
  is_persistent : Bool
  address : @frame.IPv4Address
  mask : @frame.IPv4Address
  gateway : @frame.IPv4Address
} derive(Eq)

///|
pub(all) enum SetBlock {
  NameOfStation(NameOfStationBlock)
  IPParameter(IPParameterBlock)
} derive(Eq)

///|
pub(all) struct SetRequest {
  destination : @frame.MacAddress
  source : @frame.MacAddress
  xid : Int
  blocks : Array[SetBlock]
} derive(Eq)

///|
fn encode_name_of_station_payload(block : NameOfStationBlock) -> Bytes {
  let output : Array[Byte] = []
  push_u16_be(output, if block.is_persistent { 1 } else { 0 })
  append_bytes(output, @ascii.encode(block.value[:]))
  Bytes::from_array(output)
}

///|
fn encode_ip_parameter_payload(block : IPParameterBlock) -> Bytes {
  let output : Array[Byte] = []
  push_u16_be(output, if block.is_persistent { 1 } else { 0 })
  append_bytes(output, block.address.octets())
  append_bytes(output, block.mask.octets())
  append_bytes(output, block.gateway.octets())
  Bytes::from_array(output)
}

///|
fn encode_set_block(block : SetBlock) -> Bytes {
  let output : Array[Byte] = []
  match block {
    NameOfStation(data) => {
      let payload = encode_name_of_station_payload(data)
      append_payload_block(
        output, dcp_option_device, dcp_suboption_name_of_station, payload,
      )
    }
    IPParameter(data) => {
      let payload = encode_ip_parameter_payload(data)
      append_payload_block(
        output, dcp_option_ip, dcp_suboption_ip_parameter, payload,
      )
    }
  }
  Bytes::from_array(output)
}

///|
pub fn encode_set_request(request : SetRequest) -> Bytes {
  let block_bytes : Array[Byte] = []
  for block in request.blocks {
    append_bytes(block_bytes, encode_set_block(block))
  }
  encode_dcp_ethernet_frame(
    request.destination,
    request.source,
    frame_id_get_set,
    dcp_service_id_set,
    dcp_service_type_request,
    request.xid,
    0,
    Bytes::from_array(block_bytes),
  )
}

///|
pub fn encode_set_name_request(
  destination : @frame.MacAddress,
  source : @frame.MacAddress,
  xid : Int,
  station_name : String,
  is_persistent? : Bool = false,
) -> Bytes {
  encode_set_request(SetRequest::{
    destination,
    source,
    xid,
    blocks: [
      NameOfStation(NameOfStationBlock::{ is_persistent, value: station_name }),
    ],
  })
}

///|
pub fn encode_set_ip_request(
  destination : @frame.MacAddress,
  source : @frame.MacAddress,
  xid : Int,
  address : @frame.IPv4Address,
  mask : @frame.IPv4Address,
  gateway : @frame.IPv4Address,
  is_persistent? : Bool = false,
) -> Bytes {
  encode_set_request(SetRequest::{
    destination,
    source,
    xid,
    blocks: [
      IPParameter(IPParameterBlock::{ is_persistent, address, mask, gateway }),
    ],
  })
}