1use std::fmt;
2use std::borrow::Cow;
3
4use crate::common::*;
5use crate::types::*;
6use crate::element::*;
7use crate::error::*;
8use crate::attrib::*;
9use crate::elementstore::*;
10use crate::store::*;
11use crate::metadata::*;
12use crate::select::*;
13use crate::document::*;
14
15#[derive(Clone)]
16pub struct TextParameters {
18    pub set: Option<String>,
19    pub textclass: Option<String>,
20    pub strict: bool,
21    pub retaintokenisation: bool,
22}
23
24impl<'a> Default for TextParameters {
25    fn default() -> Self {
26        Self {
27            set: Some(DEFAULT_TEXT_SET.to_string()),
28            textclass: Some("current".to_string()),
29            strict: false,
30            retaintokenisation: false,
31        }
32    }
33}
34
35impl TextParameters {
36    pub fn new() -> Self {
37        Self::default()
38    }
39
40    pub fn retaintokenisation(mut self, retaintokenisation: bool) -> Self {
41        self.retaintokenisation = retaintokenisation;
42        self
43    }
44
45    pub fn set(mut self, set: &str) -> Self {
46        self.set = Some(set.to_string());
47        self
48    }
49
50    pub fn textclass(mut self, textclass: &str) -> Self {
51        self.textclass = Some(textclass.to_string());
52        self
53    }
54}
55
56
57
58
59impl<'a> Element<'a> {
60
61    pub fn text_by_key(&self, set: DecKey, textclass: ClassKey, strict: bool, retaintokenisation: bool, previousdelimiter: Option<String>) -> Result<String,FoliaError> {
63        let doc = self.document().ok_or(FoliaError::KeyError("Element has no associated document".to_string()))?;
64
65        let properties = doc.props(self.elementtype());
66
67        if properties.textcontainer {
68            let mut text: String = String::new();
70            for item in self.elementdata().data.iter()  {
71                match item {
72                    DataType::Text(item_text) => {
73                        text += &item_text;
74                    },
75                    DataType::Element(element_key) => {
76                        if let Some(element) = doc.get_element(*element_key) {
77                            let properties = doc.props(element.elementtype());
78                            if properties.printable {
79                                if !text.is_empty() {
80                                    if let Some(textdelimiter) = properties.textdelimiter {
81                                        text += textdelimiter;
82                                    }
83                                }
84                                let textpart = element.text_by_key(set,textclass,strict, retaintokenisation,None)?;
85                                text += &textpart;
86                            }
87                        }
88                    },
89                    _ => {},
90                }
91            }
92            Ok(text)
93        } else if !properties.printable || properties.hidden {
94            Err(FoliaError::NoTextError("No such text".to_string()))
95        } else {
96            let mut delimiter: String = String::new();
98            let mut text: String = String::new();
99            let mut textcontent_element: Option<Element> = None;
100            for element in self.elementdata().data.iter() {
101                if let DataType::Element(element_key) = element {
102                    if let Some(element) = doc.get_element(*element_key) {
103                        if ElementGroup::Structure.contains(element.elementtype()) ||
104                           element.elementtype() == ElementType::Correction ||
105                           ElementGroup::Span.contains(element.elementtype()) {
106
107                           if let Ok(textpart) = element.text_by_key(set,textclass,false, retaintokenisation, Some(delimiter.clone())) {
108                               text += &textpart;
110                               if let Ok(s) = element.get_textdelimiter(retaintokenisation) {
111                                   delimiter = s.to_string();
112                               }
113                           }
114                        } else if element.elementtype() == ElementType::WordReference {
115                            if let Some(element) = element.resolve() {
117                               if let Ok(textpart) = element.text_by_key(set,textclass,false, retaintokenisation, Some(delimiter.clone())) {
118                                   text += &textpart;
120                                   if let Ok(s) = element.get_textdelimiter(retaintokenisation) {
121                                       delimiter = s.to_string();
122                                   }
123                               }
124                            }
125                        } else if element.elementtype() == ElementType::TextContent {
126                            textcontent_element = Some(element);
127                        }
128                    }
129                }
130            }
131            if text.is_empty() && textcontent_element.is_some() {
132                if let Ok(parttext) = textcontent_element.unwrap().text_by_key(set,textclass,false,retaintokenisation, None) {
133                    text = parttext
134                }
135            }
136
137            if !text.is_empty() && previousdelimiter.is_some() {
138                text = previousdelimiter.unwrap() + text.as_str();
139            }
140
141            if !text.is_empty() {
142                Ok(text)
143            } else {
144                Err(FoliaError::NoTextError("No such text".to_string()))
145            }
146        }
147    }
148
149    pub fn get_textdelimiter(&self, retaintokenisation: bool) -> Result<Cow<str>,FoliaError> {
151        let doc = self.document().ok_or(FoliaError::KeyError("Element has no associated document".to_string()))?;
152        let properties =  doc.props(self.elementtype());
153        if properties.textdelimiter.is_none() {
154            for item in self.elementdata().data.iter().rev() {
156                if let DataType::Element(element_key) = item {
157                    if let Some(element) = doc.get_element(*element_key) {
158                        match element.get_textdelimiter(retaintokenisation) {
160                            Ok(Cow::Borrowed(s)) => {
161                                return Ok(Cow::Owned(s.to_owned()));
162                            },
163                            Ok(Cow::Owned(s)) => {
164                                return Ok(Cow::Owned(s));
165                            },
166                            Err(e) => {
167                                return Err(e);
168                            }
169                        }
170                    }
171                }
172            }
173            Ok(Cow::Borrowed(""))
174        } else if properties.optional_attribs.contains(&AttribType::SPACE) {
175            let space: bool = retaintokenisation || match self.attrib(AttribType::SPACE) {
176                Some(Attribute::Space(space)) => {
177                    *space
178                },
179                _ => {
180                    true
181                }
182            };
183            if space {
184                Ok(Cow::Borrowed(properties.textdelimiter.unwrap()))
185            } else {
186                Ok(Cow::Borrowed(""))
187            }
188        } else {
189            Ok(Cow::Borrowed(properties.textdelimiter.unwrap()))
190        }
191    }
192
193    pub fn text(&self, textparameters: &TextParameters) -> Result<String,FoliaError> {
197        let doc = self.document().ok_or(FoliaError::KeyError("Element has no associated document".to_string()))?;
198        if let Some(dec_key) = doc.get_declaration_key_by_id(Declaration::index_id(AnnotationType::TEXT, &textparameters.set.as_ref().map(|s| s.as_str())).as_str()) {
199            let class_key = doc.class_key(dec_key, &textparameters.textclass.as_ref().map(|s| s.as_str()).expect("unwrapping textclass")  )?;
200            self.text_by_key(dec_key, class_key,textparameters.strict,textparameters.retaintokenisation, None)
201        } else {
202            Err(FoliaError::EncodeError(format!("No declaration for the specified text set ({})", textparameters.set.as_ref().map(|s| s.as_str()).expect("unwrapping set"))))
203        }
204    }
205}
206
207
208
209
210impl Document {
211    pub fn text_by_key(&self, element_key: ElementKey, set: DecKey, textclass: ClassKey, strict: bool, retaintokenisation: bool) -> Result<String,FoliaError> {
213        if let Some(element) = self.get_element(element_key) {
214            element.text_by_key(set, textclass, strict, retaintokenisation,None)
215        } else {
216            Err(FoliaError::KeyError(format!("No such element key: {}", element_key)))
217        }
218    }
219
220    pub fn text(&self, element_key: ElementKey, textparameters: &TextParameters) -> Result<String,FoliaError> {
222        if let Some(element) = self.get_element(element_key) {
223            element.text(textparameters)
224        } else {
225            Err(FoliaError::KeyError(format!("No such element key: {}", element_key)))
226        }
227    }
228}