//! Option flags that shape the generated regex.

/// Flags that control output shape.
///
/// Build with [`Options::default`] and set fields directly, or use the builder
/// methods. Every flag except `relax_zeros` defaults to "unset", which the
/// algorithm treats as off.
///
/// ```
/// use regex_range::Options;
///
/// let opts = Options::default().capture(true).shorthand(true);
/// assert_eq!(opts.capture, Some(true));
/// assert_eq!(opts.shorthand, Some(true));
/// ```
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Options {
    /// Relax leading-zero matching for padded ranges.
    ///
    /// `None` and `Some(true)` both relax (the default). `Some(false)` makes
    /// leading zeros mandatory. With relaxing on, a band that needs two leading
    /// zeros emits `0{0,2}`. With it off, the same band emits `00`. See
    /// [`strict_zeros`](Options::strict_zeros) for the inverse alias.
    pub relax_zeros: Option<bool>,

    /// Back-compatible inverse of [`relax_zeros`](Options::relax_zeros).
    ///
    /// When set to a boolean it overrides `relax_zeros`: `Some(true)` turns
    /// relaxing off, `Some(false)` turns it on. `None` leaves `relax_zeros`
    /// untouched.
    pub strict_zeros: Option<bool>,

    /// Emit `\d` instead of `[0-9]` for full-digit positions.
    ///
    /// Only `Some(true)` enables shorthand. Any other value keeps `[0-9]`.
    pub shorthand: Option<bool>,

    /// Wrap the whole result in a capturing group `(...)`.
    ///
    /// Only `Some(true)` enables it. Capture wraps even a single alternative and
    /// takes precedence over `wrap`.
    pub capture: Option<bool>,

    /// Wrap a multi-alternative result in a non-capturing group `(?:...)`.
    ///
    /// `None` and `Some(true)` both wrap. `Some(false)` suppresses the wrapper.
    /// A single-alternative result is never wrapped unless `capture` is set.
    pub wrap: Option<bool>,
}

impl Options {
    /// Set [`relax_zeros`](Options::relax_zeros).
    pub fn relax_zeros(mut self, v: bool) -> Self {
        self.relax_zeros = Some(v);
        self
    }

    /// Set [`strict_zeros`](Options::strict_zeros).
    pub fn strict_zeros(mut self, v: bool) -> Self {
        self.strict_zeros = Some(v);
        self
    }

    /// Set [`shorthand`](Options::shorthand).
    pub fn shorthand(mut self, v: bool) -> Self {
        self.shorthand = Some(v);
        self
    }

    /// Set [`capture`](Options::capture).
    pub fn capture(mut self, v: bool) -> Self {
        self.capture = Some(v);
        self
    }

    /// Set [`wrap`](Options::wrap).
    pub fn wrap(mut self, v: bool) -> Self {
        self.wrap = Some(v);
        self
    }

    /// Resolve raw flags into the values the algorithm uses.
    ///
    /// `relax_zeros` defaults to `true`. A boolean `strict_zeros` overrides it:
    /// strict on means relax off, strict off means relax on. The other flags
    /// collapse to plain booleans.
    pub(crate) fn resolve(&self) -> Resolved {
        let mut relax = self.relax_zeros.unwrap_or(true);
        if let Some(strict) = self.strict_zeros {
            relax = !strict;
        }
        Resolved {
            relax_zeros: relax,
            shorthand: self.shorthand == Some(true),
            capture: self.capture == Some(true),
            wrap_false: self.wrap == Some(false),
        }
    }
}

/// Resolved option values used by the pattern builder.
#[derive(Debug, Clone, Copy)]
pub(crate) struct Resolved {
    /// Whether leading zeros are optional in padded output.
    pub relax_zeros: bool,
    /// Whether full-digit classes render as `\d`.
    pub shorthand: bool,
    /// Whether to wrap the result in a capturing group.
    pub capture: bool,
    /// Whether `wrap` was explicitly set to false.
    pub wrap_false: bool,
}
