1use crate::{
4 error::{parse::validate::ValidationError, utils::MetaData},
5 knot::Address,
6 line::{InternalChoice, InternalLine},
7 story::validate::{ValidateContent, ValidationData},
8};
9
10#[cfg(feature = "serde_support")]
11use serde::{Deserialize, Serialize};
12
13#[derive(Clone, Debug)]
14#[cfg_attr(feature = "serde_support", derive(Deserialize, Serialize))]
15pub struct RootNode {
17 pub address: Address,
19 pub items: Vec<NodeItem>,
21}
22
23#[derive(Clone, Debug)]
24#[cfg_attr(feature = "serde_support", derive(Deserialize, Serialize))]
25pub struct Branch {
30 pub choice: InternalChoice,
32 pub items: Vec<NodeItem>,
34 pub num_visited: u32,
36}
37
38#[derive(Clone, Debug)]
39#[cfg_attr(feature = "serde_support", derive(Deserialize, Serialize))]
40pub enum NodeItem {
43 Line(InternalLine),
44 BranchingPoint(Vec<Branch>),
45}
46
47#[cfg(test)]
48impl NodeItem {
50 pub fn is_branching_choice(&self) -> bool {
51 match self {
52 NodeItem::BranchingPoint(..) => true,
53 _ => false,
54 }
55 }
56
57 pub fn is_line(&self) -> bool {
58 match self {
59 NodeItem::Line(..) => true,
60 _ => false,
61 }
62 }
63}
64
65impl ValidateContent for RootNode {
66 fn validate(
67 &mut self,
68 error: &mut ValidationError,
69 current_location: &Address,
70 meta_data: &MetaData,
71 data: &ValidationData,
72 ) {
73 self.items
74 .iter_mut()
75 .for_each(|item| item.validate(error, current_location, meta_data, data))
76 }
77}
78
79impl ValidateContent for Branch {
80 fn validate(
81 &mut self,
82 error: &mut ValidationError,
83 current_location: &Address,
84 meta_data: &MetaData,
85 data: &ValidationData,
86 ) {
87 let num_errors = error.num_errors();
88
89 self.choice
90 .validate(error, current_location, meta_data, data);
91
92 if let Some((choice_display_line, items)) = self.items.split_first_mut() {
97 if num_errors == error.num_errors() {
98 choice_display_line.validate(error, current_location, meta_data, data);
99 }
100
101 items
102 .iter_mut()
103 .for_each(|item| item.validate(error, current_location, meta_data, data));
104 }
105 }
106}
107
108impl ValidateContent for NodeItem {
109 fn validate(
110 &mut self,
111 error: &mut ValidationError,
112 current_location: &Address,
113 meta_data: &MetaData,
114 data: &ValidationData,
115 ) {
116 match self {
117 NodeItem::BranchingPoint(branches) => branches
118 .iter_mut()
119 .for_each(|item| item.validate(error, current_location, meta_data, data)),
120 NodeItem::Line(line) => line.validate(error, current_location, meta_data, data),
121 };
122 }
123}
124
125pub mod builders {
126 use super::{Branch, NodeItem, RootNode};
133
134 use crate::{
135 knot::{Address, AddressKind},
136 line::{InternalChoice, InternalLine},
137 };
138
139 #[cfg(test)]
140 use crate::line::LineChunk;
141
142 pub struct RootNodeBuilder {
147 address: Address,
148 items: Vec<NodeItem>,
149 }
150
151 impl RootNodeBuilder {
152 pub fn from_address(knot: &str, stitch: &str) -> Self {
153 let address = Address::Validated(AddressKind::Location {
154 knot: knot.to_string(),
155 stitch: stitch.to_string(),
156 });
157
158 RootNodeBuilder {
159 address,
160 items: Vec::new(),
161 }
162 }
163
164 pub fn build(self) -> RootNode {
165 RootNode {
166 address: self.address,
167 items: self.items,
168 }
169 }
170
171 pub fn add_branching_choice(&mut self, branching_set: Vec<Branch>) {
172 self.add_item(NodeItem::BranchingPoint(branching_set));
173 }
174
175 pub fn add_item(&mut self, item: NodeItem) {
176 self.items.push(item);
177 }
178
179 pub fn add_line(&mut self, line: InternalLine) {
180 self.add_item(NodeItem::Line(line));
181 }
182
183 #[cfg(test)]
184 pub fn empty() -> Self {
185 Self::from_address("", "")
186 }
187
188 #[cfg(test)]
189 pub fn with_item(mut self, item: NodeItem) -> Self {
190 self.items.push(item);
191 self
192 }
193
194 #[cfg(test)]
195 pub fn with_branching_choice(self, branching_choice_set: NodeItem) -> Self {
196 self.with_item(branching_choice_set)
197 }
198
199 #[cfg(test)]
200 pub fn with_line_chunk(self, chunk: LineChunk) -> Self {
201 self.with_item(NodeItem::Line(InternalLine::from_chunk(chunk)))
202 }
203
204 #[cfg(test)]
205 pub fn with_text_line_chunk(self, content: &str) -> Self {
206 self.with_item(NodeItem::Line(InternalLine::from_string(content)))
207 }
208 }
209
210 pub struct BranchBuilder {
219 choice: InternalChoice,
220 items: Vec<NodeItem>,
221 }
222
223 impl BranchBuilder {
224 pub fn from_choice(choice: InternalChoice) -> Self {
225 let line = choice.display_text.clone();
226
227 BranchBuilder {
228 choice,
229 items: vec![NodeItem::Line(line)],
230 }
231 }
232
233 pub fn build(self) -> Branch {
234 Branch {
235 choice: self.choice,
236 items: self.items,
237 num_visited: 0,
238 }
239 }
240
241 pub fn add_branching_choice(&mut self, branching_set: Vec<Branch>) {
242 self.add_item(NodeItem::BranchingPoint(branching_set));
243 }
244
245 pub fn add_item(&mut self, item: NodeItem) {
246 self.items.push(item);
247 }
248
249 pub fn add_line(&mut self, line: InternalLine) {
250 self.add_item(NodeItem::Line(line));
251 }
252
253 #[cfg(test)]
254 pub fn with_item(mut self, item: NodeItem) -> Self {
255 self.items.push(item);
256 self
257 }
258
259 #[cfg(test)]
260 pub fn with_branching_choice(self, branching_choice_set: NodeItem) -> Self {
261 self.with_item(branching_choice_set)
262 }
263
264 #[cfg(test)]
265 pub fn with_text_line_chunk(self, content: &str) -> Self {
266 self.with_item(NodeItem::Line(InternalLine::from_string(content)))
267 }
268 }
269
270 #[cfg(test)]
271 pub struct BranchingPointBuilder {
272 items: Vec<Branch>,
273 }
274
275 #[cfg(test)]
276 impl BranchingPointBuilder {
277 pub fn new() -> Self {
278 BranchingPointBuilder { items: Vec::new() }
279 }
280
281 pub fn with_branch(mut self, choice: Branch) -> Self {
282 self.items.push(choice);
283 self
284 }
285
286 pub fn build(self) -> NodeItem {
287 NodeItem::BranchingPoint(self.items)
288 }
289 }
290}