///|
pub(all) enum Capability {
  RenderFrameVt
  RenderFrameState
  ViewportResize
  ServerScrollback
  ClientAttachAck
  MoonIdeHover
  FilesystemWatch
  Unknown(String)
} derive(Debug, Eq)

///|
pub fn Capability::from_wire(value : String) -> Capability {
  match value {
    "render_frame_vt" => RenderFrameVt
    "render_frame_state" => RenderFrameState
    "viewport_resize" => ViewportResize
    "server_scrollback" => ServerScrollback
    "client_attach_ack" => ClientAttachAck
    "moon_ide_hover" => MoonIdeHover
    "filesystem_watch" => FilesystemWatch
    other => Unknown(other)
  }
}

///|
pub fn Capability::to_wire(self : Capability) -> String {
  match self {
    RenderFrameVt => "render_frame_vt"
    RenderFrameState => "render_frame_state"
    ViewportResize => "viewport_resize"
    ServerScrollback => "server_scrollback"
    ClientAttachAck => "client_attach_ack"
    MoonIdeHover => "moon_ide_hover"
    FilesystemWatch => "filesystem_watch"
    Unknown(value) => value
  }
}

///|
pub struct CapabilitySet(Array[Capability]) derive(Debug, Eq)

///|
pub fn CapabilitySet::empty() -> CapabilitySet {
  CapabilitySet([])
}

///|
pub fn CapabilitySet::new(values : Array[Capability]) -> CapabilitySet {
  CapabilitySet(values.copy())
}

///|
pub fn CapabilitySet::from_wire(values : Array[String]) -> CapabilitySet {
  CapabilitySet(values.map(fn(value) { Capability::from_wire(value) }))
}

///|
pub fn CapabilitySet::to_wire(self : CapabilitySet) -> Array[String] {
  self.0.map(fn(value) { value.to_wire() })
}

///|
pub impl ToJson for CapabilitySet with fn to_json(self) {
  self.to_wire().to_json()
}

///|
pub impl @json.FromJson for CapabilitySet with fn from_json(json, path) {
  let values : Array[String] = @json.FromJson::from_json(json, path)
  CapabilitySet::from_wire(values)
}

///|
pub fn CapabilitySet::to_log_string(self : CapabilitySet) -> String {
  let parts : Array[String] = []
  for capability in self.to_wire() {
    parts.push(@debug.to_string(capability))
  }
  let joined = parts.join(", ")
  "[\{joined}]"
}

///|
pub fn CapabilitySet::length(self : CapabilitySet) -> Int {
  self.0.length()
}

///|
pub fn CapabilitySet::supports(
  self : CapabilitySet,
  capability : Capability,
) -> Bool {
  for value in self.0 {
    if value == capability {
      return true
    }
  }
  false
}

///|
pub fn CapabilitySet::supports_render_frame_vt(self : CapabilitySet) -> Bool {
  self.supports(RenderFrameVt)
}

///|
pub fn CapabilitySet::supports_render_frame_state(self : CapabilitySet) -> Bool {
  self.supports(RenderFrameState)
}

///|
pub fn CapabilitySet::supports_viewport_resize(self : CapabilitySet) -> Bool {
  self.supports(ViewportResize)
}

///|
pub fn CapabilitySet::supports_server_scrollback(self : CapabilitySet) -> Bool {
  self.supports(ServerScrollback)
}

///|
pub fn CapabilitySet::supports_client_attach_ack(self : CapabilitySet) -> Bool {
  self.supports(ClientAttachAck)
}

///|
pub fn CapabilitySet::supports_moon_ide_hover(self : CapabilitySet) -> Bool {
  self.supports(MoonIdeHover)
}

///|
pub fn CapabilitySet::supports_filesystem_watch(self : CapabilitySet) -> Bool {
  self.supports(FilesystemWatch)
}