use core::{Glue, Scaled};
use super::keyword::parse_keyword;
use crate::prelude as txl;
use crate::token::Value;
use crate::traits::*;
use crate::*;
impl Parsable for Glue {
    fn parse_impl<S: TexlangState>(input: &mut vm::ExpandedStream<S>) -> txl::Result<Self> {
        let negative = match super::integer::parse_optional_signs(input)? {
            None => 1,
            Some(_) => -1,
        };
        let first_token = input.next_or_err(GlueEndOfInputError {})?;
        let width = match first_token.value() {
            Value::CommandRef(command_ref) => {
                use super::integer::InternalNumber;
                match super::integer::parse_internal_number(input, first_token, command_ref)? {
                    InternalNumber::Integer(i) => {
                        super::dimen::scan_and_apply_units(
                            input,
                            first_token,
                            i.abs(),
                            Scaled::ZERO,
                            None,
                        )? * negative
                            * i.signum()
                    }
                    InternalNumber::Dimen(d) => d * negative,
                    InternalNumber::Glue(g) => {
                        return Ok(g * negative);
                    }
                }
            }
            _ => {
                input.back(first_token);
                core::Scaled::parse(input)? * negative
            }
        };
        let mut g = Glue {
            width,
            ..Default::default()
        };
        if parse_keyword(input, "plus")? {
            g.stretch = super::dimen::scan_dimen(input, Some(&mut g.stretch_order))?
        }
        if parse_keyword(input, "minus")? {
            g.shrink = super::dimen::scan_dimen(input, Some(&mut g.shrink_order))?
        };
        Ok(g)
    }
}
#[derive(Debug)]
struct GlueEndOfInputError;
impl error::EndOfInputError for GlueEndOfInputError {
    fn doing(&self) -> String {
        "parsing a glue".into()
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    use crate::parse::testing::*;
    use core::GlueOrder;
    #[derive(Default)]
    struct State;
    impl TexlangState for State {}
    parse_success_tests![
        (
            width_1,
            "0pt",
            Glue {
                ..Default::default()
            }
        ),
        (
            width_2,
            "1pt",
            Glue {
                width: Scaled::ONE,
                ..Default::default()
            }
        ),
        (
            width_3,
            "-1pt",
            Glue {
                width: -Scaled::ONE,
                ..Default::default()
            }
        ),
        (
            stretch_1,
            "1pt plus 1pt",
            Glue {
                width: Scaled::ONE,
                stretch: Scaled::ONE,
                ..Default::default()
            }
        ),
        (
            stretch_fil,
            "1pt plus 1fil",
            Glue {
                width: Scaled::ONE,
                stretch: Scaled::ONE,
                stretch_order: GlueOrder::Fil,
                ..Default::default()
            }
        ),
        (
            stretch_fill,
            "1pt plus 1fill",
            Glue {
                width: Scaled::ONE,
                stretch: Scaled::ONE,
                stretch_order: GlueOrder::Fill,
                ..Default::default()
            }
        ),
        (
            stretch_filll,
            "1pt plus 1filll",
            Glue {
                width: Scaled::ONE,
                stretch: Scaled::ONE,
                stretch_order: GlueOrder::Filll,
                ..Default::default()
            }
        ),
    ];
    parse_failure_tests!(
        Glue,
        State,
        (
            stretch_overflow_1,
            "1pt plus 30000000fil",
            Glue {
                width: Scaled::ONE,
                stretch: Scaled::MAX_DIMEN,
                stretch_order: GlueOrder::Fil,
                ..Default::default()
            }
        ),
        (
            stretch_overflow_2,
            "1pt plus -30000000fil",
            Glue {
                width: Scaled::ONE,
                stretch: -Scaled::MAX_DIMEN,
                stretch_order: GlueOrder::Fil,
                ..Default::default()
            }
        ),
        (
            stretch_fillll,
            "1pt plus 2fillll",
            Glue {
                width: Scaled::ONE,
                stretch: Scaled::ONE * 2,
                stretch_order: GlueOrder::Filll,
                ..Default::default()
            }
        ),
    );
}