///|
priv struct JsonCursor {
  value : Json
  path_value : String
}

///|
fn JsonCursor::new(value : Json, path : String) -> JsonCursor {
  { value, path_value: path }
}

///|
fn parse_json_cursor(input : String) -> Result[JsonCursor, HarError] {
  let parsed = @json.parse(input) catch {
    _ => return Err(HarError::new(InvalidJson, "$", "input is not valid JSON"))
  }
  Ok(JsonCursor::new(parsed, "$"))
}

///|
fn JsonCursor::path(self : JsonCursor) -> String {
  self.path_value
}

///|
fn JsonCursor::field_path(self : JsonCursor, field : String) -> String {
  append_json_field(self.path_value, field)
}

///|
fn JsonCursor::as_object(
  self : JsonCursor,
) -> Result[Map[String, Json], HarError] {
  match self.value {
    Object(object) => Ok(object)
    _ =>
      Err(
        HarError::new(ExpectedObject, self.path_value, "expected a JSON object"),
      )
  }
}

///|
fn JsonCursor::as_array(self : JsonCursor) -> Result[Array[Json], HarError] {
  match self.value {
    Array(items) => Ok(items)
    _ =>
      Err(
        HarError::new(ExpectedArray, self.path_value, "expected a JSON array"),
      )
  }
}

///|
fn JsonCursor::as_string(self : JsonCursor) -> Result[String, HarError] {
  match self.value {
    String(value) => Ok(value)
    _ =>
      Err(
        HarError::new(ExpectedString, self.path_value, "expected a JSON string"),
      )
  }
}

///|
fn JsonCursor::as_number(self : JsonCursor) -> Result[Double, HarError] {
  match self.value {
    Number(value, ..) => Ok(value)
    _ =>
      Err(
        HarError::new(ExpectedNumber, self.path_value, "expected a JSON number"),
      )
  }
}

///|
fn JsonCursor::as_bool(self : JsonCursor) -> Result[Bool, HarError] {
  match self.value {
    True => Ok(true)
    False => Ok(false)
    _ =>
      Err(
        HarError::new(
          ExpectedBoolean,
          self.path_value,
          "expected a JSON boolean",
        ),
      )
  }
}

///|
fn JsonCursor::required_field(
  self : JsonCursor,
  field : String,
) -> Result[JsonCursor, HarError] {
  let object = match self.as_object() {
    Ok(value) => value
    Err(error) => return Err(error)
  }
  match object.get(field) {
    Some(value) => Ok(JsonCursor::new(value, self.field_path(field)))
    None =>
      Err(
        HarError::new(
          MissingField,
          self.field_path(field),
          "required field is missing",
        ),
      )
  }
}

///|
fn JsonCursor::optional_field(
  self : JsonCursor,
  field : String,
) -> Result[JsonCursor?, HarError] {
  let object = match self.as_object() {
    Ok(value) => value
    Err(error) => return Err(error)
  }
  match object.get(field) {
    Some(Null) | None => Ok(None)
    Some(value) => Ok(Some(JsonCursor::new(value, self.field_path(field))))
  }
}

///|
fn JsonCursor::required_string(
  self : JsonCursor,
  field : String,
) -> Result[String, HarError] {
  match self.required_field(field) {
    Ok(cursor) => cursor.as_string()
    Err(error) => Err(error)
  }
}

///|
fn JsonCursor::optional_string(
  self : JsonCursor,
  field : String,
) -> Result[String?, HarError] {
  match self.optional_field(field) {
    Err(error) => Err(error)
    Ok(None) => Ok(None)
    Ok(Some(cursor)) =>
      match cursor.as_string() {
        Ok(value) => Ok(Some(value))
        Err(error) => Err(error)
      }
  }
}

///|
fn JsonCursor::required_number(
  self : JsonCursor,
  field : String,
) -> Result[Double, HarError] {
  match self.required_field(field) {
    Ok(cursor) => cursor.as_number()
    Err(error) => Err(error)
  }
}

///|
fn JsonCursor::optional_number(
  self : JsonCursor,
  field : String,
) -> Result[Double?, HarError] {
  match self.optional_field(field) {
    Err(error) => Err(error)
    Ok(None) => Ok(None)
    Ok(Some(cursor)) =>
      match cursor.as_number() {
        Ok(value) => Ok(Some(value))
        Err(error) => Err(error)
      }
  }
}

///|
fn JsonCursor::optional_bool(
  self : JsonCursor,
  field : String,
) -> Result[Bool?, HarError] {
  match self.optional_field(field) {
    Err(error) => Err(error)
    Ok(None) => Ok(None)
    Ok(Some(cursor)) =>
      match cursor.as_bool() {
        Ok(value) => Ok(Some(value))
        Err(error) => Err(error)
      }
  }
}

///|
fn JsonCursor::optional_array(
  self : JsonCursor,
  field : String,
) -> Result[Array[JsonCursor], HarError] {
  match self.optional_field(field) {
    Err(error) => Err(error)
    Ok(None) => Ok([])
    Ok(Some(cursor)) => cursor.to_cursor_array()
  }
}

///|
fn JsonCursor::required_array(
  self : JsonCursor,
  field : String,
) -> Result[Array[JsonCursor], HarError] {
  let cursor = match self.required_field(field) {
    Ok(value) => value
    Err(error) => return Err(error)
  }
  cursor.to_cursor_array()
}

///|
fn JsonCursor::required_object(
  self : JsonCursor,
  field : String,
) -> Result[JsonCursor, HarError] {
  let cursor = match self.required_field(field) {
    Ok(value) => value
    Err(error) => return Err(error)
  }
  match cursor.as_object() {
    Ok(_) => Ok(cursor)
    Err(error) => Err(error)
  }
}

///|
fn JsonCursor::optional_object(
  self : JsonCursor,
  field : String,
) -> Result[JsonCursor?, HarError] {
  match self.optional_field(field) {
    Err(error) => Err(error)
    Ok(None) => Ok(None)
    Ok(Some(cursor)) =>
      match cursor.as_object() {
        Ok(_) => Ok(Some(cursor))
        Err(error) => Err(error)
      }
  }
}

///|
fn JsonCursor::to_cursor_array(
  self : JsonCursor,
) -> Result[Array[JsonCursor], HarError] {
  let values = match self.as_array() {
    Ok(value) => value
    Err(error) => return Err(error)
  }
  let result : Array[JsonCursor] = []
  for index, value in values {
    result.push(
      JsonCursor::new(value, append_json_index(self.path_value, index)),
    )
  }
  Ok(result)
}

///|