use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use crate::comptime::ScriptError;
use crate::parser::{DialogueChoice, DialogueEnding};
use crate::ParseResult;
#[derive(Clone, Debug, Default)]
pub enum ParseState {
ComptimeScript(Box<ParseState>),
#[default]
Metadata,
Message,
Choices(ChoicesState),
}
#[derive(Clone, Debug, Default)]
pub enum ChoicesState {
#[default]
Choices,
}
#[derive(Debug, Error, PartialEq)]
pub enum ParseError {
#[error("Encountered {0} while trying to parse interaction endings...")]
MalformedEnding(String),
#[error("Tried to push a mix of endings at: {0}")]
MixedEndings(String),
#[error("{0} is not a valid interaction ID")]
InvalidID(String),
#[error("Could not split {0}. Is this supposed to be metadata?")]
NotMeta(String),
#[error("{0} is not a valid metadata directive")]
InvalidMeta(String),
#[error("No interaction to set the ending for!")]
EndingNoIX,
#[error("No interaction to push the page into!")]
PushPageNoIX,
#[error("No interaction to push onto the parser's list!")]
PushEmptyIX,
#[error("Attempt to push a duplicate interaction")]
PushDuplicateIX,
#[error("Attempt to push a page after an ending in interaction")]
PageAfterEnding,
#[error("Failed while running comptime script")]
Panic(ScriptError),
}
impl From<ScriptError> for ParseError {
fn from(value: ScriptError) -> Self {
Self::Panic(value)
}
}
pub type InteractionMap = HashMap<String, Interaction>;
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct Interaction {
pub pages: Vec<Page>,
pub ending: DialogueEnding,
}
impl Interaction {
pub fn push_choice(&mut self, to_push: DialogueChoice) -> ParseResult<()> {
use DialogueEnding::*;
match &mut self.ending {
end @ End => {
*end = Choices(vec![to_push]);
Ok(())
}
Choices(ref mut list) => {
list.push(to_push);
Ok(())
}
Label(l) => Err(ParseError::MixedEndings(l.to_string())),
}
}
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct Page {
pub metadata: PageMeta,
pub content: String,
}
impl Page {
pub fn from_content(content: String) -> Self {
Self {
content,
metadata: PageMeta::default(),
}
}
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub enum Speaker {
Named(String),
#[default]
Narrator,
Unknown,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct PageMeta {
pub speaker: Metaline<Speaker>,
pub vox: Metaline<String>,
}
impl PageMeta {
pub fn nochange() -> Self {
use Metaline::NoChange;
Self {
speaker: NoChange,
vox: NoChange,
}
}
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub enum Metaline<T> {
Permanent(T),
PageOnly(T),
#[default]
NoChange,
}
impl<T> Metaline<T> {
pub fn new(val: T, pageonly: bool) -> Self {
if pageonly {
Self::PageOnly(val)
} else {
Self::Permanent(val)
}
}
pub fn try_unwrap(&self) -> Option<&T> {
match self {
Self::Permanent(val) | Self::PageOnly(val) => Some(val),
Self::NoChange => None,
}
}
pub fn unwrap(&self) -> &T {
self.try_unwrap().unwrap()
}
}