From a983a705954cce13cb59e65eab2fd88f47b530af Mon Sep 17 00:00:00 2001
From: Alan Birchler De Allende <alan.birchler@telecom-paris.fr>
Date: Thu, 11 Apr 2024 21:25:58 +0200
Subject: [PATCH] Fixed the following bugs with the AI AT drawing
 functionality: - Duplicate attack nodes were being drawn - Attack nodes that
 were connectionless were not being drawn - Operation nodes were sometimes
 being drawn as the wrong type

---
 src/main/java/ui/MainGUI.java                 |   1 +
 src/main/java/ui/atd/ATDConstraint.java       |   4 +-
 .../java/ui/atd/AttackTreeDiagramPanel.java   | 140 +++++++++++-------
 3 files changed, 93 insertions(+), 52 deletions(-)

diff --git a/src/main/java/ui/MainGUI.java b/src/main/java/ui/MainGUI.java
index 37325cddcb..dba35755c8 100644
--- a/src/main/java/ui/MainGUI.java
+++ b/src/main/java/ui/MainGUI.java
@@ -1897,6 +1897,7 @@ public class MainGUI implements ActionListener, WindowListener, KeyListener, Per
         atp.addAttackTreeDiagram(tabName);
         atp.atdp.drawable = false;
         atp.atdp.drawFromAttackTreeModel(_at);
+        atp.atdp.drawConnectionlessAttacks(_at);
         atp.atdp.drawable = true;
         atp.atdp.repaint();
         TraceManager.addDev("Draw AT 4");
