blob: 41635299ce4bb85328f0de67642f6e6eb401fc7d [file] [log] [blame]
package fsm
import (
"bytes"
"fmt"
)
// Visualize outputs a visualization of a FSM in Graphviz format.
func Visualize(fsm *FSM) string {
var buf bytes.Buffer
// we sort the key alphabetically to have a reproducible graph output
sortedEKeys := getSortedTransitionKeys(fsm.transitions)
sortedStateKeys, _ := getSortedStates(fsm.transitions)
writeHeaderLine(&buf)
writeTransitions(&buf, fsm.current, sortedEKeys, fsm.transitions)
writeStates(&buf, sortedStateKeys)
writeFooter(&buf)
return buf.String()
}
func writeHeaderLine(buf *bytes.Buffer) {
buf.WriteString(fmt.Sprintf(`digraph fsm {`))
buf.WriteString("\n")
}
func writeTransitions(buf *bytes.Buffer, current string, sortedEKeys []eKey, transitions map[eKey]string) {
// make sure the current state is at top
for _, k := range sortedEKeys {
if k.src == current {
v := transitions[k]
buf.WriteString(fmt.Sprintf(` "%s" -> "%s" [ label = "%s" ];`, k.src, v, k.event))
buf.WriteString("\n")
}
}
for _, k := range sortedEKeys {
if k.src != current {
v := transitions[k]
buf.WriteString(fmt.Sprintf(` "%s" -> "%s" [ label = "%s" ];`, k.src, v, k.event))
buf.WriteString("\n")
}
}
buf.WriteString("\n")
}
func writeStates(buf *bytes.Buffer, sortedStateKeys []string) {
for _, k := range sortedStateKeys {
buf.WriteString(fmt.Sprintf(` "%s";`, k))
buf.WriteString("\n")
}
}
func writeFooter(buf *bytes.Buffer) {
buf.WriteString(fmt.Sprintln("}"))
}