Documentation
use super::atom::AtomVec;

use super::FromBuf;
use super::FromBufError;
use std::num::{ParseFloatError, ParseIntError};
impl FromBuf for String {
    type Error = ();
    fn from_buf(buf: Vec<u8>) -> Result<Self, FromBufError<Self::Error>> {
        match String::from_utf8(buf) {
            Ok(value) => Ok(value.trim().to_owned()),
            _ => Err(FromBufError::InvalidUtf8String),
        }
    }
}

impl FromBuf for Vec<u8> {
    type Error = ();
    fn from_buf(buf: Vec<u8>) -> Result<Self, FromBufError<Self::Error>> {
        Ok(buf)
    }
}

impl FromBuf for char {
    type Error = ();

    fn from_buf(buf: Vec<u8>) -> Result<Self, FromBufError<Self::Error>> {
        let Ok(buf) = String::from_buf(buf) else {
            return Err(FromBufError::InvalidUtf8String);
        };
        if buf.is_empty() {
            Err(FromBufError::Empty)
        } else {
            Ok(buf.chars().next().expect("Unreachable!"))
        }
    }
}

impl FromBuf for Vec<char> {
    type Error = ();

    fn from_buf(buf: Vec<u8>) -> Result<Self, FromBufError<Self::Error>> {
        let Ok(buf) = String::from_buf(buf) else {
            return Err(FromBufError::InvalidUtf8String)
        };
        if buf.is_empty() {
            Err(FromBufError::Empty)
        } else {
            Ok(buf.chars().collect())
        }
    }
}

impl<T: AtomVec> FromBuf for Vec<T> {
    type Error = T::Error;

    fn from_buf(buf: Vec<u8>) -> Result<Self, FromBufError<Self::Error>> {
        let Ok(buf) = String::from_buf(buf) else {
            return Err(FromBufError::InvalidUtf8String);
        };
        let splits: Vec<&str> = buf.split(" ").collect();
        let mut values = Vec::new();
        for item in splits {
            let item = item.trim();
            if item.is_empty() {
                continue;
            }
            let value = T::from_buf(item.as_bytes().to_vec())?;
            values.push(value);
        }
        Ok(values)
    }
}

macro_rules! convert_int {
    ($($ty:ty), *) => {
        $(
            impl FromBuf for $ty {
                type Error = ParseIntError;

                fn from_buf(buf: Vec<u8>) -> Result<Self, FromBufError<Self::Error>> {
                    let Ok(buf) = String::from_buf(buf) else {
                        return Err(FromBufError::InvalidUtf8String);
                    };
                    match buf.parse() {
                        Ok(value) => Ok(value),
                        Err(e) => {
                            let mut number = 0;
                            match Base::new(&buf) {
                                Some(base) => match base {
                                    Base::Binary(binary) => {
                                        for item in binary.chars() {
                                            if item == '1' {
                                                number = number * 2 + 1;
                                            } else {
                                                number *= 2;
                                            }
                                        }
                                        Ok(number)
                                    }
                                    Base::Octal(oct) => {
                                        for item in oct.as_bytes().iter() {
                                            let value = (*item - b'0') as Self;
                                            number = number * 8 + value;
                                        }
                                        Ok(number)
                                    }
                                    Base::Hex(hex) => {
                                        for item in hex.as_bytes().iter() {
                                            number = number * 16 + to_hex(*item) as Self;
                                        }
                                        Ok(number)
                                    }
                                },
                                _ => Err(FromBufError::ConvertError(e)),
                            }
                        }
                    }
                }
            }

        )*
    };
}

convert_int!(u8, u16, u32, usize, u64, u128, i8, i16, i32, isize, i64, i128);

macro_rules! convert_float {
    ($($ty:ty), *) => {
        $(
            impl FromBuf for $ty {
                type Error = ParseFloatError;
                fn from_buf(buf: Vec<u8>) -> Result<Self, FromBufError<Self::Error>> {
                    let Ok(buf) = String::from_buf(buf) else {
                        return Err(FromBufError::InvalidUtf8String);
                    };
                    match buf.parse() {
                        Ok(value) => Ok(value),
                        Err(e) => Err(FromBufError::ConvertError(e))
                    }
                }
            }
        )*
    };
}
convert_float!(f32, f64);

enum Base {
    Binary(String),
    Octal(String),
    Hex(String),
}

impl Base {
    fn new(value: &str) -> Option<Base> {
        let value = value.to_ascii_lowercase();
        if value.starts_with("0b") {
            if is_binary(&value[2..]) {
                Some(Base::Binary((&value[2..]).to_owned()))
            } else {
                None
            }
        } else if value.ends_with("b") {
            if is_binary(&value[..value.len() - 1]) {
                Some(Base::Binary((&value[..value.len() - 1]).to_owned()))
            } else {
                None
            }
        } else if value.starts_with("0x") {
            if is_hex(&value[2..]) {
                Some(Base::Hex((&value[2..]).to_owned()))
            } else {
                None
            }
        } else if value.ends_with("h") {
            if is_hex(&value[..value.len() - 1]) {
                Some(Base::Hex((&value[..value.len() - 1]).to_owned()))
            } else {
                None
            }
        } else if value.starts_with("0o") {
            if is_oct(&value[2..]) {
                Some(Base::Octal((&value[2..]).to_owned()))
            } else {
                None
            }
        } else {
            None
        }
    }
}

fn is_binary(value: &str) -> bool {
    !value.as_bytes().iter().any(|f| *f != b'0' && *f != b'1')
}

fn is_oct(value: &str) -> bool {
    !value
        .as_bytes()
        .iter()
        .any(|value| !(*value >= b'0' && *value <= b'7'))
}

fn is_hex(value: &str) -> bool {
    !value.as_bytes().iter().any(|value| match *value {
        b'0'..=b'7' => false,
        b'a'..=b'f' => false,
        _ => true,
    })
}

fn to_hex(byte: u8) -> i32 {
    match byte {
        b'0'..=b'9' => (byte - b'0') as i32,
        b'a'..=b'f' => (byte - b'a' + 10) as i32,
        b'A'..=b'F' => (byte - b'A' + 10) as i32,
        _ => unreachable!(),
    }
}