use super::{tag_answer::AnswerState, tag_inline::InlineState, tag_task::TaskState, Result};
use crate::ast2::{parse_document, Anchor, CommandKind, Content};
use crate::utils::file::FileAccessor;
use crate::utils::path::PathResolver;
use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::Arc;
use uuid::Uuid;
#[derive(Debug)]
pub enum AnchorState {
Answer(AnswerState),
Inline(InlineState),
Task(TaskState),
}
#[derive(Debug)]
pub struct AnchorAnalysis {
pub anchor: Anchor,
pub state: AnchorState,
}
#[derive(Debug)]
pub struct ContextAnalysis {
pub anchors: HashMap<Uuid, AnchorAnalysis>,
}
pub fn analyze_context(
file_access: Arc<dyn FileAccessor>,
path_res: Arc<dyn PathResolver>,
context_name: &str,
) -> Result<ContextAnalysis> {
let analyzer = Analyzer {
file_access,
path_res,
};
analyzer.run(context_name)
}
struct Analyzer {
file_access: Arc<dyn FileAccessor>,
path_res: Arc<dyn PathResolver>,
}
impl Analyzer {
fn run(&self, context_name: &str) -> Result<ContextAnalysis> {
let path = self.path_res.resolve_input_file(context_name)?;
let content = self.file_access.read_file(&path)?;
let doc = parse_document(&content)?;
let mut analysis = ContextAnalysis {
anchors: HashMap::new(),
};
for node in doc.content {
if let Content::Anchor(anchor) = node {
if let Some(state) = self.extract_anchor_state(&anchor)? {
let anchor_analysis = AnchorAnalysis {
anchor: anchor.clone(),
state,
};
analysis.anchors.insert(anchor.uuid, anchor_analysis);
}
}
}
Ok(analysis)
}
fn extract_anchor_state(&self, anchor: &Anchor) -> Result<Option<AnchorState>> {
match anchor.command {
CommandKind::Answer => {
let state = self.load_state::<AnswerState>(anchor.command, &anchor.uuid)?;
Ok(Some(AnchorState::Answer(state)))
}
CommandKind::Inline => {
let state = self.load_state::<InlineState>(anchor.command, &anchor.uuid)?;
Ok(Some(AnchorState::Inline(state)))
}
CommandKind::Task => {
let state = self.load_state::<TaskState>(anchor.command, &anchor.uuid)?;
Ok(Some(AnchorState::Task(state)))
}
_ => Ok(None),
}
}
fn get_state_path(&self, command: CommandKind, uuid: &Uuid) -> Result<PathBuf> {
let meta_path = self
.path_res
.resolve_metadata(&command.to_string(), &uuid)?;
let state_path = meta_path.join("state.json");
Ok(state_path)
}
pub fn load_state<T: serde::de::DeserializeOwned>(
&self,
command: CommandKind,
uuid: &Uuid,
) -> Result<T> {
let state_path = self.get_state_path(command, uuid)?;
let state = self.file_access.read_file(&state_path)?;
let state: T = serde_json::from_str(&state)?;
Ok(state)
}
}