commit 8dc25caadc740f8dc2d02af8225a280c9891e7c8
Author: Vojtěch Bartička <aitakaitov@gmail.com>
Date:   Thu Apr 28 11:39:17 2022 +0200

    Added padding size calculation to html rendering

diff --git a/Backend/Core/GraphUtils/Intersections.cs b/Backend/Core/GraphUtils/Intersections.cs
new file mode 100644
index 0000000..468ccb3
--- /dev/null
+++ b/Backend/Core/GraphUtils/Intersections.cs
@@ -0,0 +1,142 @@
+﻿using Core.Entities;
+
+namespace Core.GraphUtils
+{
+    public class Intersections
+    {
+        public static Dictionary<AnnotationTag, List<AnnotationTag>> FindIntersections(List<AnnotationTag> tags)
+        {
+            var intersections = new Dictionary<AnnotationTag, List<AnnotationTag>>();
+
+            for (int i = 0; i < tags.Count; i++)
+            {
+                var tagWho = tags[i];
+                intersections[tagWho] = new();
+                for (int j = 0; j < tags.Count; j++)
+                {
+                    if (i == j) { continue; }
+                    var tagWith = tags[j];
+
+                    if (!((tagWho.Position + tagWho.Length < tagWith.Position) || (tagWith.Position + tagWith.Length < tagWho.Position)))
+                    {
+                        intersections[tagWho].Add(tagWith);
+                    }
+                }
+            }
+
+            return intersections;
+        }
+
+        public static Dictionary<AnnotationTag, int> ColorGraph(Dictionary<AnnotationTag, List<AnnotationTag>> source)
+        {
+            var res = ConvertToMatrix(source);
+            var matrix = res.Item1;
+            var tagToIntDict = res.Item2;
+            var intToTagDict = res.Item3;
+
+            var colors = new int[matrix.GetLength(0)];
+            for (int i = 0; i < colors.Length; i++)
+            {
+                colors[i] = -1;
+            }
+
+            for (int coloredNode = 0; coloredNode < colors.Length; coloredNode++)
+            {
+                var neighbours = GetNeighbours(coloredNode, matrix);
+                var neighbourColors = GetNodeColors(neighbours, colors);
+                colors[coloredNode] = GetLowestUnusedColor(neighbourColors);
+            }
+
+            var coloring = new Dictionary<AnnotationTag, int>();
+            for (int i = 0; i < colors.Length; i++)
+            {
+                coloring[intToTagDict[i]] = colors[i];
+            }
+
+            return coloring;
+        }
+
+        private static int GetLowestUnusedColor(List<int> colors)
+        {
+            int lowestUnusedColor = 0;
+            colors.Sort();
+            for (int i = 0; i < colors.Count; i++)
+            {
+                if (colors[i] > i)
+                {
+                    lowestUnusedColor = i;
+                    break;
+                }
+                else
+                {
+                    lowestUnusedColor++;
+                }
+            }
+
+            return lowestUnusedColor;
+        }
+
+        private static List<int> GetNodeColors(List<int> nodes, int[] colors)
+        {
+            var usedColors = new List<int>();
+            foreach (var node in nodes)
+            {
+                if (colors[node] != -1)
+                {
+                    usedColors.Add(colors[node]);
+                }
+            }
+
+            return usedColors;
+        }
+
+        private static List<int> GetNeighbours(int node, int[,] matrix)
+        {
+            List<int> neighbours = new();
+            for (int i = 0; i < matrix.GetLength(0); i++)
+            {
+                if (matrix[node, i] == 1)
+                {
+                    neighbours.Add(i);
+                }
+            }
+
+            return neighbours;
+        }
+
+        private static (int[,], Dictionary<AnnotationTag, int>, Dictionary<int, AnnotationTag>) ConvertToMatrix(Dictionary<AnnotationTag, List<AnnotationTag>> source)
+        {
+            int[,] matrix = new int[source.Count, source.Count];
+            for (int i = 0; i < source.Count; i++)
+            {
+                for (int j = 0; j < source.Count; j++)
+                {
+                    matrix[i, j] = 0;
+                }
+            }
+
+            var tagToIntDict = new Dictionary<AnnotationTag, int>();
+            var intToTagDict = new Dictionary<int, AnnotationTag>();
+
+            int k = 0;
+            foreach (var key in source.Keys)
+            {
+                tagToIntDict[key] = k;
+                intToTagDict[k] = key;
+                k++;
+            }
+
+            foreach (var key in source.Keys)
+            {
+                int keyInt = tagToIntDict[key];
+                foreach (var neighbour in source[key])
+                {
+                    int neighbourInt = tagToIntDict[neighbour];
+                    matrix[keyInt, neighbourInt] = 1;
+                }
+            }
+
+            return (matrix, tagToIntDict, intToTagDict);
+        }
+    }
+}
diff --git a/Backend/Core/Services/AnnotationService/AnnotationServiceEF.cs b/Backend/Core/Services/AnnotationService/AnnotationServiceEF.cs
index 10e15a9..e28353e 100644
--- a/Backend/Core/Services/AnnotationService/AnnotationServiceEF.cs
+++ b/Backend/Core/Services/AnnotationService/AnnotationServiceEF.cs
@@ -15,6 +15,7 @@ using Ganss.XSS;
 using HtmlAgilityPack;
 using System.Text.RegularExpressions;
 using Newtonsoft.Json;
