diff options
Diffstat (limited to 'support/latex-dependency-grapher/source/main/java/ch/bfh/lpdg/GraphHelper.java')
-rw-r--r-- | support/latex-dependency-grapher/source/main/java/ch/bfh/lpdg/GraphHelper.java | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/support/latex-dependency-grapher/source/main/java/ch/bfh/lpdg/GraphHelper.java b/support/latex-dependency-grapher/source/main/java/ch/bfh/lpdg/GraphHelper.java new file mode 100644 index 0000000000..fd6a754b7d --- /dev/null +++ b/support/latex-dependency-grapher/source/main/java/ch/bfh/lpdg/GraphHelper.java @@ -0,0 +1,181 @@ +package ch.bfh.lpdg; + +import ch.bfh.lpdg.datastructure.Dependency; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; + +public class GraphHelper { + + public final static GraphHelper INSTANCE = new GraphHelper(); + private final InteractionHandler interactionHandler = InteractionHandler.getInstance(); + + private GraphHelper() { + } + + public static GraphHelper getInstance() { + return INSTANCE; + } + + /** + * This method creates a new .tex file containing a list of the found dependencies and the dependeccy graph created with Graphviz + * + * @param dependency for which the .tex file should be created + * @param outputPath in which the created file should be located. + * @return the path of the newly created .tex file. + */ + public Path createFileForDependency(final Dependency dependency, final String outputPath) { + final String dependencyFileName = "dependencies_" + dependency.getName() + ".tex"; + final String dependencyFilePath = outputPath + dependencyFileName; + var dependencyFile = new File(outputPath + dependencyFileName); + + var latexHelper = new LatexHelper(); + this.writeDependencyToFile(dependencyFile, dependency); + + var result = latexHelper.compileTempDocument(outputPath, dependencyFilePath); + interactionHandler.printDebugMessage(String.valueOf(result)); + + if (!generatePdfFromDotFile(outputPath + "dependencyGraph.dot")) { + interactionHandler.printDebugMessage("Something went wrong trying to generate a pdf from the dot file."); + } + + //Second compile cycle to include the generated graph in the file. + var result2 = latexHelper.compileTempDocument(outputPath, dependencyFilePath); + interactionHandler.printDebugMessage(String.valueOf(result2)); + + return dependencyFile.toPath(); + } + + /** + * This method created the .tex file containing a list of the dependencies and its graph. + * + * @param file in which should be written + * @param dependency the dependency for which the graph should be created + */ + private void writeDependencyToFile(final File file, final Dependency dependency) { + try { + final String dependencyList = dependency.toLaTeXString(); + final String graphString = dependency.toGraphString(); + final String truncatedGraphString = this.truncateGraphString(graphString); + final String reorganizedGraphString = this.reorganizeGraphString(truncatedGraphString); + + BufferedWriter writer = Files.newBufferedWriter(file.toPath()); + writer.write(""" + \\documentclass{article} + \\usepackage[pdf]{graphviz} + \\usepackage{pdflscape} + \\begin{document} + \\begin{verbatim} + """); + writer.write(dependencyList); + writer.write("\\end{verbatim}\n"); + + if (dependency.getDependencyList().size() != 0) { + writer.write("\\pagebreak\n"); + writer.write("\\begin{landscape}\n"); + writer.write("\\digraph{dependencyGraph}{\n"); + writer.write("\tnewrank=true;\n\t"); + writer.write("\trank=\"same\";\n\t"); + writer.write("\trankdir=TB;\n\t"); + writer.write("\tratio=\"fill\";\n\t"); + writer.write("\tsize=\"8.3,11.7!\";\n\t"); + writer.write("\tmargin=0;\n\t"); + writer.write(reorganizedGraphString); + writer.write("}\n"); + writer.write("\\end{landscape}\n"); + } + + writer.write("\\end{document}\n"); + writer.close(); + } catch (IOException e) { + System.err.println("Error in the temporary file: " + e); + } + } + + /** + * Removes duplicated lines from graphString + * + * @param graphString for which duplicated lines should be removed + * @return a truncated string + */ + private String truncateGraphString(final String graphString) { + StringBuilder builder = new StringBuilder(); + for (String line : new LinkedHashSet<>(Arrays.asList(graphString.split("\n")))) { + builder.append(line).append("\n"); + } + return builder.toString(); + } + + private String reorganizeGraphString(String graphString) { + StringBuilder result = new StringBuilder(); + String[] lines = graphString.split("\n"); + + Map<String, Integer> lastOccurrences = new LinkedHashMap<>(); + + // Iterate to find the last occurrence index for each node + for (int i = 0; i < lines.length; i++) { + String line = lines[i].trim(); + if (!line.isEmpty()) { + String[] parts = line.split(" -> "); + String rightNode = parts[1].substring(0, parts[1].indexOf(';')).trim(); + lastOccurrences.put(rightNode, i); + } + } + + // Append lines with the last occurrences + for (int i : lastOccurrences.values()) { + result.append(lines[i]).append("\n"); + } + + // Append lines with other occurrences + for (int i = 0; i < lines.length; i++) { + String line = lines[i].trim(); + if (!line.isEmpty()) { + String[] parts = line.split(" -> "); + String rightNode = parts[1].substring(0, parts[1].indexOf(';')).trim(); + + // Skip if it's the last occurrence + if (i != lastOccurrences.get(rightNode)) { + result.append(lines[i]).append("\n"); + } + } + } + + return result.toString(); + } + + /** + * This method generated a pdf document for the .dot document. + * This is required to include it to the .tex document given to the user. + * + * @param dependencyGraphPath of the generated .dot file + * @return if the generation was successful or not + */ + private boolean generatePdfFromDotFile(final String dependencyGraphPath) { + try { + List<String> cmd = Arrays.asList( + "dot", + "-Tpdf", + "-o", dependencyGraphPath.replace("dot", "pdf"), + dependencyGraphPath); + + ProcessBuilder processBuilder = new ProcessBuilder(cmd); + + // Redirect the error stream to the output stream + processBuilder.redirectErrorStream(true); + + Process process = processBuilder.start(); + + var res = process.waitFor(); + + return res == 0; + } catch (Exception e) { + System.err.println("Error while compiling the dot file to pdf: " + e); + return false; + } + } +}
\ No newline at end of file |