1use std::{
2 cell::RefCell,
3 collections::{HashMap, HashSet},
4 rc::Rc,
5};
6
7use serde_json::Map;
8
9use crate::{
10 callstack::CallStack,
11 json::{json_read, json_write},
12 list_definitions_origin::ListDefinitionsOrigin,
13 state_patch::StatePatch,
14 story_error::StoryError,
15 value::Value,
16 value_type::{ValueType, VariablePointerValue},
17 variable_assigment::VariableAssignment,
18};
19
20#[derive(Clone)]
21pub(crate) struct VariablesState {
22 pub global_variables: HashMap<String, Rc<Value>>,
23 pub default_global_variables: HashMap<String, Rc<Value>>,
24 pub batch_observing_variable_changes: bool,
25 pub callstack: Rc<RefCell<CallStack>>,
26 pub changed_variables_for_batch_obs: Option<HashSet<String>>,
27 pub patch: Option<StatePatch>,
28 list_defs_origin: Rc<ListDefinitionsOrigin>,
29}
30
31impl VariablesState {
32 pub fn new(
33 callstack: Rc<RefCell<CallStack>>,
34 list_defs_origin: Rc<ListDefinitionsOrigin>,
35 ) -> VariablesState {
36 VariablesState {
37 global_variables: HashMap::new(),
38 default_global_variables: HashMap::new(),
39 batch_observing_variable_changes: false,
40 callstack,
41 changed_variables_for_batch_obs: None,
42 patch: None,
43 list_defs_origin,
44 }
45 }
46
47 pub fn start_variable_observation(&mut self) {
48 self.batch_observing_variable_changes = true;
49 self.changed_variables_for_batch_obs = Some(HashSet::new());
50 }
51
52 pub fn complete_variable_observation(&mut self) -> HashMap<String, ValueType> {
53 self.batch_observing_variable_changes = false;
54
55 let mut changed_vars = HashMap::with_capacity(0);
56
57 if let Some(changed_variables_for_batch_obs) = self.changed_variables_for_batch_obs.take() {
60 for variable_name in changed_variables_for_batch_obs {
61 let current_value = self.global_variables.get(&variable_name).unwrap();
62
63 changed_vars.insert(variable_name, current_value.value.clone());
64 }
65 }
66
67 if let Some(patch) = &self.patch {
69 for variable_name in patch.changed_variables.iter() {
70 if let Some(patched_val) = patch.get_global(variable_name) {
71 changed_vars.insert(variable_name.to_string(), patched_val.value.clone());
72 }
73 }
74 }
75
76 changed_vars
77 }
78
79 pub fn snapshot_default_globals(&mut self) {
80 for (k, v) in self.global_variables.iter() {
81 self.default_global_variables.insert(k.clone(), v.clone());
82 }
83 }
84
85 pub fn apply_patch(&mut self) {
86 for (name, value) in self.patch.as_ref().unwrap().globals.iter() {
87 self.global_variables.insert(name.clone(), value.clone());
88 }
89
90 if let Some(changed_variables) = &mut self.changed_variables_for_batch_obs {
91 for name in self.patch.as_ref().unwrap().changed_variables.iter() {
92 changed_variables.insert(name.clone());
93 }
94 }
95
96 self.patch = None;
97 }
98
99 pub fn assign(
100 &mut self,
101 var_ass: &VariableAssignment,
102 value: Rc<Value>,
103 ) -> Result<(), StoryError> {
104 let mut name = var_ass.variable_name.to_string();
105 let mut context_index = -1;
106 let mut set_global;
107
108 if var_ass.is_new_declaration {
110 set_global = var_ass.is_global;
111 } else {
112 set_global = self.global_variable_exists_with_name(&name);
113 }
114
115 let mut value = value;
116 if var_ass.is_new_declaration {
118 if let Some(var_pointer) = Value::get_value::<&VariablePointerValue>(value.as_ref()) {
119 value = self.resolve_variable_pointer(var_pointer);
120 }
121 } else {
122 loop {
126 let existing_pointer = self.get_raw_variable_with_name(&name, context_index);
127
128 match existing_pointer {
129 Some(existing_pointer) => {
130 match Value::get_value::<&VariablePointerValue>(existing_pointer.as_ref()) {
131 Some(pv) => {
132 name = pv.variable_name.to_string();
133 context_index = pv.context_index;
134 set_global = context_index == 0;
135 }
136 None => break,
137 }
138 }
139 None => break,
140 }
141 }
142 }
143
144 if set_global {
145 self.set_global(&name, value);
146 } else {
147 self.callstack.borrow_mut().set_temporary_variable(
148 name,
149 value,
150 var_ass.is_new_declaration,
151 context_index,
152 )?;
153 }
154
155 Ok(())
156 }
157
158 pub fn global_variable_exists_with_name(&self, name: &str) -> bool {
159 self.global_variables.contains_key(name) || self.default_global_variables.contains_key(name)
160 }
161
162 fn resolve_variable_pointer(&self, var_pointer: &VariablePointerValue) -> Rc<Value> {
168 let mut context_index = var_pointer.context_index;
169 if context_index == -1 {
170 context_index = self.get_context_index_of_variable_named(&var_pointer.variable_name);
171 }
172
173 let value_of_variable_pointed_to =
174 self.get_raw_variable_with_name(&var_pointer.variable_name, context_index);
175 if let Some(value_of_variable_pointed_to) = value_of_variable_pointed_to {
181 if Value::get_value::<&VariablePointerValue>(value_of_variable_pointed_to.as_ref())
182 .is_some()
183 {
184 return value_of_variable_pointed_to;
185 }
186 }
187
188 Rc::new(Value::new_variable_pointer(
189 &var_pointer.variable_name,
190 context_index,
191 ))
192 }
193
194 pub fn set(&mut self, variable_name: &str, value_type: ValueType) -> Result<bool, StoryError> {
196 if !self.default_global_variables.contains_key(variable_name) {
197 return Err(StoryError::BadArgument(format!(
198 "Cannot assign to a variable {} that hasn't been declared in the story",
199 variable_name
200 )));
201 }
202
203 let val = Value::new_value_type(value_type);
204
205 let notify = self.set_global(variable_name, Rc::new(val));
206
207 Ok(notify)
208 }
209
210 pub fn get(&self, variable_name: &str) -> Option<ValueType> {
211 if self.patch.is_some() {
212 if let Some(var) = self.patch.as_ref().unwrap().get_global(variable_name) {
213 return Some(var.value.clone());
214 }
215 }
216
217 if let Some(var_contents) = self.global_variables.get(variable_name) {
222 return Some(var_contents.value.clone());
223 } else if let Some(var_contents) = self.default_global_variables.get(variable_name) {
224 return Some(var_contents.value.clone());
225 }
226
227 None
228 }
229
230 fn get_context_index_of_variable_named(&self, var_name: &str) -> i32 {
236 if self.global_variable_exists_with_name(var_name) {
237 return 0;
238 }
239
240 return self.callstack.borrow().get_current_element_index();
241 }
242
243 fn get_raw_variable_with_name(&self, name: &str, context_index: i32) -> Option<Rc<Value>> {
244 if context_index == 0 || context_index == -1 {
246 if let Some(patch) = &self.patch {
247 if let Some(global) = patch.get_global(name) {
248 return Some(global);
249 }
250 }
251
252 if let Some(global) = self.global_variables.get(name) {
253 return Some(global.clone());
254 }
255
256 if let Some(default_global) = self.default_global_variables.get(name) {
264 return Some(default_global.clone());
265 }
266
267 if let Some(list_item_value) =
268 self.list_defs_origin.find_single_item_list_with_name(name)
269 {
270 return Some(list_item_value.clone());
271 }
272 }
273
274 let var_value = self
276 .callstack
277 .borrow()
278 .get_temporary_variable_with_name(name, context_index);
279
280 var_value
281 }
282
283 fn set_global(&mut self, name: &str, value: Rc<Value>) -> bool {
285 let mut old_value: Option<Rc<Value>> = None;
286
287 if let Some(patch) = &self.patch {
288 old_value = patch.get_global(name);
289 }
290
291 if old_value.is_none() {
292 old_value = self.global_variables.get(name).cloned();
293 }
294
295 if let Some(old_value) = &old_value {
296 Value::retain_list_origins_for_assignment(old_value.as_ref(), value.as_ref());
297 }
298
299 if let Some(patch) = &mut self.patch {
300 patch.set_global(name, value.clone());
301 } else {
302 self.global_variables
303 .insert(name.to_string(), value.clone());
304 }
305
306 if old_value.is_none() || !Rc::ptr_eq(old_value.as_ref().unwrap(), &value) {
307 if self.batch_observing_variable_changes {
308 if let Some(patch) = &mut self.patch {
309 patch.add_changed_variable(name);
310 } else if let Some(changed_variables) = &mut self.changed_variables_for_batch_obs {
311 changed_variables.insert(name.to_string());
312 }
313 } else {
314 return true;
315 }
316 }
317
318 false
319 }
320
321 pub fn get_variable_with_name(&self, name: &str, context_index: i32) -> Option<Rc<Value>> {
322 let var_value = self.get_raw_variable_with_name(name, context_index);
323 if let Some(vv) = var_value.clone() {
325 if let Some(var_pointer) = Value::get_value::<&VariablePointerValue>(vv.as_ref()) {
326 return self.value_at_variable_pointer(var_pointer);
327 }
328 }
329
330 var_value
331 }
332
333 fn value_at_variable_pointer(&self, pointer: &VariablePointerValue) -> Option<Rc<Value>> {
334 self.get_variable_with_name(&pointer.variable_name, pointer.context_index)
335 }
336
337 pub fn set_callstack(&mut self, callstack: Rc<RefCell<CallStack>>) {
338 self.callstack = callstack;
339 }
340
341 pub(crate) fn write_json(&self) -> Result<serde_json::Value, StoryError> {
342 let mut jobj: Map<String, serde_json::Value> = Map::new();
343
344 for (name, val) in self.global_variables.iter() {
345 let default_val = self.default_global_variables.get(name);
347 if let Some(default_val) = default_val {
348 if self.val_equal(val, default_val) {
349 continue;
350 }
351 }
352
353 jobj.insert(name.clone(), json_write::write_rtobject(val.clone())?);
354 }
355
356 Ok(serde_json::Value::Object(jobj))
357 }
358
359 fn val_equal(&self, val: &Value, default_val: &Value) -> bool {
360 match &val.value {
361 ValueType::Bool(val) => match default_val.value {
362 ValueType::Bool(default_val) => *val == default_val,
363 _ => false,
364 },
365 ValueType::Int(val) => match default_val.value {
366 ValueType::Int(default_val) => *val == default_val,
367 _ => false,
368 },
369 ValueType::Float(val) => match default_val.value {
370 ValueType::Float(default_val) => *val == default_val,
371 _ => false,
372 },
373 ValueType::List(val) => match &default_val.value {
374 ValueType::List(default_val) => *val == *default_val,
375 _ => false,
376 },
377 ValueType::String(val) => match &default_val.value {
378 ValueType::String(default_val) => val.string.eq(&default_val.string),
379 _ => false,
380 },
381 ValueType::DivertTarget(val) => match &default_val.value {
382 ValueType::DivertTarget(default_val) => *val == *default_val,
383 _ => false,
384 },
385 ValueType::VariablePointer(val) => match &default_val.value {
386 ValueType::VariablePointer(default_val) => *val == *default_val,
387 _ => false,
388 },
389 }
390 }
391
392 pub(crate) fn load_json(
393 &mut self,
394 jobj: &Map<String, serde_json::Value>,
395 ) -> Result<(), StoryError> {
396 self.global_variables.clear();
397
398 for (k, v) in self.default_global_variables.iter() {
399 let loaded_token = jobj.get(k);
400
401 if let Some(loaded_token) = loaded_token {
402 self.global_variables.insert(
403 k.to_string(),
404 json_read::jtoken_to_runtime_object(loaded_token, None)?
405 .into_any()
406 .downcast::<Value>()
407 .unwrap(),
408 );
409 } else {
410 self.global_variables.insert(k.clone(), v.clone());
411 }
412 }
413
414 Ok(())
415 }
416}