+using Core.GraphUtils;
 
 namespace Core.Services.AnnotationService
 {
@@ -293,7 +294,7 @@ namespace Core.Services.AnnotationService
 
             HtmlDocument doc = new HtmlDocument();
             doc.LoadHtml(docToRender);
-            var cssNode = GenerateCSS(doc, tags, new());
+            var cssNode = GenerateCSS(doc, tags);
             doc.DocumentNode.ChildNodes.Insert(0, cssNode);
 
             return doc.DocumentNode.OuterHtml;
@@ -493,19 +494,19 @@ namespace Core.Services.AnnotationService
             }
         }
 
-        private HtmlNode GenerateCSS(HtmlDocument docToEdit, List<AnnotationTag> tags, List<int> paddings)
+        private HtmlNode GenerateCSS(HtmlDocument docToEdit, List<AnnotationTag> tags)
         {
             HtmlNode style = docToEdit.CreateElement("style");
 
             string inner = "span.annotation {border-bottom: 2px solid;}";
             inner += "span {line-height: 30px}\n";
 
-            // TODO temporary
-            int lastPadding = 0;
+            var tagPaddingDict = Intersections.ColorGraph(Intersections.FindIntersections(tags));
+
             foreach (var tag in tags)
             {
-                inner += $"span[{TAG_INSTANCE_ATTRIBUTE_NAME}=\"{tag.Instance}\"] {{ border-color:{tag.Tag.Color}; padding-bottom: {lastPadding % 5}px }}";
-                lastPadding += 2;
+                var padding = (tagPaddingDict[tag] + 1) * 2;
+                inner += $"span[{TAG_INSTANCE_ATTRIBUTE_NAME}=\"{tag.Instance}\"] {{ border-color:{tag.Tag.Color}; padding-bottom: {padding}px }}";
             }
 
             inner += "span[end=\"1\"] {border-end-end-radius: 0px; border-right: 1px solid darkgray}\n";
@@ -621,7 +622,7 @@ namespace Core.Services.AnnotationService
                 }
             }
 
-            var cssNode = GenerateCSS(docToEdit, tags, new());
+            var cssNode = GenerateCSS(docToEdit, tags);
             docToEdit.DocumentNode.ChildNodes.Insert(0, cssNode);
 
             return docToEdit.DocumentNode.OuterHtml;
@@ -691,7 +692,7 @@ namespace Core.Services.AnnotationService
                 }
             }
 
-            var cssNode = GenerateCSS(docToEdit, tags, new());
+            var cssNode = GenerateCSS(docToEdit, tags);
             docToEdit.DocumentNode.ChildNodes.Insert(0, cssNode);
 
             return docToEdit.DocumentNode.OuterHtml;
