1use crate::{pdf_document, };
2use core::panic;
3use std::{
4 collections::{HashMap, HashSet,},
5
6 hash::Hash,
7 ops::{Deref, DerefMut, },
8 time::{Instant, },
9 vec,
10};
11use uuid::Uuid;
12
13#[derive(PartialEq, Clone, Debug)]
14pub enum TimeOfDay {
15 Day(String),
16 Night(String),
17 Morning(String),
18 Evening(String),
19 Afternoon(String),
20 Extras(Option<HashMap<String, String>>),
21}
22
23
24#[derive(PartialEq, Clone, Debug)]
25pub struct TimeOfDayCollection {
26 pub day: TimeOfDay,
27 pub night: TimeOfDay,
28 pub morning: TimeOfDay,
29 pub evening: TimeOfDay,
30 pub afternoon: TimeOfDay,
31 pub extras: Option<HashMap<String, String>>,
32}
33impl Default for TimeOfDayCollection {
34 fn default() -> Self {
35 return Self {
36 day: TimeOfDay::Day("DAY".into()),
37 night: TimeOfDay::Night("NIGHT".into()),
38 morning: TimeOfDay::Morning("MORNING".into()),
39 evening: TimeOfDay::Evening("EVENING".into()),
40 afternoon: TimeOfDay::Afternoon("AFTERNOON".into()),
41 extras: None,
42 };
43 }
44}
45impl TimeOfDayCollection {
46 pub fn is_time_of_day(&self, target: &String) -> bool {
47 let vars: Vec<&TimeOfDay> = vec![
48 &self.day,
49 &self.night,
50 &self.morning,
51 &self.evening,
52 &self.afternoon,
53 ];
54
55 for time in vars {
56 match time {
57 TimeOfDay::Day(string)
58 | TimeOfDay::Night(string)
59 | TimeOfDay::Morning(string)
60 | TimeOfDay::Evening(string)
61 | TimeOfDay::Afternoon(string) => {
62 if string == target {
63 return true;
64 }
65 }
66 _ => {}
67 }
68 }
69
70 match &self.extras {
71 None => {
72 return false;
73 }
74 Some(e) => {
75 for (_, string) in e {
76 if target == string {
77 return true;
78 }
79 }
80 }
81 }
82
83 return false;
84 }
85
86 pub fn get_time_of_day(&self, target: &String) -> Option<TimeOfDay> {
87 let vars: Vec<&TimeOfDay> = vec![
88 &self.day,
89 &self.night,
90 &self.morning,
91 &self.evening,
92 &self.afternoon,
93 ];
94
95 for time in vars {
96 match time {
97 TimeOfDay::Day(string)
98 | TimeOfDay::Night(string)
99 | TimeOfDay::Morning(string)
100 | TimeOfDay::Evening(string)
101 | TimeOfDay::Afternoon(string) => {
102 if string == target {
103 return Some(time.clone());
104 }
105 }
106 _ => {}
107 }
108 }
109
110 match &self.extras {
111 None => {
112 return None;
113 }
114 Some(e) => {
115 for (_, string) in e {
116 if target == string {
117 return Some(TimeOfDay::Extras(None)); }
119 }
120 }
121 }
122
123 return None;
124 }
125}
126
127#[derive(PartialEq, Clone, Copy, Debug)]
128pub enum PageFormat {
129 US,
130 A4,
131 OTHER,
132}
133
134#[derive(Default, Clone, Debug, Copy, PartialEq, Eq, Hash)]
166#[repr(u8)]
167#[allow(non_camel_case_types)]
168pub enum SPType {
169 SP_ACTION = 0,
170
171 SP_CHARACTER,
172 SP_CHARACTER_EXTENSION, SP_DG_MORE_CONTINUED, SP_PARENTHETICAL,
175 SP_DIALOGUE,
176 SP_TRANSITION,
177
178 SP_SCENE_HEADING(SceneHeadingElement), SP_SHOT_ANGLE, SP_PAGENUM, SP_SCENENUM, SP_PAGE_HEADER, SP_PAGE_REVISION_LABEL, SP_LINE_REVISION_MARKER, SP_MORE_CONTINUED,
200 SP_FOOTER, SP_DUAL_CHARACTERS,
204 SP_DUAL_DIALOGUES,
205
206 SP_DD_L_CHARACTER,
207 SP_DD_L_CHARACTER_EXTENSION,
208 SP_DD_L_PARENTHETICAL,
209 SP_DD_L_DIALOGUE,
210 SP_DD_L_MORE_CONTINUED,
211
212 SP_DD_R_CHARACTER,
213 SP_DD_R_CHARACTER_EXTENSION,
214 SP_DD_R_PARENTHETICAL,
215 SP_DD_R_DIALOGUE,
216 SP_DD_R_MORE_CONTINUED,
217
218 TP_TITLE,
220 TP_BYLINE,
221 TP_AUTHOR,
222 TP_DRAFT_DATE,
223 TP_CONTACT,
224 SP_OTHER,
226 SP_BLANK, SP_OMITTED,
228 NON_CONTENT_TOP,
230 NON_CONTENT_BOTTOM,
231 NON_CONTENT_LEFT,
232 NON_CONTENT_RIGHT,
233
234 #[default]
235 NONE,
236 _TYPECOUNT,
237}
238
239#[derive(Default, PartialEq, Clone, Debug, Eq, Hash)]
243pub struct CharacterID(Uuid);
244impl Deref for CharacterID {
245 type Target = Uuid;
246 fn deref(&self) -> &Self::Target {
247 &self.0
248 }
249}
250impl DerefMut for CharacterID {
251 fn deref_mut(&mut self) -> &mut Self::Target {
252 &mut self.0
253 }
254}
255impl CharacterID {
256 pub fn new() -> Self {
257 CharacterID(Uuid::new_v4())
258 }
259}
260
261#[derive(Default, PartialEq, Clone, Debug, Eq, Hash)]
262pub struct Character {
263 pub name: String,
264 pub id: CharacterID,
265}
266impl Character {
267 pub fn is_line(&self, line: &Line) -> bool {
268 let mut maybe_character_name = String::new();
269 let mut previous_type: Option<SPType> = Some(SPType::NONE);
270 for text_element in &line.text_elements {
271 if previous_type != text_element.element_type {
272 if maybe_character_name == self.name {
273 println!("'howdy y'all");
274 return true;
275 }
276 maybe_character_name = String::new();
277 }
278 match text_element.element_type {
279 Some(SPType::SP_CHARACTER)
280 | Some(SPType::SP_DD_L_CHARACTER)
281 | Some(SPType::SP_DD_R_CHARACTER) => {
282 if !maybe_character_name.is_empty() {
283 maybe_character_name.push(' ');
284 }
285 maybe_character_name.push_str(&text_element.text.clone());
286 }
287 _ => {}
288 }
289 previous_type = text_element.element_type.clone();
290 }
291 if maybe_character_name == self.name {
292 return true;
294 }
295
296 false
297 }
298}
299
300#[derive(Default, PartialEq, Clone, Debug, Eq, Hash)]
302pub struct PageID(pub Uuid);
303impl Deref for PageID {
304 type Target = Uuid;
305 fn deref(&self) -> &Self::Target {
306 &self.0
307 }
308}
309
310impl DerefMut for PageID {
311 fn deref_mut(&mut self) -> &mut Self::Target {
312 &mut self.0
313 }
314}
315
316#[derive(Default, PartialEq, Clone, Debug)]
317pub struct PageNumber(pub String);
318impl Deref for PageNumber {
319 type Target = String;
320 fn deref(&self) -> &Self::Target {
321 &self.0
322 }
323}
324impl DerefMut for PageNumber {
325 fn deref_mut(&mut self) -> &mut Self::Target {
326 &mut self.0
327 }
328}
329
330#[derive(Default, PartialEq, Clone, Debug)]
332pub struct SceneNumber(pub String);
333
334#[derive(Default, PartialEq, Clone, Copy, Debug, Hash, Eq)]
335pub struct SceneID(pub Uuid);
336impl Deref for SceneID {
337 type Target = Uuid;
338 fn deref(&self) -> &Self::Target {
339 &self.0
340 }
341}
342impl DerefMut for SceneID {
343 fn deref_mut(&mut self) -> &mut Self::Target {
344 &mut self.0
345 }
346}
347impl SceneID {
348 pub fn new() -> Self {
349 SceneID(Uuid::new_v4())
350 }
351}
352
353#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash)]
359pub enum SceneHeadingElement {
360 Line, Environment,
362 Location,
363 SubLocation,
364 TimeOfDay,
365 Continuity, TimePeriod, Separator, SceneNumber,
369 SlugOther,
370}
371
372#[derive(PartialEq, Clone, Debug)]
374pub struct Scene {
375 pub start: ScreenplayCoordinate,
376
377 pub environment: Environment,
378 pub number: Option<SceneNumber>,
379 pub revised: bool,
380
381 pub story_locations: Vec<LocationID>,
382 pub story_time_of_day: Option<TimeOfDay>, }
384
385pub struct EnvironmentStrings {
386 pub int: Vec<String>,
387 pub ext: Vec<String>,
388 pub combo: Vec<String>,
389}
390impl Default for EnvironmentStrings {
391 fn default() -> Self {
392 EnvironmentStrings {
393 int: vec!["INT.".into()],
394 ext: vec!["EXT.".into()],
395 combo: vec![
396 "INT./EXT.".into(),
397 "I./E.".into(),
398 "EXT./INT.".into(),
399 "E./I.".into(),
400 ],
401 }
402 }
403}
404
405#[derive(Clone, Debug, PartialEq)]
406pub enum Environment {
407 Int,
408 Ext,
409 Combo(Option<Vec<Environment>>),
410}
411impl Environment {
412 pub fn from_str(string: &String, current_env_strs: &EnvironmentStrings) -> Option<Self> {
413 if current_env_strs.int.contains(&string) {
414 return Some(Environment::Int);
415 }
416 if current_env_strs.ext.contains(&string) {
417 return Some(Environment::Ext);
418 }
419 if current_env_strs.combo.contains(&string) {
420 return Some(Environment::Combo(None));
422 }
423 None
424 }
425}
426
427#[derive(Default, PartialEq, Clone, Debug, Eq, Hash)]
428pub struct LocationID(Uuid);
429
430impl Deref for LocationID {
431 type Target = Uuid;
432 fn deref(&self) -> &Self::Target {
433 &self.0
434 }
435}
436impl DerefMut for LocationID {
437 fn deref_mut(&mut self) -> &mut Self::Target {
438 &mut self.0
439 }
440}
441impl LocationID {
442 pub fn new() -> Self {
443 LocationID(Uuid::new_v4())
444 }
445}
446
447#[derive(Default, PartialEq, Clone, Debug)]
448pub struct LocationNode {
449 pub string: String,
450 pub sublocations: HashSet<LocationID>, pub superlocation: Option<LocationID>, }
453impl LocationNode {
454 pub fn add_sublocation(&mut self, new_id: LocationID) -> bool {
455 self.sublocations.insert(new_id)
456 }
457
458 pub fn subpath_exists<'a>(
466 &'a self,
467 this_location_id: &'a LocationID,
468 subpath: &[String],
469 screenplay: &'a ScreenplayDocument,
470 ) -> Option<(&'a LocationID, Vec<String>)> {
471 if subpath.is_empty() {
472 return None;
473 }
474
475 let subpath_root = &subpath[0];
476
477 for id in &self.sublocations {
478 let Some(sublocation) = screenplay.locations.get(id) else {
479 continue;
480 };
481 if sublocation.string == *subpath_root {
482 if subpath.len() == 1 {
483 return Some((id, Vec::new()));
484 }
485 if subpath.len() > 1 && sublocation.sublocations.is_empty() {
486 return Some((id, Vec::from(&subpath[1..])));
487 }
488 return sublocation.subpath_exists(id, &subpath[1..], screenplay);
489 }
490 }
491
492 Some((this_location_id, subpath.to_vec()))
493 }
494}
495
496#[derive(Default, PartialEq, Clone, Debug)]
499pub struct TextElement {
500 pub text: String,
501 pub element_type: Option<SPType>,
502 pub preceding_whitespace_chars: u64,
503 pub element_position: Option<pdf_document::TextPosition>,
504}
505
506#[derive(Default, PartialEq, Clone, Debug)]
507pub struct Line {
508 pub text_elements: Vec<TextElement>,
509 pub scene_number: Option<String>,
510 pub scene_id: Option<SceneID>,
511 pub line_type: Option<SPType>,
512 pub preceding_empty_lines: u64,
513 pub revised: bool,
514 pub blank: bool,
515}
516
517#[derive(Default, PartialEq, Clone, Debug)]
518pub struct Page {
519 pub lines: Vec<Line>,
520 pub page_number: Option<PageNumber>,
521 pub revised: bool,
522 pub revision_label: Option<String>,
523 pub revision_date: Option<String>,
524 pub page_format: Option<PageFormat>,
525}
526
527#[derive(Default, PartialEq, Clone, Debug, Hash, Eq, PartialOrd)]
528pub struct ScreenplayCoordinate {
529 pub page: usize,
530 pub line: usize,
531 pub element: Option<u64>,
532}
533
534#[derive(Default, PartialEq, Clone, Debug)]
535pub struct ScreenplayDocument {
536 pub pages: Vec<Page>,
537 pub revisions: Option<Vec<String>>, pub scenes: HashMap<SceneID, Scene>,
539 pub locations: HashMap<LocationID, LocationNode>,
540 pub characters: HashSet<Character>,
541 pub page_numbers: HashMap<PageID, PageNumber>,
542}
543impl ScreenplayDocument {
544 pub fn new() -> Self {
545 ScreenplayDocument {
546 pages: Vec::new(),
547 revisions: None,
548 scenes: HashMap::new(),
549 locations: HashMap::new(),
550 characters: HashSet::new(),
551 page_numbers: HashMap::new(),
552 }
553 }
554
555
556}