diff --git a/src/main/java/ui/atd/ATDConstraint.java b/src/main/java/ui/atd/ATDConstraint.java
index 186a00835e..6122220148 100644
--- a/src/main/java/ui/atd/ATDConstraint.java
+++ b/src/main/java/ui/atd/ATDConstraint.java
@@ -255,10 +255,10 @@ public class ATDConstraint extends TGCScalableWithInternalComponent implements S
 
     public void setType(String _type) {
         value = STEREOTYPES[0];
-        _type = _type.toUpperCase();
+        _type ="<<" + _type.toUpperCase() + ">>";
 
         for(int i=STEREOTYPES.length-1; i>0; i--) {
-            if (STEREOTYPES[i].indexOf(_type) > - 1) {
+            if (STEREOTYPES[i].equals(_type)) {
                 value = STEREOTYPES[i];
                 break;
             }
diff --git a/src/main/java/ui/atd/AttackTreeDiagramPanel.java b/src/main/java/ui/atd/AttackTreeDiagramPanel.java
index a68f5f2051..50ec12efa6 100644
--- a/src/main/java/ui/atd/AttackTreeDiagramPanel.java
+++ b/src/main/java/ui/atd/AttackTreeDiagramPanel.java
@@ -58,6 +58,7 @@ import ui.ucd.UCDActor;
 
 import java.awt.*;
 import java.util.*;
+import java.util.List;
 
 //import org.w3c.dom.*;
 //import org.xml.sax.*;
@@ -197,16 +198,38 @@ public class AttackTreeDiagramPanel extends TDiagramPanel implements TDPWithAttr
         return drawAttackFromAttackTreeModel(mapOfComponents, _at, root, null, -1, 600, 100, 1200);
     }
 
+    public void drawConnectionlessAttacks(AttackTree _at) {
+        int x = 0;
+
+        for(Attack att: _at.getAttacks()) {
+            ATDAttack attack = alreadyDrawnAttack(att);
+
+            if (attack == null) {
+                attack = new ATDAttack(x, 0, getMinX(), getMaxX(), getMinY(), getMaxY(), true, null, this);
+                attack.setValue(att.getName());
+                attack.setRootAttack(att.isRoot());
+                attack.setDescription(att.getDescription());
+                addBuiltComponent(attack);
+
+                x = x + attack.getWidth();
+            }
+        }
+    }
+
     public String drawAttackFromAttackTreeModel(HashMap<AttackElement, TGComponent> _mapOfComponents, AttackTree _at, Attack _att,
                                                 ATDConstraint _const, int _valueConst, int _x, int _y, int _length) {
+        ATDAttack attack = alreadyDrawnAttack(_att);
 
-        // We draw the attack
-        ATDAttack attack = new ATDAttack(_x, _y, getMinX(), getMaxX(), getMinY(), getMaxY(), true, null, this);
-        attack.setValue(_att.getName());
-        attack.setRootAttack(_att.isRoot());
-        attack.setDescription(_att.getDescription());
-        addBuiltComponent(attack);
-        _mapOfComponents.put(_att, attack);
+        if (attack == null) {
+            // We draw the attack
+            attack = new ATDAttack(_x, _y, getMinX(), getMaxX(), getMinY(), getMaxY(), true, null, this);
+            attack.setValue(_att.getName());
+            attack.setRootAttack(_att.isRoot());
+            attack.setDescription(_att.getDescription());
+
+            addBuiltComponent(attack);
+            _mapOfComponents.put(_att, attack);
+        }
 
         // If the constraint is non-null, we link the attack to the constraint
         if (_const != null) {
@@ -232,67 +255,84 @@ public class AttackTreeDiagramPanel extends TDiagramPanel implements TDPWithAttr
         }
 
         // We look for the constraint linked to this attack
-        AttackNode nextNode = null;
-        for(AttackNode node: _at.getAttackNodes()) {
+        ArrayList<AttackNode> nextNodeList = new ArrayList<>();
+
+        for(AttackNode node : _at.getAttackNodes()) {
             if (node.getResultingAttack() == _att) {
-                nextNode = node;
-                break;
+                nextNodeList.add(node);
             }
         }
 
         // Leaf attack?
-        if (nextNode == null) {
+        if (nextNodeList.isEmpty()) {
             return null;
         }
 
-        // We create the ATDConstraint
-        _y = _y + 70;
-        ATDConstraint constraint = new ATDConstraint(_x, _y, getMinX(), getMaxX(), getMinY(), getMaxY(), true, null, this);
-        //constraint.setValue(nextNode.getName());
-        constraint.setType(nextNode.getType());
-        addBuiltComponent(constraint);
-        _mapOfComponents.put(nextNode, constraint);
-
-        TGConnectingPoint p1 = constraint.closerFreeTGConnectingPoint(attack.getX(), attack.getY(), false, true);
-        TGConnectingPoint p2 = attack.closerFreeTGConnectingPoint(constraint.getX(), constraint.getY(), true, false);
-
-        if (p1 != null && p2 != null) {
-            p1.setFree(false);
-            p2.setFree(false);
-
-            TGConnector conn = null;
-            Vector<Point> points = new Vector<Point>();
-            conn = new ATDAttackConnector(0, 0, 0, 0, 0, 0, true, null,
-                    this, p1, p2, points);
-            if (_valueConst != -1) {
-                conn.setValue("" + _valueConst);
+        for (AttackNode nextNode : nextNodeList) {
+            // We create the ATDConstraint
+            _y = _y + 70;
+            ATDConstraint constraint = new ATDConstraint(_x, _y, getMinX(), getMaxX(), getMinY(), getMaxY(), true, null, this);
+            //constraint.setValue(nextNode.getName());
+            constraint.setType(nextNode.getType());
+            addBuiltComponent(constraint);
+            _mapOfComponents.put(nextNode, constraint);
+
+            TGConnectingPoint p1 = constraint.closerFreeTGConnectingPoint(attack.getX(), attack.getY(), false, true);
+            TGConnectingPoint p2 = attack.closerFreeTGConnectingPoint(constraint.getX(), constraint.getY(), true, false);
+
+            if (p1 != null && p2 != null) {
+                p1.setFree(false);
+                p2.setFree(false);
+
+                TGConnector conn = null;
+                Vector<Point> points = new Vector<Point>();
+                conn = new ATDAttackConnector(0, 0, 0, 0, 0, 0, true, null,
+                        this, p1, p2, points);
+                if (_valueConst != -1) {
+                    conn.setValue("" + _valueConst);
+                }
+
+                if (conn != null) {
+                    addComponent(conn, 0, 0, false, true);
+                }
             }
 
-            if (conn != null) {
-                addComponent(conn, 0, 0, false, true);
+            // We now create all the sub attacks
+            int size = nextNode.getInputAttacks().size();
+            int currentBeg = _x - _length / 2;
+            int slotSize = _length / size;
+            for (int i = 0; i < size; i++) {
+                Attack nextAttack = nextNode.getInputAttacks().get(i);
+                Integer nextValue = nextNode.getInputValues().get(i);
+
+                String s = drawAttackFromAttackTreeModel(_mapOfComponents, _at, nextAttack, constraint, nextValue, currentBeg + slotSize / 2, _y + 70,
+                        slotSize);
+                currentBeg += slotSize;
+
+                if (s != null) {
+                    return s;
+                }
             }
         }
 
-        // We now create all the sub attacks
-        int size = nextNode.getInputAttacks().size();
-        int currentBeg = _x - _length/2;
-        int slotSize = _length / size;
-        for(int i=0; i<size ; i++) {
-            Attack nextAttack = nextNode.getInputAttacks().get(i);
-            Integer nextValue = nextNode.getInputValues().get(i);
+        return null;
+    }
 
-            String s = drawAttackFromAttackTreeModel(_mapOfComponents, _at, nextAttack, constraint, nextValue, currentBeg+ slotSize/2 , _y+70,
-                    slotSize);
-            currentBeg += slotSize;
+    private ATDAttack alreadyDrawnAttack(Attack attack) {
+        List<TGComponent> componentList = getComponentList();
 
-            if (s != null) {
-                return s;
-            }
+        for (TGComponent component : componentList) {
+            if (component instanceof ATDAttack) {
+                ATDAttack attackComponent = (ATDAttack) component;
 
+                if (attackComponent.getValue().equals(attack.getName()) &&
+                        attackComponent.getDescription().equals(attack.getDescription()) &&
+                        attackComponent.isRootAttack() == attack.isRoot()) {
+                    return attackComponent;
+                }
+            }
         }
 
-
         return null;
     }
-    
 }
-- 
GitLab