use crate::err::{SJFLError, Span};
use super::{Parse, Session};
use hmath::{ConversionError, Ratio};

impl Parse for Ratio {

    fn parse(s: &[u8], mut ind: usize, _: &mut Session) -> Result<(Self, usize), SJFLError> {
        let mut buffer = vec![];

        if s[ind] == b'-' {
            buffer.push(b'-');
            ind += 1;
        }

        // it allows whitespaces here (only ' ')
        while ind < s.len() && s[ind] == b' ' {
            ind += 1;
        }

        // required for error messages
        let start_ind = ind;

        while ind < s.len() && (
            (48 <= s[ind] && s[ind] <= 57)  // 0 ~ 9
            || (65 <= s[ind] && s[ind] <= 90)  // A ~ Z
            || (97 <= s[ind] && s[ind] <= 122)  // a ~ z
            || s[ind] == 46  // .
            || s[ind] == 95  // _
        ) {
            buffer.push(s[ind]);
            ind += 1;
        }

        let s = String::from_utf8_lossy(&buffer).to_string();

        return match Ratio::from_string(&s) {
            Ok(n) => Ok((n, ind)),
            Err(e) => Err(match e {
                ConversionError::NoData | ConversionError::UnexpectedEnd => SJFLError::UnexpectedEof(Span::from_index(start_ind)),
                ConversionError::InvalidChar(c) => SJFLError::UnexpectedChar(c as u8, Span::from_index(start_ind)),
                _ => unreachable!()
            })
        };

    }

}