1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
use super::Controlfield;
use super::Field;
use super::Record;
use super::Subfield;

const MARC_BREAKER_SF_DELIMITER: &str = "$";
const MARC_BREAKER_SF_DELIMITER_ESCAPE: &str = "{dollar}";

/// Replace bare subfield delimiter values with their escaped version.
pub fn escape_to_breaker(value: &str) -> String {
    value.replace(MARC_BREAKER_SF_DELIMITER, MARC_BREAKER_SF_DELIMITER_ESCAPE)
}

/// Replace escaped subfield delimiter values with the bare version.
pub fn unescape_from_breaker(value: &str) -> String {
    value.replace(MARC_BREAKER_SF_DELIMITER_ESCAPE, MARC_BREAKER_SF_DELIMITER)
}

impl Controlfield {
    pub fn to_breaker(&self) -> String {
        if !self.content().is_empty() {
            format!("={} {}", self.tag(), escape_to_breaker(self.content()))
        } else {
            format!("={}", self.tag())
        }
    }
}

impl Subfield {
    pub fn to_breaker(&self) -> String {
        format!(
            "${}{}",
            escape_to_breaker(self.code()),
            escape_to_breaker(self.content()),
        )
    }
}

impl Field {
    pub fn to_breaker(&self) -> String {
        let mut s = format!(
            "={} {}{}",
            self.tag(),
            if self.ind1() == " " {
                "\\"
            } else {
                self.ind1()
            },
            if self.ind2() == " " {
                "\\"
            } else {
                self.ind2()
            },
        );

        for sf in self.subfields() {
            s += sf.to_breaker().as_str();
        }

        s
    }
}

impl Record {
    /// Creates the MARC Breaker representation of this record as a String.
    pub fn to_breaker(&self) -> String {
        let mut s = format!("=LDR {}", &escape_to_breaker(self.leader()));

        for cfield in self.control_fields() {
            s += format!("\n{}", cfield.to_breaker()).as_str();
        }

        for field in self.fields() {
            s += format!("\n{}", field.to_breaker()).as_str();
        }

        s
    }

    /// Creates a new MARC Record from a MARC Breaker string.
    pub fn from_breaker(breaker: &str) -> Result<Self, String> {
        let mut record = Record::new();

        for line in breaker.lines() {
            record.add_breaker_line(line)?;
        }

        Ok(record)
    }

    /// Process one line of breaker text
    fn add_breaker_line(&mut self, line: &str) -> Result<(), String> {
        let mut len = line.len();
        if len < 4 {
            return Ok(());
        }

        // Step past the opening '=' character
        let line = &line[1..];
        len -= 1;

        let tag = &line[..3];

        if tag.eq("LDR") {
            if len > 4 {
                self.set_leader(&line[4..])?;
            }
            return Ok(());
        }

        // There is a space between the tag and the 1st indicator.

        if tag < "010" {
            let content = if len > 4 {
                unescape_from_breaker(&line[4..])
            } else {
                "".to_string()
            };
            let cf = Controlfield::new(tag, content)?;
            self.control_fields_mut().push(cf);
            return Ok(());
        }

        let mut field = Field::new(tag)?;

        if len > 4 {
            field.set_ind1(line[4..5].replace('\\', " "))?;
        }

        if len > 5 {
            field.set_ind2(line[5..6].replace('\\', " "))?;
        }

        if len > 6 {
            for sf in line[6..].split(MARC_BREAKER_SF_DELIMITER) {
                if sf.is_empty() {
                    continue;
                }
                let subfield = Subfield::new(&sf[..1], if sf.len() > 1 { &sf[1..] } else { "" })?;

                field.subfields_mut().push(subfield);
            }
        }

        self.fields_mut().push(field);

        Ok(())
    }
}