use crate::sketchbook::ids::{UninterpretedFnId, VarId};
use crate::sketchbook::model::{FnTree, ModelState};
use biodivine_lib_param_bn::{BooleanNetwork, FnUpdate};
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use std::fmt::{Display, Formatter};
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct UpdateFn {
expression: String,
tree: Option<FnTree>,
}
impl Display for UpdateFn {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.expression)
}
}
impl Default for UpdateFn {
fn default() -> UpdateFn {
UpdateFn {
expression: String::new(),
tree: None,
}
}
}
impl UpdateFn {
pub fn try_from_str(expression: &str, context: &ModelState) -> Result<UpdateFn, String> {
if expression.chars().all(|c| c.is_whitespace()) {
Ok(UpdateFn::default())
} else {
let syntactic_tree = FnTree::try_from_str(expression, context, None)?;
Ok(UpdateFn {
expression: syntactic_tree.to_string(context, None),
tree: Some(syntactic_tree),
})
}
}
pub fn new_empty() -> UpdateFn {
Self::default()
}
pub fn get_fn_expression(&self) -> &str {
&self.expression
}
pub fn is_unspecified(&self) -> bool {
self.tree.is_none()
}
pub fn set_fn_expression(
&mut self,
new_expression: &str,
context: &ModelState,
) -> Result<(), String> {
if new_expression.chars().all(|c| c.is_whitespace()) {
self.tree = None;
self.expression = String::new()
} else {
let syntactic_tree = FnTree::try_from_str(new_expression, context, None)?;
self.expression = syntactic_tree.to_string(context, None);
self.tree = Some(syntactic_tree);
}
Ok(())
}
pub fn to_fn_update(&self, context: &BooleanNetwork) -> Option<FnUpdate> {
self.tree
.as_ref()
.map(|tree| tree.to_fn_update_recursive(context))
}
pub fn collect_variables(&self) -> HashSet<VarId> {
if let Some(tree) = &self.tree {
tree.collect_variables()
} else {
HashSet::new()
}
}
pub fn collect_fn_symbols(&self) -> HashSet<UninterpretedFnId> {
if let Some(tree) = &self.tree {
tree.collect_fn_symbols()
} else {
HashSet::new()
}
}
pub fn substitute_var(&mut self, old_id: &VarId, new_id: &VarId, context: &ModelState) {
if let Some(tree) = &self.tree {
let new_tree = tree.substitute_var(old_id, new_id);
self.expression = new_tree.to_string(context, None);
self.tree = Some(new_tree);
}
}
pub fn substitute_fn_symbol(
&mut self,
old_id: &UninterpretedFnId,
new_id: &UninterpretedFnId,
context: &ModelState,
) {
if let Some(tree) = &self.tree {
let new_tree = tree.substitute_fn_symbol(old_id, new_id);
self.expression = new_tree.to_string(context, None);
self.tree = Some(new_tree);
}
}
pub fn with_substituted_fn_symbol(
mut original_fn: UpdateFn,
old_id: &UninterpretedFnId,
new_id: &UninterpretedFnId,
context: &ModelState,
) -> UpdateFn {
original_fn.substitute_fn_symbol(old_id, new_id, context);
original_fn
}
pub fn with_substituted_var(
mut original_fn: UpdateFn,
old_id: &VarId,
new_id: &VarId,
context: &ModelState,
) -> UpdateFn {
original_fn.substitute_var(old_id, new_id, context);
original_fn
}
}