package ru.mcs.genealogy.service;
import org.springframework.stereotype.Service;
import ru.mcs.genealogy.dto.TreeNode;
import ru.mcs.genealogy.entity.Person;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
@Service
public class GraphvizTreeService {
public String generateDOT(Person person) {
List<TreeNode> treeNodes = buildFullTree(person);
return buildDOTString(treeNodes);
}
private String buildDOTString(List<TreeNode> treeNodes) {
StringBuilder dot = new StringBuilder();
dot.append("digraph familyTree {\n");
dot.append(" rankdir=TB;\n");
dot.append(" node [shape=box, style=filled, fillcolor=lightblue];\n\n");
// dot.append(" edge [dir=back];\n\n");
// Добавляем все узлы
for (TreeNode node : treeNodes) {
Person person = node.getPerson();
dot.append(String.format(" %d [label=\"%s\"];\n",
person.getId(),
escapeString(person.getFullName())));
}
dot.append("\n");
// Добавляем связи
for (TreeNode node : treeNodes) {
Person person = node.getPerson();
if (person.getFather() != null) {
dot.append(String.format(" %d -> %d [label=\"отец\"];\n",
person.getFather().getId(),
person.getId()));
}
if (person.getMother() != null) {
dot.append(String.format(" %d -> %d [label=\"мать\"];\n",
person.getMother().getId(),
person.getId()));
}
}
dot.append("}\n");
return dot.toString();
}
private String escapeString(String input) {
return input.replace("\"", "\\\"")
.replace("\n", "\\n")
.replace("\r", "\\r");
}
public List<TreeNode> buildFullTree(Person person) {
List<TreeNode> tree = new ArrayList<>();
if (person != null) {
// Добавляем предков (отрицательные уровни)
addAncestors(person, -1, tree);
// Добавляем выбранного человека (уровень 0)
tree.add(new TreeNode(person, 0, !person.getAllChildren().isEmpty()));
// Добавляем потомков (положительные уровни)
addDescendants(person, 1, tree);
}
// Сортируем по уровням для правильного отображения
tree.sort(Comparator.comparingInt(TreeNode::getLevel));
return tree;
}
private void addAncestors(Person person, int level, List<TreeNode> tree) {
if (person == null) return;
// Добавляем отца
if (person.getFather() != null) {
tree.add(0, new TreeNode(person.getFather(), level, !person.getFather().getAllChildren().isEmpty()));
addAncestors(person.getFather(), level - 1, tree);
}
// Добавляем мать
if (person.getMother() != null) {
tree.add(0, new TreeNode(person.getMother(), level, !person.getMother().getAllChildren().isEmpty()));
addAncestors(person.getMother(), level - 1, tree);
}
}
private void addDescendants(Person person, int level, List<TreeNode> tree) {
if (person == null) return;
for (Person child : person.getAllChildren()) {
tree.add(new TreeNode(child, level, !child.getAllChildren().isEmpty()));
addDescendants(child, level + 1, tree);
}
}
}