/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Prefs file parsing utilities.

/// Parse a single pref value (if any) from the prefs file contents.
///
/// This parser could be improved (e.g., it doesn't respect comments), but it is compatible with
/// prefs files generated by Firefox.
///
/// This finds the first string match for the regex `user_pref\("PREFSTRING"[ \t\n\r\f\v,]*(.*)[ \t\n\r\f\v]*\);`.
///
/// For example:
/// ```rust
/// let input = r#"user_pref("FOOBAR", "baz");"#;
/// let expected_output = Some(r#""baz""#);
/// assert_eq!(find_pref(input, "FOOBAR"), output);
/// ```
pub fn find_pref<'a>(prefs_content: &'a str, pref: &str) -> Option<&'a str> {
    let mut search_content = prefs_content;
    loop {
        let (before, s) = search_content.split_once(&format!("\"{pref}\""))?;
        if !before.trim().ends_with("user_pref(") {
            search_content = s;
            continue;
        }
        let s = s.trim_start_matches(|c: char| c.is_whitespace() || c == ',');
        let (content, _) = s.split_once(");")?;
        return Some(content.trim());
    }
}

/// Find a single string pref (if any) from the prefs file contents.
pub fn find_string_pref<'a>(prefs_content: &'a str, pref: &str) -> Option<&'a str> {
    find_pref(prefs_content, pref).and_then(|s| s.strip_prefix('"')?.strip_suffix('"'))
}

/// Find a single bool pref (if any) from the prefs file contents.
pub fn find_bool_pref(prefs_content: &str, pref: &str) -> Option<bool> {
    find_pref(prefs_content, pref).and_then(|s| s.parse().ok())
}

// Doctests don't run for binaries, so make some unit tests instead.
#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn find_pref_read_value() {
        let input = r#"user_pref("FOOBAR", "baz");"#;
        assert_eq!(find_pref(input, "FOOBAR"), Some(r#""baz""#));
    }

    #[test]
    fn find_pref_continues_search() {
        let input = r#"
            user_pref("rawr", "FOOBAR");
            user_pref("FOOBAR", "baz");
        "#;
        assert_eq!(find_pref(input, "FOOBAR"), Some(r#""baz""#));
    }

    #[test]
    fn find_pref_missing() {
        let input = r#"
            user_pref("rawr", "FOOBAR");
            user_pref("FOOBAR", "hello");
        "#;
        assert_eq!(find_pref(input, "hello"), None);
    }

    #[test]
    fn test_find_string_pref() {
        let input = r#"user_pref("FOOBAR", "baz");"#;
        assert_eq!(find_string_pref(input, "FOOBAR"), Some("baz"));
    }

    #[test]
    fn test_find_bool_pref() {
        let input = r#"user_pref("FOOBAR", true);"#;
        assert_eq!(find_bool_pref(input, "FOOBAR"), Some(true));
        let input = r#"user_pref("FOOBAR", false);"#;
        assert_eq!(find_bool_pref(input, "FOOBAR"), Some(false));
    }
}
