// License: see LICENSE file at root directory of `master` branch

//! # Format

use {
    core::{
        fmt::{self, Display, Formatter},
        str::FromStr,
    },
    std::io::{Error, ErrorKind},

    zeros::HEX_STRS,
};

const HEX: &str = "hex";
const HEX_ARRAY: &str = "hex-array";

/// # Format
#[derive(Debug)]
pub enum Format {
    Hex,
    HexArray,
}

impl Format {

    pub fn fmt<B>(&self, bytes: B) -> String where B: AsRef<[u8]> {
        match self {
            Format::Hex => zeros::bytes_to_hex(bytes),
            Format::HexArray => {
                let bytes = bytes.as_ref();
                let mut result = String::with_capacity(bytes.len().saturating_mul(6));
                for b in bytes {
                    if result.is_empty() == false {
                        result.push_str(concat!(',', ' '));
                    }
                    result.push_str(concat!('0', 'x'));
                    result.push_str(HEX_STRS[usize::from(*b)]);
                }
                result.insert(0, '[');
                result.push(']');
                result
            },
        }
    }

}

impl FromStr for Format {

    type Err = Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.eq_ignore_ascii_case(HEX) {
            Ok(Format::Hex)
        } else if s.eq_ignore_ascii_case(HEX_ARRAY) {
            Ok(Format::HexArray)
        } else {
            Err(Error::new(ErrorKind::InvalidInput, format!("Unknown format: {:?}", s)))
        }
    }

}

impl Display for Format {

    fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
        f.write_str(match self {
            Format::Hex => HEX,
            Format::HexArray => HEX_ARRAY,
        })
    }

}
