#![allow(clippy::upper_case_acronyms, clippy::vec_init_then_push)]

mod dnscrypt;
mod dnscrypt_relay;
mod doh;
mod odoh;

pub use self::dnscrypt::*;
pub use self::dnscrypt_relay::*;
pub use self::doh::*;
pub use self::odoh::*;
use std::io::{self, Write};

pub enum InformalProperty {
    DNSSEC,
    NoLogs,
    NoFilters,
}

impl From<InformalProperty> for u64 {
    fn from(informal_property: InformalProperty) -> u64 {
        match informal_property {
            InformalProperty::DNSSEC => 0x01,
            InformalProperty::NoLogs => 0x02,
            InformalProperty::NoFilters => 0x04,
        }
    }
}

pub trait WithInformalProperty {
    fn with_informal_property(self, informal_property: InformalProperty) -> Self;
}

fn lp_encode<W: Write>(writer: &mut W, string: &[u8]) -> io::Result<()> {
    let mut encoded = vec![];
    let len = string.len();
    assert!(len <= 0xff);
    encoded.push(len as u8);
    encoded.extend(string);
    writer.write_all(&encoded)
}

fn vlp_encode<W: Write>(writer: &mut W, strings: &[Vec<u8>]) -> io::Result<()> {
    if strings.is_empty() {
        return writer.write_all(&[0u8]);
    }
    let mut encoded = vec![];
    let mut it = strings.iter();
    let mut next = it.next();
    while let Some(string) = next {
        next = it.next();
        let len = string.len();
        assert!(len < 0x80);
        match next {
            None => encoded.push(len as u8),
            _ => encoded.push(0x80 | len as u8),
        };
        encoded.extend(&string[..]);
    }
    writer.write_all(&encoded)
}

#[test]
fn test_doh() {
    let b = DoHBuilder::new("example.com".to_owned(), "/dns".to_owned())
        .with_address("127.0.0.1:443".to_string())
        .with_informal_property(InformalProperty::DNSSEC)
        .serialize()
        .unwrap();
    assert_eq!(
        b,
        "sdns://AgEAAAAAAAAADTEyNy4wLjAuMTo0NDMAC2V4YW1wbGUuY29tBC9kbnM",
    )
}
