use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::process::Command;
use graphviz_dot_builder::traits::DotTranslatable;
use graphviz_dot_builder::edge::edge::GraphVizEdge;
use graphviz_dot_builder::edge::style::{GraphvizEdgeStyleItem, GvArrowHeadStyle};
use graphviz_dot_builder::graph::graph::GraphVizDiGraph;
use graphviz_dot_builder::item::node::node::GraphVizNode;
use graphviz_dot_builder::item::node::style::GraphvizNodeStyle;
use graphviz_dot_builder::traits::DotBuildable;
use crate::core::terms::position::PositionInLanguageTerm;
use crate::core::terms::term::{LanguageTerm, RewritableLanguageOperatorSymbol};
pub trait TermDrawingContext<LOS : RewritableLanguageOperatorSymbol> {
fn get_operator_representation_as_graphviz_node_style(
&self,
operator : &LOS
) -> GraphvizNodeStyle;
}
pub fn draw_term_tree_with_graphviz<
LOS : RewritableLanguageOperatorSymbol,
TDC : TermDrawingContext<LOS>
>(
tdc : &TDC,
term : &LanguageTerm<LOS>,
temp_file_path : &Path,
output_file_path : &Path,
)
{
let mut temp_file = File::create(temp_file_path).unwrap();
let _ = temp_file.write( term_gv_repr::<LOS,TDC>(tdc,term).to_dot_string().as_bytes() );
let _ = Command::new("dot")
.arg("-Tpng")
.arg(temp_file_path)
.arg("-o")
.arg(output_file_path)
.output();
}
pub fn term_gv_repr<
LOS : RewritableLanguageOperatorSymbol,
TDC : TermDrawingContext<LOS>
>(
tdc : &TDC,
term : &LanguageTerm<LOS>) -> GraphVizDiGraph
{
let mut digraph = GraphVizDiGraph::new(vec![]);
term_gv_repr_rec::<LOS,TDC>(tdc,term,PositionInLanguageTerm::get_root_position(), &mut digraph);
digraph
}
fn term_gv_repr_rec<
LOS : RewritableLanguageOperatorSymbol,
TDC : TermDrawingContext<LOS>
>(
tdc : &TDC,
term : &LanguageTerm<LOS>,
current_pos : PositionInLanguageTerm,
gv_graph : &mut GraphVizDiGraph) -> String
{
let node_name = format!("p{:}",current_pos);
{
let parent_node_gv_options = tdc.get_operator_representation_as_graphviz_node_style(&term.operator);
gv_graph.add_node( GraphVizNode::new(node_name.clone(), parent_node_gv_options) );
}
for (n,sub_term) in term.sub_terms.iter().enumerate() {
let child_pos = current_pos.get_position_of_nth_child(n);
let child_node_name = term_gv_repr_rec(
tdc,
sub_term,
child_pos,
gv_graph
);
let gv_edge = GraphVizEdge::new(node_name.clone(),
None,
child_node_name,
None,
vec![ GraphvizEdgeStyleItem::Head( GvArrowHeadStyle::NoArrow )]);
gv_graph.add_edge(gv_edge);
}
node_name
}