///|
/// Q value (0.000 - 1.000)
pub(all) struct QValue {
  value : Int
} derive(Eq)

///|
pub fn QValue::parse(input : String) -> Result[QValue, AcceptError] {
  let s = acc_trim_string(input)
  if s.length() == 0 {
    return Err(InvalidQValue)
  }
  if s == "1" {
    return Ok({ value: 1000 })
  }
  if acc_string_starts_with(s, "1.") {
    let rest = acc_string_slice_from(s, 2)
    if rest.length() == 0 {
      return Ok({ value: 1000 })
    }
    // Must be all zeros
    let mut idx = 0
    while idx < rest.length() {
      if acc_char_at(rest, idx) != 48 { // not '0'
        return Err(InvalidQValue)
      }
      idx = idx + 1
    }
    return Ok({ value: 1000 })
  }
  if s == "0" {
    return Ok({ value: 0 })
  }
  if acc_string_starts_with(s, "0.") {
    let rest = acc_string_slice_from(s, 2)
    if rest.length() > 3 || rest.length() == 0 {
      return Err(InvalidQValue)
    }
    // Check all digits
    let mut idx = 0
    while idx < rest.length() {
      let ch = acc_char_at(rest, idx)
      if ch < 48 || ch > 57 { // not '0'-'9'
        return Err(InvalidQValue)
      }
      idx = idx + 1
    }
    // Calculate value
    let mut value = 0
    let mut idx = 0
    while idx < rest.length() {
      let digit = acc_char_at(rest, idx) - 48
      let multiplier = acc_int_pow(10, 2 - idx)
      value = value + digit * multiplier
      idx = idx + 1
    }
    return Ok({ value, })
  }
  Err(InvalidQValue)
}

///|
pub fn QValue::value(self : QValue) -> Int {
  self.value
}

///|
pub fn QValue::to_string(self : QValue) -> String {
  if self.value == 1000 {
    "1"
  } else if self.value == 0 {
    "0"
  } else {
    let frac = if self.value >= 100 {
      self.value.to_string()
    } else if self.value >= 10 {
      "0" + (self.value * 10).to_string()
    } else {
      "00" + self.value.to_string()
    }
    // Trim trailing zeros
    let mut trimmed = frac
    if acc_string_ends_with(trimmed, "0") {
      trimmed = acc_trim_trailing_zeros(trimmed)
    }
    if acc_string_ends_with(trimmed, "0") {
      trimmed = acc_trim_trailing_zeros(trimmed)
    }
    if acc_string_ends_with(trimmed, "0") {
      trimmed = acc_trim_trailing_zeros(trimmed)
    }
    "0." + trimmed
  }
}