<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Force-Directed Tree</title>
    <script src="https://d3js.org/d3.v7.min.js"></script>
    <style>
      svg {
        width: 100%;
        height: 600px;
      }
      .link {
        stroke: #999;
        stroke-opacity: 0.6;
        marker-end: url(#arrow);
      }
      .link_no_arrow {
        stroke: #999;
        stroke-opacity: 0.6;
      }
      .node image {
        cursor: pointer;
      }
      .node circle {
        fill: lightblue;
        stroke: steelblue;
        stroke-width: 1.5px;
      }
      .highlighted {
        stroke: red;
        stroke-width: 3px;
      }
      .tooltip {
        position: absolute;
        background: lightgray;
        padding: 5px;
        border-radius: 5px;
        visibility: hidden;
      }
    </style>
  </head>
  <body>
    <p></p>
    {{ pathway.name|safe }}
    <div id="viz">
      <svg width="2000" height="2000">
        <!-- Sehr großes SVG für Zoom -->
        <defs>
          <marker
            id="arrow"
            viewBox="0 0 10 10"
            refX="43"
            refY="5"
            markerWidth="6"
            markerHeight="6"
            orient="auto-start-reverse"
          >
            <path d="M 0 0 L 10 5 L 0 10 z" fill="#999" />
          </marker>
        </defs>
        <g id="zoomable"></g>
      </svg>
    </div>
    <div id="tooltip" class="tooltip"></div>

    {# prettier-ignore-start #}
<script>
function assignPositions(nodes) {
    const levelSpacing = 75; // Vertikaler Abstand zwischen den Tiefen
    const horizontalSpacing = 75; // Abstand zwischen Knoten auf gleicher Tiefe
    const depthMap = new Map();

    nodes.forEach(node => {
        if (!depthMap.has(node.depth)) {
            depthMap.set(node.depth, 0);
        }

        // Gleichmäßige horizontale Verteilung je nach Anzahl Knoten pro Tiefe
        const nodesInLevel = nodes.filter(n => n.depth === node.depth).length;
        node.fx = width / 2 + depthMap.get(node.depth) * horizontalSpacing - ((nodesInLevel - 1) * horizontalSpacing) / 2;
        node.fy = node.depth * levelSpacing + 50;

        depthMap.set(node.depth, depthMap.get(node.depth) + 1);
    });
}

function nodeClick(event, node, t) {
    console.log(node);
    d3.select(t).select("circle").classed("highlighted", !d3.select(t).select("circle").classed("highlighted"));
}

        const nodeRadius = 20;
        const linkDistance = 100;
        const chargeStrength = -200;
        const depthSpacing = 150;
        const width = 800, height = 600;

        const tooltip = d3.select("#tooltip");
        const zoomable = d3.select("#zoomable");

        // Zoom Funktion aktivieren
        const zoom = d3.zoom()
            .scaleExtent([0.5, 5])
            .on("zoom", (event) => {
                zoomable.attr("transform", event.transform);
            });

        d3.select("svg").call(zoom);

        data = {{ pathway.d3_json | safe }};
        nodes = data['nodes'];
        links = data['links'];

        assignPositions(nodes);

        // Physik-Simulation für den Graphen
<!--        const simulation = d3.forceSimulation(nodes)-->
<!--            .force("link", d3.forceLink(links).id(d => d.id).distance(linkDistance))-->
<!--            .force("y", d3.forceY(d => d.depth * depthSpacing + 50))-->
<!--            .force("x", d3.forceX(width / 2))-->
<!--            .force("charge", d3.forceManyBody().strength(chargeStrength))-->
<!--            .force("center", d3.forceCenter(width / 2, height / 4))-->
<!--            .on("tick", ticked);-->
<!--        -->
        const simulation = d3.forceSimulation(nodes)
            .force("link", d3.forceLink(links).id(d => d.id).distance(linkDistance))
            .force("charge", d3.forceManyBody().strength(chargeStrength))
            .force("center", d3.forceCenter(width / 2, height / 4))
            .on("tick", ticked);

        // Kanten zeichnen
        const link = zoomable.append("g")
            .selectAll("line")
            .data(links)
            .enter().append("line")
            // Check if target is pseudo and draw marker only if not pseudo
            .attr("class", d => d.target.pseudo ? "link_no_arrow" : "link")
            .on("mouseover", (event, d) => {
                tooltip.style("visibility", "visible")
                       .text(`Link: ${d.source.id} → ${d.target.id}`)
                       .style("top", `${event.pageY + 5}px`)
                       .style("left", `${event.pageX + 5}px`);
            })
            .on("mouseout", () => tooltip.style("visibility", "hidden"));

        // Knoten zeichnen
        const node = zoomable.append("g")
            .selectAll("g")
            .data(nodes)
            .enter().append("g")
            .call(d3.drag()
                .on("start", dragstarted)
                .on("drag", dragged)
                .on("end", dragended))
            .on("click", function(event, d) {
                nodeClick(event, d, this);
<!--                console.log(event); console.log(d);console.log(this);-->
<!--                d3.select(this).select("circle").classed("highlighted", !d3.select(this).select("circle").classed("highlighted"));-->
            })
            .on("mouseover", (event, d) => {
                if (d.pseudo) {
                    return
                }
                tooltip.style("visibility", "visible")
                       .text(`Node: ${d.id} Depth: ${d.depth}`)
                       .style("top", `${event.pageY + 5}px`)
                       .style("left", `${event.pageX + 5}px`);
            })
            .on("mouseout", () => tooltip.style("visibility", "hidden"));

        // Kreise für die Knoten hinzufügen
        node.append("circle")
            // make radius "invisible"
            .attr("r", d => d.pseudo ? 0.01 : nodeRadius)
            .style("fill", "#e8e8e8");

        // Add image only for non pseudo nodes
        node.filter(d => !d.pseudo).append("image")
            .attr("xlink:href", d => d.image)
            .attr("x", -nodeRadius)
            .attr("y", -nodeRadius)
            .attr("width", nodeRadius * 2)
            .attr("height", nodeRadius * 2);


        // Funktion für das Update der Positionen
        function ticked() {
            link.attr("x1", d => d.source.x)
                .attr("y1", d => d.source.y)
                .attr("x2", d => d.target.x)
                .attr("y2", d => d.target.y);

            node.attr("transform", d => `translate(${d.x},${d.y})`);
        }

        function dragstarted(event, d) {
            if (!event.active) simulation.alphaTarget(0.3).restart();
            d.fx = d.x; // Setzt die Fixierung auf die aktuelle Position
            d.fy = d.y;
        }

        function dragged(event, d) {
            d.fx = event.x; // Position direkt an Maus anpassen
            d.fy = event.y;
        }

        function dragended(event, d) {
            if (!event.active) simulation.alphaTarget(0);
            // Knoten bleibt an der neuen Position und wird nicht zurückgezogen
        }

</script>
{# prettier-ignore-end #}
    <svg width="400" height="300">
      <path
        d="M200,50 C200,100 150,150 150,200"
        stroke="black"
        fill="none"
        stroke-width="2"
      />
      <path
        d="M200,50 C200,100 250,150 250,200"
        stroke="black"
        fill="none"
        stroke-width="2"
      />

      <!-- Knoten -->
      <circle cx="200" cy="50" r="5" fill="blue" />
      <circle cx="150" cy="200" r="5" fill="red" />
      <circle cx="250" cy="200" r="5" fill="red" />
    </svg>
  </body>
  {% load static %}
  <script src="{% static 'js/pw.js' %}"></script>
</html>
