use super::{FieldLineValue, FieldSection, PseudoHeaders};
use crate::{Status, headers::entry_name::EntryName};
pub(super) type QifGroup = Vec<(String, String)>;
pub(super) fn parse(content: &str) -> Vec<QifGroup> {
let mut groups: Vec<QifGroup> = Vec::new();
let mut current: QifGroup = Vec::new();
for line in content.lines() {
let line = line.trim_end_matches('\r');
if line.starts_with('#') {
continue;
}
if line.is_empty() {
if !current.is_empty() {
groups.push(std::mem::take(&mut current));
}
continue;
}
if let Some((name, value)) = line.split_once('\t') {
current.push((name.to_owned(), value.to_owned()));
}
}
if !current.is_empty() {
groups.push(current);
}
groups
}
pub(super) fn field_section_to_pairs(fs: FieldSection<'static>) -> QifGroup {
let (pseudos, headers) = fs.into_parts();
let mut pairs = Vec::new();
pseudo_pairs(&pseudos, &mut pairs);
for (name, values) in &headers {
for value in values {
pairs.push((name.to_string().to_lowercase(), value.to_string()));
}
}
pairs
}
fn pseudo_pairs(p: &PseudoHeaders<'_>, out: &mut QifGroup) {
if let Some(m) = p.method() {
out.push((":method".into(), m.to_string()));
}
if let Some(s) = p.status() {
out.push((":status".into(), status_code_str(s)));
}
if let Some(v) = p.path() {
out.push((":path".into(), v.to_string()));
}
if let Some(v) = p.scheme() {
out.push((":scheme".into(), v.to_string()));
}
if let Some(v) = p.authority() {
out.push((":authority".into(), v.to_string()));
}
if let Some(v) = p.protocol() {
out.push((":protocol".into(), v.to_string()));
}
}
fn status_code_str(s: Status) -> String {
s.to_string()
.split_whitespace()
.next()
.unwrap_or("0")
.to_owned()
}
pub(super) fn build_field_lines(
group: &QifGroup,
) -> Result<Vec<(EntryName<'static>, FieldLineValue<'static>, bool)>, String> {
group
.iter()
.map(|(name, value)| {
let entry_name = EntryName::try_from(name.as_bytes().to_vec())
.map_err(|()| format!("parsing name {name:?}: invalid header name"))?;
Ok((
entry_name,
FieldLineValue::Owned(value.clone().into_bytes()),
false,
))
})
.collect()
}