Browse Source

Google Code Style

TomTroppmann 2 years ago
parent
commit
0f2afae254
100 changed files with 18340 additions and 17475 deletions
  1. 30 23
      README.md
  2. 20 25
      config/log.properties
  3. 238 246
      config/randomizer/elements.json
  4. 303 314
      config/randomizer/elements_prod_overhead.json
  5. 12 13
      license.md
  6. 34 33
      res/images/logo/holeg.svg
  7. 339 314
      src/holeg/addon/RandomOfferdFlexibility.java
  8. 65 60
      src/holeg/addon/RandomSwitch.java
  9. 285 283
      src/holeg/addon/Randomizer.java
  10. 149 155
      src/holeg/addon/helper/EmailNotification.java
  11. 44 39
      src/holeg/addon/helper/FlexibilitySketch.java
  12. 68 60
      src/holeg/addon/helper/HolonElementSketch.java
  13. 138 124
      src/holeg/addon/helper/RandomPriotity.java
  14. 202 194
      src/holeg/algorithm/binary/AcoAlgorithm.java
  15. 374 382
      src/holeg/algorithm/binary/BaseLine.java
  16. 268 232
      src/holeg/algorithm/binary/GaAlgorithm.java
  17. 352 394
      src/holeg/algorithm/binary/PsoAlgorithm.java
  18. 469 452
      src/holeg/algorithm/example/DemoAlgo.java
  19. 540 523
      src/holeg/algorithm/example/FlexExample.java
  20. 120 119
      src/holeg/algorithm/objective_function/Evaluation.java
  21. 448 427
      src/holeg/algorithm/objective_function/GraphMetrics.java
  22. 192 188
      src/holeg/algorithm/objective_function/ObjectiveFunctionByCarlos.java
  23. 50 47
      src/holeg/algorithm/objective_function/SwitchObjectiveFunction.java
  24. 283 280
      src/holeg/algorithm/objective_function/TopologieObjectiveFunction.java
  25. 200 174
      src/holeg/algorithm/topologie/AcoAlgorithm.java
  26. 269 216
      src/holeg/algorithm/topologie/GaAlgorithm.java
  27. 360 310
      src/holeg/algorithm/topologie/PsoAlgorithm.java
  28. 7 5
      src/holeg/api/AddOn.java
  29. 1325 1276
      src/holeg/api/AlgorithmFrameworkFlex.java
  30. 1211 1171
      src/holeg/api/TopologieAlgorithmFramework.java
  31. 33 31
      src/holeg/interfaces/GraphEditable.java
  32. 63 59
      src/holeg/interfaces/LocalMode.java
  33. 3 1
      src/holeg/interfaces/TimelineDependent.java
  34. 116 118
      src/holeg/model/AbstractCanvasObject.java
  35. 34 30
      src/holeg/model/Constrain.java
  36. 145 145
      src/holeg/model/Edge.java
  37. 202 197
      src/holeg/model/Flexibility.java
  38. 195 193
      src/holeg/model/GroupNode.java
  39. 262 252
      src/holeg/model/Holon.java
  40. 337 335
      src/holeg/model/HolonElement.java
  41. 277 270
      src/holeg/model/HolonObject.java
  42. 223 222
      src/holeg/model/HolonSwitch.java
  43. 85 82
      src/holeg/model/Model.java
  44. 17 19
      src/holeg/model/Node.java
  45. 105 91
      src/holeg/preferences/ColorPreference.java
  46. 91 67
      src/holeg/preferences/ImagePreference.java
  47. 31 23
      src/holeg/preferences/PreferenceKeys.java
  48. 52 45
      src/holeg/serialize/CategoryAdapter.java
  49. 22 18
      src/holeg/serialize/EdgeDeserializer.java
  50. 9 10
      src/holeg/serialize/EdgeSerializer.java
  51. 52 39
      src/holeg/serialize/ModelDeserializer.java
  52. 2 1
      src/holeg/serialize/PostDeserialize.java
  53. 17 17
      src/holeg/serialize/PostDeserializeEnabler.java
  54. 128 126
      src/holeg/ui/controller/CanvasController.java
  55. 473 452
      src/holeg/ui/controller/Control.java
  56. 14 13
      src/holeg/ui/controller/IndexTranslator.java
  57. 104 94
      src/holeg/ui/controller/SimulationManager.java
  58. 51 54
      src/holeg/ui/model/GuiSettings.java
  59. 35 34
      src/holeg/ui/model/IdCounter.java
  60. 20 19
      src/holeg/ui/model/LimitedSizeQueue.java
  61. 28 26
      src/holeg/ui/model/PriorityCount.java
  62. 33 29
      src/holeg/ui/model/UndoHistory.java
  63. 43 43
      src/holeg/ui/view/Main.java
  64. 359 331
      src/holeg/ui/view/canvas/Canvas.java
  65. 91 81
      src/holeg/ui/view/canvas/CanvasCollectionPanel.java
  66. 227 192
      src/holeg/ui/view/canvas/Rendering.java
  67. 58 63
      src/holeg/ui/view/category/Category.java
  68. 230 206
      src/holeg/ui/view/category/CategoryPanel.java
  69. 118 133
      src/holeg/ui/view/component/ButtonTabComponent.java
  70. 56 54
      src/holeg/ui/view/component/Console.java
  71. 85 87
      src/holeg/ui/view/component/TrippleCheckBox.java
  72. 77 70
      src/holeg/ui/view/dialog/AboutUsPopUp.java
  73. 170 160
      src/holeg/ui/view/dialog/AddElementPopUp.java
  74. 264 242
      src/holeg/ui/view/dialog/AddObjectPopUp.java
  75. 53 50
      src/holeg/ui/view/dialog/CanvasResizePopUp.java
  76. 272 262
      src/holeg/ui/view/dialog/CreateTemplatePopUp.java
  77. 139 129
      src/holeg/ui/view/dialog/EditEdgesPopUp.java
  78. 56 51
      src/holeg/ui/view/dialog/NewCategoryDialog.java
  79. 99 98
      src/holeg/ui/view/image/Import.java
  80. 543 501
      src/holeg/ui/view/information/HolonInformationPanel.java
  81. 197 189
      src/holeg/ui/view/inspector/Inspector.java
  82. 561 530
      src/holeg/ui/view/inspector/InspectorTable.java
  83. 915 911
      src/holeg/ui/view/inspector/UnitGraph.java
  84. 58 45
      src/holeg/ui/view/inspector/UnitGraphPoint.java
  85. 18 15
      src/holeg/ui/view/main/Appearance.java
  86. 382 368
      src/holeg/ui/view/main/Gui.java
  87. 365 352
      src/holeg/ui/view/main/TimePanel.java
  88. 176 165
      src/holeg/ui/view/window/AddOnWindow.java
  89. 605 555
      src/holeg/ui/view/window/FlexWindow.java
  90. 169 158
      src/holeg/ui/view/window/Outliner.java
  91. 12 11
      src/holeg/utility/events/Action.java
  92. 14 11
      src/holeg/utility/events/Event.java
  93. 8 7
      src/holeg/utility/listener/LostFocusListener.java
  94. 16 8
      src/holeg/utility/listener/ResizeListener.java
  95. 17 14
      src/holeg/utility/listener/SimpleDocumentListener.java
  96. 34 25
      src/holeg/utility/listener/WindowClosingListener.java
  97. 41 32
      src/holeg/utility/math/Maths.java
  98. 76 70
      src/holeg/utility/math/Random.java
  99. 26 25
      src/holeg/utility/math/decimal/Format.java
  100. 56 40
      src/holeg/utility/math/decimal/Sampler.java

+ 30 - 23
README.md

@@ -8,16 +8,23 @@ Cyber-physical systems simulation software following a Holon-based smart grid sy
 
 
 ## Introduction and User Manual
 ## Introduction and User Manual
 
 
-The Wiki contains some general [Information](https://git.tk.informatik.tu-darmstadt.de/carlos.garcia/praktikum-holons/wiki/Introduction) and a [User Manual](https://git.tk.informatik.tu-darmstadt.de/carlos.garcia/praktikum-holons/wiki/User+Manual)
+The Wiki contains some
+general [Information](https://git.tk.informatik.tu-darmstadt.de/carlos.garcia/praktikum-holons/wiki/Introduction)
+and
+a [User Manual](https://git.tk.informatik.tu-darmstadt.de/carlos.garcia/praktikum-holons/wiki/User+Manual)
 
 
 ## API Instructions
 ## API Instructions
 
 
-Check out the [API Instructions Wiki](https://git.tk.informatik.tu-darmstadt.de/carlos.garcia/praktikum-holons/wiki/Algorithms) for some Instructions
+Check out
+the [API Instructions Wiki](https://git.tk.informatik.tu-darmstadt.de/carlos.garcia/praktikum-holons/wiki/Algorithms)
+for some Instructions
 
 
 ## License
 ## License
 
 
-This project is licensed under a modified MIT License - see the [LICENSE.md](https://git.tk.informatik.tu-darmstadt.de/carlos.garcia/praktikum-holons/src/master/license.md) file for details
-	
+This project is licensed under a modified MIT License - see
+the [LICENSE.md](https://git.tk.informatik.tu-darmstadt.de/carlos.garcia/praktikum-holons/src/master/license.md)
+file for details
+
 ## Built With
 ## Built With
 
 
 * [JUnit](http://junit.org) - The used test system
 * [JUnit](http://junit.org) - The used test system
@@ -28,37 +35,37 @@ This project is licensed under a modified MIT License - see the [LICENSE.md](htt
 
 
 ### Version 1.0 to 1.1.0
 ### Version 1.0 to 1.1.0
 
 
-*  Kevin Julian Trometer
-*  Dominik Fabio Rieder
-*  Teh-Hai Julian Zheng
-*  Edgardo Ernesto Palza Paredes
-*  Jessey Steven Widhalm
+* Kevin Julian Trometer
+* Dominik Fabio Rieder
+* Teh-Hai Julian Zheng
+* Edgardo Ernesto Palza Paredes
+* Jessey Steven Widhalm
 
 
 ### Version 2.0
 ### Version 2.0
 
 
-*  Isabella Dix
-*  Carlos Garcia
+* Isabella Dix
+* Carlos Garcia
 
 
 ### Version 2.1 [Changelog](https://git.tk.informatik.tu-darmstadt.de/carlos.garcia/praktikum-holons/src/master/ChangelogV2_1.md)
 ### Version 2.1 [Changelog](https://git.tk.informatik.tu-darmstadt.de/carlos.garcia/praktikum-holons/src/master/ChangelogV2_1.md)
 
 
-*  Andreas T. Meyer-Berg
-*  Ludwig Tietze
-*  Antonio Schneider
-*  Tom Troppmann
+* Andreas T. Meyer-Berg
+* Ludwig Tietze
+* Antonio Schneider
+* Tom Troppmann
 
 
 ## Under contract from:
 ## Under contract from:
 
 
-*  Darmstadt University of Technology
-*  Department of Computer Science, Telecooperation
-*  Hochschulstr. 10
-*  Informatik Telecooperation Lab (TK)
-*  D-64289 Darmstadt, Germany
+* Darmstadt University of Technology
+* Department of Computer Science, Telecooperation
+* Hochschulstr. 10
+* Informatik Telecooperation Lab (TK)
+* D-64289 Darmstadt, Germany
 
 
 ### Version 1.0 to 1.1.0
 ### Version 1.0 to 1.1.0
 
 
-*  Andreas Tundis
-*  Carlos Garcia
+* Andreas Tundis
+* Carlos Garcia
 
 
 ### Version 2.1
 ### Version 2.1
 
 
-*  Rolf Egert
+* Rolf Egert

+ 20 - 25
config/log.properties

@@ -1,26 +1,21 @@
-handlers = java.util.logging.FileHandler, java.util.logging.ConsoleHandler
-.level = ALL
-
-java.util.logging.FileHandler.level     = ALL
-java.util.logging.FileHandler.filter    =
-java.util.logging.FileHandler.formatter =
-java.util.logging.FileHandler.encoding  =
-java.util.logging.FileHandler.limit     =
-java.util.logging.FileHandler.count     =
-java.util.logging.FileHandler.append    = false
-java.util.logging.FileHandler.pattern   = all.%u.%g.log
-
-java.util.logging.ConsoleHandler.level     = ALL
-java.util.logging.ConsoleHandler.filter    =
-java.util.logging.ConsoleHandler.formatter =
-java.util.logging.ConsoleHandler.encoding  =
-
-
-
-# 
-holeg.level = INFO
-holeg.ui.level = FINE
+handlers=java.util.logging.FileHandler, java.util.logging.ConsoleHandler
+.level=ALL
+java.util.logging.FileHandler.level=ALL
+java.util.logging.FileHandler.filter=
+java.util.logging.FileHandler.formatter=
+java.util.logging.FileHandler.encoding=
+java.util.logging.FileHandler.limit=
+java.util.logging.FileHandler.count=
+java.util.logging.FileHandler.append=false
+java.util.logging.FileHandler.pattern=all.%u.%g.log
+java.util.logging.ConsoleHandler.level=ALL
+java.util.logging.ConsoleHandler.filter=
+java.util.logging.ConsoleHandler.formatter=
+java.util.logging.ConsoleHandler.encoding=
+#
+holeg.level=INFO
+holeg.ui.level=FINE
 # Disable Swing and Awt Logging
 # Disable Swing and Awt Logging
-java.awt.level  = OFF
-sun.awt.level = OFF
-javax.swing.level = OFF
+java.awt.level=OFF
+sun.awt.level=OFF
+javax.swing.level=OFF

+ 238 - 246
config/randomizer/elements.json

@@ -1,248 +1,240 @@
 [
 [
-    {
-        "name" : "Lights",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "priority" : "Low",
-        "energy" : -100.0
-    }
-    ,{
-        "name" : "LED-TV",
-        "minAmount" : 1,
-        "maxAmount" : 2,
-        "priority" : "Low",
-        "energy" : -85.0
-    }
-    ,{
-        "name" : "Ceiling-Fan",
-        "minAmount" : 1,
-        "maxAmount" : 2,
-        "priority" : "Low",
-        "energy" : -70.0
-    }
-    ,{
-        "name" : "Coffee-Maker",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "priority" : "Low",
-        "energy" : -800.0
-    }
-    ,{
-        "name" : "PC",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "priority" : "Essential",
-        "energy" : -450.0,
-		"onFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 300,
-			"maxCost" : 400,
-			"minDuration" : 1,
-			"maxDuration" : 10,
-			"minCooldown" : 0,
-			"maxCooldown" : 3
-		},
-		"offFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 300,
-			"maxCost" : 400,
-			"minDuration" : 1,
-			"maxDuration" : 10,
-			"minCooldown" : 0,
-			"maxCooldown" : 3
-		}
-        
-    }
-	,{
-        "name" : "Fridge",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "priority" : "Low",
-        "energy" : -300.0,
-		"onFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 100,
-			"maxCost" : 200,
-			"minDuration" : 1,
-			"maxDuration" : 10,
-			"minCooldown" : 0,
-			"maxCooldown" : 3
-		},
-		"offFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 100,
-			"maxCost" : 200,
-			"minDuration" : 1,
-			"maxDuration" : 10,
-			"minCooldown" : 0,
-			"maxCooldown" : 3
-		}
-    }
-	,{
-        "name" : "Water-Heater",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "priority" : "Medium",
-        "energy" : -1300.0,
-        
-		"onFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 200,
-			"maxCost" : 250,
-			"minDuration" : 1,
-			"maxDuration" : 1,
-			"minCooldown" : 0,
-			"maxCooldown" : 3
-		},
-		"offFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 200,
-			"maxCost" : 250,
-			"minDuration" : 1,
-			"maxDuration" : 1,
-			"minCooldown" : 0,
-			"maxCooldown" : 3
-		}
-    }
-	,{
-        "name" : "Microwave",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "priority" : "Low",
-        "energy" : -700.0
-    }
-	,{
-        "name" : "Toaster",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "priority" : "Low",
-        "energy" : -800.0
-    }
-	,{
-        "name" : "Washing-Machine",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "energy" : -500.0,
-        "priority" : "Low",
-        
-		"onFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 50,
-			"maxCost" : 100,
-			"minDuration" : 1,
-			"maxDuration" : 10,
-			"minCooldown" : 0,
-			"maxCooldown" : 3
-		},
-		"offFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 50,
-			"maxCost" : 100,
-			"minDuration" : 1,
-			"maxDuration" : 10,
-			"minCooldown" : 0,
-			"maxCooldown" : 3
-		}
-    }
-	,{
-        "name" : "Solar-Panel",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "priority" : "Low",
-        "energy" : 2000.0,
-        
-		"onFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 120,
-			"maxCost" : 300,
-			"minDuration" : 1,
-			"maxDuration" : 10,
-			"minCooldown" : 0,
-			"maxCooldown" : 3
-		},
-		"offFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 120,
-			"maxCost" : 300,
-			"minDuration" : 1,
-			"maxDuration" : 10,
-			"minCooldown" : 0,
-			"maxCooldown" : 3
-		}
-    }
-	,{
-        "name" : "Radio",
-        "minAmount" : 1,
-        "maxAmount" : 10,
-        "priority" : "Low",
-        "energy" : -50.0
-    }
-	,{
-        "name" : "Oven",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "energy" : -2000.0,
-        "priority" : "Medium",
-		"onFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 200,
-			"maxCost" : 350,
-			"minDuration" : 1,
-			"maxDuration" : 10,
-			"minCooldown" : 0,
-			"maxCooldown" : 3
-
-		},
-		"offFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 200,
-			"maxCost" : 350,
-			"minDuration" : 1,
-			"maxDuration" : 10,
-			"minCooldown" : 0,
-			"maxCooldown" : 3
-
-		}
-    }
-	,{
-        "name" : "Air-Conditioner",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "priority" : "Low",
-        "energy" : -2500.0,
-        
-		"onFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 100,
-			"maxCost" : 250,
-			"minDuration" : 1,
-			"maxDuration" : 10,
-			"minCooldown" : 0,
-			"maxCooldown" : 3
-		},
-		"offFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 100,
-			"maxCost" : 250,
-			"minDuration" : 1,
-			"maxDuration" : 10,
-			"minCooldown" : 0,
-			"maxCooldown" : 3
-		}
-    }
-	,{
-        "name" : "Paper-Shredder",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "priority" : "Low",
-        "energy" : -220.0
-    }
-	,{
-        "name" : "Vacuum-Cleaner",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "priority" : "Low",
-        "energy" : -220.0
-    }
-	
+  {
+    "name": "Lights",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "priority": "Low",
+    "energy": -100.0
+  },
+  {
+    "name": "LED-TV",
+    "minAmount": 1,
+    "maxAmount": 2,
+    "priority": "Low",
+    "energy": -85.0
+  },
+  {
+    "name": "Ceiling-Fan",
+    "minAmount": 1,
+    "maxAmount": 2,
+    "priority": "Low",
+    "energy": -70.0
+  },
+  {
+    "name": "Coffee-Maker",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "priority": "Low",
+    "energy": -800.0
+  },
+  {
+    "name": "PC",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "priority": "Essential",
+    "energy": -450.0,
+    "onFlex": {
+      "flexChance": 0.95,
+      "minCost": 300,
+      "maxCost": 400,
+      "minDuration": 1,
+      "maxDuration": 10,
+      "minCooldown": 0,
+      "maxCooldown": 3
+    },
+    "offFlex": {
+      "flexChance": 0.95,
+      "minCost": 300,
+      "maxCost": 400,
+      "minDuration": 1,
+      "maxDuration": 10,
+      "minCooldown": 0,
+      "maxCooldown": 3
+    }
+  },
+  {
+    "name": "Fridge",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "priority": "Low",
+    "energy": -300.0,
+    "onFlex": {
+      "flexChance": 0.95,
+      "minCost": 100,
+      "maxCost": 200,
+      "minDuration": 1,
+      "maxDuration": 10,
+      "minCooldown": 0,
+      "maxCooldown": 3
+    },
+    "offFlex": {
+      "flexChance": 0.95,
+      "minCost": 100,
+      "maxCost": 200,
+      "minDuration": 1,
+      "maxDuration": 10,
+      "minCooldown": 0,
+      "maxCooldown": 3
+    }
+  },
+  {
+    "name": "Water-Heater",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "priority": "Medium",
+    "energy": -1300.0,
+    "onFlex": {
+      "flexChance": 0.95,
+      "minCost": 200,
+      "maxCost": 250,
+      "minDuration": 1,
+      "maxDuration": 1,
+      "minCooldown": 0,
+      "maxCooldown": 3
+    },
+    "offFlex": {
+      "flexChance": 0.95,
+      "minCost": 200,
+      "maxCost": 250,
+      "minDuration": 1,
+      "maxDuration": 1,
+      "minCooldown": 0,
+      "maxCooldown": 3
+    }
+  },
+  {
+    "name": "Microwave",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "priority": "Low",
+    "energy": -700.0
+  },
+  {
+    "name": "Toaster",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "priority": "Low",
+    "energy": -800.0
+  },
+  {
+    "name": "Washing-Machine",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "energy": -500.0,
+    "priority": "Low",
+    "onFlex": {
+      "flexChance": 0.95,
+      "minCost": 50,
+      "maxCost": 100,
+      "minDuration": 1,
+      "maxDuration": 10,
+      "minCooldown": 0,
+      "maxCooldown": 3
+    },
+    "offFlex": {
+      "flexChance": 0.95,
+      "minCost": 50,
+      "maxCost": 100,
+      "minDuration": 1,
+      "maxDuration": 10,
+      "minCooldown": 0,
+      "maxCooldown": 3
+    }
+  },
+  {
+    "name": "Solar-Panel",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "priority": "Low",
+    "energy": 2000.0,
+    "onFlex": {
+      "flexChance": 0.95,
+      "minCost": 120,
+      "maxCost": 300,
+      "minDuration": 1,
+      "maxDuration": 10,
+      "minCooldown": 0,
+      "maxCooldown": 3
+    },
+    "offFlex": {
+      "flexChance": 0.95,
+      "minCost": 120,
+      "maxCost": 300,
+      "minDuration": 1,
+      "maxDuration": 10,
+      "minCooldown": 0,
+      "maxCooldown": 3
+    }
+  },
+  {
+    "name": "Radio",
+    "minAmount": 1,
+    "maxAmount": 10,
+    "priority": "Low",
+    "energy": -50.0
+  },
+  {
+    "name": "Oven",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "energy": -2000.0,
+    "priority": "Medium",
+    "onFlex": {
+      "flexChance": 0.95,
+      "minCost": 200,
+      "maxCost": 350,
+      "minDuration": 1,
+      "maxDuration": 10,
+      "minCooldown": 0,
+      "maxCooldown": 3
+    },
+    "offFlex": {
+      "flexChance": 0.95,
+      "minCost": 200,
+      "maxCost": 350,
+      "minDuration": 1,
+      "maxDuration": 10,
+      "minCooldown": 0,
+      "maxCooldown": 3
+    }
+  },
+  {
+    "name": "Air-Conditioner",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "priority": "Low",
+    "energy": -2500.0,
+    "onFlex": {
+      "flexChance": 0.95,
+      "minCost": 100,
+      "maxCost": 250,
+      "minDuration": 1,
+      "maxDuration": 10,
+      "minCooldown": 0,
+      "maxCooldown": 3
+    },
+    "offFlex": {
+      "flexChance": 0.95,
+      "minCost": 100,
+      "maxCost": 250,
+      "minDuration": 1,
+      "maxDuration": 10,
+      "minCooldown": 0,
+      "maxCooldown": 3
+    }
+  },
+  {
+    "name": "Paper-Shredder",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "priority": "Low",
+    "energy": -220.0
+  },
+  {
+    "name": "Vacuum-Cleaner",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "priority": "Low",
+    "energy": -220.0
+  }
 ]
 ]

+ 303 - 314
config/randomizer/elements_prod_overhead.json

@@ -1,326 +1,315 @@
 [
 [
-    {
-        "name" : "Lights",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "priority" : "Low",
-        "energy" : -100.0
+  {
+    "name": "Lights",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "priority": "Low",
+    "energy": -100.0
+  },
+  {
+    "name": "LED-TV",
+    "minAmount": 1,
+    "maxAmount": 2,
+    "priority": "Low",
+    "energy": -85.0
+  },
+  {
+    "name": "Ceiling-Fan",
+    "minAmount": 1,
+    "maxAmount": 2,
+    "priority": "Low",
+    "energy": -70.0
+  },
+  {
+    "name": "Coffee-Maker",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "priority": "Low",
+    "energy": -800.0
+  },
+  {
+    "name": "PC",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "priority": "Essential",
+    "energy": -450.0,
+    "onFlex": {
+      "flexChance": 0.95,
+      "minCost": 300,
+      "maxCost": 400,
+      "minDuration": 10,
+      "maxDuration": 3600,
+      "minCooldown": 7200,
+      "maxCooldown": 86400
+    },
+    "offFlex": {
+      "flexChance": 0.95,
+      "minCost": 300,
+      "maxCost": 400,
+      "minDuration": 10,
+      "maxDuration": 3600,
+      "minCooldown": 7200,
+      "maxCooldown": 86400
     }
     }
-    ,{
-        "name" : "LED-TV",
-        "minAmount" : 1,
-        "maxAmount" : 2,
-        "priority" : "Low",
-        "energy" : -85.0
+  },
+  {
+    "name": "Fridge",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "priority": "Low",
+    "energy": -300.0,
+    "onFlex": {
+      "flexChance": 0.95,
+      "minCost": 100,
+      "maxCost": 200,
+      "minDuration": 120,
+      "maxDuration": 10800,
+      "minCooldown": 3600,
+      "maxCooldown": 86400
+    },
+    "offFlex": {
+      "flexChance": 0.95,
+      "minCost": 100,
+      "maxCost": 200,
+      "minDuration": 120,
+      "maxDuration": 10800,
+      "minCooldown": 3600,
+      "maxCooldown": 86400
     }
     }
-    ,{
-        "name" : "Ceiling-Fan",
-        "minAmount" : 1,
-        "maxAmount" : 2,
-        "priority" : "Low",
-        "energy" : -70.0
+  },
+  {
+    "name": "Water-Heater",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "priority": "Medium",
+    "energy": -1300.0,
+    "onFlex": {
+      "flexChance": 0.95,
+      "minCost": 200,
+      "maxCost": 250,
+      "minDuration": 1800,
+      "maxDuration": 7200,
+      "minCooldown": 3600,
+      "maxCooldown": 86400
+    },
+    "offFlex": {
+      "flexChance": 0.95,
+      "minCost": 200,
+      "maxCost": 250,
+      "minDuration": 1800,
+      "maxDuration": 7200,
+      "minCooldown": 3600,
+      "maxCooldown": 86400
     }
     }
-    ,{
-        "name" : "Coffee-Maker",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "priority" : "Low",
-        "energy" : -800.0
+  },
+  {
+    "name": "Microwave",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "priority": "Low",
+    "energy": -700.0
+  },
+  {
+    "name": "Toaster",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "priority": "Low",
+    "energy": -800.0
+  },
+  {
+    "name": "Washing-Machine",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "energy": -500.0,
+    "priority": "Low",
+    "onFlex": {
+      "flexChance": 0.95,
+      "minCost": 50,
+      "maxCost": 100,
+      "minDuration": 900,
+      "maxDuration": 7200,
+      "minCooldown": 3600,
+      "maxCooldown": 86400
+    },
+    "offFlex": {
+      "flexChance": 0.95,
+      "minCost": 50,
+      "maxCost": 100,
+      "minDuration": 900,
+      "maxDuration": 7200,
+      "minCooldown": 3600,
+      "maxCooldown": 86400
     }
     }
-    ,{
-        "name" : "PC",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "priority" : "Essential",
-        "energy" : -450.0,
-		"onFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 300,
-			"maxCost" : 400,
-			"minDuration" : 10,
-			"maxDuration" : 3600,
-			"minCooldown" : 7200,
-			"maxCooldown" : 86400
-		},
-		"offFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 300,
-			"maxCost" : 400,
-			"minDuration" : 10,
-			"maxDuration" : 3600,
-			"minCooldown" : 7200,
-			"maxCooldown" : 86400
-		}
-        
+  },
+  {
+    "name": "Solar-Panel",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "priority": "Low",
+    "energy": 2000.0,
+    "onFlex": {
+      "flexChance": 0.95,
+      "minCost": 120,
+      "maxCost": 300,
+      "minDuration": 900,
+      "maxDuration": 7200,
+      "minCooldown": 3600,
+      "maxCooldown": 86400
+    },
+    "offFlex": {
+      "flexChance": 0.95,
+      "minCost": 120,
+      "maxCost": 300,
+      "minDuration": 900,
+      "maxDuration": 7200,
+      "minCooldown": 3600,
+      "maxCooldown": 86400
     }
     }
-	,{
-        "name" : "Fridge",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "priority" : "Low",
-        "energy" : -300.0,
-		"onFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 100,
-			"maxCost" : 200,
-			"minDuration" : 120,
-			"maxDuration" : 10800,
-			"minCooldown" : 3600,
-			"maxCooldown" : 86400
-		},
-		"offFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 100,
-			"maxCost" : 200,
-			"minDuration" : 120,
-			"maxDuration" : 10800,
-			"minCooldown" : 3600,
-			"maxCooldown" : 86400
-		}
+  },
+  {
+    "name": "Solar-Panel",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "priority": "Low",
+    "energy": 2000.0,
+    "onFlex": {
+      "flexChance": 0.95,
+      "minCost": 120,
+      "maxCost": 300,
+      "minDuration": 900,
+      "maxDuration": 7200,
+      "minCooldown": 3600,
+      "maxCooldown": 86400
+    },
+    "offFlex": {
+      "flexChance": 0.95,
+      "minCost": 120,
+      "maxCost": 300,
+      "minDuration": 900,
+      "maxDuration": 7200,
+      "minCooldown": 3600,
+      "maxCooldown": 86400
     }
     }
-	,{
-        "name" : "Water-Heater",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "priority" : "Medium",
-        "energy" : -1300.0,
-        
-		"onFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 200,
-			"maxCost" : 250,
-			"minDuration" : 1800,
-			"maxDuration" : 7200,
-			"minCooldown" : 3600,
-			"maxCooldown" : 86400
-		},
-		"offFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 200,
-			"maxCost" : 250,
-			"minDuration" : 1800,
-			"maxDuration" : 7200,
-			"minCooldown" : 3600,
-			"maxCooldown" : 86400
-		}
+  },
+  {
+    "name": "Solar-Panel",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "priority": "Low",
+    "energy": 2000.0,
+    "onFlex": {
+      "flexChance": 0.95,
+      "minCost": 120,
+      "maxCost": 300,
+      "minDuration": 900,
+      "maxDuration": 7200,
+      "minCooldown": 3600,
+      "maxCooldown": 86400
+    },
+    "offFlex": {
+      "flexChance": 0.95,
+      "minCost": 120,
+      "maxCost": 300,
+      "minDuration": 900,
+      "maxDuration": 7200,
+      "minCooldown": 3600,
+      "maxCooldown": 86400
     }
     }
-	,{
-        "name" : "Microwave",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "priority" : "Low",
-        "energy" : -700.0
+  },
+  {
+    "name": "Solar-Panel",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "priority": "Low",
+    "energy": 2000.0,
+    "onFlex": {
+      "flexChance": 0.95,
+      "minCost": 120,
+      "maxCost": 300,
+      "minDuration": 900,
+      "maxDuration": 7200,
+      "minCooldown": 3600,
+      "maxCooldown": 86400
+    },
+    "offFlex": {
+      "flexChance": 0.95,
+      "minCost": 120,
+      "maxCost": 300,
+      "minDuration": 900,
+      "maxDuration": 7200,
+      "minCooldown": 3600,
+      "maxCooldown": 86400
     }
     }
-	,{
-        "name" : "Toaster",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "priority" : "Low",
-        "energy" : -800.0
+  },
+  {
+    "name": "Radio",
+    "minAmount": 1,
+    "maxAmount": 10,
+    "priority": "Low",
+    "energy": -50.0
+  },
+  {
+    "name": "Oven",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "energy": -2000.0,
+    "priority": "Medium",
+    "onFlex": {
+      "flexChance": 0.95,
+      "minCost": 200,
+      "maxCost": 350,
+      "minDuration": 1800,
+      "maxDuration": 10800,
+      "minCooldown": 7200,
+      "maxCooldown": 86400
+    },
+    "offFlex": {
+      "flexChance": 0.95,
+      "minCost": 200,
+      "maxCost": 350,
+      "minDuration": 1800,
+      "maxDuration": 10800,
+      "minCooldown": 7200,
+      "maxCooldown": 86400
     }
     }
-	,{
-        "name" : "Washing-Machine",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "energy" : -500.0,
-        "priority" : "Low",
-        
-		"onFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 50,
-			"maxCost" : 100,
-			"minDuration" : 900,
-			"maxDuration" : 7200,
-			"minCooldown" : 3600,
-			"maxCooldown" : 86400
-		},
-		"offFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 50,
-			"maxCost" : 100,
-			"minDuration" : 900,
-			"maxDuration" : 7200,
-			"minCooldown" : 3600,
-			"maxCooldown" : 86400
-		}
+  },
+  {
+    "name": "Air-Conditioner",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "priority": "Low",
+    "energy": -2500.0,
+    "onFlex": {
+      "flexChance": 0.95,
+      "minCost": 100,
+      "maxCost": 250,
+      "minDuration": 1800,
+      "maxDuration": 10800,
+      "minCooldown": 1800,
+      "maxCooldown": 86400
+    },
+    "offFlex": {
+      "flexChance": 0.95,
+      "minCost": 100,
+      "maxCost": 250,
+      "minDuration": 1800,
+      "maxDuration": 10800,
+      "minCooldown": 1800,
+      "maxCooldown": 86400
     }
     }
-	,{
-        "name" : "Solar-Panel",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "priority" : "Low",
-        "energy" : 2000.0,
-        
-		"onFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 120,
-			"maxCost" : 300,
-			"minDuration" : 900,
-			"maxDuration" : 7200,
-			"minCooldown" : 3600,
-			"maxCooldown" : 86400
-		},
-		"offFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 120,
-			"maxCost" : 300,
-			"minDuration" : 900,
-			"maxDuration" : 7200,
-			"minCooldown" : 3600,
-			"maxCooldown" : 86400
-		}
-    }
-	,{
-        "name" : "Solar-Panel",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "priority" : "Low",
-        "energy" : 2000.0,
-        
-		"onFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 120,
-			"maxCost" : 300,
-			"minDuration" : 900,
-			"maxDuration" : 7200,
-			"minCooldown" : 3600,
-			"maxCooldown" : 86400
-		},
-		"offFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 120,
-			"maxCost" : 300,
-			"minDuration" : 900,
-			"maxDuration" : 7200,
-			"minCooldown" : 3600,
-			"maxCooldown" : 86400
-		}
-    }
-	,{
-        "name" : "Solar-Panel",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "priority" : "Low",
-        "energy" : 2000.0,
-        
-		"onFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 120,
-			"maxCost" : 300,
-			"minDuration" : 900,
-			"maxDuration" : 7200,
-			"minCooldown" : 3600,
-			"maxCooldown" : 86400
-		},
-		"offFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 120,
-			"maxCost" : 300,
-			"minDuration" : 900,
-			"maxDuration" : 7200,
-			"minCooldown" : 3600,
-			"maxCooldown" : 86400
-		}
-    }
-	,{
-        "name" : "Solar-Panel",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "priority" : "Low",
-        "energy" : 2000.0,
-        
-		"onFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 120,
-			"maxCost" : 300,
-			"minDuration" : 900,
-			"maxDuration" : 7200,
-			"minCooldown" : 3600,
-			"maxCooldown" : 86400
-		},
-		"offFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 120,
-			"maxCost" : 300,
-			"minDuration" : 900,
-			"maxDuration" : 7200,
-			"minCooldown" : 3600,
-			"maxCooldown" : 86400
-		}
-    }
-	,{
-        "name" : "Radio",
-        "minAmount" : 1,
-        "maxAmount" : 10,
-        "priority" : "Low",
-        "energy" : -50.0
-    }
-	,{
-        "name" : "Oven",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "energy" : -2000.0,
-        "priority" : "Medium",
-		"onFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 200,
-			"maxCost" : 350,
-			"minDuration" : 1800,
-			"maxDuration" : 10800,
-			"minCooldown" : 7200,
-			"maxCooldown" : 86400
-
-		},
-		"offFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 200,
-			"maxCost" : 350,
-			"minDuration" : 1800,
-			"maxDuration" : 10800,
-			"minCooldown" : 7200,
-			"maxCooldown" : 86400
-
-		}
-    }
-	,{
-        "name" : "Air-Conditioner",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "priority" : "Low",
-        "energy" : -2500.0,
-        
-		"onFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 100,
-			"maxCost" : 250,
-			"minDuration" : 1800,
-			"maxDuration" : 10800,
-			"minCooldown" : 1800,
-			"maxCooldown" : 86400
-		},
-		"offFlex" : {
-			"flexChance" : 0.95,
-			"minCost" : 100,
-			"maxCost" : 250,
-			"minDuration" : 1800,
-			"maxDuration" : 10800,
-			"minCooldown" : 1800,
-			"maxCooldown" : 86400
-		}
-    }
-	,{
-        "name" : "Paper-Shredder",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "priority" : "Low",
-        "energy" : -220.0
-    }
-	,{
-        "name" : "Vacuum-Cleaner",
-        "minAmount" : 1,
-        "maxAmount" : 1,
-        "priority" : "Low",
-        "energy" : -220.0
-    }
-	
+  },
+  {
+    "name": "Paper-Shredder",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "priority": "Low",
+    "energy": -220.0
+  },
+  {
+    "name": "Vacuum-Cleaner",
+    "minAmount": 1,
+    "maxAmount": 1,
+    "priority": "Low",
+    "energy": -220.0
+  }
 ]
 ]

+ 12 - 13
license.md

@@ -1,16 +1,15 @@
 # Copyright (c) 2017 Carlos Garcia Cordero, Rolf Egert
 # Copyright (c) 2017 Carlos Garcia Cordero, Rolf Egert
 
 
-Permission is hereby granted, free of charge, to any person obtaining a copy of this 
-software and associated documentation files (the "Software"), to deal in the Software 
-without restriction, including without limitation the rights to use, copy, modify, merge
-publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons 
-to whom the Software is furnished to do so, subject to the following conditions:
-The above copyright notice and this permission notice shall be included in all copies or 
-substantial portions of the Software.
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all copies or substantial
+portions of the Software.
 
 
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
-INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
-PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
-FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
-OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
-DEALINGS IN THE SOFTWARE.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
+OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 34 - 33
res/images/logo/holeg.svg

@@ -1,52 +1,53 @@
 <?xml version="1.0" encoding="iso-8859-1"?>
 <?xml version="1.0" encoding="iso-8859-1"?>
 <!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
 <!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
-	 viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
-<path style="fill:#507C5C;" d="M196.594,512c-1.716,0-3.45-0.313-5.119-0.96c-5.85-2.273-9.504-8.13-8.971-14.384l14.522-170.571
-	H48.049c-4.648,0-8.999-2.283-11.64-6.108c-2.641-3.825-3.235-8.702-1.588-13.049L147.627,9.135C149.71,3.637,154.976,0,160.854,0
-	h232.583c4.743,0,9.167,2.376,11.788,6.328c2.621,3.952,3.088,8.955,1.242,13.321l-49.4,116.91h106.884
-	c5.391,0,10.311,3.064,12.692,7.9s1.803,10.606-1.485,14.876l-48.819,63.388c-4.767,6.191-13.648,7.341-19.837,2.576
-	c-6.19-4.767-7.343-13.648-2.576-19.837l31.278-40.612h-99.471c-4.743,0-9.167-2.376-11.788-6.328s-3.088-8.955-1.242-13.321
-	l49.402-116.912H170.623L68.532,297.794h143.894c3.961,0,7.739,1.661,10.418,4.576c2.679,2.917,4.013,6.822,3.676,10.768
-	l-11.743,137.929l121.963-158.363c4.768-6.19,13.648-7.341,19.837-2.576c6.19,4.767,7.342,13.648,2.576,19.837L207.803,506.485
-	C205.066,510.04,200.889,512,196.594,512z"/>
-<polygon style="fill:#CFF09E;" points="274.026,255.36 129.983,255.36 199.925,70.724 307.059,70.724 249.356,207.284 
-	346.772,207.284 259.542,338.02 "/>
-<path style="fill:#507C5C;" d="M259.538,352.166c-1.76,0-3.54-0.328-5.255-1.016c-6.21-2.487-9.828-8.983-8.674-15.572
-	l11.579-66.073H129.985c-4.648,0-8.999-2.283-11.64-6.108c-2.641-3.825-3.235-8.702-1.588-13.048l69.94-184.636
-	c2.082-5.498,7.348-9.135,13.228-9.135H307.06c4.743,0,9.167,2.376,11.788,6.328c2.621,3.952,3.088,8.955,1.241,13.321l-49.4,116.91
-	h76.084c5.217,0,10.012,2.873,12.471,7.473c2.461,4.6,2.19,10.183-0.706,14.522l-87.232,130.737
-	C268.618,349.899,264.153,352.166,259.538,352.166z M150.466,241.215h123.56c4.178,0,8.143,1.847,10.831,5.047
-	c2.686,3.2,3.822,7.425,3.101,11.539l-2.886,16.47l35.259-52.843h-70.974c-4.743,0-9.169-2.376-11.788-6.328
-	c-2.62-3.952-3.086-8.955-1.24-13.321l49.399-116.91h-76.035L150.466,241.215z"/>
+<svg style="enable-background:new 0 0 512 512;" id="Layer_1" version="1.1"
+  viewBox="0 0 512 512" x="0px"
+  xmlns="http://www.w3.org/2000/svg" y="0px" xml:space="preserve">
 <g>
 <g>
 </g>
 </g>
-<g>
+  <g>
 </g>
 </g>
-<g>
+  <g>
 </g>
 </g>
-<g>
+  <g>
 </g>
 </g>
-<g>
+  <g>
 </g>
 </g>
-<g>
+  <g>
 </g>
 </g>
-<g>
+  <g>
 </g>
 </g>
-<g>
+  <g>
 </g>
 </g>
-<g>
+  <g>
 </g>
 </g>
-<g>
+  <g>
 </g>
 </g>
-<g>
+  <g>
 </g>
 </g>
-<g>
+  <g>
 </g>
 </g>
-<g>
+  <g>
 </g>
 </g>
-<g>
+  <g>
 </g>
 </g>
-<g>
+  <g>
 </g>
 </g>
+  <path style="fill:#507C5C;" d="M196.594,512c-1.716,0-3.45-0.313-5.119-0.96c-5.85-2.273-9.504-8.13-8.971-14.384l14.522-170.571
+	H48.049c-4.648,0-8.999-2.283-11.64-6.108c-2.641-3.825-3.235-8.702-1.588-13.049L147.627,9.135C149.71,3.637,154.976,0,160.854,0
+	h232.583c4.743,0,9.167,2.376,11.788,6.328c2.621,3.952,3.088,8.955,1.242,13.321l-49.4,116.91h106.884
+	c5.391,0,10.311,3.064,12.692,7.9s1.803,10.606-1.485,14.876l-48.819,63.388c-4.767,6.191-13.648,7.341-19.837,2.576
+	c-6.19-4.767-7.343-13.648-2.576-19.837l31.278-40.612h-99.471c-4.743,0-9.167-2.376-11.788-6.328s-3.088-8.955-1.242-13.321
+	l49.402-116.912H170.623L68.532,297.794h143.894c3.961,0,7.739,1.661,10.418,4.576c2.679,2.917,4.013,6.822,3.676,10.768
+	l-11.743,137.929l121.963-158.363c4.768-6.19,13.648-7.341,19.837-2.576c6.19,4.767,7.342,13.648,2.576,19.837L207.803,506.485
+	C205.066,510.04,200.889,512,196.594,512z"/>
+  <path style="fill:#507C5C;" d="M259.538,352.166c-1.76,0-3.54-0.328-5.255-1.016c-6.21-2.487-9.828-8.983-8.674-15.572
+	l11.579-66.073H129.985c-4.648,0-8.999-2.283-11.64-6.108c-2.641-3.825-3.235-8.702-1.588-13.048l69.94-184.636
+	c2.082-5.498,7.348-9.135,13.228-9.135H307.06c4.743,0,9.167,2.376,11.788,6.328c2.621,3.952,3.088,8.955,1.241,13.321l-49.4,116.91
+	h76.084c5.217,0,10.012,2.873,12.471,7.473c2.461,4.6,2.19,10.183-0.706,14.522l-87.232,130.737
+	C268.618,349.899,264.153,352.166,259.538,352.166z M150.466,241.215h123.56c4.178,0,8.143,1.847,10.831,5.047
+	c2.686,3.2,3.822,7.425,3.101,11.539l-2.886,16.47l35.259-52.843h-70.974c-4.743,0-9.169-2.376-11.788-6.328
+	c-2.62-3.952-3.086-8.955-1.24-13.321l49.399-116.91h-76.035L150.466,241.215z"/>
+  <polygon style="fill:#CFF09E;" points="274.026,255.36 129.983,255.36 199.925,70.724 307.059,70.724 249.356,207.284
+	346.772,207.284 259.542,338.02 "/>
 </svg>
 </svg>

+ 339 - 314
src/holeg/addon/RandomOfferdFlexibility.java

@@ -1,5 +1,10 @@
 package holeg.addon;
 package holeg.addon;
 
 
+import holeg.api.AddOn;
+import holeg.model.Flexibility;
+import holeg.model.Flexibility.FlexState;
+import holeg.model.HolonElement.Priority;
+import holeg.ui.controller.Control;
 import java.awt.BorderLayout;
 import java.awt.BorderLayout;
 import java.awt.ComponentOrientation;
 import java.awt.ComponentOrientation;
 import java.awt.Dimension;
 import java.awt.Dimension;
@@ -16,7 +21,6 @@ import java.util.Locale;
 import java.util.Random;
 import java.util.Random;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
-
 import javax.swing.BorderFactory;
 import javax.swing.BorderFactory;
 import javax.swing.JButton;
 import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JCheckBox;
@@ -27,325 +31,346 @@ import javax.swing.JPanel;
 import javax.swing.JSlider;
 import javax.swing.JSlider;
 import javax.swing.text.NumberFormatter;
 import javax.swing.text.NumberFormatter;
 
 
-import holeg.api.AddOn;
-import holeg.model.Flexibility;
-import holeg.model.Flexibility.FlexState;
-import holeg.model.HolonElement.Priority;
-import holeg.ui.controller.Control;
-
 /**
 /**
  * A short algorithm to distribute the Priorities for the whole Canvas.
  * A short algorithm to distribute the Priorities for the whole Canvas.
- * @author tom
  *
  *
+ * @author tom
  */
  */
 
 
 
 
 public class RandomOfferdFlexibility implements AddOn {
 public class RandomOfferdFlexibility implements AddOn {
-	private static final Logger log = Logger.getLogger(RandomOfferdFlexibility.class.getName());
-	
-	
-	
-	
-	
-	private Control  control;
-	
-	private JPanel content = new JPanel();
-
-
-
-	private class PriorityDependeces{
-		public JCheckBox checkbox;
-		public JSlider slider = new JSlider(JSlider.HORIZONTAL,0, 100, 50);
-		
-		public JLabel positive = new JLabel("0 \u2192 0(0)");
-		public JLabel negative = new JLabel("0 \u2192 0(0)");
-		public FlexOffered offer = new FlexOffered();
-		public List<Flexibility> flexList = new ArrayList<Flexibility>();
-		public PriorityDependeces(String name){
-			checkbox = new JCheckBox(name, true);
-		}
-		public void update() {
-			List<Flexibility> positiveList = flexList.stream().filter(flex -> flex.isPositive()).collect(Collectors.toList());
-			offer.positive.maximumOffered = positiveList.size();
-			offer.positive.actualOffered = (int)positiveList.stream().filter(flex -> (flex.offered)).count();
-			List<Flexibility> negativeList = flexList.stream().filter(flex -> flex.isNegative()).collect(Collectors.toList());
-			offer.negative.maximumOffered = negativeList.size();
-			offer.negative.actualOffered = (int)negativeList.stream().filter(flex -> (flex.offered)).count();
-			offer.updateActualProportion();
-			setTarget(offer.proportion);
-		}
-		public void setTarget(double proprotion) {
-			offer.updateTarget(proprotion);
-			//Update slider
-			slider.setValue((int)(offer.proportion * 100.0));
-			//Update Label
-			positive.setText(offer.positive.actualOffered + " \u2192 " + offer.positive.targetOffered + "(" + offer.positive.maximumOffered + ")");
-			negative.setText(offer.negative.actualOffered + " \u2192 " + offer.negative.targetOffered + "(" + offer.negative.maximumOffered + ")");
-
-		}
-		public void updateCanvasToTargetAmounts() {
-			List<Flexibility> positiveList = flexList.stream().filter(flex -> flex.isPositive()).collect(Collectors.toList());
-			Collections.shuffle(positiveList, new Random());
-			for(int i = 0; i < positiveList.size(); i++){
-				positiveList.get(i).offered = (i < offer.positive.targetOffered);
-			}
-			List<Flexibility> negativeList = flexList.stream().filter(flex -> flex.isNegative()).collect(Collectors.toList());
-			Collections.shuffle(negativeList, new Random());
-			for(int i = 0; i < negativeList.size(); i++){
-				negativeList.get(i).offered = (i < offer.negative.targetOffered);
-			}
-			if(control != null) {
-				control.calculateStateForCurrentIteration();
-			}
-		}
-	}
-	private class FlexOffered{
-		public double proportion = 0.5;
-		public FlexTypeOffered positive = new FlexTypeOffered();
-		public FlexTypeOffered negative = new FlexTypeOffered();
-		public void updateTarget(double proportion) {
-			//Clamp between 0 and 1
-			proportion = Math.min(1, Math.max(0, proportion));
-			if(1 == proportion) {
-				negative.targetOffered = 0;
-				positive.targetOffered = positive.maximumOffered;
-			}else if(0 == proportion) {
-				positive.targetOffered = 0;
-				negative.targetOffered = negative.maximumOffered;
-			}else {
-				//x * proportion = positive.maximumOffered
-				int maximumAmountBothA = (int)((double)positive.maximumOffered /proportion);
-				int amountOtherSide = maximumAmountBothA - positive.maximumOffered;
-				if(amountOtherSide <= negative.maximumOffered) {
-					negative.targetOffered = amountOtherSide;
-					positive.targetOffered = positive.maximumOffered;
-				}else {
-					int maximumAmountBothB = (int)((double)negative.maximumOffered / (1.0 -proportion));
-					int amountOtherSideB = maximumAmountBothB - negative.maximumOffered;
-					positive.targetOffered = amountOtherSideB;
-					negative.targetOffered = negative.maximumOffered;
-				}
-			}
-		}
-		public void updateActualProportion() {
-			if(positive.actualOffered + negative.actualOffered == 0) {
-				proportion = 0.5;
-			}else {
-				proportion = (double)positive.actualOffered / (double)(positive.actualOffered + negative.actualOffered);
-			}
-		}
-		public double getActualProportion() {
-			if(positive.actualOffered + negative.actualOffered == 0) {
-				return 0.5;
-			}
-			return (double)positive.actualOffered / (double)(positive.actualOffered + negative.actualOffered);
-		}
-	}
-	private class FlexTypeOffered{
-		int actualOffered = 0;
-		int maximumOffered = 0;
-		int targetOffered = 0;
-	}
-	PriorityDependeces low = new PriorityDependeces("low");
-	PriorityDependeces medium = new PriorityDependeces("medium");
-	PriorityDependeces high = new PriorityDependeces("high");
-	PriorityDependeces essential = new PriorityDependeces("essential");
-	
-	
-
-	
-	
-	
-	
-	
-	
-	
-	
-	public static void main(String[] args)
-	{
-	      JFrame newFrame = new JFrame("exampleWindow");
-	      RandomOfferdFlexibility instance = new RandomOfferdFlexibility();
-	      newFrame.setContentPane(instance.getPanel());
-	      newFrame.pack();
-	      newFrame.setVisible(true);
-	      newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
-	}
-	
-	
-	
-	public RandomOfferdFlexibility(){
-		low.offer.positive.maximumOffered = low.offer.positive.actualOffered =  1000;
-		low.offer.negative.maximumOffered = low.offer.negative.actualOffered = 2000;
-		double distribution = 0.8; 
-		low.offer.updateTarget(distribution);
-		log.info("distribution:" + distribution + " Positive:" + low.offer.positive.targetOffered
-				+ " Negative:" + low.offer.negative.targetOffered);
-		log.info("actualDistribution:" + low.offer.getActualProportion());
-		
-		
-		content.setLayout(new BorderLayout());
-		content.add(createFlexPanel(), BorderLayout.CENTER);
-		JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING));
-
-		JButton buttonReload = new JButton("Reload");
-		buttonReload.setToolTipText("Press to relaod all canvas changes.");
-		buttonReload.addActionListener(actionEvent -> update());
-		buttonPanel.add(buttonReload);
-		JButton buttonRun = new JButton("Run");
-		buttonRun.setToolTipText("Changes the actual offered flex to the random target amount of selected prioritys.");
-		buttonRun.addActionListener(actionEvent -> run());
-		buttonPanel.add(buttonRun);
-		content.add(buttonPanel, BorderLayout.PAGE_END);
-
-		//content.setPreferredSize(new Dimension(300,500));
-	}
-	private JPanel createFlexPanel() {
-		JPanel flexPanel = new JPanel();
-		flexPanel.setBorder(BorderFactory.createTitledBorder("Flexibility"));
-		flexPanel.setLayout(new GridBagLayout());
-		GridBagConstraints c = new GridBagConstraints();
-		
-		c.fill = GridBagConstraints.HORIZONTAL;
-		c.gridx = 0;
-		c.gridy = 0;
-		c.ipadx = 10;
-		//c.ipady = 100;
-		
-		//Label
-		flexPanel.add(new JLabel("Priority:"), c);
-		c.gridx++;
-		flexPanel.add(new JLabel("Target:"), c);
-		c.gridx++;
-		flexPanel.add(new JLabel("Positive#(Available):"), c);
-		c.gridx++;
-		flexPanel.add(new JLabel("Negative#(Available):"), c);
-
-		c.gridx = 0;
-		c.gridy = 1;
-		
-		
-		flexPanel.add(low.checkbox, c);c.gridx++;
-		c.weightx = 1;
-		flexPanel.add(createTargetSetterPanel(this.low), c);c.gridx++;
-		c.weightx = 0;
-		flexPanel.add(this.low.positive, c);c.gridx++;
-		flexPanel.add(this.low.negative, c);
-		
-		c.gridx = 0;
-		c.gridy = 2;
-		
-		flexPanel.add(medium.checkbox, c);c.gridx++;
-		flexPanel.add(createTargetSetterPanel(this.medium), c);c.gridx++;
-		flexPanel.add(this.medium.positive, c);c.gridx++;
-		flexPanel.add(this.medium.negative, c);
-		
-		c.gridx = 0;
-		c.gridy = 3;
-		
-		
-		flexPanel.add(high.checkbox, c);c.gridx++;
-		flexPanel.add(createTargetSetterPanel(this.high), c);c.gridx++;
-		flexPanel.add(this.high.positive, c);c.gridx++;
-		flexPanel.add(this.high.negative, c);
-		
-		c.gridx = 0;
-		c.gridy = 4;
-		
-		flexPanel.add(essential.checkbox, c);c.gridx++;
-		flexPanel.add(createTargetSetterPanel(this.essential), c);c.gridx++;
-		flexPanel.add(this.essential.positive, c);c.gridx++;
-		flexPanel.add(this.essential.negative, c);
-		
-		return flexPanel;
-	}
-
-	private JPanel createTargetSetterPanel(PriorityDependeces priorityD) {
-		JPanel panel = new JPanel();
-		panel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10));
-		panel.setLayout(new GridBagLayout());
-		GridBagConstraints c = new GridBagConstraints();
-		c.fill = GridBagConstraints.HORIZONTAL;
-		c.gridx = 0;
-		c.gridy = 0;
-		c.weightx = 0;
-		c.anchor = GridBagConstraints.NORTH;
-		panel.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
-		NumberFormat doubleFormat = NumberFormat.getNumberInstance(Locale.US);
-		doubleFormat.setMinimumFractionDigits(0);
-		doubleFormat.setMaximumFractionDigits(2);
-		doubleFormat.setRoundingMode(RoundingMode.HALF_UP);
-		NumberFormatter doubleFormatter = new NumberFormatter(doubleFormat);
-		doubleFormatter.setMinimum(0.0);
-		doubleFormatter.setMaximum(1.0);
-		//doubleFormatter.setCommitsOnValidEdit(true);
-		JFormattedTextField change = new JFormattedTextField(doubleFormatter);
-		change.addActionListener(ChangeEvent -> priorityD.slider.setValue((int)(Double.parseDouble(change.getValue().toString()) * 100.0)));
-		change.setText("0.1");
-		change.setPreferredSize(new Dimension(40,20));
-		panel.add(change, c);
-		c.fill = GridBagConstraints.HORIZONTAL;
-		c.gridx = 1;
-		c.weightx = 1;
-		priorityD.slider.setMajorTickSpacing(50);
-		priorityD.slider.setMinorTickSpacing(5);
-		priorityD.slider.setPaintTicks(true);
-		Hashtable<Integer, JLabel> labelTable = new Hashtable<Integer, JLabel>();
-		labelTable.put( Integer.valueOf( 0 ), new JLabel("Positiv") );
-		labelTable.put( Integer.valueOf( 100 ), new JLabel("Negativ") );
-		priorityD.slider.addChangeListener(changeEvent -> {
-			priorityD.offer.proportion = (double)priorityD.slider.getValue()/100.0;
-			priorityD.slider.setToolTipText("" + priorityD.offer.proportion);
-			change.setText("" +priorityD.offer.proportion);
-			priorityD.setTarget(priorityD.offer.proportion);
-		});
-		priorityD.slider.setLabelTable( labelTable );
-		priorityD.slider.setPaintLabels(true);
-		panel.add(priorityD.slider, c);
-		return panel;
-	}
-	
-	
-	
-	
-	
-	private void run() {
-		if(control == null) {
-			return;
-		}
-		if(low.checkbox.isSelected()) low.updateCanvasToTargetAmounts();
-		if(medium.checkbox.isSelected()) medium.updateCanvasToTargetAmounts();
-		if(high.checkbox.isSelected()) high.updateCanvasToTargetAmounts();
-		if(essential.checkbox.isSelected()) essential.updateCanvasToTargetAmounts();
-	}
-	
-	
-	public void update() {
-		if(control == null) {
-			return;
-		}
-		control.calculateStateForCurrentIteration();
-		List<Flexibility> flexList = control.getModel().getAllFlexibilities();
-		List<Flexibility> allOfferedFlex = flexList.stream().filter(flex -> flex.getState().equals(FlexState.OFFERED)).toList();
-
-		low.flexList = allOfferedFlex.stream().filter(flex -> flex.getElement().getPriority() == Priority.Low).collect(Collectors.toList());
-		medium.flexList = allOfferedFlex.stream().filter(flex -> flex.getElement().getPriority() == Priority.Medium).collect(Collectors.toList());
-		high.flexList = allOfferedFlex.stream().filter(flex -> flex.getElement().getPriority() == Priority.High).collect(Collectors.toList());
-		essential.flexList = allOfferedFlex.stream().filter(flex -> flex.getElement().getPriority() == Priority.Essential).collect(Collectors.toList());
-		low.update();
-		medium.update();
-		high.update();
-		essential.update();
-	}
-	
-	
-	@Override
-	public JPanel getPanel() {
-		return content;
-	}
-	@Override
-	public void setController(Control control) {
-		this.control = control;
-		update();
-	}
+
+  private static final Logger log = Logger.getLogger(RandomOfferdFlexibility.class.getName());
+  PriorityDependeces low = new PriorityDependeces("low");
+  PriorityDependeces medium = new PriorityDependeces("medium");
+  PriorityDependeces high = new PriorityDependeces("high");
+  PriorityDependeces essential = new PriorityDependeces("essential");
+  private Control control;
+  private JPanel content = new JPanel();
+  public RandomOfferdFlexibility() {
+    low.offer.positive.maximumOffered = low.offer.positive.actualOffered = 1000;
+    low.offer.negative.maximumOffered = low.offer.negative.actualOffered = 2000;
+    double distribution = 0.8;
+    low.offer.updateTarget(distribution);
+    log.info("distribution:" + distribution + " Positive:" + low.offer.positive.targetOffered
+        + " Negative:" + low.offer.negative.targetOffered);
+    log.info("actualDistribution:" + low.offer.getActualProportion());
+
+    content.setLayout(new BorderLayout());
+    content.add(createFlexPanel(), BorderLayout.CENTER);
+    JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING));
+
+    JButton buttonReload = new JButton("Reload");
+    buttonReload.setToolTipText("Press to relaod all canvas changes.");
+    buttonReload.addActionListener(actionEvent -> update());
+    buttonPanel.add(buttonReload);
+    JButton buttonRun = new JButton("Run");
+    buttonRun.setToolTipText(
+        "Changes the actual offered flex to the random target amount of selected prioritys.");
+    buttonRun.addActionListener(actionEvent -> run());
+    buttonPanel.add(buttonRun);
+    content.add(buttonPanel, BorderLayout.PAGE_END);
+
+    //content.setPreferredSize(new Dimension(300,500));
+  }
+
+  public static void main(String[] args) {
+    JFrame newFrame = new JFrame("exampleWindow");
+    RandomOfferdFlexibility instance = new RandomOfferdFlexibility();
+    newFrame.setContentPane(instance.getPanel());
+    newFrame.pack();
+    newFrame.setVisible(true);
+    newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+  }
+
+  private JPanel createFlexPanel() {
+    JPanel flexPanel = new JPanel();
+    flexPanel.setBorder(BorderFactory.createTitledBorder("Flexibility"));
+    flexPanel.setLayout(new GridBagLayout());
+    GridBagConstraints c = new GridBagConstraints();
+
+    c.fill = GridBagConstraints.HORIZONTAL;
+    c.gridx = 0;
+    c.gridy = 0;
+    c.ipadx = 10;
+    //c.ipady = 100;
+
+    //Label
+    flexPanel.add(new JLabel("Priority:"), c);
+    c.gridx++;
+    flexPanel.add(new JLabel("Target:"), c);
+    c.gridx++;
+    flexPanel.add(new JLabel("Positive#(Available):"), c);
+    c.gridx++;
+    flexPanel.add(new JLabel("Negative#(Available):"), c);
+
+    c.gridx = 0;
+    c.gridy = 1;
+
+    flexPanel.add(low.checkbox, c);
+    c.gridx++;
+    c.weightx = 1;
+    flexPanel.add(createTargetSetterPanel(this.low), c);
+    c.gridx++;
+    c.weightx = 0;
+    flexPanel.add(this.low.positive, c);
+    c.gridx++;
+    flexPanel.add(this.low.negative, c);
+
+    c.gridx = 0;
+    c.gridy = 2;
+
+    flexPanel.add(medium.checkbox, c);
+    c.gridx++;
+    flexPanel.add(createTargetSetterPanel(this.medium), c);
+    c.gridx++;
+    flexPanel.add(this.medium.positive, c);
+    c.gridx++;
+    flexPanel.add(this.medium.negative, c);
+
+    c.gridx = 0;
+    c.gridy = 3;
+
+    flexPanel.add(high.checkbox, c);
+    c.gridx++;
+    flexPanel.add(createTargetSetterPanel(this.high), c);
+    c.gridx++;
+    flexPanel.add(this.high.positive, c);
+    c.gridx++;
+    flexPanel.add(this.high.negative, c);
+
+    c.gridx = 0;
+    c.gridy = 4;
+
+    flexPanel.add(essential.checkbox, c);
+    c.gridx++;
+    flexPanel.add(createTargetSetterPanel(this.essential), c);
+    c.gridx++;
+    flexPanel.add(this.essential.positive, c);
+    c.gridx++;
+    flexPanel.add(this.essential.negative, c);
+
+    return flexPanel;
+  }
+
+  private JPanel createTargetSetterPanel(PriorityDependeces priorityD) {
+    JPanel panel = new JPanel();
+    panel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10));
+    panel.setLayout(new GridBagLayout());
+    GridBagConstraints c = new GridBagConstraints();
+    c.fill = GridBagConstraints.HORIZONTAL;
+    c.gridx = 0;
+    c.gridy = 0;
+    c.weightx = 0;
+    c.anchor = GridBagConstraints.NORTH;
+    panel.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
+    NumberFormat doubleFormat = NumberFormat.getNumberInstance(Locale.US);
+    doubleFormat.setMinimumFractionDigits(0);
+    doubleFormat.setMaximumFractionDigits(2);
+    doubleFormat.setRoundingMode(RoundingMode.HALF_UP);
+    NumberFormatter doubleFormatter = new NumberFormatter(doubleFormat);
+    doubleFormatter.setMinimum(0.0);
+    doubleFormatter.setMaximum(1.0);
+    //doubleFormatter.setCommitsOnValidEdit(true);
+    JFormattedTextField change = new JFormattedTextField(doubleFormatter);
+    change.addActionListener(ChangeEvent -> priorityD.slider.setValue(
+        (int) (Double.parseDouble(change.getValue().toString()) * 100.0)));
+    change.setText("0.1");
+    change.setPreferredSize(new Dimension(40, 20));
+    panel.add(change, c);
+    c.fill = GridBagConstraints.HORIZONTAL;
+    c.gridx = 1;
+    c.weightx = 1;
+    priorityD.slider.setMajorTickSpacing(50);
+    priorityD.slider.setMinorTickSpacing(5);
+    priorityD.slider.setPaintTicks(true);
+    Hashtable<Integer, JLabel> labelTable = new Hashtable<Integer, JLabel>();
+    labelTable.put(Integer.valueOf(0), new JLabel("Positiv"));
+    labelTable.put(Integer.valueOf(100), new JLabel("Negativ"));
+    priorityD.slider.addChangeListener(changeEvent -> {
+      priorityD.offer.proportion = (double) priorityD.slider.getValue() / 100.0;
+      priorityD.slider.setToolTipText("" + priorityD.offer.proportion);
+      change.setText("" + priorityD.offer.proportion);
+      priorityD.setTarget(priorityD.offer.proportion);
+    });
+    priorityD.slider.setLabelTable(labelTable);
+    priorityD.slider.setPaintLabels(true);
+    panel.add(priorityD.slider, c);
+    return panel;
+  }
+
+  private void run() {
+    if (control == null) {
+      return;
+    }
+    if (low.checkbox.isSelected()) {
+      low.updateCanvasToTargetAmounts();
+    }
+    if (medium.checkbox.isSelected()) {
+      medium.updateCanvasToTargetAmounts();
+    }
+    if (high.checkbox.isSelected()) {
+      high.updateCanvasToTargetAmounts();
+    }
+    if (essential.checkbox.isSelected()) {
+      essential.updateCanvasToTargetAmounts();
+    }
+  }
+
+  public void update() {
+    if (control == null) {
+      return;
+    }
+    control.calculateStateForCurrentIteration();
+    List<Flexibility> flexList = control.getModel().getAllFlexibilities();
+    List<Flexibility> allOfferedFlex = flexList.stream()
+        .filter(flex -> flex.getState().equals(FlexState.OFFERED)).toList();
+
+    low.flexList = allOfferedFlex.stream()
+        .filter(flex -> flex.getElement().getPriority() == Priority.Low)
+        .collect(Collectors.toList());
+    medium.flexList = allOfferedFlex.stream()
+        .filter(flex -> flex.getElement().getPriority() == Priority.Medium)
+        .collect(Collectors.toList());
+    high.flexList = allOfferedFlex.stream()
+        .filter(flex -> flex.getElement().getPriority() == Priority.High)
+        .collect(Collectors.toList());
+    essential.flexList = allOfferedFlex.stream()
+        .filter(flex -> flex.getElement().getPriority() == Priority.Essential)
+        .collect(Collectors.toList());
+    low.update();
+    medium.update();
+    high.update();
+    essential.update();
+  }
+
+  @Override
+  public JPanel getPanel() {
+    return content;
+  }
+
+  @Override
+  public void setController(Control control) {
+    this.control = control;
+    update();
+  }
+
+  private class PriorityDependeces {
+
+    public JCheckBox checkbox;
+    public JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 100, 50);
+
+    public JLabel positive = new JLabel("0 \u2192 0(0)");
+    public JLabel negative = new JLabel("0 \u2192 0(0)");
+    public FlexOffered offer = new FlexOffered();
+    public List<Flexibility> flexList = new ArrayList<Flexibility>();
+
+    public PriorityDependeces(String name) {
+      checkbox = new JCheckBox(name, true);
+    }
+
+    public void update() {
+      List<Flexibility> positiveList = flexList.stream().filter(flex -> flex.isPositive())
+          .collect(Collectors.toList());
+      offer.positive.maximumOffered = positiveList.size();
+      offer.positive.actualOffered = (int) positiveList.stream().filter(flex -> (flex.offered))
+          .count();
+      List<Flexibility> negativeList = flexList.stream().filter(flex -> flex.isNegative())
+          .collect(Collectors.toList());
+      offer.negative.maximumOffered = negativeList.size();
+      offer.negative.actualOffered = (int) negativeList.stream().filter(flex -> (flex.offered))
+          .count();
+      offer.updateActualProportion();
+      setTarget(offer.proportion);
+    }
+
+    public void setTarget(double proprotion) {
+      offer.updateTarget(proprotion);
+      //Update slider
+      slider.setValue((int) (offer.proportion * 100.0));
+      //Update Label
+      positive.setText(
+          offer.positive.actualOffered + " \u2192 " + offer.positive.targetOffered + "("
+              + offer.positive.maximumOffered + ")");
+      negative.setText(
+          offer.negative.actualOffered + " \u2192 " + offer.negative.targetOffered + "("
+              + offer.negative.maximumOffered + ")");
+
+    }
+
+    public void updateCanvasToTargetAmounts() {
+      List<Flexibility> positiveList = flexList.stream().filter(flex -> flex.isPositive())
+          .collect(Collectors.toList());
+      Collections.shuffle(positiveList, new Random());
+      for (int i = 0; i < positiveList.size(); i++) {
+        positiveList.get(i).offered = (i < offer.positive.targetOffered);
+      }
+      List<Flexibility> negativeList = flexList.stream().filter(flex -> flex.isNegative())
+          .collect(Collectors.toList());
+      Collections.shuffle(negativeList, new Random());
+      for (int i = 0; i < negativeList.size(); i++) {
+        negativeList.get(i).offered = (i < offer.negative.targetOffered);
+      }
+      if (control != null) {
+        control.calculateStateForCurrentIteration();
+      }
+    }
+  }
+
+  private class FlexOffered {
+
+    public double proportion = 0.5;
+    public FlexTypeOffered positive = new FlexTypeOffered();
+    public FlexTypeOffered negative = new FlexTypeOffered();
+
+    public void updateTarget(double proportion) {
+      //Clamp between 0 and 1
+      proportion = Math.min(1, Math.max(0, proportion));
+      if (1 == proportion) {
+        negative.targetOffered = 0;
+        positive.targetOffered = positive.maximumOffered;
+      } else if (0 == proportion) {
+        positive.targetOffered = 0;
+        negative.targetOffered = negative.maximumOffered;
+      } else {
+        //x * proportion = positive.maximumOffered
+        int maximumAmountBothA = (int) ((double) positive.maximumOffered / proportion);
+        int amountOtherSide = maximumAmountBothA - positive.maximumOffered;
+        if (amountOtherSide <= negative.maximumOffered) {
+          negative.targetOffered = amountOtherSide;
+          positive.targetOffered = positive.maximumOffered;
+        } else {
+          int maximumAmountBothB = (int) ((double) negative.maximumOffered / (1.0 - proportion));
+          int amountOtherSideB = maximumAmountBothB - negative.maximumOffered;
+          positive.targetOffered = amountOtherSideB;
+          negative.targetOffered = negative.maximumOffered;
+        }
+      }
+    }
+
+    public void updateActualProportion() {
+      if (positive.actualOffered + negative.actualOffered == 0) {
+        proportion = 0.5;
+      } else {
+        proportion = (double) positive.actualOffered / (double) (positive.actualOffered
+            + negative.actualOffered);
+      }
+    }
+
+    public double getActualProportion() {
+      if (positive.actualOffered + negative.actualOffered == 0) {
+        return 0.5;
+      }
+      return (double) positive.actualOffered / (double) (positive.actualOffered
+          + negative.actualOffered);
+    }
+  }
+
+  private class FlexTypeOffered {
+
+    int actualOffered = 0;
+    int maximumOffered = 0;
+    int targetOffered = 0;
+  }
 
 
 }
 }

+ 65 - 60
src/holeg/addon/RandomSwitch.java

@@ -1,9 +1,11 @@
 package holeg.addon;
 package holeg.addon;
 
 
+import holeg.api.AddOn;
+import holeg.model.HolonSwitch.SwitchMode;
+import holeg.ui.controller.Control;
 import java.awt.BorderLayout;
 import java.awt.BorderLayout;
 import java.awt.Dimension;
 import java.awt.Dimension;
 import java.util.Hashtable;
 import java.util.Hashtable;
-
 import javax.swing.BorderFactory;
 import javax.swing.BorderFactory;
 import javax.swing.BoxLayout;
 import javax.swing.BoxLayout;
 import javax.swing.JButton;
 import javax.swing.JButton;
@@ -11,15 +13,12 @@ import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JPanel;
 import javax.swing.JSlider;
 import javax.swing.JSlider;
 
 
-import holeg.api.AddOn;
-import holeg.model.HolonSwitch.SwitchMode;
-import holeg.ui.controller.Control;
-
 public class RandomSwitch implements AddOn {
 public class RandomSwitch implements AddOn {
-	private double  randomChance = 0.5;
-	private Control  control;
-	
-	private JPanel content = new JPanel();
+
+  private double randomChance = 0.5;
+  private Control control;
+
+  private JPanel content = new JPanel();
 //	To Test the Layout Faster   
 //	To Test the Layout Faster   
 //	public static void main(String[] args)
 //	public static void main(String[] args)
 //    {
 //    {
@@ -30,56 +29,62 @@ public class RandomSwitch implements AddOn {
 //        newFrame.setVisible(true);
 //        newFrame.setVisible(true);
 //	      newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 //	      newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 //    }
 //    }
-	
-	public RandomSwitch(){
-		content.setLayout(new BorderLayout());
-		content.add(createParameterPanel(), BorderLayout.CENTER);
-		JButton buttonRun = new JButton("Run");
-		buttonRun.addActionListener(actionEvent -> run());
-		content.add(buttonRun, BorderLayout.PAGE_END);
-		content.setPreferredSize(new Dimension(300,300));
-	}
-	private JPanel createParameterPanel() {
-		JPanel parameterPanel = new JPanel();
-		parameterPanel.setLayout(new BoxLayout(parameterPanel, BoxLayout.PAGE_AXIS));
-		parameterPanel.add(createFlipChanceSlider());
-		return parameterPanel;
-	}
-	private JSlider createFlipChanceSlider() {
-		JSlider flipChance =new JSlider(JSlider.HORIZONTAL,0, 100, 50);
-		flipChance.setBorder(BorderFactory.createTitledBorder("FlipChance"));
-		flipChance.setMajorTickSpacing(50);
-		flipChance.setMinorTickSpacing(5);
-		flipChance.setPaintTicks(true);
-		Hashtable<Integer, JLabel> labelTable = new Hashtable<Integer, JLabel>();
-		labelTable.put( Integer.valueOf(0), new JLabel("0.0") );
-		labelTable.put( Integer.valueOf(50), new JLabel("0.5") );
-		labelTable.put( Integer.valueOf(100), new JLabel("1.0") );
-		flipChance.addChangeListener(actionEvent ->randomChance =(double)flipChance.getValue()/100.0);
-		flipChance.setLabelTable( labelTable );
-		flipChance.setPaintLabels(true);
-		return flipChance;
-	}
-	private void run() {
-		control.getModel().getCanvas().getAllSwitchObjectsRecursive().forEach(s -> {
-			// Set to Manual Mode
-			s.setMode(SwitchMode.Manual);
-			// Generate a random number between 0 and 1
-			double randomDouble = Math.random();
-			if (randomDouble < randomChance) {
-				s.flipManualState();
-			}
-		});
-		control.calculateStateForCurrentIteration();
-	}
-	@Override
-	public JPanel getPanel() {
-		return content;
-	}
-	@Override
-	public void setController(Control control) {
-		this.control = control;
-		
-	}
+
+  public RandomSwitch() {
+    content.setLayout(new BorderLayout());
+    content.add(createParameterPanel(), BorderLayout.CENTER);
+    JButton buttonRun = new JButton("Run");
+    buttonRun.addActionListener(actionEvent -> run());
+    content.add(buttonRun, BorderLayout.PAGE_END);
+    content.setPreferredSize(new Dimension(300, 300));
+  }
+
+  private JPanel createParameterPanel() {
+    JPanel parameterPanel = new JPanel();
+    parameterPanel.setLayout(new BoxLayout(parameterPanel, BoxLayout.PAGE_AXIS));
+    parameterPanel.add(createFlipChanceSlider());
+    return parameterPanel;
+  }
+
+  private JSlider createFlipChanceSlider() {
+    JSlider flipChance = new JSlider(JSlider.HORIZONTAL, 0, 100, 50);
+    flipChance.setBorder(BorderFactory.createTitledBorder("FlipChance"));
+    flipChance.setMajorTickSpacing(50);
+    flipChance.setMinorTickSpacing(5);
+    flipChance.setPaintTicks(true);
+    Hashtable<Integer, JLabel> labelTable = new Hashtable<Integer, JLabel>();
+    labelTable.put(Integer.valueOf(0), new JLabel("0.0"));
+    labelTable.put(Integer.valueOf(50), new JLabel("0.5"));
+    labelTable.put(Integer.valueOf(100), new JLabel("1.0"));
+    flipChance.addChangeListener(
+        actionEvent -> randomChance = (double) flipChance.getValue() / 100.0);
+    flipChance.setLabelTable(labelTable);
+    flipChance.setPaintLabels(true);
+    return flipChance;
+  }
+
+  private void run() {
+    control.getModel().getCanvas().getAllSwitchObjectsRecursive().forEach(s -> {
+      // Set to Manual Mode
+      s.setMode(SwitchMode.Manual);
+      // Generate a random number between 0 and 1
+      double randomDouble = Math.random();
+      if (randomDouble < randomChance) {
+        s.flipManualState();
+      }
+    });
+    control.calculateStateForCurrentIteration();
+  }
+
+  @Override
+  public JPanel getPanel() {
+    return content;
+  }
+
+  @Override
+  public void setController(Control control) {
+    this.control = control;
+
+  }
 
 
 }
 }

+ 285 - 283
src/holeg/addon/Randomizer.java

@@ -1,5 +1,21 @@
 package holeg.addon;
 package holeg.addon;
 
 
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonIOException;
+import com.google.gson.JsonParser;
+import com.google.gson.JsonSyntaxException;
+import holeg.addon.helper.HolonElementSketch;
+import holeg.addon.helper.RandomPriotity;
+import holeg.api.AddOn;
+import holeg.model.AbstractCanvasObject;
+import holeg.model.HolonElement;
+import holeg.model.HolonObject;
+import holeg.preferences.ImagePreference;
+import holeg.ui.controller.Control;
+import holeg.ui.view.image.Import;
+import holeg.utility.math.Random;
 import java.awt.BorderLayout;
 import java.awt.BorderLayout;
 import java.awt.Dimension;
 import java.awt.Dimension;
 import java.io.File;
 import java.io.File;
@@ -11,7 +27,6 @@ import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Hashtable;
 import java.util.List;
 import java.util.List;
-
 import javax.swing.BorderFactory;
 import javax.swing.BorderFactory;
 import javax.swing.Box;
 import javax.swing.Box;
 import javax.swing.BoxLayout;
 import javax.swing.BoxLayout;
@@ -29,290 +44,277 @@ import javax.swing.JSplitPane;
 import javax.swing.filechooser.FileNameExtensionFilter;
 import javax.swing.filechooser.FileNameExtensionFilter;
 import javax.swing.text.NumberFormatter;
 import javax.swing.text.NumberFormatter;
 
 
-import com.google.gson.Gson;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonIOException;
-import com.google.gson.JsonParser;
-import com.google.gson.JsonSyntaxException;
+public class Randomizer implements AddOn {
 
 
-import holeg.addon.helper.HolonElementSketch;
-import holeg.addon.helper.RandomPriotity;
-import holeg.api.AddOn;
-import holeg.model.AbstractCanvasObject;
-import holeg.model.HolonElement;
-import holeg.model.HolonObject;
-import holeg.preferences.ImagePreference;
-import holeg.ui.controller.Control;
-import holeg.ui.view.image.Import;
-import holeg.utility.math.Random;
+  private final JPanel content = new JPanel();
+  private final JPanel tablePanel = new JPanel();
+  private final RandomPriotity prioPanel = new RandomPriotity();
+  private final JCheckBox priorityCheckbox = new JCheckBox("Random");
+  private final HashMap<HolonObject, Boolean> objectMap = new HashMap<>();
+  private final List<JCheckBox> checkboxList = new ArrayList<>();
+  public double randomChance = 1.0;
+  private Control control;
+  private int minAmountOfElements = 3;
+  private int maxAmountOfElements = 7;
+  private boolean useRandomPriority = true;
+  private File file;
+  public Randomizer() {
+    content.setLayout(new BorderLayout());
+    JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, createParameterPanel(),
+        createFilterPanel());
+    splitPane.setDividerLocation(0.5);
+    content.add(splitPane, BorderLayout.CENTER);
 
 
-public class Randomizer implements AddOn {
-	private Control  control;
-	private int minAmountOfElements = 3;
-	private int maxAmountOfElements = 7;
-	private final JPanel content = new JPanel();
-	private final JPanel tablePanel = new JPanel();
-	private final RandomPriotity prioPanel = new RandomPriotity();
-	private final JCheckBox priorityCheckbox = new JCheckBox("Random");
-	private boolean useRandomPriority = true;
-
-	//To Test the Layout Faster   
-	public static void main(String[] args)
-    {
-        JFrame newFrame = new JFrame("exampleWindow");
-        Randomizer instance = new Randomizer();
-        newFrame.setContentPane(instance.getPanel());
-        newFrame.pack();
-        newFrame.setVisible(true);
-	      newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+    JButton buttonRun = new JButton("Run");
+    buttonRun.addActionListener(actionEvent -> run());
+    content.add(buttonRun, BorderLayout.PAGE_END);
+  }
+
+  //To Test the Layout Faster
+  public static void main(String[] args) {
+    JFrame newFrame = new JFrame("exampleWindow");
+    Randomizer instance = new Randomizer();
+    newFrame.setContentPane(instance.getPanel());
+    newFrame.pack();
+    newFrame.setVisible(true);
+    newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+  }
+
+  private JScrollPane createFilterPanel() {
+    //Table
+
+    tablePanel.setLayout(new BoxLayout(tablePanel, BoxLayout.PAGE_AXIS));
+    JScrollPane scrollPanel = new JScrollPane(tablePanel);
+    scrollPanel.setPreferredSize(new Dimension(300, 300));
+
+    fillTablePanel();
+    return scrollPanel;
+  }
+
+  private void fillTablePanel() {
+    //Clear old Data
+    tablePanel.removeAll();
+    checkboxList.clear();
+
+    //HeadPanel
+    int lineSpace = 20;
+    JPanel headPanel = new JPanel();
+    headPanel.setLayout(new BoxLayout(headPanel, BoxLayout.LINE_AXIS));
+    headPanel.add(new JLabel("FILTER"));
+    JButton updateButton = new JButton();
+    updateButton.setIcon(
+        new ImageIcon(Import.loadImage(ImagePreference.Canvas.ReplaceSymbol, 15, 15)));
+    updateButton.addActionListener(action -> {
+      this.updateFilterList();
+      content.updateUI();
+    });
+    updateButton.setToolTipText("Manuel updates the filter list with all canvas objects.");
+    headPanel.add(updateButton);
+    headPanel.add(Box.createHorizontalGlue());
+    headPanel.add(new JLabel("SelectAll"));
+    JCheckBox selectAllCheckbox = new JCheckBox();
+    selectAllCheckbox.setSelected(true);
+    selectAllCheckbox.addItemListener(
+        input -> checkboxList.forEach(box -> box.setSelected(selectAllCheckbox.isSelected())));
+    headPanel.add(selectAllCheckbox);
+    tablePanel.add(headPanel);
+
+    //Entrys
+    for (HolonObject hObject : objectMap.keySet().stream()
+        .sorted(Comparator.comparing(AbstractCanvasObject::getName)).toList()) {
+      //Entry
+      JPanel entryPanel = new JPanel();
+      entryPanel.setLayout(new BoxLayout(entryPanel, BoxLayout.LINE_AXIS));
+      JLabel label = new JLabel(hObject.getName() + "[" + hObject.getId() + "]",
+          new ImageIcon(Import.loadImage(hObject.getImagePath(), lineSpace, lineSpace)),
+          JLabel.LEFT);
+      entryPanel.add(label);
+      entryPanel.add(Box.createHorizontalGlue());
+      JCheckBox checkbox = new JCheckBox();
+      checkbox.setSelected(true);
+      checkbox.addItemListener(change -> objectMap.put(hObject, checkbox.isSelected()));
+      checkboxList.add(checkbox);
+      entryPanel.add(checkbox);
+      tablePanel.add(entryPanel);
+    }
+  }
+
+
+  private JSplitPane createParameterPanel() {
+
+    JPanel choosePanel = new JPanel(null);
+    choosePanel.setPreferredSize(new Dimension(300, 200));
+    choosePanel.setMinimumSize(new Dimension(300, 200));
+    JLabel minAmount = new JLabel("minAmountOfElements:");
+    minAmount.setBounds(20, 60, 200, 20);
+    choosePanel.add(minAmount);
+    JLabel maxAmount = new JLabel("maxAmountOfElements:");
+    maxAmount.setBounds(20, 85, 200, 20);
+    choosePanel.add(maxAmount);
+
+    //Integer formatter
+    NumberFormat format = NumberFormat.getIntegerInstance();
+    format.setGroupingUsed(false);
+    format.setParseIntegerOnly(true);
+    NumberFormatter integerFormatter = new NumberFormatter(format);
+    integerFormatter.setMinimum(0);
+    integerFormatter.setCommitsOnValidEdit(true);
+
+    JFormattedTextField minAmountTextField = new JFormattedTextField(integerFormatter);
+    minAmountTextField.setValue(this.minAmountOfElements);
+    minAmountTextField.setToolTipText("Only positive Integer.");
+    minAmountTextField.addPropertyChangeListener(
+        actionEvent -> this.minAmountOfElements = Integer.parseInt(
+            minAmountTextField.getValue().toString()));
+    minAmountTextField.setBounds(220, 60, 50, 20);
+    choosePanel.add(minAmountTextField);
+
+    JFormattedTextField maxAmountTextField = new JFormattedTextField(integerFormatter);
+    maxAmountTextField.setValue(this.maxAmountOfElements);
+    maxAmountTextField.setToolTipText("Only positive Integer.");
+    maxAmountTextField.addPropertyChangeListener(
+        actionEvent -> this.maxAmountOfElements = Integer.parseInt(
+            maxAmountTextField.getValue().toString()));
+    maxAmountTextField.setBounds(220, 85, 50, 20);
+    choosePanel.add(maxAmountTextField);
+
+    JButton chooseFileButton = new JButton("Choose File");
+    chooseFileButton.setBounds(20, 10, 200, 30);
+    chooseFileButton.addActionListener(actionEvent -> file = openCatalogFile());
+    choosePanel.add(chooseFileButton);
+
+    JSlider bitSlider = createFlipChanceSlider();
+    bitSlider.setBounds(10, 110, 280, 80);
+    choosePanel.add(bitSlider);
+
+    JPanel prioritySelectionPanel = new JPanel();
+    prioritySelectionPanel.setLayout(new BoxLayout(prioritySelectionPanel, BoxLayout.PAGE_AXIS));
+    //priorityCheckbox.setAlignmentY(0.0f);
+    //selection
+    prioritySelectionPanel.add(this.priorityCheckbox);
+    priorityCheckbox.addItemListener(change -> {
+      prioPanel.setEnabled(priorityCheckbox.isSelected());
+      useRandomPriority = priorityCheckbox.isSelected();
+    });
+    priorityCheckbox.setSelected(useRandomPriority);
+
+    prioritySelectionPanel.add(prioPanel);
+    JSplitPane parameterPanel = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, choosePanel,
+        prioritySelectionPanel);
+    parameterPanel.setPreferredSize(new Dimension(600, 200));
+
+    return parameterPanel;
+  }
+
+  private void run() {
+    List<HolonElementSketch> holonElementCatalog = new ArrayList<>();
+    if (file == null) {
+      file = openCatalogFile();
+    }
+    if (file == null) {
+      return;
+    }
+    readCatalogFromJson(file, holonElementCatalog);
+    holonElementCatalog.forEach(HolonElementSketch::checkValues);
+    objectMap.forEach((hObject, state) -> {
+      //Ignore Filtered objects
+      if (!state) {
+        return;
+      }
+      //Randomize
+      hObject.clearElements();
+      int randomAmountOfElementsToAdd = Random.nextIntegerInRange(minAmountOfElements,
+          maxAmountOfElements + 1);
+      for (int i = 0; i < randomAmountOfElementsToAdd; i++) {
+        HolonElement ele = holonElementCatalog.get(
+                Random.nextIntegerInRange(0, holonElementCatalog.size()))
+            .createHolonElement(hObject, Random.nextDouble() < randomChance);
+        if (this.useRandomPriority) {
+          ele.setPriority(prioPanel.getPriority());
+        }
+        hObject.add(ele);
+      }
+
+    });
+    control.updateStateForCurrentIteration();
+  }
+
+
+  public void updateFilterList() {
+    objectMap.clear();
+    if (control != null) {
+      control.getModel().getCanvas().getAllHolonObjectsRecursive()
+          .forEach(object -> objectMap.put(object, true));
+    }
+    this.fillTablePanel();
+  }
+
+  @Override
+  public JPanel getPanel() {
+    return content;
+  }
+
+  @Override
+  public void setController(Control control) {
+    this.control = control;
+
+    //Update Filter List
+    updateFilterList();
+  }
+
+
+  private JSlider createFlipChanceSlider() {
+    JSlider flipChance = new JSlider(JSlider.HORIZONTAL, 0, 100, 100);
+    flipChance.setBorder(BorderFactory.createTitledBorder("ActiveProbability"));
+    flipChance.setMajorTickSpacing(50);
+    flipChance.setMinorTickSpacing(5);
+    flipChance.setPaintTicks(true);
+    Hashtable<Integer, JLabel> labelTable = new Hashtable<>();
+    labelTable.put(0, new JLabel("0.0"));
+    labelTable.put(50, new JLabel("0.5"));
+    labelTable.put(100, new JLabel("1.0"));
+    flipChance.setToolTipText("" + randomChance);
+    flipChance.addChangeListener(actionEvent -> {
+      randomChance = (double) flipChance.getValue() / 100.0;
+      flipChance.setToolTipText("" + randomChance);
+    });
+    flipChance.setLabelTable(labelTable);
+    flipChance.setPaintLabels(true);
+    return flipChance;
+  }
+
+
+  private void readCatalogFromJson(File file, List<HolonElementSketch> catalog) {
+    Gson gson = new Gson();
+    try {
+      JsonElement jsonTreeRoot = JsonParser.parseReader(new FileReader(file));
+      if (jsonTreeRoot.isJsonArray()) {
+        JsonArray jsonArray = jsonTreeRoot.getAsJsonArray();
+        jsonArray.forEach(jsonObject -> {
+          HolonElementSketch newObject = gson.fromJson(jsonObject, HolonElementSketch.class);
+          catalog.add(newObject);
+        });
+      }
+    } catch (JsonSyntaxException | JsonIOException | FileNotFoundException e) {
+      e.printStackTrace();
+    }
+
+  }
+
+
+  public File openCatalogFile() {
+    JFileChooser fileChooser = new JFileChooser();
+    fileChooser.setCurrentDirectory(
+        new File(System.getProperty("user.dir") + "/config/randomizer/"));
+    fileChooser.setFileFilter(new FileNameExtensionFilter("JSON Files", "json"));
+    fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+    fileChooser.setAcceptAllFileFilterUsed(false);
+    int result = fileChooser.showOpenDialog(content);
+    if (result == JFileChooser.APPROVE_OPTION) {
+      //Found a file
+      return fileChooser.getSelectedFile();
     }
     }
-	private File file;
-	public double randomChance = 1.0;
-	
-	
-	private final HashMap<HolonObject, Boolean> objectMap = new HashMap<>();
-	private final List<JCheckBox> checkboxList = new ArrayList<>();
-	
-	
-	
-	
-	
-	
-	public Randomizer(){
-		content.setLayout(new BorderLayout());
-		JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, createParameterPanel(), createFilterPanel());
-		splitPane.setDividerLocation(0.5);
-		content.add(splitPane, BorderLayout.CENTER);
-
-		JButton buttonRun = new JButton("Run");
-		buttonRun.addActionListener(actionEvent -> run());
-		content.add(buttonRun, BorderLayout.PAGE_END);
-	}
-	private JScrollPane createFilterPanel() {
-		//Table
-		
-		tablePanel.setLayout(new BoxLayout(tablePanel, BoxLayout.PAGE_AXIS));
-		JScrollPane scrollPanel = new JScrollPane(tablePanel);
-		scrollPanel.setPreferredSize(new Dimension(300,300));
-		
-		
-		
-		fillTablePanel();
-		return scrollPanel;
-	}
-	
-	private void fillTablePanel() {
-		//Clear old Data
-		tablePanel.removeAll();
-		checkboxList.clear();
-		
-		//HeadPanel
-		int lineSpace = 20;
-		JPanel headPanel = new JPanel();
-		headPanel.setLayout(new BoxLayout(headPanel, BoxLayout.LINE_AXIS));
-		headPanel.add(new JLabel("FILTER"));
-		JButton updateButton = new JButton();
-		updateButton.setIcon(new ImageIcon(Import.loadImage(ImagePreference.Canvas.ReplaceSymbol, 15, 15)));
-		updateButton.addActionListener(action -> {
-			this.updateFilterList();
-			content.updateUI();
-		});
-		updateButton.setToolTipText("Manuel updates the filter list with all canvas objects.");
-		headPanel.add(updateButton);
-		headPanel.add(Box.createHorizontalGlue());
-		headPanel.add(new JLabel("SelectAll"));
-		JCheckBox selectAllCheckbox = new JCheckBox();
-		selectAllCheckbox.setSelected(true);
-		selectAllCheckbox.addItemListener(input -> checkboxList.forEach(box -> box.setSelected(selectAllCheckbox.isSelected())));
-		headPanel.add(selectAllCheckbox);
-		tablePanel.add(headPanel);
-		
-		
-		//Entrys
-		for(HolonObject hObject: objectMap.keySet().stream().sorted(Comparator.comparing(AbstractCanvasObject::getName)).toList()) {
-			//Entry
-			JPanel entryPanel = new JPanel();
-			entryPanel.setLayout(new BoxLayout(entryPanel, BoxLayout.LINE_AXIS));
-			JLabel label = new JLabel(hObject.getName() + "[" + hObject.getId() + "]", new ImageIcon(Import.loadImage(hObject.getImagePath(), lineSpace, lineSpace)), JLabel.LEFT);
-			entryPanel.add(label);
-			entryPanel.add(Box.createHorizontalGlue());
-			JCheckBox checkbox = new JCheckBox();
-			checkbox.setSelected(true);
-			checkbox.addItemListener(change -> objectMap.put(hObject, checkbox.isSelected()));
-			checkboxList.add(checkbox);
-			entryPanel.add(checkbox);
-			tablePanel.add(entryPanel);
-		}
-	}
-	
-	
-	private JSplitPane createParameterPanel() {
-		
-		JPanel choosePanel = new JPanel(null);
-		choosePanel.setPreferredSize(new Dimension(300,200));
-		choosePanel.setMinimumSize(new Dimension(300,200));
-		JLabel minAmount = new JLabel("minAmountOfElements:");
-		minAmount.setBounds(20, 60 , 200, 20);
-		choosePanel.add(minAmount);
-		JLabel maxAmount = new JLabel("maxAmountOfElements:");
-		maxAmount.setBounds(20, 85 , 200, 20);
-		choosePanel.add(maxAmount);
-		
-		//Integer formatter
-		NumberFormat format = NumberFormat.getIntegerInstance();
-		format.setGroupingUsed(false);
-		format.setParseIntegerOnly(true);
-		NumberFormatter integerFormatter = new NumberFormatter(format);
-		integerFormatter.setMinimum(0);
-		integerFormatter.setCommitsOnValidEdit(true);
-				
-				
-		JFormattedTextField minAmountTextField = new  JFormattedTextField(integerFormatter);
-		minAmountTextField.setValue(this.minAmountOfElements);
-		minAmountTextField.setToolTipText("Only positive Integer.");
-		minAmountTextField.addPropertyChangeListener(actionEvent -> this.minAmountOfElements = Integer.parseInt(minAmountTextField.getValue().toString()));
-		minAmountTextField.setBounds(220, 60, 50, 20);
-		choosePanel.add(minAmountTextField);
-		
-		JFormattedTextField maxAmountTextField = new  JFormattedTextField(integerFormatter);
-		maxAmountTextField.setValue(this.maxAmountOfElements);
-		maxAmountTextField.setToolTipText("Only positive Integer.");
-		maxAmountTextField.addPropertyChangeListener(actionEvent -> this.maxAmountOfElements = Integer.parseInt(maxAmountTextField.getValue().toString()));
-		maxAmountTextField.setBounds(220, 85, 50, 20);
-		choosePanel.add(maxAmountTextField);
-		
-		JButton chooseFileButton = new JButton("Choose File");
-		chooseFileButton.setBounds(20, 10, 200, 30);
-		chooseFileButton.addActionListener(actionEvent -> file = openCatalogFile());
-		choosePanel.add(chooseFileButton);
-		
-		
-		JSlider bitSlider = createFlipChanceSlider();
-		bitSlider.setBounds(10, 110, 280, 80);
-		choosePanel.add(bitSlider);
-		
-		JPanel prioritySelectionPanel = new JPanel();
-		prioritySelectionPanel.setLayout(new BoxLayout(prioritySelectionPanel, BoxLayout.PAGE_AXIS));
-		//priorityCheckbox.setAlignmentY(0.0f);
-		//selection
-		prioritySelectionPanel.add(this.priorityCheckbox);
-		priorityCheckbox.addItemListener(change -> {
-			prioPanel.setEnabled(priorityCheckbox.isSelected());
-			useRandomPriority = priorityCheckbox.isSelected();
-		});
-		priorityCheckbox.setSelected(useRandomPriority);
-		
-		
-		prioritySelectionPanel.add(prioPanel);
-		JSplitPane parameterPanel = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, choosePanel, prioritySelectionPanel);
-		parameterPanel.setPreferredSize(new Dimension(600,200));
-		
-		return parameterPanel;
-	}
-	
-	private void run() {
-		List<HolonElementSketch> holonElementCatalog = new ArrayList<>();
-		if(file == null)file = openCatalogFile();
-		if(file == null) return;
-		readCatalogFromJson(file, holonElementCatalog);
-		holonElementCatalog.forEach(HolonElementSketch::checkValues);
-		objectMap.forEach((hObject, state) ->{
-			//Ignore Filtered objects
-			if(!state) {
-				return;
-			}
-			//Randomize
-			hObject.clearElements();
-			int randomAmountOfElementsToAdd = Random.nextIntegerInRange(minAmountOfElements, maxAmountOfElements + 1);
-			for(int i = 0; i < randomAmountOfElementsToAdd; i++) {
-				HolonElement ele = holonElementCatalog.get(Random.nextIntegerInRange(0, holonElementCatalog.size())).createHolonElement(hObject, Random.nextDouble() < randomChance );
-				if(this.useRandomPriority) ele.setPriority(prioPanel.getPriority());
-				hObject.add(ele);			
-			}
-			
-		});
-		control.updateStateForCurrentIteration();
-	}
-
-	
-	public void updateFilterList() {
-		objectMap.clear();
-		if(control != null) {
-			control.getModel().getCanvas().getAllHolonObjectsRecursive().forEach(object -> objectMap.put(object, true));
-		}
-		this.fillTablePanel();
-	}
-	
-	@Override
-	public JPanel getPanel() {
-		return content;
-	}
-	@Override
-	public void setController(Control control) {
-		this.control = control;
-		
-		//Update Filter List
-		updateFilterList();
-	}
-	
-
-	private JSlider createFlipChanceSlider() {
-		JSlider flipChance =new JSlider(JSlider.HORIZONTAL,0, 100, 100);
-		flipChance.setBorder(BorderFactory.createTitledBorder("ActiveProbability"));
-		flipChance.setMajorTickSpacing(50);
-		flipChance.setMinorTickSpacing(5);
-		flipChance.setPaintTicks(true);
-		Hashtable<Integer, JLabel> labelTable = new Hashtable<>();
-		labelTable.put(0, new JLabel("0.0") );
-		labelTable.put(50, new JLabel("0.5") );
-		labelTable.put(100, new JLabel("1.0") );
-		flipChance.setToolTipText("" +randomChance);
-		flipChance.addChangeListener(actionEvent ->{
-			randomChance  =(double)flipChance.getValue()/100.0;
-			flipChance.setToolTipText("" +randomChance);
-		});
-		flipChance.setLabelTable( labelTable );
-		flipChance.setPaintLabels(true);
-		return flipChance;
-	}
-	
-	
-	
-	
-	private void readCatalogFromJson(File file, List<HolonElementSketch> catalog) {
-		Gson gson = new Gson();
-		try {
-			JsonElement jsonTreeRoot = JsonParser.parseReader(new FileReader(file));
-			if(jsonTreeRoot.isJsonArray()) {
-				JsonArray jsonArray = jsonTreeRoot.getAsJsonArray();
-				jsonArray.forEach(jsonObject -> {
-					HolonElementSketch newObject= gson.fromJson( jsonObject, HolonElementSketch.class);
-					catalog.add(newObject);
-				});
-			}	
-		} catch (JsonSyntaxException | JsonIOException | FileNotFoundException e) {
-			e.printStackTrace();
-		}
-
-	}
-	
-	
-	
-	
-	
-	public File openCatalogFile() {		
-		JFileChooser fileChooser = new JFileChooser();
-		fileChooser.setCurrentDirectory(new File(System.getProperty("user.dir")+"/config/randomizer/"));
-		fileChooser.setFileFilter(new FileNameExtensionFilter("JSON Files", "json"));
-		fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
-		fileChooser.setAcceptAllFileFilterUsed(false);
-		int result = fileChooser.showOpenDialog(content);
-		if(result == JFileChooser.APPROVE_OPTION) {
-			//Found a file
-			return fileChooser.getSelectedFile();
-		}
-		return null;
-	}
+    return null;
+  }
 
 
 }
 }

+ 149 - 155
src/holeg/addon/helper/EmailNotification.java

@@ -1,11 +1,14 @@
 package holeg.addon.helper;
 package holeg.addon.helper;
+
+import holeg.preferences.ImagePreference;
+import holeg.preferences.PreferenceKeys;
+import holeg.ui.view.image.Import;
 import java.awt.BorderLayout;
 import java.awt.BorderLayout;
 import java.awt.ComponentOrientation;
 import java.awt.ComponentOrientation;
 import java.awt.Dimension;
 import java.awt.Dimension;
 import java.awt.FlowLayout;
 import java.awt.FlowLayout;
 import java.awt.GridLayout;
 import java.awt.GridLayout;
-import java.util.prefs.*;
-
+import java.util.prefs.Preferences;
 import javax.swing.BorderFactory;
 import javax.swing.BorderFactory;
 import javax.swing.JButton;
 import javax.swing.JButton;
 import javax.swing.JFrame;
 import javax.swing.JFrame;
@@ -13,161 +16,152 @@ import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JPanel;
 import javax.swing.JPasswordField;
 import javax.swing.JPasswordField;
 import javax.swing.JTextField;
 import javax.swing.JTextField;
+import org.apache.commons.mail.DefaultAuthenticator;
+import org.apache.commons.mail.Email;
+import org.apache.commons.mail.EmailException;
+import org.apache.commons.mail.SimpleEmail;
 
 
-import holeg.preferences.PreferenceKeys;
-import org.apache.commons.mail.*;
 
 
-import holeg.preferences.ImagePreference;
-import holeg.ui.view.image.Import;
+public class EmailNotification {
+
+  private static final Preferences prefs = Preferences.userNodeForPackage(EmailNotification.class);
+  private static final EmailSmtpInformation info = new EmailSmtpInformation();
+
+  public static void main(String[] args) {
+    OpenEmailSettings(null);
+  }
+
+  public static void OpenEmailSettings(JPanel parent) {
+    loadPreferences();
+    JFrame frame = new JFrame();
+    frame.setTitle("Email Settings");
+    frame.setIconImage(Import.loadImage(ImagePreference.Logo, 30, 30));
+    frame.setContentPane(createEditFormular(frame));
+    frame.pack();
+    frame.setPreferredSize(new Dimension(400, frame.getHeight()));
+    frame.pack();
+    frame.setVisible(true);
+    frame.setLocationRelativeTo(parent);
+    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+  }
+
+  private static JPanel createEditFormular(JFrame frame) {
+    JPanel panel = new JPanel();
+    panel.setLayout(new BorderLayout());
+    panel.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
+
+    JPanel infoPanel = new JPanel();
+    GridLayout infoLayout = new GridLayout(0, 2);
+    infoPanel.add(new JLabel("SMTP Hostname:"));
+    JTextField hostnameTextField = new JTextField(info.Hostname);
+    infoPanel.add(hostnameTextField);
+    infoPanel.add(new JLabel("Port:"));
+    JTextField portTextField = new JTextField(Integer.toString(info.Port));
+    infoPanel.add(portTextField);
+    infoPanel.add(new JLabel("Username:"));
+    JTextField usernameTextField = new JTextField(info.Username);
+    infoPanel.add(usernameTextField);
+    infoPanel.add(new JLabel("Password:"));
+    JPasswordField passwordTextField = new JPasswordField(info.Password);
+    infoPanel.add(passwordTextField);
+    infoPanel.add(new JLabel("From Email:"));
+    JTextField fromEmailTextField = new JTextField(info.FromEmail);
+    infoPanel.add(fromEmailTextField);
+    infoPanel.add(new JLabel("To Email:"));
+    JTextField toEmailTextField = new JTextField(info.ToEmail);
+    infoPanel.add(toEmailTextField);
+    infoPanel.setLayout(infoLayout);
+    panel.add(infoPanel, BorderLayout.CENTER);
+
+    JPanel controlPanel = new JPanel();
+    controlPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+    controlPanel.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
+    JButton cancelButton = new JButton("Cancel");
+    cancelButton.addActionListener(event -> frame.dispose());
+    controlPanel.add(cancelButton);
+    JButton applyButton = new JButton("Apply and Close");
+    applyButton.addActionListener(event -> {
+      // parse Textfields
+      info.Hostname = hostnameTextField.getText();
+      info.Port = Integer.parseInt(portTextField.getText());
+      info.Username = usernameTextField.getText();
+      info.Password = String.valueOf(passwordTextField.getPassword());
+      info.FromEmail = fromEmailTextField.getText();
+      info.ToEmail = toEmailTextField.getText();
+      // Save Preferences
+      savePreferences();
+      frame.dispose();
+    });
+    controlPanel.add(applyButton);
+
+    JButton testButton = new JButton("Send Test-Email");
+    testButton.addActionListener(event -> {
+      // parse Textfields
+      EmailSmtpInformation testInfo = new EmailSmtpInformation();
+      testInfo.Hostname = hostnameTextField.getText();
+      testInfo.Port = Integer.parseInt(portTextField.getText());
+      testInfo.Username = usernameTextField.getText();
+      testInfo.Password = String.valueOf(passwordTextField.getPassword());
+      testInfo.FromEmail = fromEmailTextField.getText();
+      testInfo.ToEmail = toEmailTextField.getText();
+      sendEmail(testInfo, "Holeg Notification Test", "Success.");
+    });
+    controlPanel.add(testButton);
+
+    panel.add(controlPanel, BorderLayout.PAGE_END);
+
+    return panel;
+  }
+
+  public static void sendEmail(String subject, String message) {
+    loadPreferences();
+    sendEmail(info, subject, message);
+  }
+
+  public static void sendEmail(EmailSmtpInformation info, String subject, String message) {
+    Email email = new SimpleEmail();
+    email.setHostName(info.Hostname);
+    email.setSmtpPort(info.Port);
+    email.setAuthenticator(new DefaultAuthenticator(info.Username, info.Password));
+    email.setSSLOnConnect(true);
+    email.setSubject(subject);
+    try {
+      email.setFrom(info.FromEmail);
+      email.setMsg(message);
+      email.addTo(info.ToEmail);
+      email.send();
+    } catch (EmailException e) {
+      e.printStackTrace();
+    }
+  }
+
+  private static void savePreferences() {
+    prefs.put(PreferenceKeys.EmailNotification.Hostname, info.Hostname);
+    prefs.putInt(PreferenceKeys.EmailNotification.Port, info.Port);
+    prefs.put(PreferenceKeys.EmailNotification.Username, info.Username);
+    prefs.put(PreferenceKeys.EmailNotification.Password, info.Password);
+    prefs.put(PreferenceKeys.EmailNotification.FromEmail, info.FromEmail);
+    prefs.put(PreferenceKeys.EmailNotification.ToEmail, info.ToEmail);
+  }
+
+  private static void loadPreferences() {
+    info.Hostname = prefs.get(PreferenceKeys.EmailNotification.Hostname, "");
+    info.Port = prefs.getInt(PreferenceKeys.EmailNotification.Port, 465);
+    info.Username = prefs.get(PreferenceKeys.EmailNotification.Username, "");
+    info.Password = prefs.get(PreferenceKeys.EmailNotification.Password, "");
+    info.FromEmail = prefs.get(PreferenceKeys.EmailNotification.FromEmail, "");
+    info.ToEmail = prefs.get(PreferenceKeys.EmailNotification.ToEmail, "");
+  }
+
+  public static class EmailSmtpInformation {
+
+    public String Hostname;
+    public int Port;
+    public String Username;
+    public String Password;
+    public String FromEmail;
+    public String ToEmail;
+  }
 
 
 
 
-public class EmailNotification {
-	private static final Preferences prefs = Preferences.userNodeForPackage(EmailNotification.class);
-	private static final EmailSmtpInformation info = new EmailSmtpInformation();
-
-	public static class EmailSmtpInformation{
-		public String Hostname;
-		public int Port;
-		public String Username;
-		public String Password;
-		public String FromEmail;
-		public String ToEmail;
-	}
-	
-	
-	
-	
-	
-	
-	
-	public static void main(String[] args) {
-		OpenEmailSettings(null);
-	}
-
-	public static void OpenEmailSettings(JPanel parent) {
-		loadPreferences();
-		JFrame frame = new JFrame();
-		frame.setTitle("Email Settings");
-		frame.setIconImage(Import.loadImage(ImagePreference.Logo,30,30));
-		frame.setContentPane(createEditFormular(frame));
-		frame.pack();
-		frame.setPreferredSize(new Dimension(400,frame.getHeight()));
-		frame.pack();
-		frame.setVisible(true);
-		frame.setLocationRelativeTo(parent);
-		frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
-	}
-	
-	
-	private static JPanel createEditFormular(JFrame frame) {
-		JPanel panel = new JPanel();
-		panel.setLayout(new BorderLayout());
-		panel.setBorder(BorderFactory.createEmptyBorder(0,5,0,5));
-		
-		JPanel infoPanel = new JPanel();
-		GridLayout infoLayout= new GridLayout(0,2);
-		infoPanel.add(new JLabel("SMTP Hostname:"));
-		JTextField hostnameTextField = new JTextField(info.Hostname);
-		infoPanel.add(hostnameTextField);
-		infoPanel.add(new JLabel("Port:"));
-		JTextField portTextField = new JTextField(Integer.toString(info.Port));
-		infoPanel.add(portTextField);
-		infoPanel.add(new JLabel("Username:"));
-		JTextField usernameTextField = new JTextField(info.Username);
-		infoPanel.add(usernameTextField);
-		infoPanel.add(new JLabel("Password:"));
-		JPasswordField  passwordTextField = new JPasswordField (info.Password);
-		infoPanel.add(passwordTextField);
-		infoPanel.add(new JLabel("From Email:"));
-		JTextField fromEmailTextField = new JTextField(info.FromEmail);
-		infoPanel.add(fromEmailTextField);
-		infoPanel.add(new JLabel("To Email:"));
-		JTextField toEmailTextField = new JTextField(info.ToEmail);
-		infoPanel.add(toEmailTextField);
-		infoPanel.setLayout(infoLayout);
-		panel.add(infoPanel, BorderLayout.CENTER);
-		
-		JPanel controlPanel = new JPanel();
-		controlPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
-		controlPanel.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
-		JButton cancelButton = new JButton("Cancel");
-		cancelButton.addActionListener(event -> frame.dispose());
-		controlPanel.add(cancelButton);
-		JButton applyButton = new JButton("Apply and Close");
-		applyButton.addActionListener(event -> {
-			// parse Textfields
-			info.Hostname = hostnameTextField.getText();
-			info.Port = Integer.parseInt(portTextField.getText());
-			info.Username = usernameTextField.getText();
-			info.Password =  String.valueOf(passwordTextField.getPassword());
-			info.FromEmail = fromEmailTextField.getText();
-			info.ToEmail = toEmailTextField.getText();
-			// Save Preferences
-			savePreferences();
-			frame.dispose();
-		});
-		controlPanel.add(applyButton);
-		
-		JButton testButton = new JButton("Send Test-Email");
-		testButton.addActionListener(event -> {
-			// parse Textfields
-			EmailSmtpInformation testInfo = new EmailSmtpInformation();
-			testInfo.Hostname = hostnameTextField.getText();
-			testInfo.Port = Integer.parseInt(portTextField.getText());
-			testInfo.Username = usernameTextField.getText();
-			testInfo.Password = String.valueOf(passwordTextField.getPassword());
-			testInfo.FromEmail = fromEmailTextField.getText();
-			testInfo.ToEmail = toEmailTextField.getText();
-			sendEmail(testInfo, "Holeg Notification Test", "Success.");
-		});
-		controlPanel.add(testButton);
-		
-		panel.add(controlPanel, BorderLayout.PAGE_END);
-		
-		
-		
-		return panel;
-	}
-	public static void sendEmail(String subject, String message) {
-		loadPreferences();
-		sendEmail(info, subject, message);
-	}
-
-	public static void sendEmail(EmailSmtpInformation info, String subject, String message) {
-		Email email = new SimpleEmail();
-		email.setHostName(info.Hostname);
-		email.setSmtpPort(info.Port);
-		email.setAuthenticator(new DefaultAuthenticator(info.Username, info.Password));
-		email.setSSLOnConnect(true);
-		email.setSubject(subject);
-		try {
-			email.setFrom(info.FromEmail);
-			email.setMsg(message);
-			email.addTo(info.ToEmail);
-			email.send();
-		} catch (EmailException e) {
-			e.printStackTrace();
-		}
-	}
-	
-	private static void savePreferences() {
-		prefs.put(PreferenceKeys.EmailNotification.Hostname, info.Hostname);
-		prefs.putInt(PreferenceKeys.EmailNotification.Port, info.Port);
-		prefs.put(PreferenceKeys.EmailNotification.Username, info.Username);
-		prefs.put(PreferenceKeys.EmailNotification.Password, info.Password);
-		prefs.put(PreferenceKeys.EmailNotification.FromEmail, info.FromEmail);
-		prefs.put(PreferenceKeys.EmailNotification.ToEmail, info.ToEmail);
-	}
-	
-	private static void loadPreferences() {
-		info.Hostname = prefs.get(PreferenceKeys.EmailNotification.Hostname, "");
-		info.Port = prefs.getInt(PreferenceKeys.EmailNotification.Port, 465);
-		info.Username = prefs.get(PreferenceKeys.EmailNotification.Username, "");
-		info.Password = prefs.get(PreferenceKeys.EmailNotification.Password, "");
-		info.FromEmail= prefs.get(PreferenceKeys.EmailNotification.FromEmail, "");
-		info.ToEmail = prefs.get(PreferenceKeys.EmailNotification.ToEmail, "");
-	}
-	
-	
-	
 }
 }

+ 44 - 39
src/holeg/addon/helper/FlexibilitySketch.java

@@ -1,43 +1,48 @@
 package holeg.addon.helper;
 package holeg.addon.helper;
 
 
-public class FlexibilitySketch{
-	public double flexChance;
-	public float minCost;
-	public float maxCost;
-	/** The Duration in TimeSteps how long the Flexibility is activated.*/
-	public int minDuration;
-	public int maxDuration;
-	/** The Duration after a successful activation between the next possible activation.*/
-	public int minCooldown;
-	public int maxCooldown;
-	
-	
-	public void checkValues(){
+public class FlexibilitySketch {
 
 
-		minDuration = Math.abs(minDuration);
-		maxDuration = Math.abs(maxDuration);
-		if(maxDuration < minDuration) {
-			//Swap
-			int intermediate = minDuration;
-			minDuration = maxDuration;
-			maxDuration = intermediate;
-		}
-		minCooldown = Math.abs(minCooldown);
-		maxCooldown = Math.abs(maxCooldown);
-		if(maxCooldown < minCooldown) {
-			//Swap
-			int intermediate = minCooldown;
-			minCooldown = maxCooldown;
-			maxCooldown = intermediate;
-		}
-		minCost = Math.abs(minCost);
-		maxCost = Math.abs(maxCost);
-		if(maxCost < minCost) {
-			//Swap
-			float intermediate = minCost;
-			minCost = maxCost;
-			maxCost = intermediate;
-		}
-		flexChance = Math.max(0, Math.min(1, flexChance)); //Clamp
-	}
+  public double flexChance;
+  public float minCost;
+  public float maxCost;
+  /**
+   * The Duration in TimeSteps how long the Flexibility is activated.
+   */
+  public int minDuration;
+  public int maxDuration;
+  /**
+   * The Duration after a successful activation between the next possible activation.
+   */
+  public int minCooldown;
+  public int maxCooldown;
+
+
+  public void checkValues() {
+
+    minDuration = Math.abs(minDuration);
+    maxDuration = Math.abs(maxDuration);
+    if (maxDuration < minDuration) {
+      //Swap
+      int intermediate = minDuration;
+      minDuration = maxDuration;
+      maxDuration = intermediate;
+    }
+    minCooldown = Math.abs(minCooldown);
+    maxCooldown = Math.abs(maxCooldown);
+    if (maxCooldown < minCooldown) {
+      //Swap
+      int intermediate = minCooldown;
+      minCooldown = maxCooldown;
+      maxCooldown = intermediate;
+    }
+    minCost = Math.abs(minCost);
+    maxCost = Math.abs(maxCost);
+    if (maxCost < minCost) {
+      //Swap
+      float intermediate = minCost;
+      minCost = maxCost;
+      maxCost = intermediate;
+    }
+    flexChance = Math.max(0, Math.min(1, flexChance)); //Clamp
+  }
 }
 }

+ 68 - 60
src/holeg/addon/helper/HolonElementSketch.java

@@ -3,68 +3,76 @@ package holeg.addon.helper;
 import holeg.model.Constrain;
 import holeg.model.Constrain;
 import holeg.model.Flexibility;
 import holeg.model.Flexibility;
 import holeg.model.HolonElement;
 import holeg.model.HolonElement;
-import holeg.model.HolonObject;
 import holeg.model.HolonElement.Priority;
 import holeg.model.HolonElement.Priority;
+import holeg.model.HolonObject;
 import holeg.utility.math.Random;
 import holeg.utility.math.Random;
 
 
 public class HolonElementSketch {
 public class HolonElementSketch {
-	//HolonElement
-	public String name;
-	public int minAmount;
-	public int maxAmount;
-	public float energy;
-	
-	public String priority;
-	
-	public FlexibilitySketch onFlex;
-	public FlexibilitySketch offFlex;
-	
-	public HolonElementSketch(String name, float energy) {
-		this.name = name;
-		this.energy = energy;
-	}
-	public HolonElement createHolonElement(HolonObject parentObject, boolean active) {
-		HolonElement ele = new HolonElement(parentObject, name, energy);
-		ele.active = active;
-		if(onFlex != null && Random.nextDouble() < onFlex.flexChance)addFlex(ele, parentObject.getName(), true);
-		if(offFlex != null && Random.nextDouble() < offFlex.flexChance)addFlex(ele, parentObject.getName(), false);
-		ele.setPriority(Priority.valueOf(priority));
-		return ele;
-	}
-	
-	public void checkValues() {
-		minAmount = Math.abs(minAmount);
-		maxAmount = Math.abs(maxAmount);
-		if(maxAmount < minAmount) {
-			//Swap
-			int intermediate = minAmount;
-			minAmount = maxAmount;
-			maxAmount = intermediate;
-		}
-		if(onFlex != null) {
-			onFlex.checkValues();				
-		}
-		if(offFlex != null) {
-			onFlex.checkValues();				
-		}
-	}
-	
-	public void addFlex(HolonElement ele, String nameOfHolonObject,boolean onConstrain) {
-		Flexibility toCreateFlex = new Flexibility(ele);
-		FlexibilitySketch constrain = onConstrain?onFlex:offFlex;
-		
-		
-		toCreateFlex.name = nameOfHolonObject + "_" + ele.getName() + (onConstrain?"_OnFlex":"_OffFlex");
-		toCreateFlex.speed = 0;
-		toCreateFlex.setDuration(Random.nextIntegerInRange(constrain.minDuration, constrain.maxDuration+1));
-		toCreateFlex.cost = Random.nextFloatInRange(constrain.minCost, constrain.maxCost);
-		toCreateFlex.setCooldown(Random.nextIntegerInRange(constrain.minCooldown, constrain.maxCooldown+1));
-		toCreateFlex.offered=true;
-		if(onConstrain) {
-			toCreateFlex.constrainList.add(Constrain.createOnConstrain());
-		}else {
-			toCreateFlex.constrainList.add(Constrain.createOffConstrain());
-		}
-		ele.flexList.add(toCreateFlex);
-	}
+
+  //HolonElement
+  public String name;
+  public int minAmount;
+  public int maxAmount;
+  public float energy;
+
+  public String priority;
+
+  public FlexibilitySketch onFlex;
+  public FlexibilitySketch offFlex;
+
+  public HolonElementSketch(String name, float energy) {
+    this.name = name;
+    this.energy = energy;
+  }
+
+  public HolonElement createHolonElement(HolonObject parentObject, boolean active) {
+    HolonElement ele = new HolonElement(parentObject, name, energy);
+    ele.active = active;
+    if (onFlex != null && Random.nextDouble() < onFlex.flexChance) {
+      addFlex(ele, parentObject.getName(), true);
+    }
+    if (offFlex != null && Random.nextDouble() < offFlex.flexChance) {
+      addFlex(ele, parentObject.getName(), false);
+    }
+    ele.setPriority(Priority.valueOf(priority));
+    return ele;
+  }
+
+  public void checkValues() {
+    minAmount = Math.abs(minAmount);
+    maxAmount = Math.abs(maxAmount);
+    if (maxAmount < minAmount) {
+      //Swap
+      int intermediate = minAmount;
+      minAmount = maxAmount;
+      maxAmount = intermediate;
+    }
+    if (onFlex != null) {
+      onFlex.checkValues();
+    }
+    if (offFlex != null) {
+      offFlex.checkValues();
+    }
+  }
+
+  public void addFlex(HolonElement ele, String nameOfHolonObject, boolean onConstrain) {
+    Flexibility toCreateFlex = new Flexibility(ele);
+    FlexibilitySketch constrain = onConstrain ? onFlex : offFlex;
+
+    toCreateFlex.name =
+        nameOfHolonObject + "_" + ele.getName() + (onConstrain ? "_OnFlex" : "_OffFlex");
+    toCreateFlex.speed = 0;
+    toCreateFlex.setDuration(
+        Random.nextIntegerInRange(constrain.minDuration, constrain.maxDuration + 1));
+    toCreateFlex.cost = Random.nextFloatInRange(constrain.minCost, constrain.maxCost);
+    toCreateFlex.setCooldown(
+        Random.nextIntegerInRange(constrain.minCooldown, constrain.maxCooldown + 1));
+    toCreateFlex.offered = true;
+    if (onConstrain) {
+      toCreateFlex.constrainList.add(Constrain.createOnConstrain());
+    } else {
+      toCreateFlex.constrainList.add(Constrain.createOffConstrain());
+    }
+    ele.flexList.add(toCreateFlex);
+  }
 }
 }

+ 138 - 124
src/holeg/addon/helper/RandomPriotity.java

@@ -1,136 +1,150 @@
 package holeg.addon.helper;
 package holeg.addon.helper;
 
 
+import holeg.model.HolonElement.Priority;
 import java.util.Hashtable;
 import java.util.Hashtable;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
-
 import javax.swing.BorderFactory;
 import javax.swing.BorderFactory;
 import javax.swing.BoxLayout;
 import javax.swing.BoxLayout;
 import javax.swing.JLabel;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JPanel;
 import javax.swing.JSlider;
 import javax.swing.JSlider;
 
 
-import holeg.model.HolonElement.Priority;
+public class RandomPriotity extends JPanel {
+
+  private static final Logger log = Logger.getLogger(RandomPriotity.class.getName());
+  private final int start = 0, end = 100;
+  /**
+   * Its like a Gradient the Values are on one Axis from Start to End: |--start--lm--mh--he--end--|
+   * lm: lowMedium mh: mediumHigh he: highEssential
+   */
+  private int lm = 25, mh = 50, he = 75;
+  private JSlider lowChanceSlider = new JSlider(JSlider.HORIZONTAL, 0, 100, lm - start);
+  private JSlider mediumChanceSlider = new JSlider(JSlider.HORIZONTAL, 0, 100, mh - lm);
+  private JSlider highChanceSlider = new JSlider(JSlider.HORIZONTAL, 0, 100, he - mh);
+  private JSlider essentialChanceSlider = new JSlider(JSlider.HORIZONTAL, 0, 100, end - he);
+
+
+  public RandomPriotity() {
+    this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
+    this.add(initVisualizeSlider(this.lowChanceSlider, "Low"));
+    this.add(initVisualizeSlider(this.mediumChanceSlider, "Medium"));
+    this.add(initVisualizeSlider(this.highChanceSlider, "High"));
+    this.add(initVisualizeSlider(this.essentialChanceSlider, "Essential"));
+    lowChanceSlider.setToolTipText("" + ((double) lowChanceSlider.getValue() / 100.0));
+    mediumChanceSlider.setToolTipText("" + ((double) mediumChanceSlider.getValue() / 100.0));
+    highChanceSlider.setToolTipText("" + ((double) highChanceSlider.getValue() / 100.0));
+    essentialChanceSlider.setToolTipText("" + ((double) essentialChanceSlider.getValue() / 100.0));
+    lowChanceSlider.addChangeListener(actionEvent -> {
+      setLM(lowChanceSlider.getValue());
+      updateSliders();
+      lowChanceSlider.setToolTipText("" + ((double) lowChanceSlider.getValue() / 100.0));
+      log.info("lowChance = " + lowChanceSlider.getValue());
+    });
+    mediumChanceSlider.addChangeListener(actionEvent -> {
+      if (lm + mediumChanceSlider.getValue() <= 100) {
+        setMH(lm + mediumChanceSlider.getValue());
+      } else {
+        setLM(end - mediumChanceSlider.getValue());
+      }
+      updateSliders();
+      mediumChanceSlider.setToolTipText("" + ((double) mediumChanceSlider.getValue() / 100.0));
+      log.info("mediumChance = " + mediumChanceSlider.getValue());
+    });
+    highChanceSlider.addChangeListener(actionEvent -> {
+      if (mh + highChanceSlider.getValue() <= 100) {
+        setHE(mh + highChanceSlider.getValue());
+      } else {
+        setMH(end - highChanceSlider.getValue());
+      }
+      updateSliders();
+      highChanceSlider.setToolTipText("" + ((double) highChanceSlider.getValue() / 100.0));
+      log.info("highChance = " + highChanceSlider.getValue());
+    });
+    essentialChanceSlider.addChangeListener(actionEvent -> {
+      setHE(end - essentialChanceSlider.getValue());
+      updateSliders();
+      essentialChanceSlider.setToolTipText(
+          "" + ((double) essentialChanceSlider.getValue() / 100.0));
+      log.info("essentialChance = " + essentialChanceSlider.getValue());
+    });
+  }
+
+  private void setLM(int value) {
+    lm = clamp(value, 0, 100);
+    if (lm > mh) {
+      mh = lm;
+    }
+    if (lm > he) {
+      he = lm;
+    }
+  }
+
+  private void setMH(int value) {
+    mh = clamp(value, 0, 100);
+    if (mh < lm) {
+      lm = mh;
+    }
+    if (mh > he) {
+      he = mh;
+    }
+  }
+
+  private void setHE(int value) {
+    he = clamp(value, 0, 100);
+    if (he < lm) {
+      lm = he;
+    }
+    if (he < mh) {
+      mh = he;
+    }
+  }
+
+
+  private int clamp(int input, int min, int max) {
+    return Math.max(min, Math.min(max, input));
+  }
+
+
+  private void updateSliders() {
+    lowChanceSlider.setValue(lm - start);
+    mediumChanceSlider.setValue(mh - lm);
+    highChanceSlider.setValue(he - mh);
+    essentialChanceSlider.setValue(end - he);
+  }
+
+
+  private JSlider initVisualizeSlider(JSlider jslider, String name) {
+    jslider.setBorder(BorderFactory.createTitledBorder(name));
+    jslider.setMajorTickSpacing(50);
+    jslider.setMinorTickSpacing(5);
+    jslider.setPaintTicks(true);
+    Hashtable<Integer, JLabel> labelTable = new Hashtable<Integer, JLabel>();
+    labelTable.put(Integer.valueOf(0), new JLabel("0.0"));
+    labelTable.put(Integer.valueOf(50), new JLabel("0.5"));
+    labelTable.put(Integer.valueOf(100), new JLabel("1.0"));
+    jslider.setLabelTable(labelTable);
+    jslider.setPaintLabels(true);
+    return jslider;
+  }
+
+  public Priority getPriority() {
+    double randomDoubleInRange = Math.random() * 100.0;
+    if (randomDoubleInRange <= lm) {
+      return Priority.Low;
+    } else if (randomDoubleInRange <= mh) {
+      return Priority.Medium;
+    } else if (randomDoubleInRange <= he) {
+      return Priority.High;
+    } else {
+      return Priority.Essential;
+    }
+  }
 
 
-public class RandomPriotity extends JPanel{
-	private static final Logger log = Logger.getLogger(RandomPriotity.class.getName());
-	/**
-	 * Its like a Gradient the Values are on one Axis from Start to End:
-	 * |--start--lm--mh--he--end--|
-	 * lm: lowMedium
-	 * mh: mediumHigh
-	 * he: highEssential
-	 */
-	private int lm = 25 , mh = 50, he = 75;
-	private final int start = 0, end = 100;
-	
-	private JSlider lowChanceSlider = new JSlider(JSlider.HORIZONTAL,0, 100, lm - start);
-	private JSlider mediumChanceSlider = new JSlider(JSlider.HORIZONTAL,0, 100, mh - lm);
-	private JSlider highChanceSlider = new JSlider(JSlider.HORIZONTAL,0, 100, he - mh);
-	private JSlider essentialChanceSlider = new JSlider(JSlider.HORIZONTAL,0, 100, end - he);
-	
-	
-	public RandomPriotity(){
-		this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
-		this.add(initVisualizeSlider(this.lowChanceSlider, "Low"));
-		this.add(initVisualizeSlider(this.mediumChanceSlider, "Medium"));
-		this.add(initVisualizeSlider(this.highChanceSlider, "High"));
-		this.add(initVisualizeSlider(this.essentialChanceSlider, "Essential"));
-		lowChanceSlider.setToolTipText("" +((double)lowChanceSlider.getValue()/ 100.0));
-		mediumChanceSlider.setToolTipText("" +((double)mediumChanceSlider.getValue()/ 100.0));
-		highChanceSlider.setToolTipText("" +((double)highChanceSlider.getValue()/ 100.0));
-		essentialChanceSlider.setToolTipText("" +((double)essentialChanceSlider.getValue()/ 100.0));
-		lowChanceSlider.addChangeListener(actionEvent ->{
-			setLM(lowChanceSlider.getValue());
-			updateSliders();
-			lowChanceSlider.setToolTipText("" +((double)lowChanceSlider.getValue()/ 100.0));
-			log.info("lowChance = " +lowChanceSlider.getValue());
-		});
-		mediumChanceSlider.addChangeListener(actionEvent ->{
-			if(lm + mediumChanceSlider.getValue() <= 100) setMH(lm + mediumChanceSlider.getValue());
-			else setLM(end - mediumChanceSlider.getValue());
-			updateSliders();
-			mediumChanceSlider.setToolTipText("" +((double)mediumChanceSlider.getValue()/ 100.0));
-			log.info("mediumChance = " +  mediumChanceSlider.getValue());
-		});
-		highChanceSlider.addChangeListener(actionEvent ->{
-			if(mh + highChanceSlider.getValue() <= 100) setHE(mh + highChanceSlider.getValue());
-			else setMH(end - highChanceSlider.getValue());
-			updateSliders();
-			highChanceSlider.setToolTipText("" +((double)highChanceSlider.getValue()/ 100.0));
-			log.info("highChance = " +highChanceSlider.getValue());
-		});
-		essentialChanceSlider.addChangeListener(actionEvent ->{
-			setHE(end - essentialChanceSlider.getValue());
-			updateSliders();
-			essentialChanceSlider.setToolTipText("" +((double)essentialChanceSlider.getValue()/ 100.0));
-			log.info("essentialChance = " +essentialChanceSlider.getValue());
-		});
-	}
-
-	private void setLM(int value) {
-		lm = clamp(value, 0, 100);
-		if(lm > mh) mh = lm;
-		if(lm > he) he = lm;
-	}
-	
-	private void setMH(int value) {
-		mh = clamp(value, 0, 100);
-		if(mh < lm) lm = mh;
-		if(mh > he) he = mh;
-	}
-	
-	private void setHE(int value) {
-		he = clamp(value, 0, 100);
-		if(he < lm) lm = he;
-		if(he < mh) mh = he;
-	}
-	
-	
-	private int clamp(int input, int min , int max) {
-		return Math.max(min, Math.min(max, input));
-	}
-	
-	
-	private void updateSliders(){
-		lowChanceSlider.setValue(lm - start);
-		mediumChanceSlider.setValue(mh - lm);
-		highChanceSlider.setValue(he - mh);
-		essentialChanceSlider.setValue(end - he);
-	}
-	
-	
-
-	private JSlider initVisualizeSlider(JSlider jslider, String name) {
-		jslider.setBorder(BorderFactory.createTitledBorder(name));
-		jslider.setMajorTickSpacing(50);
-		jslider.setMinorTickSpacing(5);
-		jslider.setPaintTicks(true);
-		Hashtable<Integer, JLabel> labelTable = new Hashtable<Integer, JLabel>();
-		labelTable.put( Integer.valueOf( 0 ), new JLabel("0.0") );
-		labelTable.put( Integer.valueOf( 50 ), new JLabel("0.5") );
-		labelTable.put( Integer.valueOf( 100 ), new JLabel("1.0") );
-		jslider.setLabelTable( labelTable );
-		jslider.setPaintLabels(true);
-		return jslider;
-	}
-	
-	public Priority getPriority() {
-		double randomDoubleInRange = Math.random() * 100.0;
-		if(randomDoubleInRange <= lm) {
-			return Priority.Low;
-		} else if(randomDoubleInRange <= mh) {
-			return Priority.Medium;
-		} else if(randomDoubleInRange <= he) {
-			return Priority.High;
-		} else {
-			return Priority.Essential;
-		}
-	}
-	@Override
-	public void setEnabled(boolean value) {
-		lowChanceSlider.setEnabled(value);
-		mediumChanceSlider.setEnabled(value);
-		highChanceSlider.setEnabled(value);
-		essentialChanceSlider.setEnabled(value);
-	}
+  @Override
+  public void setEnabled(boolean value) {
+    lowChanceSlider.setEnabled(value);
+    mediumChanceSlider.setEnabled(value);
+    highChanceSlider.setEnabled(value);
+    essentialChanceSlider.setEnabled(value);
+  }
 }
 }

+ 202 - 194
src/holeg/algorithm/binary/AcoAlgorithm.java

@@ -1,211 +1,219 @@
 package holeg.algorithm.binary;
 package holeg.algorithm.binary;
 
 
+import holeg.api.AlgorithmFrameworkFlex;
+import holeg.utility.math.decimal.Format;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
 import java.util.ListIterator;
 import java.util.ListIterator;
-
 import javax.swing.JFrame;
 import javax.swing.JFrame;
 
 
-import holeg.api.AlgorithmFrameworkFlex;
-import holeg.utility.math.decimal.Format;
+public class AcoAlgorithm extends AlgorithmFrameworkFlex {
+
+  //Parameter for Algo with default Values:
+  /**
+   * Should be even.
+   */
+  private int popsize = 20;
+  private int maxGenerations = 200;
+  /**
+   * The vaporization factor;
+   */
+  private double p = 0.3;
+  private double convergenceFactorReset = 0.99;
+  private boolean moreInformation = false;
+
+
+  public AcoAlgorithm() {
+    super();
+    addIntParameter("Population size", popsize, intValue -> popsize = intValue, () -> popsize, 1);
+    addIntParameter("Generations", maxGenerations, intValue -> maxGenerations = intValue,
+        () -> maxGenerations, 1);
+    addDoubleParameter("Vaporization rate", p, doubleValue -> p = doubleValue, () -> p, 0.0, 1.0);
+    addDoubleParameter("Convergence factor threshold", convergenceFactorReset,
+        doubleValue -> convergenceFactorReset = doubleValue, () -> convergenceFactorReset, 0.0,
+        1.0);
+    addBooleanParameter("Detailed information", moreInformation,
+        booleanValue -> moreInformation = booleanValue);
+  }
+
+
+  public static void main(String[] args) {
+    JFrame newFrame = new JFrame("exampleWindow");
+    AcoAlgorithm instance = new AcoAlgorithm();
+    newFrame.setContentPane(instance.getPanel());
+    newFrame.pack();
+    newFrame.setVisible(true);
+    newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+  }
+
+
+  @Override
+  protected int getProgressBarMaxCount() {
+    return rounds * popsize * maxGenerations;
+  }
+
+
+  /**
+   * Algorithm 20 !! Fitness is better when smaller.: PseudoCode: Best <- actual; pheromones =
+   * initPheromons(); for(maxGeneration times){ population = createSolutionsBiasedBy(pheromones);
+   * for(each Individual i from population){ fitness <- evaluatePosition(i); if(fitness <
+   * best.fitnessValue) Best <- i; } vaporizeIntensifiePheromons(pheromones); }
+   *
+   * @return
+   */
+  @Override
+  protected Individual executeAlgo() {
+    Individual best = new Individual();
+    best.position = extractPositionAndAccess();
+    if (moreInformation) {
+      console.println("Bit-Array_length: " + best.position.size());
+    }
+    best.fitness = evaluatePosition(best.position);
+    List<Double> runList = new ArrayList<Double>();
+    runList.add(best.fitness);
+    console.print("Start with: " + Format.doubleFixedPlaces(2, best.fitness));
+    if (moreInformation) {
+      console.println("");
+    }
+    if (best.position.isEmpty()) {
+      return best;
+    }
+    int problemSize = best.position.size();
+    List<Double> pheromones = initPheromones(problemSize);
+    List<Individual> population = new ArrayList<Individual>();
+    if (moreInformation) {
+      console.println("Size To Test:" + population.size());
+    }
+    for (int generation = 0; generation < maxGenerations; generation++) {
+      population.clear();
+      population = constructSolutionsBiasedBy(pheromones);
+      if (moreInformation) {
+        console.println("Generation" + generation + " start with Fitness: " + best.fitness);
+      }
+      for (Individual i : population) {
+        i.fitness = evaluatePosition(i.position);
+        if (moreInformation) {
+          console.println("Fitness" + Format.doubleFixedPlaces(2, i.fitness));
+        }
+        if (i.fitness < best.fitness) {
+          best = i;
+        }
+      }
+      runList.add(best.fitness);
+      if (moreInformation) {
+        console.println("________________");
+      }
+      vaporizeIntensifiePheromons(pheromones, best.position, problemSize);
+      double cf = calculateConvergenceFactor(pheromones, problemSize);
+      if (moreInformation) {
+        console.println("ConvergenceFactor = " + cf);
+      }
+      if (cf > this.convergenceFactorReset) {
+        pheromones = initPheromones(problemSize);
+      }
+      if (cancel) {
+        return null;
+      }
+    }
+
+    console.println("   End With:" + Format.doubleFixedPlaces(2, best.fitness));
+    this.runList = runList;
+    return best;
+
+  }
+
+
+  /**
+   * tj1 is the pheromon level in the j position cf is the convergence factor cf e [0;1] difference
+   * = | tj1 - tj0 | = | tj1 - (1 - tj1) |
+   *
+   * @param pheromones
+   * @return cf
+   */
+  private double calculateConvergenceFactor(List<Double> pheromones, int problemSize) {
+    double sumOfDifference = pheromones.stream().map(tj1 -> Math.abs(tj1 - (1.0 - tj1)))
+        .reduce(0.0, Double::sum);
+    double cf = sumOfDifference / (double) problemSize;
+    return cf;
+  }
+
+  /**
+   * pheromone <- (1-p) * pheromone; if(best is true at this position) pheromone <- pheromone + p;
+   *
+   * @param pheromones
+   * @param position
+   */
+  private void vaporizeIntensifiePheromons(List<Double> pheromones, List<Boolean> position,
+      int problemSize) {
+    ListIterator<Double> iterPheromone = pheromones.listIterator();
+    ListIterator<Boolean> iterBest = position.listIterator();
+    for (int i = 0; i < problemSize; i++) {
+      double pheromone = iterPheromone.next();
+      boolean bestDecision = iterBest.next();
+      iterPheromone.set((1.0 - p) * pheromone + (bestDecision ? p : 0.0));
+    }
+  }
+
+  /**
+   * @param pheromones
+   * @return
+   */
+  private List<Individual> constructSolutionsBiasedBy(List<Double> pheromones) {
+    List<Individual> population = new ArrayList<Individual>();
+    for (int i = 0; i < popsize; i++) {
+      population.add(constructASolutionBiasedBy(pheromones));
+    }
+    return population;
+  }
+
+
+  /**
+   * Walks the path with a ant and decide by pheromones if should take true or false; A pheromone
+   * have a level of 0 < pheromone < 1. A Pheromone is  equal to the probability.
+   *
+   * @param pheromones
+   * @return
+   */
+  private Individual constructASolutionBiasedBy(List<Double> pheromones) {
+    Individual result = new Individual();
+    result.position = new ArrayList<Boolean>();
+    for (double pheromone : pheromones) {
+      result.position.add((Random.nextDouble() < pheromone));
+    }
+    return result;
+  }
+
+  /**
+   * Initialize Pheromons with 0.5
+   */
+  private List<Double> initPheromones(int problemSize) {
+    List<Double> result = new ArrayList<Double>();
+    for (int i = 0; i < problemSize; i++) {
+      result.add(0.5);
+    }
+    return result;
+  }
+
 
 
-public class AcoAlgorithm extends AlgorithmFrameworkFlex{
-	
-	//Parameter for Algo with default Values:
-	/**
-	 * Should be even.
-	 */
-	private int popsize = 20;
-	private int maxGenerations = 200;
-	/**
-	 * The vaporization factor;
-	 */
-	private double p = 0.3;
-	private double convergenceFactorReset = 0.99;
-	private boolean moreInformation = false;
-	
-	
-	
-	public AcoAlgorithm() {
-		super();
-		addIntParameter("Population size", popsize, intValue -> popsize = intValue, () -> popsize, 1);
-		addIntParameter("Generations", maxGenerations, intValue -> maxGenerations = intValue, () -> maxGenerations, 1);
-		addDoubleParameter("Vaporization rate", p, doubleValue -> p = doubleValue, () -> p, 0.0, 1.0);
-		addDoubleParameter("Convergence factor threshold", convergenceFactorReset, doubleValue -> convergenceFactorReset = doubleValue, () -> convergenceFactorReset, 0.0, 1.0);
-		addBooleanParameter("Detailed information", moreInformation, booleanValue -> moreInformation = booleanValue);
-	}
-	
-	
-	
-	public static void main(String[] args)
-	{
-	      JFrame newFrame = new JFrame("exampleWindow");
-	      AcoAlgorithm instance = new AcoAlgorithm();
-	      newFrame.setContentPane(instance.getPanel());
-	      newFrame.pack();
-	      newFrame.setVisible(true);
-	      newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
-	}
-
-	
-
-
-	@Override
-	protected int getProgressBarMaxCount() {
-		return rounds * popsize * maxGenerations;
-	}
-	
-	
-	/** 	
-	 * 	Algorithm 20 !! Fitness is better when smaller.: 
-	 *  PseudoCode:
-	 *  Best <- actual;
-	 *  pheromones = initPheromons();
-	 * 	for(maxGeneration times){
-	 * 		population = createSolutionsBiasedBy(pheromones);
-	 * 		for(each Individual i from population){
-	 * 			fitness <- evaluatePosition(i);
-	 * 			if(fitness < best.fitnessValue) Best <- i;
-	 * 		}
-	 * 		vaporizeIntensifiePheromons(pheromones);
-	 * 	}
-	 * @return 
-	 */
-	@Override
-	protected Individual executeAlgo() {
-		Individual best = new Individual();
-		best.position = extractPositionAndAccess();
-		if(moreInformation )console.println("Bit-Array_length: " + best.position.size());
-		best.fitness = evaluatePosition(best.position);
-		List<Double> runList = new ArrayList<Double>();
-		runList.add(best.fitness);
-		console.print("Start with: " + Format.doubleFixedPlaces(2, best.fitness));
-		if(moreInformation)console.println("");
-		if(best.position.isEmpty()) return best;
-		int problemSize = best.position.size();
-		List<Double> pheromones = initPheromones(problemSize);
-		List<Individual> population = new ArrayList<Individual>();
-		if(moreInformation)console.println("Size To Test:" + population.size());
-		for(int generation = 0; generation< maxGenerations; generation++) {
-			population.clear();
-			population = constructSolutionsBiasedBy(pheromones);
-			if(moreInformation)console.println("Generation" + generation + " start with Fitness: " + best.fitness);
-			for(Individual i : population) {
-				i.fitness = evaluatePosition(i.position);
-				if(moreInformation)console.println("Fitness" + Format.doubleFixedPlaces(2, i.fitness));
-				if(i.fitness < best.fitness) best = i;	
-			}
-			runList.add(best.fitness);
-			if(moreInformation)console.println("________________");
-			vaporizeIntensifiePheromons(pheromones, best.position, problemSize);
-			double cf = calculateConvergenceFactor(pheromones, problemSize);
-			if(moreInformation)console.println("ConvergenceFactor = " + cf);
-			if(cf > this.convergenceFactorReset) {
-				pheromones = initPheromones(problemSize);
-			}
-			if(cancel)return null;
-		}
-		
-		
-		console.println("   End With:" + Format.doubleFixedPlaces(2, best.fitness));
-		this.runList = runList;
-		return best;
-		
-	}
-			
-			
-	/**
-	 * tj1 is the pheromon level in the j position
-	 * cf is the convergence factor cf e [0;1]
-	 * difference = | tj1 - tj0 | = | tj1 - (1 - tj1) |
-	 * 
-	 * 
-	 * 
-	 * @param pheromones
-	 * @return cf
-	 */
-	private double calculateConvergenceFactor(List<Double> pheromones,int problemSize) {
-		double sumOfDifference = pheromones.stream().map(tj1 -> Math.abs(tj1 - (1.0 - tj1))).reduce(0.0, Double::sum);
-		double cf = sumOfDifference / (double)problemSize;
-		return cf;
-	}
-	/**
-	 * pheromone <- (1-p) * pheromone;
-	 * if(best is true at this position) pheromone <- pheromone + p;
-	 * @param pheromones
-	 * @param position
-	 */
-	private void vaporizeIntensifiePheromons(List<Double> pheromones, List<Boolean> position, int problemSize) {
-		ListIterator<Double> iterPheromone = pheromones.listIterator();
-		ListIterator<Boolean> iterBest = position.listIterator();
-		for(int i = 0; i < problemSize; i++) {
-			double pheromone = iterPheromone.next();
-			boolean bestDecision = iterBest.next();
-			iterPheromone.set((1.0 - p) * pheromone + (bestDecision?p:0.0));
-		}
-	}
-	/**
-	 * 
-	 * @param pheromones
-	 * @return
-	 */
-	private List<Individual> constructSolutionsBiasedBy(List<Double> pheromones) {
-		List<Individual> population =  new ArrayList<Individual>();
-		for(int i = 0; i < popsize; i++) {
-			population.add(constructASolutionBiasedBy(pheromones));
-		}
-		return population;
-	}
-	
-	
-	/**
-	 * Walks the path with a ant and decide by pheromones if should take true or false;
-	 * A pheromone have a level of 0 < pheromone < 1.
-	 * A Pheromone is  equal to the probability.
-	 * @param pheromones
-	 * @return
-	 */
-	private Individual constructASolutionBiasedBy(List<Double> pheromones) {
-		Individual result = new Individual();
-		result.position = new ArrayList<Boolean>();
-		for(double pheromone : pheromones) {
-			result.position.add((Random.nextDouble() < pheromone));
-		}
-		return result;
-	}
-	/**
-	 * Initialize Pheromons with 0.5
-	 */
-	private List<Double> initPheromones(int problemSize) {
-		List<Double> result = new ArrayList<Double>();
-		for(int i = 0; i < problemSize;i++) {
-			result.add(0.5);
-		}
-		return result;
-	}
-
-
-
-	@Override
-	protected String algoInformationToPrint() {
+  @Override
+  protected String algoInformationToPrint() {
 //		private int popsize = 20;
 //		private int popsize = 20;
 //		private int maxGenerations = 200;
 //		private int maxGenerations = 200;
 //		private double p = 0.3;
 //		private double p = 0.3;
 //		private double convergenceFactorReset = 0.99;
 //		private double convergenceFactorReset = 0.99;
-		return "AcoAlgo"
-				+ " Rounds: " + rounds 
-				+ " Iterations: " + maxGenerations 
-				+ " Individuals: " +  popsize
-				+ " vaporization: " +  Format.doubleAllPlaces(p)
-				+ " convergenceFactorReset: " +  Format.doubleAllPlaces(convergenceFactorReset);
-	}
+    return "AcoAlgo"
+        + " Rounds: " + rounds
+        + " Iterations: " + maxGenerations
+        + " Individuals: " + popsize
+        + " vaporization: " + Format.doubleAllPlaces(p)
+        + " convergenceFactorReset: " + Format.doubleAllPlaces(convergenceFactorReset);
+  }
 
 
 
 
+  @Override
+  protected String plottFileName() {
+    return "plottAcoAlgo.txt";
+  }
 
 
-	@Override
-	protected String plottFileName() {
-		return "plottAcoAlgo.txt";
-	}
 
 
-	
 }
 }

+ 374 - 382
src/holeg/algorithm/binary/BaseLine.java

@@ -1,5 +1,15 @@
 package holeg.algorithm.binary;
 package holeg.algorithm.binary;
 
 
+import holeg.api.AddOn;
+import holeg.model.AbstractCanvasObject;
+import holeg.model.GroupNode;
+import holeg.model.HolonElement;
+import holeg.model.HolonObject;
+import holeg.model.HolonSwitch;
+import holeg.model.HolonSwitch.SwitchMode;
+import holeg.model.HolonSwitch.SwitchState;
+import holeg.model.Model;
+import holeg.ui.controller.Control;
 import java.awt.BorderLayout;
 import java.awt.BorderLayout;
 import java.awt.Component;
 import java.awt.Component;
 import java.awt.Dimension;
 import java.awt.Dimension;
@@ -10,7 +20,6 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.List;
 import java.util.Optional;
 import java.util.Optional;
 import java.util.stream.Stream;
 import java.util.stream.Stream;
-
 import javax.swing.BorderFactory;
 import javax.swing.BorderFactory;
 import javax.swing.ImageIcon;
 import javax.swing.ImageIcon;
 import javax.swing.JButton;
 import javax.swing.JButton;
@@ -23,256 +32,229 @@ import javax.swing.JScrollPane;
 import javax.swing.JSplitPane;
 import javax.swing.JSplitPane;
 import javax.swing.JTextArea;
 import javax.swing.JTextArea;
 
 
-import holeg.api.AddOn;
-import holeg.model.AbstractCanvasObject;
-import holeg.model.GroupNode;
-import holeg.model.HolonElement;
-import holeg.model.HolonObject;
-import holeg.model.HolonSwitch;
-import holeg.model.HolonSwitch.SwitchMode;
-import holeg.model.HolonSwitch.SwitchState;
-import holeg.ui.controller.Control;
-import holeg.model.Model;
 
 
+public class BaseLine implements AddOn {
 
 
+  //Parameter for Algo with default Values:
+  private boolean closeSwitches = true;
 
 
+  //Settings For GroupNode using and cancel
+  private boolean useGroupNode = false;
+  private Optional<GroupNode> groupNode = Optional.empty();
+  private boolean cancel = false;
 
 
 
 
-public class BaseLine implements AddOn {
-	//Parameter for Algo with default Values:
-	private boolean closeSwitches = true;
-	
-	//Settings For GroupNode using and cancel
-	private boolean useGroupNode = false;
-	private Optional<GroupNode> groupNode = Optional.empty();
-	private boolean cancel = false;
-
-
-	//Parameter defined by Algo
-	private HashMap<Integer, AccessWrapper> access;
-	private List<Boolean> initialState;
-	private List<HolonSwitch> switchList;
-	private List<HolonObject> objectList;
-	
-	//Gui Part:
-	private Control  control;
-	private JTextArea textArea;
-	private JPanel content = new JPanel();
-	//ProgressBar
-	private long startTime;
-	private Thread runThread;
-	
-	
-	public static void main(String[] args)
-	{
-	      JFrame newFrame = new JFrame("exampleWindow");
-	      BaseLine instance = new BaseLine();
-	      newFrame.setContentPane(instance.getPanel());
-	      newFrame.pack();
-	      newFrame.setVisible(true);
-	      newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
-	}
-	public BaseLine() {
-		content.setLayout(new BorderLayout());
-	
-		textArea = new JTextArea();
-		textArea.setEditable(false);
-		JScrollPane scrollPane = new JScrollPane(textArea);
-		JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
-				createOptionPanel() , scrollPane);
-		splitPane.setResizeWeight(0.0);
-		content.add(splitPane, BorderLayout.CENTER);
-		content.setPreferredSize(new Dimension(800,800));	
-	}
-	public JPanel createOptionPanel() {
-		JPanel optionPanel = new JPanel(new BorderLayout());
-		JScrollPane scrollPane = new JScrollPane(createParameterPanel());
-		scrollPane.setBorder(BorderFactory.createTitledBorder("Parameter"));
-		optionPanel.add(scrollPane,  BorderLayout.CENTER);
-		optionPanel.add(createButtonPanel(), BorderLayout.PAGE_END);
-		return optionPanel;
-	}
-	
-	private Component createParameterPanel() {
-		JPanel parameterPanel = new JPanel(null);
-		parameterPanel.setPreferredSize(new Dimension(510,300));
-		
-		
-	
-		JLabel showDiagnosticsLabel = new JLabel("Set all switches closed:");
-		showDiagnosticsLabel.setBounds(200, 60, 170, 20);
-		parameterPanel.add(showDiagnosticsLabel);		
-	
-		
-		JPanel borderPanel = new JPanel(null);
-		borderPanel.setBounds(200, 85, 185, 50);
-		borderPanel.setBorder(BorderFactory.createTitledBorder(""));
-		parameterPanel.add(borderPanel);	
-		
-		JLabel showGroupNodeLabel = new JLabel("Use Group Node:");
-		showGroupNodeLabel.setBounds(10, 1, 170, 20);
-		borderPanel.add(showGroupNodeLabel);	
-		
-		JButton selectGroupNodeButton = new JButton("Select GroupNode");
-		selectGroupNodeButton.setEnabled(false);
-		selectGroupNodeButton.setBounds(10, 25, 165, 20);
-		selectGroupNodeButton.addActionListener(actionEvent -> selectGroupNode());
-		borderPanel.add(selectGroupNodeButton);	
-		
-		JCheckBox useGroupNodeCheckBox = new JCheckBox();
-		useGroupNodeCheckBox.setSelected(false);
-		useGroupNodeCheckBox.setBounds(155, 1, 25, 20);
-		useGroupNodeCheckBox.addActionListener(actionEvent -> {
-			useGroupNode = useGroupNodeCheckBox.isSelected();
-			selectGroupNodeButton.setEnabled(useGroupNode);
-		});
-		borderPanel.add(useGroupNodeCheckBox);
-		
-		
-		JCheckBox switchesCheckBox = new JCheckBox();
-		switchesCheckBox.setSelected(closeSwitches);
-		switchesCheckBox.setBounds(370, 60, 25, 20);
-		switchesCheckBox.addActionListener(actionEvent -> closeSwitches = switchesCheckBox.isSelected());
-		parameterPanel.add(switchesCheckBox);
-		
-
-		
-		
-		return parameterPanel;
-	}
-	public JPanel createButtonPanel() {
-		JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
-		JButton cancelButton =  new JButton("Cancel Run");
-		cancelButton.addActionListener(actionEvent -> cancel());
-		buttonPanel.add(cancelButton);
-		JButton clearButton =  new JButton("Clear Console");
-		clearButton.addActionListener(actionEvent -> clear());
-		buttonPanel.add(clearButton);
-		JButton resetButton =  new JButton("Reset");
-		resetButton.setToolTipText("Resets the State to before the Algorithm has runed.");
-		resetButton.addActionListener(actionEvent -> reset());
-		buttonPanel.add(resetButton);
-		JButton runButton =  new JButton("Run");
-		runButton.addActionListener(actionEvent -> {
-			Runnable task = () -> run();
-			runThread = new Thread(task);
-			runThread.start();
-		});
-		buttonPanel.add(runButton);
-		return buttonPanel;
-	}
-	private void cancel() {
-		if(runThread.isAlive()) {
-			println("");
-			println("Cancel run.");
-			cancel = true;
-		} else {
-			println("Nothing to cancel.");
-		}
-	}
-	
-	private void run() {
-		cancel = false;
-		disableGuiInput(true);
-		startTimer();
-		executeBaseLine();
-		if(cancel) {
-			reset();
-			disableGuiInput(false);
-			return;
-		}
-		printElapsedTime();
-		disableGuiInput(false);
-	}
-	
-	private void reset() {
-		if(initialState != null) {
-			println("Resetting..");
-			resetState();
-			updateVisual();
-		}else {
-			println("No run inistialized.");
-		}
-	}
-	
-	
-	private void disableGuiInput(boolean bool) {
-		control.guiSetEnabled(bool);
-	}
-	
-	
-	
-
-	
-	
-	@Override
-	public JPanel getPanel() {
-		return content;
-	}
-	@Override
-	public void setController(Control control) {
-		this.control = control;
-		
-	}
-	private void clear() {
-		textArea.setText("");
-	}
-	private void println(String message) {
-		textArea.append(message  + "\n");
-	}
-	private void selectGroupNode() {
-		Object[] possibilities = control.getModel().getCanvas().getAllGroupNodeObjectsRecursive().toArray();
-		GroupNode selected = (GroupNode) JOptionPane.showInputDialog(content, "Select GroupNode:", "GroupNode?",  JOptionPane.OK_OPTION,new ImageIcon(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)) , possibilities, "");
-		if(selected != null) {
-			println("Selected: " + selected);
-			groupNode = Optional.of(selected);
-		}
-		
-	}
-	
-	private void startTimer(){
-		startTime = System.currentTimeMillis();
-	}
-	private void printElapsedTime(){
-		long elapsedMilliSeconds = System.currentTimeMillis() - startTime;
-		println("Execution Time of Algo in Milliseconds:" + elapsedMilliSeconds);
-	}
-	
-	
-	
-	
-	//Algo Part:
-	/**
-	 * The Execution of the BaseLine Algo.
-	 * 
-	 * 
-	 * Begin
-	 * 		set HolonElements aktiv;
-	 * 		for(All Networks) do
-	 * 			if(not (production < consumption)) continue;
-	 * 			inAktiveCount = 0;
-	 * 			while(inAktiveCount <= consumerWihtMaxNumberElements) do
-	 * 				conList = createListWithConsumerThatHaveInActiveElementsAmountOf(inAktiveCount);
-	 * 				sortByBiggestElement(conList);
-	 * 				for(con : conList) do
-	 * 					for(element : con.getAllActiveElementsSortByConsumption) do 
-	 * 						if(element <= production) do 
-	 * 							set element inAktiv;
-	 * 							continue;
-	 * 						end do
-	 * 					end do
-	 * 				end do
-	 * 				inAktiveCount += 1;
-	 * 			end while
-	 * 		end for
-	 * End
-	 * 
-	 */
-	private void executeBaseLine() {
-		extractPositionAndAccess();
-		if(closeSwitches)setAllSwitchesClosed();
-		setHolonElemntsAktiv();
-		control.calculateStateForCurrentIteration();
+  //Parameter defined by Algo
+  private HashMap<Integer, AccessWrapper> access;
+  private List<Boolean> initialState;
+  private List<HolonSwitch> switchList;
+  private List<HolonObject> objectList;
+
+  //Gui Part:
+  private Control control;
+  private JTextArea textArea;
+  private JPanel content = new JPanel();
+  //ProgressBar
+  private long startTime;
+  private Thread runThread;
+
+
+  public BaseLine() {
+    content.setLayout(new BorderLayout());
+
+    textArea = new JTextArea();
+    textArea.setEditable(false);
+    JScrollPane scrollPane = new JScrollPane(textArea);
+    JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
+        createOptionPanel(), scrollPane);
+    splitPane.setResizeWeight(0.0);
+    content.add(splitPane, BorderLayout.CENTER);
+    content.setPreferredSize(new Dimension(800, 800));
+  }
+
+  public static void main(String[] args) {
+    JFrame newFrame = new JFrame("exampleWindow");
+    BaseLine instance = new BaseLine();
+    newFrame.setContentPane(instance.getPanel());
+    newFrame.pack();
+    newFrame.setVisible(true);
+    newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+  }
+
+  public JPanel createOptionPanel() {
+    JPanel optionPanel = new JPanel(new BorderLayout());
+    JScrollPane scrollPane = new JScrollPane(createParameterPanel());
+    scrollPane.setBorder(BorderFactory.createTitledBorder("Parameter"));
+    optionPanel.add(scrollPane, BorderLayout.CENTER);
+    optionPanel.add(createButtonPanel(), BorderLayout.PAGE_END);
+    return optionPanel;
+  }
+
+  private Component createParameterPanel() {
+    JPanel parameterPanel = new JPanel(null);
+    parameterPanel.setPreferredSize(new Dimension(510, 300));
+
+    JLabel showDiagnosticsLabel = new JLabel("Set all switches closed:");
+    showDiagnosticsLabel.setBounds(200, 60, 170, 20);
+    parameterPanel.add(showDiagnosticsLabel);
+
+    JPanel borderPanel = new JPanel(null);
+    borderPanel.setBounds(200, 85, 185, 50);
+    borderPanel.setBorder(BorderFactory.createTitledBorder(""));
+    parameterPanel.add(borderPanel);
+
+    JLabel showGroupNodeLabel = new JLabel("Use Group Node:");
+    showGroupNodeLabel.setBounds(10, 1, 170, 20);
+    borderPanel.add(showGroupNodeLabel);
+
+    JButton selectGroupNodeButton = new JButton("Select GroupNode");
+    selectGroupNodeButton.setEnabled(false);
+    selectGroupNodeButton.setBounds(10, 25, 165, 20);
+    selectGroupNodeButton.addActionListener(actionEvent -> selectGroupNode());
+    borderPanel.add(selectGroupNodeButton);
+
+    JCheckBox useGroupNodeCheckBox = new JCheckBox();
+    useGroupNodeCheckBox.setSelected(false);
+    useGroupNodeCheckBox.setBounds(155, 1, 25, 20);
+    useGroupNodeCheckBox.addActionListener(actionEvent -> {
+      useGroupNode = useGroupNodeCheckBox.isSelected();
+      selectGroupNodeButton.setEnabled(useGroupNode);
+    });
+    borderPanel.add(useGroupNodeCheckBox);
+
+    JCheckBox switchesCheckBox = new JCheckBox();
+    switchesCheckBox.setSelected(closeSwitches);
+    switchesCheckBox.setBounds(370, 60, 25, 20);
+    switchesCheckBox.addActionListener(
+        actionEvent -> closeSwitches = switchesCheckBox.isSelected());
+    parameterPanel.add(switchesCheckBox);
+
+    return parameterPanel;
+  }
+
+  public JPanel createButtonPanel() {
+    JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+    JButton cancelButton = new JButton("Cancel Run");
+    cancelButton.addActionListener(actionEvent -> cancel());
+    buttonPanel.add(cancelButton);
+    JButton clearButton = new JButton("Clear Console");
+    clearButton.addActionListener(actionEvent -> clear());
+    buttonPanel.add(clearButton);
+    JButton resetButton = new JButton("Reset");
+    resetButton.setToolTipText("Resets the State to before the Algorithm has runed.");
+    resetButton.addActionListener(actionEvent -> reset());
+    buttonPanel.add(resetButton);
+    JButton runButton = new JButton("Run");
+    runButton.addActionListener(actionEvent -> {
+      Runnable task = () -> run();
+      runThread = new Thread(task);
+      runThread.start();
+    });
+    buttonPanel.add(runButton);
+    return buttonPanel;
+  }
+
+  private void cancel() {
+    if (runThread.isAlive()) {
+      println("");
+      println("Cancel run.");
+      cancel = true;
+    } else {
+      println("Nothing to cancel.");
+    }
+  }
+
+  private void run() {
+    cancel = false;
+    disableGuiInput(true);
+    startTimer();
+    executeBaseLine();
+    if (cancel) {
+      reset();
+      disableGuiInput(false);
+      return;
+    }
+    printElapsedTime();
+    disableGuiInput(false);
+  }
+
+  private void reset() {
+    if (initialState != null) {
+      println("Resetting..");
+      resetState();
+      updateVisual();
+    } else {
+      println("No run inistialized.");
+    }
+  }
+
+
+  private void disableGuiInput(boolean bool) {
+    control.guiSetEnabled(bool);
+  }
+
+
+  @Override
+  public JPanel getPanel() {
+    return content;
+  }
+
+  @Override
+  public void setController(Control control) {
+    this.control = control;
+
+  }
+
+  private void clear() {
+    textArea.setText("");
+  }
+
+  private void println(String message) {
+    textArea.append(message + "\n");
+  }
+
+  private void selectGroupNode() {
+    Object[] possibilities = control.getModel().getCanvas().getAllGroupNodeObjectsRecursive()
+        .toArray();
+    GroupNode selected = (GroupNode) JOptionPane.showInputDialog(content, "Select GroupNode:",
+        "GroupNode?", JOptionPane.OK_OPTION,
+        new ImageIcon(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)), possibilities, "");
+    if (selected != null) {
+      println("Selected: " + selected);
+      groupNode = Optional.of(selected);
+    }
+
+  }
+
+  private void startTimer() {
+    startTime = System.currentTimeMillis();
+  }
+
+  private void printElapsedTime() {
+    long elapsedMilliSeconds = System.currentTimeMillis() - startTime;
+    println("Execution Time of Algo in Milliseconds:" + elapsedMilliSeconds);
+  }
+
+  //Algo Part:
+
+  /**
+   * The Execution of the BaseLine Algo.
+   * <p>
+   * <p>
+   * Begin set HolonElements aktiv; for(All Networks) do if(not (production < consumption))
+   * continue; inAktiveCount = 0; while(inAktiveCount <= consumerWihtMaxNumberElements) do conList =
+   * createListWithConsumerThatHaveInActiveElementsAmountOf(inAktiveCount);
+   * sortByBiggestElement(conList); for(con : conList) do for(element :
+   * con.getAllActiveElementsSortByConsumption) do if(element <= production) do set element inAktiv;
+   * continue; end do end do end do inAktiveCount += 1; end while end for End
+   */
+  private void executeBaseLine() {
+    extractPositionAndAccess();
+    if (closeSwitches) {
+      setAllSwitchesClosed();
+    }
+    setHolonElemntsAktiv();
+    control.calculateStateForCurrentIteration();
 //		DecoratedState actualstate = control.getSimManager().getActualDecorState().get();	
 //		DecoratedState actualstate = control.getSimManager().getActualDecorState().get();	
 //		for(DecoratedNetwork net : actualstate.getNetworkList()) {
 //		for(DecoratedNetwork net : actualstate.getNetworkList()) {
 //			float production = net.getSupplierList().stream().map(supplier -> supplier.getEnergyToSupplyNetwork()).reduce(0.0f, (a, b) -> a + b);
 //			float production = net.getSupplierList().stream().map(supplier -> supplier.getEnergyToSupplyNetwork()).reduce(0.0f, (a, b) -> a + b);
@@ -305,140 +287,150 @@ public class BaseLine implements AddOn {
 //				}
 //				}
 //			}
 //			}
 //		}
 //		}
-		updateVisual();
-	}
-
-	
-	
-
-	private void setHolonElemntsAktiv() {
-		for(int i = 0;i<access.size();i++) {
-			AccessWrapper aw = access.get(i);
-			if(aw.getType() == AccessWrapper.HOLONELEMENT) aw.setState(true);
-		}
-	}
-	private void setAllSwitchesClosed() {
-		for(HolonSwitch hSwitch : switchList) {
-			hSwitch.setMode(SwitchMode.Manual);
-			hSwitch.setManualState(SwitchState.Closed);
-		}
-		
-	}
-	/**
-	 * Method to get the current Position alias a ListOf Booleans for aktive settings on the Objects on the Canvas.
-	 * Also initialize the Access Hashmap to swap faster positions.
-	 * @return
-	 */
-	private List<Boolean> extractPositionAndAccess() {
-		Model model = control.getModel();
-		switchList = new ArrayList<HolonSwitch>();
-		objectList = new ArrayList<HolonObject>();
-		initialState = new ArrayList<Boolean>(); 
-		access= new HashMap<Integer, AccessWrapper>();
-		rollOutNodes((useGroupNode && groupNode.isPresent())? groupNode.get().getObjectsInThisLayer() :model.getCanvas().getObjectsInThisLayer(), initialState, model.getCurrentIteration());
-		return initialState;
-	}
-	/**
-	 * Method to extract the Informations recursively out of the Model.
-	 * @param nodes
-	 * @param positionToInit
-	 * @param timeStep
-	 */
-	private void rollOutNodes(Stream<AbstractCanvasObject> nodes, List<Boolean> positionToInit, int timeStep) {
-		nodes.forEach(aCps -> {
-			if (aCps instanceof HolonObject hO) {
-				hO.elementsStream().forEach(hE -> {
-					positionToInit.add(hE.active);
-					access.put(positionToInit.size() - 1 , new AccessWrapper(hE));					
-				});
-				objectList.add(hO);
-			}
-			else if (aCps instanceof HolonSwitch sw) {
-				positionToInit.add(sw.getState().isClosed());
-				switchList.add(sw);
-				access.put(positionToInit.size() - 1 , new AccessWrapper(sw));
-			}
-			else if(aCps instanceof GroupNode groupnode) {			
-				rollOutGroupNode(groupnode, positionToInit ,timeStep);
-			}
-		});
-
-	}
-	
-	
-	private void rollOutGroupNode (GroupNode groupNode, List<Boolean> positionToInit, int timeStep) {
-		groupNode.getAllHolonObjectsRecursive().forEach(hObject -> {
-			hObject.elementsStream().forEach(hE -> {
-				positionToInit.add(hE.active);
-				access.put(positionToInit.size() - 1 , new AccessWrapper(hE));
-			});
-			objectList.add(hObject);
-		});
-		groupNode.getAllSwitchObjectsRecursive().forEach(sw -> {
-			positionToInit.add(sw.getState().isClosed());
-			switchList.add(sw);
-			access.put(positionToInit.size() - 1 , new AccessWrapper(sw));
-		});
-		
-	}
-	
-	
-	/**
-	 * To let the User See the current state without touching the Canvas.
-	 */
-	private void updateVisual() {
-		control.calculateStateForCurrentIteration();
-	}
-	/**
-	 * Sets the Model back to its original State before the LAST run.
-	 */
-	private void resetState() {
-		setState(initialState);
-	}
-	
-	/**
-	 * Sets the State out of the given position for calculation or to show the user.
-	 * @param position
-	 */
-	private void setState(List<Boolean> position) {
-		for(int i = 0;i<position.size();i++) {
-			access.get(i).setState(position.get(i));
-		}
-	}
-	
-
-	
-	
-	
-	/**
-	 * A Wrapper Class for Access HolonElement and HolonSwitch in one Element and not have to split the List.
-	 */
-	private class AccessWrapper {
-		public static final int HOLONELEMENT = 0;
-		public static final int SWITCH = 1;
-		private int type;
-		private HolonSwitch hSwitch;
-		private HolonElement hElement;
-		public AccessWrapper(HolonSwitch hSwitch){
-			type = SWITCH;
-			this.hSwitch = hSwitch;
-		}
-		public AccessWrapper(HolonElement hElement){
-			type = HOLONELEMENT;
-			this.hElement = hElement;
-		}
-		public void setState(boolean state) {
-			if(type == HOLONELEMENT) {
-				hElement.active = state;
-			}else{//is switch
-				hSwitch.setMode(SwitchMode.Manual);
-				hSwitch.setManualState(state ? SwitchState.Closed : SwitchState.Open);
-			}
-				
-		}
-		public int getType() {
-			return type;
-		}
-	}
-	
+    updateVisual();
+  }
+
+
+  private void setHolonElemntsAktiv() {
+    for (int i = 0; i < access.size(); i++) {
+      AccessWrapper aw = access.get(i);
+      if (aw.getType() == AccessWrapper.HOLONELEMENT) {
+        aw.setState(true);
+      }
+    }
+  }
+
+  private void setAllSwitchesClosed() {
+    for (HolonSwitch hSwitch : switchList) {
+      hSwitch.setMode(SwitchMode.Manual);
+      hSwitch.setManualState(SwitchState.Closed);
+    }
+
+  }
+
+  /**
+   * Method to get the current Position alias a ListOf Booleans for aktive settings on the Objects
+   * on the Canvas. Also initialize the Access Hashmap to swap faster positions.
+   *
+   * @return
+   */
+  private List<Boolean> extractPositionAndAccess() {
+    Model model = control.getModel();
+    switchList = new ArrayList<HolonSwitch>();
+    objectList = new ArrayList<HolonObject>();
+    initialState = new ArrayList<Boolean>();
+    access = new HashMap<Integer, AccessWrapper>();
+    rollOutNodes((useGroupNode && groupNode.isPresent()) ? groupNode.get().getObjectsInThisLayer()
+        : model.getCanvas().getObjectsInThisLayer(), initialState, model.getCurrentIteration());
+    return initialState;
+  }
+
+  /**
+   * Method to extract the Informations recursively out of the Model.
+   *
+   * @param nodes
+   * @param positionToInit
+   * @param timeStep
+   */
+  private void rollOutNodes(Stream<AbstractCanvasObject> nodes, List<Boolean> positionToInit,
+      int timeStep) {
+    nodes.forEach(aCps -> {
+      if (aCps instanceof HolonObject hO) {
+        hO.elementsStream().forEach(hE -> {
+          positionToInit.add(hE.active);
+          access.put(positionToInit.size() - 1, new AccessWrapper(hE));
+        });
+        objectList.add(hO);
+      } else if (aCps instanceof HolonSwitch sw) {
+        positionToInit.add(sw.getState().isClosed());
+        switchList.add(sw);
+        access.put(positionToInit.size() - 1, new AccessWrapper(sw));
+      } else if (aCps instanceof GroupNode groupnode) {
+        rollOutGroupNode(groupnode, positionToInit, timeStep);
+      }
+    });
+
+  }
+
+
+  private void rollOutGroupNode(GroupNode groupNode, List<Boolean> positionToInit, int timeStep) {
+    groupNode.getAllHolonObjectsRecursive().forEach(hObject -> {
+      hObject.elementsStream().forEach(hE -> {
+        positionToInit.add(hE.active);
+        access.put(positionToInit.size() - 1, new AccessWrapper(hE));
+      });
+      objectList.add(hObject);
+    });
+    groupNode.getAllSwitchObjectsRecursive().forEach(sw -> {
+      positionToInit.add(sw.getState().isClosed());
+      switchList.add(sw);
+      access.put(positionToInit.size() - 1, new AccessWrapper(sw));
+    });
+
+  }
+
+
+  /**
+   * To let the User See the current state without touching the Canvas.
+   */
+  private void updateVisual() {
+    control.calculateStateForCurrentIteration();
+  }
+
+  /**
+   * Sets the Model back to its original State before the LAST run.
+   */
+  private void resetState() {
+    setState(initialState);
+  }
+
+  /**
+   * Sets the State out of the given position for calculation or to show the user.
+   *
+   * @param position
+   */
+  private void setState(List<Boolean> position) {
+    for (int i = 0; i < position.size(); i++) {
+      access.get(i).setState(position.get(i));
+    }
+  }
+
+
+  /**
+   * A Wrapper Class for Access HolonElement and HolonSwitch in one Element and not have to split
+   * the List.
+   */
+  private class AccessWrapper {
+
+    public static final int HOLONELEMENT = 0;
+    public static final int SWITCH = 1;
+    private int type;
+    private HolonSwitch hSwitch;
+    private HolonElement hElement;
+
+    public AccessWrapper(HolonSwitch hSwitch) {
+      type = SWITCH;
+      this.hSwitch = hSwitch;
+    }
+
+    public AccessWrapper(HolonElement hElement) {
+      type = HOLONELEMENT;
+      this.hElement = hElement;
+    }
+
+    public void setState(boolean state) {
+      if (type == HOLONELEMENT) {
+        hElement.active = state;
+      } else {//is switch
+        hSwitch.setMode(SwitchMode.Manual);
+        hSwitch.setManualState(state ? SwitchState.Closed : SwitchState.Open);
+      }
+
+    }
+
+    public int getType() {
+      return type;
+    }
+  }
+
 }
 }

+ 268 - 232
src/holeg/algorithm/binary/GaAlgorithm.java

@@ -1,227 +1,263 @@
 package holeg.algorithm.binary;
 package holeg.algorithm.binary;
 
 
+import holeg.api.AlgorithmFrameworkFlex;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
 import java.util.ListIterator;
 import java.util.ListIterator;
 import java.util.TreeSet;
 import java.util.TreeSet;
-
 import javax.swing.JFrame;
 import javax.swing.JFrame;
 
 
-import holeg.api.AlgorithmFrameworkFlex;
+public class GaAlgorithm extends AlgorithmFrameworkFlex {
+
+  /**
+   * Should be even.
+   */
+  private int popsize = 20;
+  private int maxGenerations = 100;
+  private double tournamentSize = 2.0;
+  private double swapProbability = 0.02;
+  private double mutateProbability = 0.02;
+  private boolean useIntervalMutation = false;
+  //private double mutateProbabilityInterval = 0.01;
+  private double maxMutationPercent = 0.01;
+  private boolean moreInformation = false;
+
+
+  public GaAlgorithm() {
+    super();
+    addIntParameter("Population size", popsize, intValue -> popsize = intValue, () -> popsize, 1);
+    addIntParameter("Generations", maxGenerations, intValue -> maxGenerations = intValue,
+        () -> maxGenerations, 1);
+    addDoubleParameter("Tournament size", tournamentSize,
+        doubleValue -> tournamentSize = doubleValue, () -> tournamentSize, 1.0);
+    addDoubleParameter("Swap probability", swapProbability,
+        doubleValue -> swapProbability = doubleValue, () -> swapProbability, 0.0, 1.0);
+    addDoubleParameter("Mutation probability", mutateProbability,
+        doubleValue -> mutateProbability = doubleValue, () -> mutateProbability, 0.0, 1.0);
+    addBooleanParameter("Interval-based mutation", useIntervalMutation,
+        booleanValue -> useIntervalMutation = booleanValue);
+    //addDoubleParameter("mutateProbabilityInterval", mutateProbabilityInterval, doubleValue -> mutateProbabilityInterval = doubleValue, () -> mutateProbabilityInterval, 0.0, 1.0);
+    addDoubleParameter("Mutation severity (% of problem size)", maxMutationPercent,
+        doubleValue -> maxMutationPercent = doubleValue, () -> maxMutationPercent, 0.0, 1.0);
+    addBooleanParameter("Detailed Information", moreInformation,
+        booleanValue -> moreInformation = booleanValue);
+  }
+
+  public static void main(String[] args) {
+    JFrame newFrame = new JFrame("exampleWindow");
+    GaAlgorithm instance = new GaAlgorithm();
+    newFrame.setContentPane(instance.getPanel());
+    newFrame.pack();
+    newFrame.setVisible(true);
+    newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+  }
+
+
+  @Override
+  protected int getProgressBarMaxCount() {
+    return this.maxGenerations * this.popsize * this.rounds + rounds;
+  }
+
+  @Override
+  protected Individual executeAlgo() {
+    Individual best = new Individual();
+    best.position = extractPositionAndAccess();
+    if (moreInformation) {
+      console.println("Bit-Array_length: " + best.position.size());
+    }
+    best.fitness = evaluatePosition(best.position);
+    List<Double> runList = new ArrayList<Double>();
+    runList.add(best.fitness);
+    console.print("Start with: " + best.fitness);
+    if (moreInformation) {
+      console.println("");
+    }
+    int problemSize = best.position.size();
+    List<Individual> population = initPopuluationRandom(problemSize, best);
+    if (moreInformation) {
+      console.println("Size To Test:" + population.size());
+    }
+    for (int generation = 0; generation < maxGenerations; generation++) {
+      if (moreInformation) {
+        console.println("Generation" + generation + " start with Fitness: " + best.fitness);
+      }
+      for (Individual i : population) {
+        i.fitness = evaluatePosition(i.position);
+        if (moreInformation) {
+          console.println("Fitness" + i.fitness);
+        }
+        if (i.fitness < best.fitness) {
+          best = i;
+        }
+
+      }
+      runList.add(best.fitness);
+      List<Individual> childList = new ArrayList<Individual>();
+      for (int k = 0; k < popsize / 2; k++) {
+        Individual parentA = selectAParent(population, popsize);
+        Individual parentB = selectAParent(population, popsize);
+        Individual childA = new Individual(parentA);
+        Individual childB = new Individual(parentB);
+        crossover(childA, childB, problemSize);
+        if (useIntervalMutation) {
+          mutateInterval(childA, problemSize);
+        } else {
+          mutate(childA, problemSize);
+        }
+        if (useIntervalMutation) {
+          mutateInterval(childB, problemSize);
+        } else {
+          mutate(childB, problemSize);
+        }
+        childList.add(childA);
+        childList.add(childB);
+      }
+      population = childList;
+      if (moreInformation) {
+        console.println("________________");
+      }
+      if (cancel) {
+        return null;
+      }
+    }
 
 
-public class GaAlgorithm extends AlgorithmFrameworkFlex{
-
-	/**
-	 * Should be even.
-	 */
-	private int popsize = 20;
-	private int maxGenerations = 100;
-	private double tournamentSize = 2.0;
-	private double swapProbability = 0.02;
-	private double mutateProbability = 0.02;
-	private boolean useIntervalMutation = false;
-	//private double mutateProbabilityInterval = 0.01;
-	private double maxMutationPercent = 0.01;
-	private boolean moreInformation = false;
-	
-	
-	public GaAlgorithm() {
-		super();
-		addIntParameter("Population size", popsize, intValue -> popsize = intValue, () -> popsize, 1);
-		addIntParameter("Generations", maxGenerations, intValue -> maxGenerations = intValue, () -> maxGenerations, 1);
-		addDoubleParameter("Tournament size", tournamentSize, doubleValue -> tournamentSize = doubleValue, () -> tournamentSize, 1.0);
-		addDoubleParameter("Swap probability", swapProbability, doubleValue -> swapProbability = doubleValue, () -> swapProbability, 0.0, 1.0);
-		addDoubleParameter("Mutation probability", mutateProbability, doubleValue -> mutateProbability = doubleValue, () -> mutateProbability, 0.0, 1.0);
-		addBooleanParameter("Interval-based mutation", useIntervalMutation, booleanValue -> useIntervalMutation = booleanValue);
-		//addDoubleParameter("mutateProbabilityInterval", mutateProbabilityInterval, doubleValue -> mutateProbabilityInterval = doubleValue, () -> mutateProbabilityInterval, 0.0, 1.0);
-		addDoubleParameter("Mutation severity (% of problem size)", maxMutationPercent, doubleValue -> maxMutationPercent = doubleValue, () -> maxMutationPercent, 0.0, 1.0);
-		addBooleanParameter("Detailed Information", moreInformation, booleanValue -> moreInformation = booleanValue);
-	}
-	
-	public static void main(String[] args)
-	{
-	      JFrame newFrame = new JFrame("exampleWindow");
-	      GaAlgorithm instance = new GaAlgorithm();
-	      newFrame.setContentPane(instance.getPanel());
-	      newFrame.pack();
-	      newFrame.setVisible(true);
-	      newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
-	}
-	
-
-	@Override
-	protected int getProgressBarMaxCount() {
-		return this.maxGenerations * this.popsize * this.rounds + rounds;
-	}
-	
-	@Override
-	protected Individual executeAlgo() {
-		Individual best = new Individual();
-		best.position = extractPositionAndAccess();
-		if(moreInformation)console.println("Bit-Array_length: " + best.position.size());
-		best.fitness = evaluatePosition(best.position);
-		List<Double> runList = new ArrayList<Double>();
-		runList.add(best.fitness);
-		console.print("Start with: " + best.fitness);
-		if(moreInformation)console.println("");
-		int problemSize = best.position.size();
-		List<Individual> population = initPopuluationRandom(problemSize, best);
-		if(moreInformation)console.println("Size To Test:" + population.size());
-		for(int generation = 0; generation< maxGenerations; generation++) {
-			if(moreInformation)console.println("Generation" + generation + " start with Fitness: " + best.fitness);
-			for(Individual i : population) {
-				i.fitness = evaluatePosition(i.position);
-				if(moreInformation)console.println("Fitness" + i.fitness);
-				if(i.fitness < best.fitness) best = i;
-				
-			}
-			runList.add(best.fitness);
-			List<Individual> childList = new ArrayList<Individual>();
-			for(int k = 0; k<popsize/2; k++) {
-				Individual parentA = selectAParent(population, popsize);
-				Individual parentB = selectAParent(population, popsize);
-				Individual childA = new Individual(parentA);
-				Individual childB = new Individual(parentB);
-				crossover(childA, childB, problemSize);
-				if(useIntervalMutation)mutateInterval(childA, problemSize);else mutate(childA, problemSize);
-				if(useIntervalMutation)mutateInterval(childB, problemSize);else mutate(childB, problemSize);
-				childList.add(childA);
-				childList.add(childB);
-			}
-			population = childList;
-			if(moreInformation)console.println("________________");
-			if(cancel)return null;
-		}
-		
-		
-		console.println("   End with:" + best.fitness);
-		this.runList = runList;
-		return best;
-	}
-	/**
-	 * Algorithm 22 Bit-Flip Mutation.
-	 * 
-	 */
-	private void mutate(Individual child, int problemSize) {
-		ListIterator<Boolean> iter = child.position.listIterator();
-		while(iter.hasNext()) {
-			boolean boolValue = iter.next();
-			if(Random.nextDouble() <=  this.mutateProbability) {
-				iter.set(!boolValue);
-			}
-		}
-	}
-	
-	/**
-	 * Algorithm rolf
-	 * 
-	 */
-	private void mutateInterval(Individual child, int problemSize) {
-		//If not mutate skip
-		if(Random.nextDouble() >  this.mutateProbability) {
-			return;
-		}
-		//println("problemSize:" + problemSize + "    maxMutationPercent:" + maxMutationPercent);
-		int maximumAmountOfMutatedBits = Math.max(1, (int)Math.round(((double) problemSize) * this.maxMutationPercent));
-		int randomUniformAmountOfMutatedValues = Random.nextIntegerInRange(1,maximumAmountOfMutatedBits + 1);
-		
-		//println("max:" + maximumAmountOfMutatedBits + "   actual:" + randomUniformAmountOfMutatedValues);
-		TreeSet<Integer> mutationLocation = new TreeSet<Integer>(); //sortedSet
-		//Choose the location to mutate
-		for(int i = 0; i< randomUniformAmountOfMutatedValues; i++) {
-			boolean success = mutationLocation.add(Random.nextIntegerInRange(0, problemSize));
-			if(!success) i--; //can be add up to some series long loops if maximumAmountOfMutatedBits get closed to problemsize.
-		}
-		//println("Set:" + mutationLocation);
-		ListIterator<Boolean> iter = child.position.listIterator();
-		if(mutationLocation.isEmpty()) return;
-		int firstindex = mutationLocation.pollFirst();
-		while(iter.hasNext()) {
-			int index = iter.nextIndex();
-			boolean boolValue = iter.next();
-			if(index == firstindex) {
-				iter.set(!boolValue);
-				if(mutationLocation.isEmpty()) break;
-				firstindex = mutationLocation.pollFirst();
-			}
-		}
-	}
-	
-	
-	
-	
-	/** 
-	 * Algorithm 25 Uniform Crossover.
-	 * Probability is set to 1/Problemsize when not changed.
-	 */
-	private void crossover(Individual childA, Individual childB, int problemSize) {
-		ListIterator<Boolean> iterA = childA.position.listIterator();
-		ListIterator<Boolean> iterB = childB.position.listIterator();
-		for(int i= 0; i < problemSize; i++) {
-			boolean boolA = iterA.next();
-			boolean boolB = iterB.next();
-			if(Random.nextDouble() <=  this.swapProbability ) {
-				//Swap 
-				iterA.set(boolB);
-				iterB.set(boolA);
-			}
-		}
-	}
-	/**
-	 * Algorithm 32 Tournament Selection.
-	 * The fitnessValues are calculated for the Population List.
-	 * PseudoCode
-	 */
-	private Individual selectAParent(List<Individual> population,int popsize) {
-		Individual tournamentBest = population.get(Random.nextIntegerInRange(0, popsize));
-		double participants;
-		for(participants = tournamentSize ; participants >= 2; participants -= 1.0) {
-			Individual next = population.get(Random.nextIntegerInRange(0, popsize));
-			if(next.fitness < tournamentBest.fitness) tournamentBest = next;
-		}
-		//if tournament size is not a whole number like 2.5 or 3.6
-		//the remaining part is the chance to fight another time; 2.7 -> 70% chance to fight a second time
-		if( participants > 1) {		
-			if(Random.nextDouble() < participants - 1.0) {
-				//println("Chance to find a match");
-				Individual next = population.get(Random.nextIntegerInRange(0, popsize));
-				if(next.fitness < tournamentBest.fitness) tournamentBest = next;
-			}
-		}
-		return tournamentBest;
-	}
-	/**
-	 * Initialize the Population with Individuals that have a random Position.
-	 */
-	private List<Individual> initPopuluationRandom(int problemSize, Individual startIndidual){
-		List<Individual> population =  new ArrayList<Individual>();
-		for(int i = 0; i < popsize -1; i++) {
-			population.add(createRandomIndividualWithoutFitness(problemSize));
-		}
-		//Add Start Position
-		population.add(new Individual(startIndidual));
-		return population;
-	}
-	
-	
-	
-	/**
-	 * Algorithm 21 The BooleanVeator initialization.
-	 * @param problemSize
-	 * @return
-	 */
-	private Individual createRandomIndividualWithoutFitness(int problemSize) {
-		//create Random Individual Without Fitness
-		Individual result = new Individual();
-		result.position = new ArrayList<Boolean>();
-		for (int index = 0; index < problemSize; index++){
-			result.position.add(Random.nextBoolean());
-		}
-		return result;
-	}
-
-	@Override
-	protected String algoInformationToPrint() {
+    console.println("   End with:" + best.fitness);
+    this.runList = runList;
+    return best;
+  }
+
+  /**
+   * Algorithm 22 Bit-Flip Mutation.
+   */
+  private void mutate(Individual child, int problemSize) {
+    ListIterator<Boolean> iter = child.position.listIterator();
+    while (iter.hasNext()) {
+      boolean boolValue = iter.next();
+      if (Random.nextDouble() <= this.mutateProbability) {
+        iter.set(!boolValue);
+      }
+    }
+  }
+
+  /**
+   * Algorithm rolf
+   */
+  private void mutateInterval(Individual child, int problemSize) {
+    //If not mutate skip
+    if (Random.nextDouble() > this.mutateProbability) {
+      return;
+    }
+    //println("problemSize:" + problemSize + "    maxMutationPercent:" + maxMutationPercent);
+    int maximumAmountOfMutatedBits = Math.max(1,
+        (int) Math.round(((double) problemSize) * this.maxMutationPercent));
+    int randomUniformAmountOfMutatedValues = Random.nextIntegerInRange(1,
+        maximumAmountOfMutatedBits + 1);
+
+    //println("max:" + maximumAmountOfMutatedBits + "   actual:" + randomUniformAmountOfMutatedValues);
+    TreeSet<Integer> mutationLocation = new TreeSet<Integer>(); //sortedSet
+    //Choose the location to mutate
+    for (int i = 0; i < randomUniformAmountOfMutatedValues; i++) {
+      boolean success = mutationLocation.add(Random.nextIntegerInRange(0, problemSize));
+      if (!success) {
+        i--; //can be add up to some series long loops if maximumAmountOfMutatedBits get closed to problemsize.
+      }
+    }
+    //println("Set:" + mutationLocation);
+    ListIterator<Boolean> iter = child.position.listIterator();
+    if (mutationLocation.isEmpty()) {
+      return;
+    }
+    int firstindex = mutationLocation.pollFirst();
+    while (iter.hasNext()) {
+      int index = iter.nextIndex();
+      boolean boolValue = iter.next();
+      if (index == firstindex) {
+        iter.set(!boolValue);
+        if (mutationLocation.isEmpty()) {
+          break;
+        }
+        firstindex = mutationLocation.pollFirst();
+      }
+    }
+  }
+
+
+  /**
+   * Algorithm 25 Uniform Crossover. Probability is set to 1/Problemsize when not changed.
+   */
+  private void crossover(Individual childA, Individual childB, int problemSize) {
+    ListIterator<Boolean> iterA = childA.position.listIterator();
+    ListIterator<Boolean> iterB = childB.position.listIterator();
+    for (int i = 0; i < problemSize; i++) {
+      boolean boolA = iterA.next();
+      boolean boolB = iterB.next();
+      if (Random.nextDouble() <= this.swapProbability) {
+        //Swap
+        iterA.set(boolB);
+        iterB.set(boolA);
+      }
+    }
+  }
+
+  /**
+   * Algorithm 32 Tournament Selection. The fitnessValues are calculated for the Population List.
+   * PseudoCode
+   */
+  private Individual selectAParent(List<Individual> population, int popsize) {
+    Individual tournamentBest = population.get(Random.nextIntegerInRange(0, popsize));
+    double participants;
+    for (participants = tournamentSize; participants >= 2; participants -= 1.0) {
+      Individual next = population.get(Random.nextIntegerInRange(0, popsize));
+      if (next.fitness < tournamentBest.fitness) {
+        tournamentBest = next;
+      }
+    }
+    //if tournament size is not a whole number like 2.5 or 3.6
+    //the remaining part is the chance to fight another time; 2.7 -> 70% chance to fight a second time
+    if (participants > 1) {
+      if (Random.nextDouble() < participants - 1.0) {
+        //println("Chance to find a match");
+        Individual next = population.get(Random.nextIntegerInRange(0, popsize));
+        if (next.fitness < tournamentBest.fitness) {
+          tournamentBest = next;
+        }
+      }
+    }
+    return tournamentBest;
+  }
+
+  /**
+   * Initialize the Population with Individuals that have a random Position.
+   */
+  private List<Individual> initPopuluationRandom(int problemSize, Individual startIndidual) {
+    List<Individual> population = new ArrayList<Individual>();
+    for (int i = 0; i < popsize - 1; i++) {
+      population.add(createRandomIndividualWithoutFitness(problemSize));
+    }
+    //Add Start Position
+    population.add(new Individual(startIndidual));
+    return population;
+  }
+
+
+  /**
+   * Algorithm 21 The BooleanVeator initialization.
+   *
+   * @param problemSize
+   * @return
+   */
+  private Individual createRandomIndividualWithoutFitness(int problemSize) {
+    //create Random Individual Without Fitness
+    Individual result = new Individual();
+    result.position = new ArrayList<Boolean>();
+    for (int index = 0; index < problemSize; index++) {
+      result.position.add(Random.nextBoolean());
+    }
+    return result;
+  }
+
+  @Override
+  protected String algoInformationToPrint() {
 //		private int popsize = 20;
 //		private int popsize = 20;
 //		private int maxGenerations = 100;
 //		private int maxGenerations = 100;
 //		private double tournamentSize = 2.0;
 //		private double tournamentSize = 2.0;
@@ -232,21 +268,21 @@ public class GaAlgorithm extends AlgorithmFrameworkFlex{
 //		private boolean useIntervalMutation = true;
 //		private boolean useIntervalMutation = true;
 //		private double mutateProbabilityInterval = 0.01;
 //		private double mutateProbabilityInterval = 0.01;
 //		private double maxMutationPercent = 0.01;
 //		private double maxMutationPercent = 0.01;
-		return "GaAlgo"
-				+ " Rounds: " + rounds 
-				+ " Iterations: " + maxGenerations
-				+ " Individuals: " + popsize
-				+ " TournamentSize: " +  tournamentSize
-				+ " SwapProbability: " +  swapProbability
-				+ (useIntervalMutation? 
-						(//" MutateProbabilityInterval: " +  mutateProbabilityInterval
-						" MaxMutationPercent: " +  maxMutationPercent)
-						: 
-						(" MutateProbability: " +  mutateProbability));
-	}
-
-	@Override
-	protected String plottFileName() {
-		return "plottGaAlgo.txt";
-	}
+    return "GaAlgo"
+        + " Rounds: " + rounds
+        + " Iterations: " + maxGenerations
+        + " Individuals: " + popsize
+        + " TournamentSize: " + tournamentSize
+        + " SwapProbability: " + swapProbability
+        + (useIntervalMutation ?
+        (//" MutateProbabilityInterval: " +  mutateProbabilityInterval
+            " MaxMutationPercent: " + maxMutationPercent)
+        :
+            (" MutateProbability: " + mutateProbability));
+  }
+
+  @Override
+  protected String plottFileName() {
+    return "plottGaAlgo.txt";
+  }
 }
 }

+ 352 - 394
src/holeg/algorithm/binary/PsoAlgorithm.java

@@ -1,258 +1,300 @@
 package holeg.algorithm.binary;
 package holeg.algorithm.binary;
 
 
+import holeg.api.AlgorithmFrameworkFlex;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
 import java.util.TreeSet;
 import java.util.TreeSet;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
-
 import javax.swing.JFrame;
 import javax.swing.JFrame;
 
 
-import holeg.api.AlgorithmFrameworkFlex;
-
-public class PsoAlgorithm extends AlgorithmFrameworkFlex{
-	//Parameter for Algo with default Values:
-	private int swarmSize = 20; 
-	private int maxIterations = 100; 
-	private double dependency = 2.07; 
-	private int mutationIteration = 1;
-	private boolean useIntervalMutation = true;
-	private double mutationRate = 0.01;
-	private double mutateProbabilityInterval = 0.01;
-	private double maxMutationPercent = 0.01;
-	private double c1, c2, w;
-	private double maxVelocity = 4.0;
-	private boolean moreInformation = false;
-	
-	
-	
-	public static void main(String[] args)
-	{
-	      JFrame newFrame = new JFrame("exampleWindow");
-	      PsoAlgorithm instance = new PsoAlgorithm();
-	      newFrame.setContentPane(instance.getPanel());
-	      newFrame.pack();
-	      newFrame.setVisible(true);
-	      newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
-	}
-	
-	
-	public PsoAlgorithm() {
-		super();
-		addIntParameter("Particles", swarmSize, intValue -> swarmSize = intValue, () -> swarmSize, 1);
-		addIntParameter("Iterations", maxIterations, intValue -> maxIterations = intValue, () -> maxIterations, 1);
-		addDoubleParameter("Dependency", dependency, doubleValue -> dependency = doubleValue, () -> dependency, 2.001, 2.4);
-		addIntParameter("Mutation iteration", mutationIteration, intValue -> mutationIteration = intValue, () -> mutationIteration, 0);
-		addBooleanParameter("Interval-based mutation", useIntervalMutation, booleanValue -> useIntervalMutation = booleanValue);
-		addDoubleParameter("Mutation probability (%)", mutateProbabilityInterval, doubleValue -> mutateProbabilityInterval = doubleValue, () -> mutateProbabilityInterval, 0.0, 1.0);
-	//	addDoubleParameter("mutationRate", mutationRate, doubleValue -> mutationRate = doubleValue, () -> mutationRate, 0.0, 1.0);
-		addDoubleParameter("Mutation severity (% of problem size)", maxMutationPercent, doubleValue -> maxMutationPercent = doubleValue, () -> maxMutationPercent, 0.0, 1.0);
-		addDoubleParameter("Velocity", maxVelocity, doubleValue -> maxVelocity = doubleValue, () -> maxVelocity, 0.0);
-		
-		addBooleanParameter("Detailed information", moreInformation , booleanValue -> moreInformation = booleanValue);
-	}
-	
-
-	@Override
-	protected int getProgressBarMaxCount() {
-		return swarmSize * (maxIterations + 1)* rounds + rounds;
-	}
-	/**
-	 *  <p>Algo from Paper:</p><font size="3"><pre>
-	 *  
-	 *  Begin
-	 *  	t = 0; {t: generation index}
-	 *  	initialize particles x<sub>p,i,j</sub>(t);
-	 *  	evaluation x<sub>p,i,j</sub>(t);
-	 *  	while (termination condition &ne; true) do
-	 *  		v<sub>i,j</sub>(t) = update v<sub>i,j</sub>(t); {by Eq. (6)}
-	 *  		x<sub>g,i,j</sub>(t) = update x<sub>g,i,j</sub>(t); {by Eq. (7)}
-	 *  		x<sub>g,i,j</sub>(t) = mutation x<sub>g,i,j</sub>(t); {by Eq. (11)}
-	 *  		x<sub>p,i,j</sub>(t) = decode x<sub>g,i,j</sub>(t); {by Eqs. (8) and (9)}
-	 *  		evaluate x<sub>p,i,j</sub>(t);
-	 *  		t = t + 1;
-	 *  	end while
-	 *  End</pre></font>
-	 *  <p>with:</p><font size="3">
-	 *  
-	 *  x<sub>g,i,j</sub>: genotype ->genetic information -> in continuous space<br>
-	 *  x<sub>p,i,j</sub>: phenotype -> observable characteristics-> in binary space<br>
-	 *  X<sub>g,max</sub>: is the Maximum here set to 4.<br>
-	 *  Eq. (6):v<sub>i,j</sub>(t + 1) = wv<sub>i,j</sub>+c<sub>1</sub>R<sub>1</sub>(P<sub>best,i,j</sub>-x<sub>p,i,j</sub>(t))+c<sub>2</sub>R<sub>2</sub>(g<sub>best,i,j</sub>-x<sub>p,i,j</sub>(t))<br>
-	 *  Eq. (7):x<sub>g,i,j</sub>(t + 1) = x<sub>g,i,j</sub>(t) + v<sub>i,j</sub>(t + 1)<br>
-	 *  Eq. (11):<b>if(</b>rand()&lt;r<sub>mu</sub><b>)then</b> x<sub>g,i,j</sub>(t + 1) = -x<sub>g,i,j</sub>(t + 1)<br>
-	 *  Eq. (8):x<sub>p,i,j</sub>(t + 1) = <b>(</b>rand() &lt; S(x<sub>g,i,j</sub>(t + 1))<b>) ?</b> 1 <b>:</b> 0<br>
-	 *  Eq. (9) Sigmoid:S(x<sub>g,i,j</sub>(t + 1)) := 1/(1 + e<sup>-x<sub>g,i,j</sub>(t + 1)</sup>)<br></font>
-	 *  <p>Parameter:</p>
-	 *  w inertia, calculated from phi(Variable:{@link #dependency})<br>
-	 *  c1:	influence, calculated from phi(Variable:{@link #dependency}) <br>
-	 *  c2:	influence, calculated from phi(Variable:{@link #dependency})<br>
-	 *  r<sub>mu</sub>: probability that the proposed operation is conducted defined by limit(Variable:{@link #})<br>
-	 *  
-	 *  
-	 */
-	@Override
-	protected Individual executeAlgo() {
-		initDependentParameter();
-		Individual globalBest = new Individual();
-		globalBest.position = extractPositionAndAccess();
-		globalBest.fitness = evaluatePosition(globalBest.position);
-		console.println("Start Value:" + globalBest.fitness);
-		int dimensions = globalBest.position.size();
-		List<Particle> swarm= initializeParticles(dimensions);
-		List<Double> runList = new ArrayList<Double>();
-		runList.add(globalBest.fitness);
-		evaluation(globalBest, swarm);
-		runList.add(globalBest.fitness);
-		for (int iteration = 0; iteration < maxIterations ; iteration++) {
-			int mutationAllowed = iteration % mutationIteration;
-			double bitsFlipped = 0;
-			for (int particleNumber = 0; particleNumber < swarmSize; particleNumber++) {
-				Particle particle = swarm.get(particleNumber);		
-				
-				if(this.useIntervalMutation) {
-					boolean allowMutation = (Random.nextDouble() <  this.mutateProbabilityInterval);
-					TreeSet<Integer> mutationLocationSet = null;
-					if(allowMutation)mutationLocationSet = locationsToMutate(dimensions);
-					for(int index = 0; index < dimensions; index++) {
-						updateVelocity(particle, index, globalBest);
-						updateGenotype(particle, index);
-						if(allowMutation &&mutationAllowed == 0 && iteration != 0 && mutationLocationSet.contains(index))mutation(particle, index);
-						decode(particle, index);
-					}
-				}else {				
-					int count = 0;
-					for(int index = 0; index < dimensions; index++) {
-						updateVelocity(particle, index, globalBest);
-						updateGenotype(particle, index);
-						if(mutationAllowed == 0 && iteration != 0 && Random.nextDouble() < mutateProbabilityInterval) {
-							count++;
-							mutation(particle, index);
-						}
-						decode(particle, index);
-					}
-					bitsFlipped += count;
-				}
-			}
-			if(moreInformation) console.println("\t\t\t\t\t\tAvgBitsMutate: " + (bitsFlipped / (double)swarmSize));
-			if(cancel)return null;
-			evaluation(globalBest, swarm);
-			runList.add(globalBest.fitness);
-			if(moreInformation) console.println("------------------------");
-		}
-		console.println(" End Value:" + globalBest.fitness);
-		this.runList = runList;
-		return globalBest;
-	}
-	/**
-	 * 
-	 * @param j maximum index of position in the particle
-	 * @return
-	 */
-	private List<Particle> initializeParticles(int j) {
-		List<Particle> swarm = new ArrayList<Particle>();
-		//Create The Particle
-		for (int particleNumber = 0; particleNumber < swarmSize; particleNumber++){
-			//Create a Random position
-			List<Boolean> aRandomPosition = new ArrayList<Boolean>();
-			for (int index = 0; index < j; index++){
-				aRandomPosition.add(Random.nextBoolean());
-			}
-			swarm.add(new Particle(aRandomPosition));
-		}
-		return swarm;
-	}
-	/**
-	 * Calculate w, c1, c2
-	 */
-	private void initDependentParameter() {
-		w = 1.0 / (dependency - 1 + Math.sqrt(dependency * dependency - 2 * dependency));
-		c1 = c2 = dependency * w;
-	}
-	/**
-	 * Evaluate each particle and update the global Best position;
-	 * @param globalBest
-	 * @param swarm
-	 */
-	private void evaluation(Individual globalBest, List<Particle> swarm) {
-		for(Particle p: swarm) {
-			double localEvaluationValue = evaluatePosition(p.xPhenotype);
-			if(moreInformation) console.println("Fitness " + localEvaluationValue);
-			p.checkNewEvaluationValue(localEvaluationValue);
-			if(localEvaluationValue < globalBest.fitness) {
-				globalBest.fitness = localEvaluationValue;
-				globalBest.position = p.localBest.position;
-			}
-		}
-	}
-	/**
-	 * 	Eq. (6):v<sub>i,j</sub>(t + 1) = wv<sub>i,j</sub>+c<sub>1</sub>R<sub>1</sub>(P<sub>best,i,j</sub>-x<sub>p,i,j</sub>(t))+c<sub>2</sub>R<sub>2</sub>(g<sub>best,i,j</sub>-x<sub>p,i,j</sub>(t))<br>
-	 * @param particle
-	 * @param index
-	 * @param globalBest
-	 */
-	private void updateVelocity(Particle particle, int index, Individual globalBest) {
-		double r1 = Random.nextDouble();
-		double r2 =	Random.nextDouble();
-		double posValue = particle.xPhenotype.get(index)?1.0:0.0;
-		particle.velocity.set(index, clamp(w*particle.velocity.get(index) + c1*r1*((particle.localBest.position.get(index)?1.0:0.0)  - posValue) + c2*r2*((globalBest.position.get(index)?1.0:0.0)- posValue)) );
-	}
-	/**
-	 * Eq. (7):x<sub>g,i,j</sub>(t + 1) = x<sub>g,i,j</sub>(t) + v<sub>i,j</sub>(t + 1)<br>
-	 * @param particle
-	 * @param index
-	 */
-	private void updateGenotype(Particle particle, int index) {
-		particle.xGenotype.set(index, clamp(particle.xGenotype.get(index) + particle.velocity.get(index)));
-	}
-	/**
-	 * Eq. (11):<b>if(</b>rand()&lt;r<sub>mu</sub><b>)then</b> x<sub>g,i,j</sub>(t + 1) = -x<sub>g,i,j</sub>(t + 1)<br>
-	 * @param particle
-	 * @param index
-	 */
-	private void mutation(Particle particle, int index) {
-		//if(Random.nextDouble() < limit) 
-			particle.xGenotype.set(index, -particle.xGenotype.get(index));
-	}
-	/**
-	 * Eq. (8):x<sub>p,i,j</sub>(t + 1) = <b>(</b>rand() &lt; S(x<sub>g,i,j</sub>(t + 1))<b>) ?</b> 1 <b>:</b> 0<br>
-	 * @param particle
-	 * @param index
-	 */
-	private void decode(Particle particle, int index) {
-		particle.xPhenotype.set(index, Random.nextDouble() < Sigmoid(particle.xGenotype.get(index)));
-	}
-	/**
-	 * Eq. (9) Sigmoid:S(x<sub>g,i,j</sub>(t + 1)) := 1/(1 + e<sup>-x<sub>g,i,j</sub>(t + 1)</sup>)<br></font>
-	 * @param value
-	 * @return
-	 */
-	private double Sigmoid(double value) {
-		return 1.0 / (1.0 + Math.exp(-value));
-	}
-
-	/**
-	 * To clamp X<sub>g,j,i</sub> and v<sub>i,j</sub> in Range [-X<sub>g,max</sub>|+X<sub>g,max</sub>] with {X<sub>g,max</sub>= 4}
-	 * @param value
-	 * @return
-	 */
-	private double clamp(double value) {
-		return Math.max(-maxVelocity, Math.min(maxVelocity, value));
-	}
-	private TreeSet<Integer> locationsToMutate(int dimensions) {
-		TreeSet<Integer> mutationLocation = new TreeSet<Integer>(); //sortedSet
-		int maximumAmountOfMutatedBits = Math.max(1, (int)Math.round(((double) dimensions) * this.maxMutationPercent));
-		int randomUniformAmountOfMutatedValues = Random.nextIntegerInRange(1,maximumAmountOfMutatedBits + 1);
-		for(int i = 0; i< randomUniformAmountOfMutatedValues; i++) {
-			boolean success = mutationLocation.add(Random.nextIntegerInRange(0, dimensions));
-			if(!success) i--; //can be add up to some series long loops if maximumAmountOfMutatedBits get closed to problemsize.
-		}
-		return mutationLocation;
-	}
-	
-	
-	
-		@Override
-	protected String algoInformationToPrint() {
+public class PsoAlgorithm extends AlgorithmFrameworkFlex {
+
+  //Parameter for Algo with default Values:
+  private int swarmSize = 20;
+  private int maxIterations = 100;
+  private double dependency = 2.07;
+  private int mutationIteration = 1;
+  private boolean useIntervalMutation = true;
+  private double mutationRate = 0.01;
+  private double mutateProbabilityInterval = 0.01;
+  private double maxMutationPercent = 0.01;
+  private double c1, c2, w;
+  private double maxVelocity = 4.0;
+  private boolean moreInformation = false;
+
+
+  public PsoAlgorithm() {
+    super();
+    addIntParameter("Particles", swarmSize, intValue -> swarmSize = intValue, () -> swarmSize, 1);
+    addIntParameter("Iterations", maxIterations, intValue -> maxIterations = intValue,
+        () -> maxIterations, 1);
+    addDoubleParameter("Dependency", dependency, doubleValue -> dependency = doubleValue,
+        () -> dependency, 2.001, 2.4);
+    addIntParameter("Mutation iteration", mutationIteration,
+        intValue -> mutationIteration = intValue, () -> mutationIteration, 0);
+    addBooleanParameter("Interval-based mutation", useIntervalMutation,
+        booleanValue -> useIntervalMutation = booleanValue);
+    addDoubleParameter("Mutation probability (%)", mutateProbabilityInterval,
+        doubleValue -> mutateProbabilityInterval = doubleValue, () -> mutateProbabilityInterval,
+        0.0, 1.0);
+    //	addDoubleParameter("mutationRate", mutationRate, doubleValue -> mutationRate = doubleValue, () -> mutationRate, 0.0, 1.0);
+    addDoubleParameter("Mutation severity (% of problem size)", maxMutationPercent,
+        doubleValue -> maxMutationPercent = doubleValue, () -> maxMutationPercent, 0.0, 1.0);
+    addDoubleParameter("Velocity", maxVelocity, doubleValue -> maxVelocity = doubleValue,
+        () -> maxVelocity, 0.0);
+
+    addBooleanParameter("Detailed information", moreInformation,
+        booleanValue -> moreInformation = booleanValue);
+  }
+
+  public static void main(String[] args) {
+    JFrame newFrame = new JFrame("exampleWindow");
+    PsoAlgorithm instance = new PsoAlgorithm();
+    newFrame.setContentPane(instance.getPanel());
+    newFrame.pack();
+    newFrame.setVisible(true);
+    newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+  }
+
+  @Override
+  protected int getProgressBarMaxCount() {
+    return swarmSize * (maxIterations + 1) * rounds + rounds;
+  }
+
+  /**
+   * <p>Algo from Paper:</p><font size="3"><pre>
+   *
+   *  Begin
+   *  	t = 0; {t: generation index}
+   *  	initialize particles x<sub>p,i,j</sub>(t);
+   *  	evaluation x<sub>p,i,j</sub>(t);
+   *  	while (termination condition &ne; true) do
+   *  		v<sub>i,j</sub>(t) = update v<sub>i,j</sub>(t); {by Eq. (6)}
+   *  		x<sub>g,i,j</sub>(t) = update x<sub>g,i,j</sub>(t); {by Eq. (7)}
+   *  		x<sub>g,i,j</sub>(t) = mutation x<sub>g,i,j</sub>(t); {by Eq. (11)}
+   *  		x<sub>p,i,j</sub>(t) = decode x<sub>g,i,j</sub>(t); {by Eqs. (8) and (9)}
+   *  		evaluate x<sub>p,i,j</sub>(t);
+   *  		t = t + 1;
+   *  	end while
+   *  End</pre></font>
+   * <p>with:</p><font size="3">
+   * <p>
+   * x<sub>g,i,j</sub>: genotype ->genetic information -> in continuous space<br> x<sub>p,i,j</sub>:
+   * phenotype -> observable characteristics-> in binary space<br> X<sub>g,max</sub>: is the Maximum
+   * here set to 4.<br> Eq. (6):v<sub>i,j</sub>(t + 1) = wv<sub>i,j</sub>+c<sub>1</sub>R<sub>1</sub>(P<sub>best,i,j</sub>-x<sub>p,i,j</sub>(t))+c<sub>2</sub>R<sub>2</sub>(g<sub>best,i,j</sub>-x<sub>p,i,j</sub>(t))<br>
+   * Eq. (7):x<sub>g,i,j</sub>(t + 1) = x<sub>g,i,j</sub>(t) + v<sub>i,j</sub>(t + 1)<br> Eq.
+   * (11):<b>if(</b>rand()&lt;r<sub>mu</sub><b>)then</b> x<sub>g,i,j</sub>(t + 1) =
+   * -x<sub>g,i,j</sub>(t + 1)<br> Eq. (8):x<sub>p,i,j</sub>(t + 1) = <b>(</b>rand() &lt;
+   * S(x<sub>g,i,j</sub>(t + 1))<b>) ?</b> 1 <b>:</b> 0<br> Eq. (9) Sigmoid:S(x<sub>g,i,j</sub>(t +
+   * 1)) := 1/(1 + e<sup>-x<sub>g,i,j</sub>(t + 1)</sup>)<br></font>
+   * <p>Parameter:</p>
+   * w inertia, calculated from phi(Variable:{@link #dependency})<br> c1:	influence, calculated from
+   * phi(Variable:{@link #dependency}) <br> c2:	influence, calculated from phi(Variable:{@link
+   * #dependency})<br> r<sub>mu</sub>: probability that the proposed operation is conducted defined
+   * by limit(Variable:{@link #})<br>
+   */
+  @Override
+  protected Individual executeAlgo() {
+    initDependentParameter();
+    Individual globalBest = new Individual();
+    globalBest.position = extractPositionAndAccess();
+    globalBest.fitness = evaluatePosition(globalBest.position);
+    console.println("Start Value:" + globalBest.fitness);
+    int dimensions = globalBest.position.size();
+    List<Particle> swarm = initializeParticles(dimensions);
+    List<Double> runList = new ArrayList<Double>();
+    runList.add(globalBest.fitness);
+    evaluation(globalBest, swarm);
+    runList.add(globalBest.fitness);
+    for (int iteration = 0; iteration < maxIterations; iteration++) {
+      int mutationAllowed = iteration % mutationIteration;
+      double bitsFlipped = 0;
+      for (int particleNumber = 0; particleNumber < swarmSize; particleNumber++) {
+        Particle particle = swarm.get(particleNumber);
+
+        if (this.useIntervalMutation) {
+          boolean allowMutation = (Random.nextDouble() < this.mutateProbabilityInterval);
+          TreeSet<Integer> mutationLocationSet = null;
+          if (allowMutation) {
+            mutationLocationSet = locationsToMutate(dimensions);
+          }
+          for (int index = 0; index < dimensions; index++) {
+            updateVelocity(particle, index, globalBest);
+            updateGenotype(particle, index);
+            if (allowMutation && mutationAllowed == 0 && iteration != 0
+                && mutationLocationSet.contains(index)) {
+              mutation(particle, index);
+            }
+            decode(particle, index);
+          }
+        } else {
+          int count = 0;
+          for (int index = 0; index < dimensions; index++) {
+            updateVelocity(particle, index, globalBest);
+            updateGenotype(particle, index);
+            if (mutationAllowed == 0 && iteration != 0
+                && Random.nextDouble() < mutateProbabilityInterval) {
+              count++;
+              mutation(particle, index);
+            }
+            decode(particle, index);
+          }
+          bitsFlipped += count;
+        }
+      }
+      if (moreInformation) {
+        console.println("\t\t\t\t\t\tAvgBitsMutate: " + (bitsFlipped / (double) swarmSize));
+      }
+      if (cancel) {
+        return null;
+      }
+      evaluation(globalBest, swarm);
+      runList.add(globalBest.fitness);
+      if (moreInformation) {
+        console.println("------------------------");
+      }
+    }
+    console.println(" End Value:" + globalBest.fitness);
+    this.runList = runList;
+    return globalBest;
+  }
+
+  /**
+   * @param j maximum index of position in the particle
+   * @return
+   */
+  private List<Particle> initializeParticles(int j) {
+    List<Particle> swarm = new ArrayList<Particle>();
+    //Create The Particle
+    for (int particleNumber = 0; particleNumber < swarmSize; particleNumber++) {
+      //Create a Random position
+      List<Boolean> aRandomPosition = new ArrayList<Boolean>();
+      for (int index = 0; index < j; index++) {
+        aRandomPosition.add(Random.nextBoolean());
+      }
+      swarm.add(new Particle(aRandomPosition));
+    }
+    return swarm;
+  }
+
+  /**
+   * Calculate w, c1, c2
+   */
+  private void initDependentParameter() {
+    w = 1.0 / (dependency - 1 + Math.sqrt(dependency * dependency - 2 * dependency));
+    c1 = c2 = dependency * w;
+  }
+
+  /**
+   * Evaluate each particle and update the global Best position;
+   *
+   * @param globalBest
+   * @param swarm
+   */
+  private void evaluation(Individual globalBest, List<Particle> swarm) {
+    for (Particle p : swarm) {
+      double localEvaluationValue = evaluatePosition(p.xPhenotype);
+      if (moreInformation) {
+        console.println("Fitness " + localEvaluationValue);
+      }
+      p.checkNewEvaluationValue(localEvaluationValue);
+      if (localEvaluationValue < globalBest.fitness) {
+        globalBest.fitness = localEvaluationValue;
+        globalBest.position = p.localBest.position;
+      }
+    }
+  }
+
+  /**
+   * Eq. (6):v<sub>i,j</sub>(t + 1) = wv<sub>i,j</sub>+c<sub>1</sub>R<sub>1</sub>(P<sub>best,i,j</sub>-x<sub>p,i,j</sub>(t))+c<sub>2</sub>R<sub>2</sub>(g<sub>best,i,j</sub>-x<sub>p,i,j</sub>(t))<br>
+   *
+   * @param particle
+   * @param index
+   * @param globalBest
+   */
+  private void updateVelocity(Particle particle, int index, Individual globalBest) {
+    double r1 = Random.nextDouble();
+    double r2 = Random.nextDouble();
+    double posValue = particle.xPhenotype.get(index) ? 1.0 : 0.0;
+    particle.velocity.set(index, clamp(w * particle.velocity.get(index) + c1 * r1 * (
+        (particle.localBest.position.get(index) ? 1.0 : 0.0) - posValue) + c2 * r2 * (
+        (globalBest.position.get(index) ? 1.0 : 0.0) - posValue)));
+  }
+
+  /**
+   * Eq. (7):x<sub>g,i,j</sub>(t + 1) = x<sub>g,i,j</sub>(t) + v<sub>i,j</sub>(t + 1)<br>
+   *
+   * @param particle
+   * @param index
+   */
+  private void updateGenotype(Particle particle, int index) {
+    particle.xGenotype.set(index,
+        clamp(particle.xGenotype.get(index) + particle.velocity.get(index)));
+  }
+
+  /**
+   * Eq. (11):<b>if(</b>rand()&lt;r<sub>mu</sub><b>)then</b> x<sub>g,i,j</sub>(t + 1) =
+   * -x<sub>g,i,j</sub>(t + 1)<br>
+   *
+   * @param particle
+   * @param index
+   */
+  private void mutation(Particle particle, int index) {
+    //if(Random.nextDouble() < limit)
+    particle.xGenotype.set(index, -particle.xGenotype.get(index));
+  }
+
+  /**
+   * Eq. (8):x<sub>p,i,j</sub>(t + 1) = <b>(</b>rand() &lt; S(x<sub>g,i,j</sub>(t + 1))<b>) ?</b> 1
+   * <b>:</b> 0<br>
+   *
+   * @param particle
+   * @param index
+   */
+  private void decode(Particle particle, int index) {
+    particle.xPhenotype.set(index, Random.nextDouble() < Sigmoid(particle.xGenotype.get(index)));
+  }
+
+  /**
+   * Eq. (9) Sigmoid:S(x<sub>g,i,j</sub>(t + 1)) := 1/(1 + e<sup>-x<sub>g,i,j</sub>(t +
+   * 1)</sup>)<br></font>
+   *
+   * @param value
+   * @return
+   */
+  private double Sigmoid(double value) {
+    return 1.0 / (1.0 + Math.exp(-value));
+  }
+
+  /**
+   * To clamp X<sub>g,j,i</sub> and v<sub>i,j</sub> in Range [-X<sub>g,max</sub>|+X<sub>g,max</sub>]
+   * with {X<sub>g,max</sub>= 4}
+   *
+   * @param value
+   * @return
+   */
+  private double clamp(double value) {
+    return Math.max(-maxVelocity, Math.min(maxVelocity, value));
+  }
+
+  private TreeSet<Integer> locationsToMutate(int dimensions) {
+    TreeSet<Integer> mutationLocation = new TreeSet<Integer>(); //sortedSet
+    int maximumAmountOfMutatedBits = Math.max(1,
+        (int) Math.round(((double) dimensions) * this.maxMutationPercent));
+    int randomUniformAmountOfMutatedValues = Random.nextIntegerInRange(1,
+        maximumAmountOfMutatedBits + 1);
+    for (int i = 0; i < randomUniformAmountOfMutatedValues; i++) {
+      boolean success = mutationLocation.add(Random.nextIntegerInRange(0, dimensions));
+      if (!success) {
+        i--; //can be add up to some series long loops if maximumAmountOfMutatedBits get closed to problemsize.
+      }
+    }
+    return mutationLocation;
+  }
+
+
+  @Override
+  protected String algoInformationToPrint() {
 //			private int swarmSize = 20; 
 //			private int swarmSize = 20; 
 //			private int maxIterations = 100; 
 //			private int maxIterations = 100; 
 //			private double limit = 0.01; 
 //			private double limit = 0.01; 
@@ -261,153 +303,69 @@ public class PsoAlgorithm extends AlgorithmFrameworkFlex{
 //			private boolean useIntervalMutation = true;
 //			private boolean useIntervalMutation = true;
 //			private double mutateProbabilityInterval = 0.01;
 //			private double mutateProbabilityInterval = 0.01;
 //			private double maxMutationPercent = 0.01;
 //			private double maxMutationPercent = 0.01;
-		return "PsoAlgo"+ " Rounds:" + rounds 
-				+ " maxIterations:" + maxIterations
-				+ " swarmSize:" + swarmSize
-				+ " dependency:" +  dependency
-				+ " mutationInterval:" +  mutationIteration
-				+ " maxVelocity: " + maxVelocity
-				+ (useIntervalMutation? 
-						(" mutateProbabilityInterval:" +  mutateProbabilityInterval
-						+ " maxMutationPercent:" +  maxMutationPercent) : " mutationRate:" + mutationRate);
-	}
-	
-	
-	
-	
-	
-	
-	
-	
-	
-	
-	
-	
-	
-	
-	
-	
-	
-	
-	
-	
-	
-	
-	
-	
-	
-	
-	
-	/**
-	 * Class to represent a Particle.
-	 */
-	private class Particle{
-		/**
-		 * The velocity of a particle.
-		 */
-		public List<Double> velocity;
-		/**
-		 * The positions genotype.
-		 */
-		public List<Double> xGenotype;
-		/**
-		 * The positions phenotype. Alias the current position.
-		 */
-		public List<Boolean> xPhenotype;
-		
-		public Individual localBest;
-		
-		Particle(List<Boolean> position){
-			this.xPhenotype = position;
-			//Init velocity, xGenotype with 0.0 values.
-			this.velocity = position.stream().map(bool -> 0.0).collect(Collectors.toList());
-			this.xGenotype = position.stream().map(bool -> 0.0).collect(Collectors.toList());
-			localBest = new Individual();
-			localBest.fitness = Double.MAX_VALUE;
-		}
-		public void checkNewEvaluationValue(double newEvaluationValue) {
-			if(newEvaluationValue < localBest.fitness) {
-				localBest.fitness = newEvaluationValue;
-				localBest.position = xPhenotype.stream().map(bool -> bool).collect(Collectors.toList());
-			}
-		}
-		public String toString() {
-			return "Particle with xPhenotype(Position), xGenotype, velocity:[" 
-					+ listToString(xPhenotype) + "],[" + listToString(xGenotype) + "],[" 
-					+ listToString(velocity) + "]";
-		}
-		private <Type> String listToString(List<Type> list) {
-			return list.stream().map(Object::toString).collect(Collectors.joining(", "));
-		}
-		
-	}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-	@Override
-	protected String plottFileName() {
-		return "plottPsoAlgo.txt";
-	}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+    return "PsoAlgo" + " Rounds:" + rounds
+        + " maxIterations:" + maxIterations
+        + " swarmSize:" + swarmSize
+        + " dependency:" + dependency
+        + " mutationInterval:" + mutationIteration
+        + " maxVelocity: " + maxVelocity
+        + (useIntervalMutation ?
+        (" mutateProbabilityInterval:" + mutateProbabilityInterval
+            + " maxMutationPercent:" + maxMutationPercent) : " mutationRate:" + mutationRate);
+  }
+
+  @Override
+  protected String plottFileName() {
+    return "plottPsoAlgo.txt";
+  }
+
+  /**
+   * Class to represent a Particle.
+   */
+  private class Particle {
+
+    /**
+     * The velocity of a particle.
+     */
+    public List<Double> velocity;
+    /**
+     * The positions genotype.
+     */
+    public List<Double> xGenotype;
+    /**
+     * The positions phenotype. Alias the current position.
+     */
+    public List<Boolean> xPhenotype;
+
+    public Individual localBest;
+
+    Particle(List<Boolean> position) {
+      this.xPhenotype = position;
+      //Init velocity, xGenotype with 0.0 values.
+      this.velocity = position.stream().map(bool -> 0.0).collect(Collectors.toList());
+      this.xGenotype = position.stream().map(bool -> 0.0).collect(Collectors.toList());
+      localBest = new Individual();
+      localBest.fitness = Double.MAX_VALUE;
+    }
+
+    public void checkNewEvaluationValue(double newEvaluationValue) {
+      if (newEvaluationValue < localBest.fitness) {
+        localBest.fitness = newEvaluationValue;
+        localBest.position = xPhenotype.stream().map(bool -> bool).collect(Collectors.toList());
+      }
+    }
+
+    public String toString() {
+      return "Particle with xPhenotype(Position), xGenotype, velocity:["
+          + listToString(xPhenotype) + "],[" + listToString(xGenotype) + "],["
+          + listToString(velocity) + "]";
+    }
+
+    private <Type> String listToString(List<Type> list) {
+      return list.stream().map(Object::toString).collect(Collectors.joining(", "));
+    }
+
+  }
 
 
-		
-		
-		
-		
-		
 
 
 }
 }

+ 469 - 452
src/holeg/algorithm/example/DemoAlgo.java

@@ -1,5 +1,15 @@
 package holeg.algorithm.example;
 package holeg.algorithm.example;
 
 
+import holeg.api.AddOn;
+import holeg.model.AbstractCanvasObject;
+import holeg.model.GroupNode;
+import holeg.model.HolonElement;
+import holeg.model.HolonObject;
+import holeg.model.HolonSwitch;
+import holeg.model.HolonSwitch.SwitchMode;
+import holeg.model.HolonSwitch.SwitchState;
+import holeg.model.Model;
+import holeg.ui.controller.Control;
 import java.awt.BorderLayout;
 import java.awt.BorderLayout;
 import java.awt.Component;
 import java.awt.Component;
 import java.awt.Dimension;
 import java.awt.Dimension;
@@ -12,7 +22,6 @@ import java.util.List;
 import java.util.Optional;
 import java.util.Optional;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Stream;
 import java.util.stream.Stream;
-
 import javax.swing.BorderFactory;
 import javax.swing.BorderFactory;
 import javax.swing.ImageIcon;
 import javax.swing.ImageIcon;
 import javax.swing.JButton;
 import javax.swing.JButton;
@@ -27,466 +36,474 @@ import javax.swing.JSplitPane;
 import javax.swing.JTextArea;
 import javax.swing.JTextArea;
 import javax.swing.text.NumberFormatter;
 import javax.swing.text.NumberFormatter;
 
 
-import holeg.api.AddOn;
-import holeg.model.AbstractCanvasObject;
-import holeg.model.GroupNode;
-import holeg.model.HolonElement;
-import holeg.model.HolonObject;
-import holeg.model.HolonSwitch;
-import holeg.model.HolonSwitch.SwitchMode;
-import holeg.model.HolonSwitch.SwitchState;
-import holeg.ui.controller.Control;
-import holeg.model.Model;
-
 public class DemoAlgo implements AddOn {
 public class DemoAlgo implements AddOn {
 
 
-	//Parameter for Algo with default Values:
-		
-		//Settings For GroupNode using and cancel
-		private boolean useGroupNode = false;
-		private Optional<GroupNode> groupNode = Optional.empty();
-		private boolean cancel = false;
-
-
-		//Parameter defined by Algo
-		private HashMap<Integer, AccessWrapper> access;
-		private List<Boolean> initialState;
-		private List<HolonSwitch> switchList;
-		private List<HolonObject> objectList;
-		
-		//Gui Part:
-		private Control  control;
-		private JTextArea textArea;
-		private JPanel content = new JPanel();
-		private long startTime;
-		private Thread runThread;
-		//Windrad
-		private HolonObject windrad;
-		
-		
-		private int waitDurationWindradStep = 400;
-		private int waitDurationEnd = 1000;
-
-		int counter;
-		
-		
-		public static void main(String[] args)
-		{
-		      JFrame newFrame = new JFrame("exampleWindow");
-		      DemoAlgo instance = new DemoAlgo();
-		      newFrame.setContentPane(instance.getPanel());
-		      newFrame.pack();
-		      newFrame.setVisible(true);
-		      newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
-		}
-		public DemoAlgo() {
-			content.setLayout(new BorderLayout());
-		
-			textArea = new JTextArea();
-			textArea.setEditable(false);
-			JScrollPane scrollPane = new JScrollPane(textArea);
-			JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
-					createOptionPanel() , scrollPane);
-			splitPane.setResizeWeight(0.0);
-			content.add(splitPane, BorderLayout.CENTER);
-			content.setPreferredSize(new Dimension(800,800));	
-		}
-		public JPanel createOptionPanel() {
-			JPanel optionPanel = new JPanel(new BorderLayout());
-			JScrollPane scrollPane = new JScrollPane(createParameterPanel());
-			scrollPane.setBorder(BorderFactory.createTitledBorder("Parameter"));
-			optionPanel.add(scrollPane,  BorderLayout.CENTER);
-			optionPanel.add(createButtonPanel(), BorderLayout.PAGE_END);
-			return optionPanel;
-		}
-		
-		private Component createParameterPanel() {
-			JPanel parameterPanel = new JPanel(null);
-			parameterPanel.setPreferredSize(new Dimension(510,300));
-			
-			
-		
+  //Parameter for Algo with default Values:
+
+  int counter;
+  //Settings For GroupNode using and cancel
+  private boolean useGroupNode = false;
+  private Optional<GroupNode> groupNode = Optional.empty();
+  private boolean cancel = false;
+  //Parameter defined by Algo
+  private HashMap<Integer, AccessWrapper> access;
+  private List<Boolean> initialState;
+  private List<HolonSwitch> switchList;
+  private List<HolonObject> objectList;
+  //Gui Part:
+  private Control control;
+  private JTextArea textArea;
+  private JPanel content = new JPanel();
+  private long startTime;
+  private Thread runThread;
+  //Windrad
+  private HolonObject windrad;
+  private int waitDurationWindradStep = 400;
+  private int waitDurationEnd = 1000;
+
+
+  public DemoAlgo() {
+    content.setLayout(new BorderLayout());
+
+    textArea = new JTextArea();
+    textArea.setEditable(false);
+    JScrollPane scrollPane = new JScrollPane(textArea);
+    JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
+        createOptionPanel(), scrollPane);
+    splitPane.setResizeWeight(0.0);
+    content.add(splitPane, BorderLayout.CENTER);
+    content.setPreferredSize(new Dimension(800, 800));
+  }
+
+  public static void main(String[] args) {
+    JFrame newFrame = new JFrame("exampleWindow");
+    DemoAlgo instance = new DemoAlgo();
+    newFrame.setContentPane(instance.getPanel());
+    newFrame.pack();
+    newFrame.setVisible(true);
+    newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+  }
+
+  public JPanel createOptionPanel() {
+    JPanel optionPanel = new JPanel(new BorderLayout());
+    JScrollPane scrollPane = new JScrollPane(createParameterPanel());
+    scrollPane.setBorder(BorderFactory.createTitledBorder("Parameter"));
+    optionPanel.add(scrollPane, BorderLayout.CENTER);
+    optionPanel.add(createButtonPanel(), BorderLayout.PAGE_END);
+    return optionPanel;
+  }
+
+  private Component createParameterPanel() {
+    JPanel parameterPanel = new JPanel(null);
+    parameterPanel.setPreferredSize(new Dimension(510, 300));
+
 //			JLabel showDiagnosticsLabel = new JLabel("Set all switches closed:");
 //			JLabel showDiagnosticsLabel = new JLabel("Set all switches closed:");
 //			showDiagnosticsLabel.setBounds(200, 60, 170, 20);
 //			showDiagnosticsLabel.setBounds(200, 60, 170, 20);
 //			parameterPanel.add(showDiagnosticsLabel);		
 //			parameterPanel.add(showDiagnosticsLabel);		
-		
-			
-			JPanel borderPanel = new JPanel(null);
-			borderPanel.setBounds(200, 85, 185, 50);
-			borderPanel.setBorder(BorderFactory.createTitledBorder(""));
-			parameterPanel.add(borderPanel);	
-			
-			JLabel showGroupNodeLabel = new JLabel("Use Group Node:");
-			showGroupNodeLabel.setBounds(10, 1, 170, 20);
-			borderPanel.add(showGroupNodeLabel);	
-			
-			JButton selectGroupNodeButton = new JButton("Select GroupNode");
-			selectGroupNodeButton.setEnabled(false);
-			selectGroupNodeButton.setBounds(10, 25, 165, 20);
-			selectGroupNodeButton.addActionListener(actionEvent -> selectGroupNode());
-			borderPanel.add(selectGroupNodeButton);	
-			
-			JCheckBox useGroupNodeCheckBox = new JCheckBox();
-			useGroupNodeCheckBox.setSelected(false);
-			useGroupNodeCheckBox.setBounds(155, 1, 25, 20);
-			useGroupNodeCheckBox.addActionListener(actionEvent -> {
-				useGroupNode = useGroupNodeCheckBox.isSelected();
-				selectGroupNodeButton.setEnabled(useGroupNode);
-			});
-			borderPanel.add(useGroupNodeCheckBox);
-			
-			
+
+    JPanel borderPanel = new JPanel(null);
+    borderPanel.setBounds(200, 85, 185, 50);
+    borderPanel.setBorder(BorderFactory.createTitledBorder(""));
+    parameterPanel.add(borderPanel);
+
+    JLabel showGroupNodeLabel = new JLabel("Use Group Node:");
+    showGroupNodeLabel.setBounds(10, 1, 170, 20);
+    borderPanel.add(showGroupNodeLabel);
+
+    JButton selectGroupNodeButton = new JButton("Select GroupNode");
+    selectGroupNodeButton.setEnabled(false);
+    selectGroupNodeButton.setBounds(10, 25, 165, 20);
+    selectGroupNodeButton.addActionListener(actionEvent -> selectGroupNode());
+    borderPanel.add(selectGroupNodeButton);
+
+    JCheckBox useGroupNodeCheckBox = new JCheckBox();
+    useGroupNodeCheckBox.setSelected(false);
+    useGroupNodeCheckBox.setBounds(155, 1, 25, 20);
+    useGroupNodeCheckBox.addActionListener(actionEvent -> {
+      useGroupNode = useGroupNodeCheckBox.isSelected();
+      selectGroupNodeButton.setEnabled(useGroupNode);
+    });
+    borderPanel.add(useGroupNodeCheckBox);
+
 //			JCheckBox switchesCheckBox = new JCheckBox();
 //			JCheckBox switchesCheckBox = new JCheckBox();
 //			switchesCheckBox.setSelected(closeSwitches);
 //			switchesCheckBox.setSelected(closeSwitches);
 //			switchesCheckBox.setBounds(370, 60, 25, 20);
 //			switchesCheckBox.setBounds(370, 60, 25, 20);
 //			switchesCheckBox.addActionListener(actionEvent -> closeSwitches = switchesCheckBox.isSelected());
 //			switchesCheckBox.addActionListener(actionEvent -> closeSwitches = switchesCheckBox.isSelected());
 //			parameterPanel.add(switchesCheckBox);
 //			parameterPanel.add(switchesCheckBox);
-			
-			JButton selectRoom1Button = new JButton("Select");
-			selectRoom1Button.setBounds(10,300, 90, 20);
-			selectRoom1Button.addActionListener(actionEvent -> this.selectHolonObject());
-			parameterPanel.add(selectRoom1Button);
-			NumberFormat format = NumberFormat.getIntegerInstance();
-			format.setGroupingUsed(false);
-			format.setParseIntegerOnly(true);
-			NumberFormatter integerFormatter = new NumberFormatter(format);
-			integerFormatter.setMinimum(0);
-			integerFormatter.setCommitsOnValidEdit(true);
-			JLabel portLabel = new JLabel("between:");
-			portLabel.setBounds(10, 330, 70, 30);
-			parameterPanel.add(portLabel);
-			JFormattedTextField betweenTF = new JFormattedTextField(integerFormatter);
-			betweenTF.setText(""+waitDurationWindradStep);
-			betweenTF.setBounds(80 ,330, 80, 30);
-			betweenTF.addPropertyChangeListener(propertyChange ->{
-				String text = betweenTF.getValue().toString();
-				text = text.replaceAll("\\s", "");
-				waitDurationWindradStep = Integer.parseInt((text));
-			});
-			parameterPanel.add(betweenTF);
-			JLabel afterLabel = new JLabel("after:");
-			afterLabel.setBounds(10, 360, 70, 30);
-			parameterPanel.add(afterLabel);
-			JFormattedTextField afterTF = new JFormattedTextField(integerFormatter);
-			afterTF.setText(""+waitDurationEnd);
-			afterTF.setBounds(80 ,360, 80, 30);
-			afterTF.addPropertyChangeListener(propertyChange ->{
-				String text = afterTF.getValue().toString();
-				text = text.replaceAll("\\s", "");
-				waitDurationEnd = Integer.parseInt((text));
-			});
-			parameterPanel.add(afterTF);
-			
-			
-			return parameterPanel;
-		}
-		public JPanel createButtonPanel() {
-			JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
-			JButton cancelButton =  new JButton("Cancel Run");
-			cancelButton.addActionListener(actionEvent -> cancel());
-			buttonPanel.add(cancelButton);
-			JButton clearButton =  new JButton("Clear Console");
-			clearButton.addActionListener(actionEvent -> clear());
-			buttonPanel.add(clearButton);
-			JButton resetButton =  new JButton("Reset");
-			resetButton.setToolTipText("Resets the State to before the Algorithm has runed.");
-			resetButton.addActionListener(actionEvent -> reset());
-			buttonPanel.add(resetButton);
-			JButton runButton =  new JButton("Run");
-			runButton.addActionListener(actionEvent -> {
-				Runnable task = () -> run();
-				runThread = new Thread(task);
-				runThread.start();
-			});
-			buttonPanel.add(runButton);
-			return buttonPanel;
-		}
-		private void cancel() {
-			if(runThread.isAlive()) {
-				println("");
-				println("Cancel run.");
-				cancel = true;
-			} else {
-				println("Nothing to cancel.");
-			}
-		}
-		
-		private void run() {
-			cancel = false;
-			disableGuiInput(true);
-			startTimer();
-			executeDemoAlgo();
-			if(cancel) {
-				reset();
-				disableGuiInput(false);
-				return;
-			}
-			printElapsedTime();
-			disableGuiInput(false);
-		}
-		
-		private void reset() {
-			if(initialState != null) {
-				println("Resetting..");
-				resetState();
-				updateVisual();
-			}else {
-				println("No run inistialized.");
-			}
-		}
-		
-		
-		private void disableGuiInput(boolean bool) {
-			control.guiSetEnabled(bool);
-		}
-		
-		
-		
-
-		
-		
-		@Override
-		public JPanel getPanel() {
-			return content;
-		}
-		@Override
-		public void setController(Control control) {
-			this.control = control;
-			
-		}
-		private void clear() {
-			textArea.setText("");
-		}
-		private void println(String message) {
-			textArea.append(message  + "\n");
-		}
-		private void selectGroupNode() {
-			Object[] possibilities = control.getModel().getCanvas().getAllGroupNodeObjectsRecursive().toArray();
-			GroupNode selected = (GroupNode) JOptionPane.showInputDialog(content, "Select GroupNode:", "GroupNode?",  JOptionPane.OK_OPTION,new ImageIcon(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)) , possibilities, "");
-			if(selected != null) {
-				println("Selected: " + selected);
-				groupNode = Optional.of(selected);
-			}
-			
-		}
-		private void startTimer(){
-			startTime = System.currentTimeMillis();
-		}
-		private void printElapsedTime(){
-			long elapsedMilliSeconds = System.currentTimeMillis() - startTime;
-			println("Execution Time of Algo in Milliseconds:" + elapsedMilliSeconds);
-		}
-		
-		
-		
-		
-		//Algo Part:
-		
-		private void executeDemoAlgo() {
-			extractPositionAndAccess();
-			counter = 0;
-			int actualIteration = control.getModel().getCurrentIteration();
-			deactivateWindrad();
-			setAllSwitchesClosed();
-			updateVisual();
-			
-			try {
-				//Schalte Slow das Windrad Ein
-				if(windrad == null)return;
-				windrad.elementsStream().forEach(hE -> {
-					hE.active = true;
-					try {
-						TimeUnit.MILLISECONDS.sleep(waitDurationWindradStep);
-					} catch (InterruptedException e) {
-					}
-					updateVisual();
-				});
-				TimeUnit.MILLISECONDS.sleep(waitDurationEnd);
-			} catch (InterruptedException e) {
-			}
-			
-			setHolonElemntsAktiv(actualIteration);
-			println("Changed Elements: " + counter);
-			updateVisual();
-		}
-
-		
-		
-
-			
-		
-		private void deactivateWindrad() {
-			if(windrad == null)return;
-			windrad.elementsStream().forEach(ele -> ele.active = false);
-		}
-		private void setHolonElemntsAktiv(int actualIteration) {
-			for(int i = 0;i<access.size();i++) {
-				AccessWrapper aw = access.get(i);
-				if(aw.getState(actualIteration) ==false) counter++;
-				if(aw.getType() == AccessWrapper.HOLONELEMENT) aw.setState(true);
-			}
-		}
-		private void setAllSwitchesClosed() {
-			for(HolonSwitch hSwitch : switchList) {
-				if(hSwitch.getManualState().isOpen()) counter++;
-				hSwitch.setMode(SwitchMode.Manual);
-				hSwitch.setManualState(SwitchState.Closed);
-			}
-			
-		}
-		/**
-		 * Method to get the current Position alias a ListOf Booleans for aktive settings on the Objects on the Canvas.
-		 * Also initialize the Access Hashmap to swap faster positions.
-		 * @return
-		 */
-		private List<Boolean> extractPositionAndAccess() {
-			Model model = control.getModel();
-			switchList = new ArrayList<HolonSwitch>();
-			objectList = new ArrayList<HolonObject>();
-			initialState = new ArrayList<Boolean>(); 
-			access= new HashMap<Integer, AccessWrapper>();
-			rollOutNodes((useGroupNode && groupNode.isPresent())? groupNode.get().getObjectsInThisLayer() :model.getCanvas().getObjectsInThisLayer(), initialState, model.getCurrentIteration());
-			return initialState;
-		}
-		/**
-		 * Method to extract the Informations recursively out of the Model.
-		 * @param nodes
-		 * @param positionToInit
-		 * @param timeStep
-		 */
-		private void rollOutNodes(Stream<AbstractCanvasObject> nodes, List<Boolean> positionToInit, int timeStep) {
-			nodes.forEach(aCps -> {
-				if (aCps instanceof HolonObject hO) {
-					hO.elementsStream().forEach(hE -> {
-						positionToInit.add(hE.active);
-						access.put(positionToInit.size() - 1 , new AccessWrapper(hE));
-					});
-					objectList.add(hO);
-				}
-				else if (aCps instanceof HolonSwitch sw) {
-					positionToInit.add(sw.getState().isClosed());
-					switchList.add(sw);
-					access.put(positionToInit.size() - 1 , new AccessWrapper(sw));
-				}
-				else if(aCps instanceof GroupNode groupnode) {			
-					rollOutGroupNode(groupnode, positionToInit ,timeStep);
-				}
-			});
-
-		}
-		
-		
-		private void rollOutGroupNode (GroupNode groupNode, List<Boolean> positionToInit, int timeStep) {
-			groupNode.getAllHolonObjectsRecursive().forEach(hObject -> {
-				hObject.elementsStream().forEach(hE -> {
-					positionToInit.add(hE.active);
-					access.put(positionToInit.size() - 1 , new AccessWrapper(hE));					
-				});
-				objectList.add(hObject);
-			});
-			groupNode.getAllSwitchObjectsRecursive().forEach(sw -> {
-				positionToInit.add(sw.getState().isClosed());
-				switchList.add(sw);
-				access.put(positionToInit.size() - 1 , new AccessWrapper(sw));
-			});
-			
-		}
-		/**
-		 * To let the User See the current state without touching the Canvas.
-		 */
-		private void updateVisual() {
-			control.calculateStateForCurrentIteration();
-		}
-		/**
-		 * Sets the Model back to its original State before the LAST run.
-		 */
-		private void resetState() {
-			setState(initialState);
-		}
-		
-		/**
-		 * Sets the State out of the given position for calculation or to show the user.
-		 * @param position
-		 */
-		private void setState(List<Boolean> position) {
-			for(int i = 0;i<position.size();i++) {
-				access.get(i).setState(position.get(i));
-			}
-		}
-		
-
-		private void selectHolonObject() {
-			List<HolonObject> holonObjectList = new ArrayList<HolonObject>();
-			addObjectToList(control.getModel().getCanvas().getObjectsInThisLayer().toList(),holonObjectList);
-			Object[] possibilities = holonObjectList.stream().map(aCps -> new Handle<HolonObject>(aCps)).toArray();
-			@SuppressWarnings("unchecked")
-			Handle<HolonObject> selected = (Handle<HolonObject>) JOptionPane.showInputDialog(content, "Select HolonObject:", "HolonObject?",  JOptionPane.OK_OPTION,new ImageIcon(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)) , possibilities, "");
-			if(selected != null) {
-				//println("Selected: " + selected);
-				windrad = selected.object;
-			}
-		}
-
-
-
-
-		private void addObjectToList(List<AbstractCanvasObject> listToSearch, List<HolonObject> listToAdd){
-			for (AbstractCanvasObject aCps : listToSearch) {
-				if (aCps instanceof HolonObject hO) listToAdd.add(hO);
-				else if(aCps instanceof GroupNode groupNode) {
-					listToAdd.addAll(groupNode.getAllHolonObjectsRecursive().toList());
-				}
-			}
-		}
-		
-		
-		
-		
-		/**
-		 * A Wrapper Class for Access HolonElement and HolonSwitch in one Element and not have to split the List.
-		 */
-		private class AccessWrapper {
-			public static final int HOLONELEMENT = 0;
-			public static final int SWITCH = 1;
-			private int type;
-			private HolonSwitch hSwitch;
-			private HolonElement hElement;
-			public AccessWrapper(HolonSwitch hSwitch){
-				type = SWITCH;
-				this.hSwitch = hSwitch;
-			}
-			public AccessWrapper(HolonElement hElement){
-				type = HOLONELEMENT;
-				this.hElement = hElement;
-			}
-			public void setState(boolean state) {
-				if(type == HOLONELEMENT) {
-					hElement.active = state;
-				}else{//is switch
-					hSwitch.setMode(SwitchMode.Manual);
-					hSwitch.setManualState(state? SwitchState.Closed: SwitchState.Open);
-				}
-					
-			}
-			public boolean getState(int timeStep) {
-				return (type == HOLONELEMENT)?hElement.active:hSwitch.getState().isClosed();
-			}
-			public int getType() {
-				return type;
-			}
-		}
-		
-		
-		
-		
-		private   class  Handle<T>{
-			public T object;
-			Handle(T object){
-				this.object = object;
-			}
-			public String toString() {
-				return object.toString();
-			}
-		}
+
+    JButton selectRoom1Button = new JButton("Select");
+    selectRoom1Button.setBounds(10, 300, 90, 20);
+    selectRoom1Button.addActionListener(actionEvent -> this.selectHolonObject());
+    parameterPanel.add(selectRoom1Button);
+    NumberFormat format = NumberFormat.getIntegerInstance();
+    format.setGroupingUsed(false);
+    format.setParseIntegerOnly(true);
+    NumberFormatter integerFormatter = new NumberFormatter(format);
+    integerFormatter.setMinimum(0);
+    integerFormatter.setCommitsOnValidEdit(true);
+    JLabel portLabel = new JLabel("between:");
+    portLabel.setBounds(10, 330, 70, 30);
+    parameterPanel.add(portLabel);
+    JFormattedTextField betweenTF = new JFormattedTextField(integerFormatter);
+    betweenTF.setText("" + waitDurationWindradStep);
+    betweenTF.setBounds(80, 330, 80, 30);
+    betweenTF.addPropertyChangeListener(propertyChange -> {
+      String text = betweenTF.getValue().toString();
+      text = text.replaceAll("\\s", "");
+      waitDurationWindradStep = Integer.parseInt((text));
+    });
+    parameterPanel.add(betweenTF);
+    JLabel afterLabel = new JLabel("after:");
+    afterLabel.setBounds(10, 360, 70, 30);
+    parameterPanel.add(afterLabel);
+    JFormattedTextField afterTF = new JFormattedTextField(integerFormatter);
+    afterTF.setText("" + waitDurationEnd);
+    afterTF.setBounds(80, 360, 80, 30);
+    afterTF.addPropertyChangeListener(propertyChange -> {
+      String text = afterTF.getValue().toString();
+      text = text.replaceAll("\\s", "");
+      waitDurationEnd = Integer.parseInt((text));
+    });
+    parameterPanel.add(afterTF);
+
+    return parameterPanel;
+  }
+
+  public JPanel createButtonPanel() {
+    JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+    JButton cancelButton = new JButton("Cancel Run");
+    cancelButton.addActionListener(actionEvent -> cancel());
+    buttonPanel.add(cancelButton);
+    JButton clearButton = new JButton("Clear Console");
+    clearButton.addActionListener(actionEvent -> clear());
+    buttonPanel.add(clearButton);
+    JButton resetButton = new JButton("Reset");
+    resetButton.setToolTipText("Resets the State to before the Algorithm has runed.");
+    resetButton.addActionListener(actionEvent -> reset());
+    buttonPanel.add(resetButton);
+    JButton runButton = new JButton("Run");
+    runButton.addActionListener(actionEvent -> {
+      Runnable task = () -> run();
+      runThread = new Thread(task);
+      runThread.start();
+    });
+    buttonPanel.add(runButton);
+    return buttonPanel;
+  }
+
+  private void cancel() {
+    if (runThread.isAlive()) {
+      println("");
+      println("Cancel run.");
+      cancel = true;
+    } else {
+      println("Nothing to cancel.");
+    }
+  }
+
+  private void run() {
+    cancel = false;
+    disableGuiInput(true);
+    startTimer();
+    executeDemoAlgo();
+    if (cancel) {
+      reset();
+      disableGuiInput(false);
+      return;
+    }
+    printElapsedTime();
+    disableGuiInput(false);
+  }
+
+  private void reset() {
+    if (initialState != null) {
+      println("Resetting..");
+      resetState();
+      updateVisual();
+    } else {
+      println("No run inistialized.");
+    }
+  }
+
+
+  private void disableGuiInput(boolean bool) {
+    control.guiSetEnabled(bool);
+  }
+
+
+  @Override
+  public JPanel getPanel() {
+    return content;
+  }
+
+  @Override
+  public void setController(Control control) {
+    this.control = control;
+
+  }
+
+  private void clear() {
+    textArea.setText("");
+  }
+
+  private void println(String message) {
+    textArea.append(message + "\n");
+  }
+
+  private void selectGroupNode() {
+    Object[] possibilities = control.getModel().getCanvas().getAllGroupNodeObjectsRecursive()
+        .toArray();
+    GroupNode selected = (GroupNode) JOptionPane.showInputDialog(content, "Select GroupNode:",
+        "GroupNode?", JOptionPane.OK_OPTION,
+        new ImageIcon(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)), possibilities, "");
+    if (selected != null) {
+      println("Selected: " + selected);
+      groupNode = Optional.of(selected);
+    }
+
+  }
+
+  private void startTimer() {
+    startTime = System.currentTimeMillis();
+  }
+
+  private void printElapsedTime() {
+    long elapsedMilliSeconds = System.currentTimeMillis() - startTime;
+    println("Execution Time of Algo in Milliseconds:" + elapsedMilliSeconds);
+  }
+
+  //Algo Part:
+
+  private void executeDemoAlgo() {
+    extractPositionAndAccess();
+    counter = 0;
+    int actualIteration = control.getModel().getCurrentIteration();
+    deactivateWindrad();
+    setAllSwitchesClosed();
+    updateVisual();
+
+    try {
+      //Schalte Slow das Windrad Ein
+      if (windrad == null) {
+        return;
+      }
+      windrad.elementsStream().forEach(hE -> {
+        hE.active = true;
+        try {
+          TimeUnit.MILLISECONDS.sleep(waitDurationWindradStep);
+        } catch (InterruptedException e) {
+        }
+        updateVisual();
+      });
+      TimeUnit.MILLISECONDS.sleep(waitDurationEnd);
+    } catch (InterruptedException e) {
+    }
+
+    setHolonElemntsAktiv(actualIteration);
+    println("Changed Elements: " + counter);
+    updateVisual();
+  }
+
+
+  private void deactivateWindrad() {
+    if (windrad == null) {
+      return;
+    }
+    windrad.elementsStream().forEach(ele -> ele.active = false);
+  }
+
+  private void setHolonElemntsAktiv(int actualIteration) {
+    for (int i = 0; i < access.size(); i++) {
+      AccessWrapper aw = access.get(i);
+      if (aw.getState(actualIteration) == false) {
+        counter++;
+      }
+      if (aw.getType() == AccessWrapper.HOLONELEMENT) {
+        aw.setState(true);
+      }
+    }
+  }
+
+  private void setAllSwitchesClosed() {
+    for (HolonSwitch hSwitch : switchList) {
+      if (hSwitch.getManualState().isOpen()) {
+        counter++;
+      }
+      hSwitch.setMode(SwitchMode.Manual);
+      hSwitch.setManualState(SwitchState.Closed);
+    }
+
+  }
+
+  /**
+   * Method to get the current Position alias a ListOf Booleans for aktive settings on the Objects
+   * on the Canvas. Also initialize the Access Hashmap to swap faster positions.
+   *
+   * @return
+   */
+  private List<Boolean> extractPositionAndAccess() {
+    Model model = control.getModel();
+    switchList = new ArrayList<HolonSwitch>();
+    objectList = new ArrayList<HolonObject>();
+    initialState = new ArrayList<Boolean>();
+    access = new HashMap<Integer, AccessWrapper>();
+    rollOutNodes((useGroupNode && groupNode.isPresent()) ? groupNode.get().getObjectsInThisLayer()
+        : model.getCanvas().getObjectsInThisLayer(), initialState, model.getCurrentIteration());
+    return initialState;
+  }
+
+  /**
+   * Method to extract the Informations recursively out of the Model.
+   *
+   * @param nodes
+   * @param positionToInit
+   * @param timeStep
+   */
+  private void rollOutNodes(Stream<AbstractCanvasObject> nodes, List<Boolean> positionToInit,
+      int timeStep) {
+    nodes.forEach(aCps -> {
+      if (aCps instanceof HolonObject hO) {
+        hO.elementsStream().forEach(hE -> {
+          positionToInit.add(hE.active);
+          access.put(positionToInit.size() - 1, new AccessWrapper(hE));
+        });
+        objectList.add(hO);
+      } else if (aCps instanceof HolonSwitch sw) {
+        positionToInit.add(sw.getState().isClosed());
+        switchList.add(sw);
+        access.put(positionToInit.size() - 1, new AccessWrapper(sw));
+      } else if (aCps instanceof GroupNode groupnode) {
+        rollOutGroupNode(groupnode, positionToInit, timeStep);
+      }
+    });
+
+  }
+
+
+  private void rollOutGroupNode(GroupNode groupNode, List<Boolean> positionToInit, int timeStep) {
+    groupNode.getAllHolonObjectsRecursive().forEach(hObject -> {
+      hObject.elementsStream().forEach(hE -> {
+        positionToInit.add(hE.active);
+        access.put(positionToInit.size() - 1, new AccessWrapper(hE));
+      });
+      objectList.add(hObject);
+    });
+    groupNode.getAllSwitchObjectsRecursive().forEach(sw -> {
+      positionToInit.add(sw.getState().isClosed());
+      switchList.add(sw);
+      access.put(positionToInit.size() - 1, new AccessWrapper(sw));
+    });
+
+  }
+
+  /**
+   * To let the User See the current state without touching the Canvas.
+   */
+  private void updateVisual() {
+    control.calculateStateForCurrentIteration();
+  }
+
+  /**
+   * Sets the Model back to its original State before the LAST run.
+   */
+  private void resetState() {
+    setState(initialState);
+  }
+
+  /**
+   * Sets the State out of the given position for calculation or to show the user.
+   *
+   * @param position
+   */
+  private void setState(List<Boolean> position) {
+    for (int i = 0; i < position.size(); i++) {
+      access.get(i).setState(position.get(i));
+    }
+  }
+
+
+  private void selectHolonObject() {
+    List<HolonObject> holonObjectList = new ArrayList<HolonObject>();
+    addObjectToList(control.getModel().getCanvas().getObjectsInThisLayer().toList(),
+        holonObjectList);
+    Object[] possibilities = holonObjectList.stream().map(aCps -> new Handle<HolonObject>(aCps))
+        .toArray();
+    @SuppressWarnings("unchecked")
+    Handle<HolonObject> selected = (Handle<HolonObject>) JOptionPane.showInputDialog(content,
+        "Select HolonObject:", "HolonObject?", JOptionPane.OK_OPTION,
+        new ImageIcon(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)), possibilities, "");
+    if (selected != null) {
+      //println("Selected: " + selected);
+      windrad = selected.object;
+    }
+  }
+
+
+  private void addObjectToList(List<AbstractCanvasObject> listToSearch,
+      List<HolonObject> listToAdd) {
+    for (AbstractCanvasObject aCps : listToSearch) {
+      if (aCps instanceof HolonObject hO) {
+        listToAdd.add(hO);
+      } else if (aCps instanceof GroupNode groupNode) {
+        listToAdd.addAll(groupNode.getAllHolonObjectsRecursive().toList());
+      }
+    }
+  }
+
+
+  /**
+   * A Wrapper Class for Access HolonElement and HolonSwitch in one Element and not have to split
+   * the List.
+   */
+  private class AccessWrapper {
+
+    public static final int HOLONELEMENT = 0;
+    public static final int SWITCH = 1;
+    private int type;
+    private HolonSwitch hSwitch;
+    private HolonElement hElement;
+
+    public AccessWrapper(HolonSwitch hSwitch) {
+      type = SWITCH;
+      this.hSwitch = hSwitch;
+    }
+
+    public AccessWrapper(HolonElement hElement) {
+      type = HOLONELEMENT;
+      this.hElement = hElement;
+    }
+
+    public void setState(boolean state) {
+      if (type == HOLONELEMENT) {
+        hElement.active = state;
+      } else {//is switch
+        hSwitch.setMode(SwitchMode.Manual);
+        hSwitch.setManualState(state ? SwitchState.Closed : SwitchState.Open);
+      }
+
+    }
+
+    public boolean getState(int timeStep) {
+      return (type == HOLONELEMENT) ? hElement.active : hSwitch.getState().isClosed();
+    }
+
+    public int getType() {
+      return type;
+    }
+  }
+
+
+  private class Handle<T> {
+
+    public T object;
+
+    Handle(T object) {
+      this.object = object;
+    }
+
+    public String toString() {
+      return object.toString();
+    }
+  }
 
 
 }
 }

+ 540 - 523
src/holeg/algorithm/example/FlexExample.java

@@ -1,5 +1,18 @@
 package holeg.algorithm.example;
 package holeg.algorithm.example;
 
 
+import holeg.api.AddOn;
+import holeg.model.AbstractCanvasObject;
+import holeg.model.Flexibility;
+import holeg.model.GroupNode;
+import holeg.model.HolonElement;
+import holeg.model.HolonElement.Priority;
+import holeg.model.HolonObject;
+import holeg.model.HolonObject.HolonObjectState;
+import holeg.model.HolonSwitch;
+import holeg.model.HolonSwitch.SwitchMode;
+import holeg.model.HolonSwitch.SwitchState;
+import holeg.model.Model;
+import holeg.ui.controller.Control;
 import java.awt.BorderLayout;
 import java.awt.BorderLayout;
 import java.awt.Component;
 import java.awt.Component;
 import java.awt.Dimension;
 import java.awt.Dimension;
@@ -14,7 +27,6 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import java.util.stream.Stream;
-
 import javax.swing.BorderFactory;
 import javax.swing.BorderFactory;
 import javax.swing.ImageIcon;
 import javax.swing.ImageIcon;
 import javax.swing.JButton;
 import javax.swing.JButton;
@@ -28,313 +40,290 @@ import javax.swing.JSplitPane;
 import javax.swing.JTextArea;
 import javax.swing.JTextArea;
 import javax.swing.text.NumberFormatter;
 import javax.swing.text.NumberFormatter;
 
 
-import holeg.api.AddOn;
-import holeg.model.AbstractCanvasObject;
-import holeg.model.Flexibility;
-import holeg.model.GroupNode;
-import holeg.model.HolonElement;
-import holeg.model.HolonObject;
-import holeg.model.HolonObject.HolonObjectState;
-import holeg.model.HolonSwitch.SwitchMode;
-import holeg.model.HolonSwitch.SwitchState;
-import holeg.model.HolonSwitch;
-import holeg.model.HolonElement.Priority;
-import holeg.ui.controller.Control;
-import holeg.model.Model;
-
 public class FlexExample implements AddOn {
 public class FlexExample implements AddOn {
-		
-		//Settings For GroupNode using and cancel
-		private boolean useGroupNode = false;
-		private Optional<GroupNode> groupnode = Optional.empty();
-		private boolean cancel = false;
-		private boolean overAllTimeSteps = false;
-		
-		
-
-		//Parameter defined by Algo
-		private HashMap<Integer, AccessWrapper> access;
-		LinkedList<List<Boolean>> resetChain = new LinkedList<List<Boolean>>();
-		private List<Boolean> initialState;
-		private List<HolonSwitch> switchList;
-		private List<HolonObject> objectList;
-		
-		//Gui Part:
-		private Control  control;
-		private JTextArea textArea;
-		private JPanel content = new JPanel();
-		//ProgressBar
-		private long startTime;
-		private Thread runThread;
-
-		
-		
-		
-		
-		
-		
-		
-		public static void main(String[] args)
-		{
-		      JFrame newFrame = new JFrame("exampleWindow");
-		      DemoAlgo instance = new DemoAlgo();
-		      newFrame.setContentPane(instance.getPanel());
-		      newFrame.pack();
-		      newFrame.setVisible(true);
-		      newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
-		}
-		public FlexExample() {
-			content.setLayout(new BorderLayout());
-		
-			textArea = new JTextArea();
-			textArea.setEditable(false);
-			JScrollPane scrollPane = new JScrollPane(textArea);
-			JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
-					createOptionPanel() , scrollPane);
-			splitPane.setResizeWeight(0.0);
-			content.add(splitPane, BorderLayout.CENTER);
-			content.setPreferredSize(new Dimension(800,800));	
-		}
-		public JPanel createOptionPanel() {
-			JPanel optionPanel = new JPanel(new BorderLayout());
-			JScrollPane scrollPane = new JScrollPane(createParameterPanel());
-			scrollPane.setBorder(BorderFactory.createTitledBorder("Parameter"));
-			optionPanel.add(scrollPane,  BorderLayout.CENTER);
-			optionPanel.add(createButtonPanel(), BorderLayout.PAGE_END);
-			return optionPanel;
-		}
-		
-		private Component createParameterPanel() {
-			JPanel parameterPanel = new JPanel(null);
-			parameterPanel.setPreferredSize(new Dimension(510,300));
-			
-			
-		
+
+  LinkedList<List<Boolean>> resetChain = new LinkedList<List<Boolean>>();
+  //Settings For GroupNode using and cancel
+  private boolean useGroupNode = false;
+  private Optional<GroupNode> groupnode = Optional.empty();
+  private boolean cancel = false;
+  private boolean overAllTimeSteps = false;
+  //Parameter defined by Algo
+  private HashMap<Integer, AccessWrapper> access;
+  private List<Boolean> initialState;
+  private List<HolonSwitch> switchList;
+  private List<HolonObject> objectList;
+
+  //Gui Part:
+  private Control control;
+  private JTextArea textArea;
+  private JPanel content = new JPanel();
+  //ProgressBar
+  private long startTime;
+  private Thread runThread;
+
+
+  public FlexExample() {
+    content.setLayout(new BorderLayout());
+
+    textArea = new JTextArea();
+    textArea.setEditable(false);
+    JScrollPane scrollPane = new JScrollPane(textArea);
+    JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
+        createOptionPanel(), scrollPane);
+    splitPane.setResizeWeight(0.0);
+    content.add(splitPane, BorderLayout.CENTER);
+    content.setPreferredSize(new Dimension(800, 800));
+  }
+
+  public static void main(String[] args) {
+    JFrame newFrame = new JFrame("exampleWindow");
+    DemoAlgo instance = new DemoAlgo();
+    newFrame.setContentPane(instance.getPanel());
+    newFrame.pack();
+    newFrame.setVisible(true);
+    newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+  }
+
+  public JPanel createOptionPanel() {
+    JPanel optionPanel = new JPanel(new BorderLayout());
+    JScrollPane scrollPane = new JScrollPane(createParameterPanel());
+    scrollPane.setBorder(BorderFactory.createTitledBorder("Parameter"));
+    optionPanel.add(scrollPane, BorderLayout.CENTER);
+    optionPanel.add(createButtonPanel(), BorderLayout.PAGE_END);
+    return optionPanel;
+  }
+
+  private Component createParameterPanel() {
+    JPanel parameterPanel = new JPanel(null);
+    parameterPanel.setPreferredSize(new Dimension(510, 300));
+
 //			JLabel showDiagnosticsLabel = new JLabel("Set all switches closed:");
 //			JLabel showDiagnosticsLabel = new JLabel("Set all switches closed:");
 //			showDiagnosticsLabel.setBounds(200, 60, 170, 20);
 //			showDiagnosticsLabel.setBounds(200, 60, 170, 20);
 //			parameterPanel.add(showDiagnosticsLabel);		
 //			parameterPanel.add(showDiagnosticsLabel);		
-		
-			
-			JPanel borderPanel = new JPanel(null);
-			borderPanel.setBounds(200, 85, 185, 50);
-			borderPanel.setBorder(BorderFactory.createTitledBorder(""));
-			parameterPanel.add(borderPanel);	
-			
-			JLabel showGroupNodeLabel = new JLabel("Use Group Node:");
-			showGroupNodeLabel.setBounds(10, 1, 170, 20);
-			borderPanel.add(showGroupNodeLabel);	
-			
-			JButton selectGroupNodeButton = new JButton("Select GroupNode");
-			selectGroupNodeButton.setEnabled(false);
-			selectGroupNodeButton.setBounds(10, 25, 165, 20);
-			selectGroupNodeButton.addActionListener(actionEvent -> selectGroupNode());
-			borderPanel.add(selectGroupNodeButton);	
-			
-			JCheckBox useGroupNodeCheckBox = new JCheckBox();
-			useGroupNodeCheckBox.setSelected(false);
-			useGroupNodeCheckBox.setBounds(155, 1, 25, 20);
-			useGroupNodeCheckBox.addActionListener(actionEvent -> {
-				useGroupNode = useGroupNodeCheckBox.isSelected();
-				selectGroupNodeButton.setEnabled(useGroupNode);
-			});
-			borderPanel.add(useGroupNodeCheckBox);
-			
-			
-			JCheckBox overAllTimeStepsCheckbox = new JCheckBox("overAllTimeSteps");
-			overAllTimeStepsCheckbox.setSelected(false);
-			overAllTimeStepsCheckbox.setBounds(20, 30, 250, 30);
-			overAllTimeStepsCheckbox.addActionListener(actionEvent -> {
-				overAllTimeSteps = overAllTimeStepsCheckbox.isSelected();
-			});
-			parameterPanel.add(overAllTimeStepsCheckbox);
-			
-			NumberFormat format = NumberFormat.getIntegerInstance();
-			format.setGroupingUsed(false);
-			format.setParseIntegerOnly(true);
-			NumberFormatter integerFormatter = new NumberFormatter(format);
-			integerFormatter.setMinimum(0);
-			integerFormatter.setCommitsOnValidEdit(true);
-			JLabel portLabel = new JLabel("between:");
-			portLabel.setBounds(10, 330, 70, 30);
-			parameterPanel.add(portLabel);
-			JLabel afterLabel = new JLabel("after:");
-			afterLabel.setBounds(10, 360, 70, 30);
-			parameterPanel.add(afterLabel);
-			
-			
-			return parameterPanel;
-		}
-		public JPanel createButtonPanel() {
-			JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
-			JButton resetButton =  new JButton("ResetAll");
-			resetButton.setToolTipText("Resets the State to before the Algorithm has runed.");
-			resetButton.addActionListener(actionEvent -> resetAll());
-			buttonPanel.add(resetButton);
-			JButton cancelButton =  new JButton("Cancel Run");
-			cancelButton.addActionListener(actionEvent -> cancel());
-			buttonPanel.add(cancelButton);
-			JButton clearButton =  new JButton("Clear Console");
-			clearButton.addActionListener(actionEvent -> clear());
-			buttonPanel.add(clearButton);
-			JButton undoButton =  new JButton("Undo");
-			undoButton.setToolTipText("One Algo Step Back.");
-			undoButton.addActionListener(actionEvent -> resetLast());
-			buttonPanel.add(undoButton);
-			JButton runButton =  new JButton("Run");
-			runButton.addActionListener(actionEvent -> {
-				Runnable task = () -> {
-					if(this.overAllTimeSteps)runAll();
-					else run();
-				};
-				runThread = new Thread(task);
-				runThread.start();
-			});
-			buttonPanel.add(runButton);
-			return buttonPanel;
-		}
-		private void cancel() {
-			if(runThread.isAlive()) {
-				println("");
-				println("Cancel run.");
-				cancel = true;
-			} else {
-				println("Nothing to cancel.");
-			}
-		}
-		
-		private void runAll() {
-			cancel = false;
-			disableGuiInput(true);
-			startTimer();
-			control.resetSimulation();
-			RunResult result= new RunResult();
-			for(int i = 0; i < 100; i++) {
-				control.getModel().setCurrentIteration(i);
-				executeDemoAlgo(result);
-				if(cancel) {
-					resetLast();
-					disableGuiInput(false);
-					return;
-				}				
-			}
-			updateVisual();
-			calculateAllResults(result);
-			println("Amount of activatedFlex:" + result.activatedFlex + "   Amount of deactivatedElements:"+ result.deactivatedElements + "   TotalCost:"+result.totalCost);
-			printElapsedTime();
-			disableGuiInput(false);
-		}
-		private void run() {
-			disableGuiInput(true);
-			startTimer();
-			executeDemoAlgo(new RunResult());
-			updateVisual();
-			printElapsedTime();
-			disableGuiInput(false);
-		}
-		
-		private void resetLast() {
-			if(!resetChain.isEmpty()) {
-				println("Resetting..");
-				resetState();
-				resetChain.removeLast();
-				control.resetSimulation();
-				updateVisual();
-			}else {
-				println("No run inistialized.");
-			}
-		}
-		
-		private void resetAll() {
-			if(!resetChain.isEmpty()) {
-				println("Resetting..");
-				setState(resetChain.getFirst());
-				resetChain.clear();
-				control.resetSimulation();
-				control.getModel().setCurrentIteration(0);
-				updateVisual();
-			}else {
-				println("No run inistialized.");
-			}
-		}
-		
-		
-		
-		private void disableGuiInput(boolean bool) {
-			control.guiSetEnabled(bool);
-		}
-		
-		
-		
-
-		
-		
-		@Override
-		public JPanel getPanel() {
-			return content;
-		}
-		@Override
-		public void setController(Control control) {
-			this.control = control;
-			
-		}
-		private void clear() {
-			textArea.setText("");
-		}
-		private void println(String message) {
-			textArea.append(message  + "\n");
-		}
-		private void selectGroupNode() {
-			Object[] possibilities = control.getModel().getCanvas().getAllGroupNodeObjectsRecursive().toArray();
-			@SuppressWarnings("unchecked")
-			GroupNode selected = (GroupNode) JOptionPane.showInputDialog(content, "Select GroupNode:", "GroupNode?",  JOptionPane.OK_OPTION,new ImageIcon(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)) , possibilities, "");
-			if(selected != null) {
-				println("Selected: " + selected);
-				groupnode = Optional.of(selected);
-			}
-			
-		}
-		private void startTimer(){
-			startTime = System.currentTimeMillis();
-		}
-		private void printElapsedTime(){
-			long elapsedMilliSeconds = System.currentTimeMillis() - startTime;
-			println("Execution Time of Algo in Milliseconds:" + elapsedMilliSeconds);
-		}
-		
-		
-		
-		
-		//Algo Part:
-		/**
-		 * The Execution of the FlexAlgo.
-		 * 
-		 * 
-		 * Begin
-		 * 		for(All Networks) do
-		 * 			
-		 * 			if(not (production < consumption)) continue;
-		 * 			
-		 * 
-		 * 			for(Priority emergencyShutDownPriority: priorityListASC) do
-		 * 				difference = Math.abs(production - consumption);
-		 * 				amountOfAllEnergyOffered = sumEnergyAvailable(flexList); 
-		 * 				if(amountOfAllEnergyOffered > difference) break; 
-		 * 				shutDownAllConsumerWithPriority(emergencyShutDownPriority)
-		 * 			end for
-		 * 			
-		 * 			takeAKombinationOfOffers(); (nach welchem Kriterium)
-		 * 			
-		 * 			
-		 * 		end for
-		 * End
-		 * 
-		 */
-		private void executeDemoAlgo(RunResult result) {
-			extractPositionAndAccess();
-			int actualIteration = control.getModel().getCurrentIteration();
-			println("TimeStep:" + actualIteration);
-			control.calculateStateForCurrentIteration();
-			List<Priority> priorityListASC = createPriorityListASC();
+
+    JPanel borderPanel = new JPanel(null);
+    borderPanel.setBounds(200, 85, 185, 50);
+    borderPanel.setBorder(BorderFactory.createTitledBorder(""));
+    parameterPanel.add(borderPanel);
+
+    JLabel showGroupNodeLabel = new JLabel("Use Group Node:");
+    showGroupNodeLabel.setBounds(10, 1, 170, 20);
+    borderPanel.add(showGroupNodeLabel);
+
+    JButton selectGroupNodeButton = new JButton("Select GroupNode");
+    selectGroupNodeButton.setEnabled(false);
+    selectGroupNodeButton.setBounds(10, 25, 165, 20);
+    selectGroupNodeButton.addActionListener(actionEvent -> selectGroupNode());
+    borderPanel.add(selectGroupNodeButton);
+
+    JCheckBox useGroupNodeCheckBox = new JCheckBox();
+    useGroupNodeCheckBox.setSelected(false);
+    useGroupNodeCheckBox.setBounds(155, 1, 25, 20);
+    useGroupNodeCheckBox.addActionListener(actionEvent -> {
+      useGroupNode = useGroupNodeCheckBox.isSelected();
+      selectGroupNodeButton.setEnabled(useGroupNode);
+    });
+    borderPanel.add(useGroupNodeCheckBox);
+
+    JCheckBox overAllTimeStepsCheckbox = new JCheckBox("overAllTimeSteps");
+    overAllTimeStepsCheckbox.setSelected(false);
+    overAllTimeStepsCheckbox.setBounds(20, 30, 250, 30);
+    overAllTimeStepsCheckbox.addActionListener(actionEvent -> {
+      overAllTimeSteps = overAllTimeStepsCheckbox.isSelected();
+    });
+    parameterPanel.add(overAllTimeStepsCheckbox);
+
+    NumberFormat format = NumberFormat.getIntegerInstance();
+    format.setGroupingUsed(false);
+    format.setParseIntegerOnly(true);
+    NumberFormatter integerFormatter = new NumberFormatter(format);
+    integerFormatter.setMinimum(0);
+    integerFormatter.setCommitsOnValidEdit(true);
+    JLabel portLabel = new JLabel("between:");
+    portLabel.setBounds(10, 330, 70, 30);
+    parameterPanel.add(portLabel);
+    JLabel afterLabel = new JLabel("after:");
+    afterLabel.setBounds(10, 360, 70, 30);
+    parameterPanel.add(afterLabel);
+
+    return parameterPanel;
+  }
+
+  public JPanel createButtonPanel() {
+    JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+    JButton resetButton = new JButton("ResetAll");
+    resetButton.setToolTipText("Resets the State to before the Algorithm has runed.");
+    resetButton.addActionListener(actionEvent -> resetAll());
+    buttonPanel.add(resetButton);
+    JButton cancelButton = new JButton("Cancel Run");
+    cancelButton.addActionListener(actionEvent -> cancel());
+    buttonPanel.add(cancelButton);
+    JButton clearButton = new JButton("Clear Console");
+    clearButton.addActionListener(actionEvent -> clear());
+    buttonPanel.add(clearButton);
+    JButton undoButton = new JButton("Undo");
+    undoButton.setToolTipText("One Algo Step Back.");
+    undoButton.addActionListener(actionEvent -> resetLast());
+    buttonPanel.add(undoButton);
+    JButton runButton = new JButton("Run");
+    runButton.addActionListener(actionEvent -> {
+      Runnable task = () -> {
+        if (this.overAllTimeSteps) {
+          runAll();
+        } else {
+          run();
+        }
+      };
+      runThread = new Thread(task);
+      runThread.start();
+    });
+    buttonPanel.add(runButton);
+    return buttonPanel;
+  }
+
+  private void cancel() {
+    if (runThread.isAlive()) {
+      println("");
+      println("Cancel run.");
+      cancel = true;
+    } else {
+      println("Nothing to cancel.");
+    }
+  }
+
+  private void runAll() {
+    cancel = false;
+    disableGuiInput(true);
+    startTimer();
+    control.resetSimulation();
+    RunResult result = new RunResult();
+    for (int i = 0; i < 100; i++) {
+      control.getModel().setCurrentIteration(i);
+      executeDemoAlgo(result);
+      if (cancel) {
+        resetLast();
+        disableGuiInput(false);
+        return;
+      }
+    }
+    updateVisual();
+    calculateAllResults(result);
+    println("Amount of activatedFlex:" + result.activatedFlex + "   Amount of deactivatedElements:"
+        + result.deactivatedElements + "   TotalCost:" + result.totalCost);
+    printElapsedTime();
+    disableGuiInput(false);
+  }
+
+  private void run() {
+    disableGuiInput(true);
+    startTimer();
+    executeDemoAlgo(new RunResult());
+    updateVisual();
+    printElapsedTime();
+    disableGuiInput(false);
+  }
+
+  private void resetLast() {
+    if (!resetChain.isEmpty()) {
+      println("Resetting..");
+      resetState();
+      resetChain.removeLast();
+      control.resetSimulation();
+      updateVisual();
+    } else {
+      println("No run inistialized.");
+    }
+  }
+
+  private void resetAll() {
+    if (!resetChain.isEmpty()) {
+      println("Resetting..");
+      setState(resetChain.getFirst());
+      resetChain.clear();
+      control.resetSimulation();
+      control.getModel().setCurrentIteration(0);
+      updateVisual();
+    } else {
+      println("No run inistialized.");
+    }
+  }
+
+
+  private void disableGuiInput(boolean bool) {
+    control.guiSetEnabled(bool);
+  }
+
+
+  @Override
+  public JPanel getPanel() {
+    return content;
+  }
+
+  @Override
+  public void setController(Control control) {
+    this.control = control;
+
+  }
+
+  private void clear() {
+    textArea.setText("");
+  }
+
+  private void println(String message) {
+    textArea.append(message + "\n");
+  }
+
+  private void selectGroupNode() {
+    Object[] possibilities = control.getModel().getCanvas().getAllGroupNodeObjectsRecursive()
+        .toArray();
+    @SuppressWarnings("unchecked")
+    GroupNode selected = (GroupNode) JOptionPane.showInputDialog(content, "Select GroupNode:",
+        "GroupNode?", JOptionPane.OK_OPTION,
+        new ImageIcon(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)), possibilities, "");
+    if (selected != null) {
+      println("Selected: " + selected);
+      groupnode = Optional.of(selected);
+    }
+
+  }
+
+  private void startTimer() {
+    startTime = System.currentTimeMillis();
+  }
+
+  private void printElapsedTime() {
+    long elapsedMilliSeconds = System.currentTimeMillis() - startTime;
+    println("Execution Time of Algo in Milliseconds:" + elapsedMilliSeconds);
+  }
+
+  //Algo Part:
+
+  /**
+   * The Execution of the FlexAlgo.
+   * <p>
+   * <p>
+   * Begin for(All Networks) do
+   * <p>
+   * if(not (production < consumption)) continue;
+   * <p>
+   * <p>
+   * for(Priority emergencyShutDownPriority: priorityListASC) do difference = Math.abs(production -
+   * consumption); amountOfAllEnergyOffered = sumEnergyAvailable(flexList);
+   * if(amountOfAllEnergyOffered > difference) break; shutDownAllConsumerWithPriority(emergencyShutDownPriority)
+   * end for
+   * <p>
+   * takeAKombinationOfOffers(); (nach welchem Kriterium)
+   * <p>
+   * <p>
+   * end for End
+   */
+  private void executeDemoAlgo(RunResult result) {
+    extractPositionAndAccess();
+    int actualIteration = control.getModel().getCurrentIteration();
+    println("TimeStep:" + actualIteration);
+    control.calculateStateForCurrentIteration();
+    List<Priority> priorityListASC = createPriorityListASC();
 //			DecoratedState actualstate = control.getSimManager().getActualDecorState().get();	
 //			DecoratedState actualstate = control.getSimManager().getActualDecorState().get();	
 //			for(DecoratedNetwork net : actualstate.getNetworkList()) {
 //			for(DecoratedNetwork net : actualstate.getNetworkList()) {
 //				float production = net.getSupplierList().stream().map(supplier -> supplier.getEnergyToSupplyNetwork()).reduce(0.0f, (a, b) -> a + b);
 //				float production = net.getSupplierList().stream().map(supplier -> supplier.getEnergyToSupplyNetwork()).reduce(0.0f, (a, b) -> a + b);
@@ -380,10 +369,11 @@ public class FlexExample implements AddOn {
 //				println("Activated FlexThisTimeStep: "+ amountflexActivated+"   CostForThisTimeStep:" + costForThisTimeStep);
 //				println("Activated FlexThisTimeStep: "+ amountflexActivated+"   CostForThisTimeStep:" + costForThisTimeStep);
 //				result.totalCost += costForThisTimeStep;
 //				result.totalCost += costForThisTimeStep;
 //			}
 //			}
-			calculateStateResult(result);
-		}
-		private void calculateStateResult(RunResult result) {
-			control.calculateStateForCurrentIteration();
+    calculateStateResult(result);
+  }
+
+  private void calculateStateResult(RunResult result) {
+    control.calculateStateForCurrentIteration();
 //			RunResult.TimeStepStateResult timeStepState = result.addTimeStepStateResult();
 //			RunResult.TimeStepStateResult timeStepState = result.addTimeStepStateResult();
 //			
 //			
 //			for(DecoratedNetwork network: control.getSimManager().getActualDecorState().get().getNetworkList()) {
 //			for(DecoratedNetwork network: control.getSimManager().getActualDecorState().get().getNetworkList()) {
@@ -402,220 +392,247 @@ public class FlexExample implements AddOn {
 //			println("ConsumerPartiallySupplied: " + timeStepState.amountOfConsumerPartiallySupplied);
 //			println("ConsumerPartiallySupplied: " + timeStepState.amountOfConsumerPartiallySupplied);
 //			println("ConsumerUnSupplied: " + timeStepState.amountOfConsumerUnSupplied);
 //			println("ConsumerUnSupplied: " + timeStepState.amountOfConsumerUnSupplied);
 //			println("ConsumerUnSupplied: " + timeStepState.amountOfPassiv);
 //			println("ConsumerUnSupplied: " + timeStepState.amountOfPassiv);
-		}
-		private void calculateAllResults(RunResult result) {
-			println("----------");
-			println("Average producer proportion: " + result.getAvergaeProportionWithState(HolonObjectState.PRODUCER));
-			println("Average producer OverSupplied: " + result.getAvergaeProportionWithState(HolonObjectState.OVER_SUPPLIED));
-			println("Average producer Supplied: " + result.getAvergaeProportionWithState(HolonObjectState.SUPPLIED));
-			println("Average producer PartiallySupplied: " + result.getAvergaeProportionWithState(HolonObjectState.PARTIALLY_SUPPLIED));
-			println("Average producer NotSupplied: " + result.getAvergaeProportionWithState(HolonObjectState.NOT_SUPPLIED));
-			println("Average producer NoEnergy: " + result.getAvergaeProportionWithState(HolonObjectState.NO_ENERGY));
-		}
-		
-		
-		
-		
-		
-		private float shutDownAllConsumerElementsWithPriority(Set<HolonElement> allHolonElemntsInThisNetwork,
-				Priority emergencyShutDownPriority, RunResult result) {
-			
-			List<HolonElement> elementsOfPriorityToShutdown = allHolonElemntsInThisNetwork.stream().filter(hElement -> hElement.isConsumer() && hElement.getPriority() == emergencyShutDownPriority && !hElement.isFlexActive() && hElement.active).collect(Collectors.toList());
-					//.forEach(hElement -> hElement.setActive(false));
-			float energyGained = elementsOfPriorityToShutdown.stream().map(hElement -> -hElement.getEnergy()).reduce(0.0f, (a, b) -> a + b);
-			elementsOfPriorityToShutdown.forEach(hElement -> hElement.active = false);
-			int shutdownCount = elementsOfPriorityToShutdown.size();
-			result.deactivatedElements += shutdownCount;
-			println("Gained " + energyGained + "Energy from Shutdown with Priority:" + emergencyShutDownPriority + " AmountOfShutDowned HolonElements: " + shutdownCount);
-			return energyGained;
-		}
-
-	
-		private float sumEnergyAvailable(List<Flexibility> flexList) {
-			HashMap<HolonElement, Flexibility> dublicateFilter = new HashMap<HolonElement, Flexibility>();
-			flexList.stream().forEach(flex -> dublicateFilter.put(flex.getElement(), flex));
-			return dublicateFilter.values().stream().map(flex -> flex.energyReleased()).reduce(0.0f,Float::sum);
-		}
-		private List<Priority> createPriorityListASC() {
-			List<Priority> priorityASC = new ArrayList<Priority>();
-			priorityASC.add(Priority.Low);
-			priorityASC.add(Priority.Medium);
-			priorityASC.add(Priority.High);
-			priorityASC.add(Priority.Essential);
-			return priorityASC;
-		}
-		/**
-		 * Method to get the current Position alias a ListOf Booleans for aktive settings on the Objects on the Canvas.
-		 * Also initialize the Access Hashmap to swap faster positions.
-		 * @return
-		 */
-		private List<Boolean> extractPositionAndAccess() {
-			Model model = control.getModel();
-			switchList = new ArrayList<HolonSwitch>();
-			objectList = new ArrayList<HolonObject>();
-			initialState = new ArrayList<Boolean>();
-			access= new HashMap<Integer, AccessWrapper>();
-			rollOutNodes((useGroupNode && (groupnode.isPresent()))? groupnode.get().getObjectsInThisLayer() :model.getCanvas().getObjectsInThisLayer(), initialState, model.getCurrentIteration());			
-			resetChain.add(initialState); 
-			return initialState;
-		}
-		/**
-		 * Method to extract the Informations recursively out of the Model.
-		 * @param nodes
-		 * @param positionToInit
-		 * @param timeStep
-		 */
-		private void rollOutNodes(Stream<AbstractCanvasObject> nodes, List<Boolean> positionToInit, int timeStep) {
-			nodes.forEach(aCps -> {
-				if (aCps instanceof HolonObject hO) {
-					hO.elementsStream().forEach(hE -> {
-						positionToInit.add(hE.active);
-						access.put(positionToInit.size() - 1 , new AccessWrapper(hE));
-					});
-					objectList.add(hO);
-				}
-				else if (aCps instanceof HolonSwitch sw) {
-					positionToInit.add(sw.getState().isClosed());
-					switchList.add(sw);
-					access.put(positionToInit.size() - 1 , new AccessWrapper(sw));
-				}
-				else if(aCps instanceof GroupNode groupnode) {			
-					rollOutGroupNode(groupnode, positionToInit ,timeStep);
-				}
-			});
-
-		}
-		
-		
-		private void rollOutGroupNode (GroupNode groupNode, List<Boolean> positionToInit, int timeStep) {
-			groupNode.getAllHolonObjectsRecursive().forEach(hObject -> {
-				hObject.elementsStream().forEach(hE -> {
-					positionToInit.add(hE.active);
-					access.put(positionToInit.size() - 1 , new AccessWrapper(hE));
-				});
-				objectList.add(hObject);
-			});
-			groupNode.getAllSwitchObjectsRecursive().forEach(sw -> {
-				positionToInit.add(sw.getState().isClosed());
-				switchList.add(sw);
-				access.put(positionToInit.size() - 1 , new AccessWrapper(sw));
-			});
-			
-		}
-		/**
-		 * To let the User See the current state without touching the Canvas.
-		 */
-		private void updateVisual() {
-			control.calculateStateForCurrentIteration();
-			//control.updateCanvas();
-			//control.getGui().triggerUpdateController(null);
-		}
-		/**
-		 * Sets the Model back to its original State before the LAST run.
-		 */
-		private void resetState() {
-			setState(resetChain.getLast());
-		}
-		
-		/**
-		 * Sets the State out of the given position for calculation or to show the user.
-		 * @param position
-		 */
-		private void setState(List<Boolean> position) {
-			for(int i = 0;i<position.size();i++) {
-				access.get(i).setState(position.get(i));
-			}
-		}
-	
-		
-		
-		
-		
-		/**
-		 * A Wrapper Class for Access HolonElement and HolonSwitch in one Element and not have to split the List.
-		 */
-		private class AccessWrapper {
-			public static final int HOLONELEMENT = 0;
-			public static final int SWITCH = 1;
-			private int type;
-			private HolonSwitch hSwitch;
-			private HolonElement hElement;
-			public AccessWrapper(HolonSwitch hSwitch){
-				type = SWITCH;
-				this.hSwitch = hSwitch;
-			}
-			public AccessWrapper(HolonElement hElement){
-				type = HOLONELEMENT;
-				this.hElement = hElement;
-			}
-			public void setState(boolean state) {
-				if(type == HOLONELEMENT) {
-					hElement.active = state;
-				}else{//is switch
-					hSwitch.setMode(SwitchMode.Manual);
-					hSwitch.setManualState(state ? SwitchState.Closed : SwitchState.Open);
-				}
-					
-			}
-		}
-		
-		
-		private class RunResult {
-			public int activatedFlex = 0;
-			public int deactivatedElements = 0;
-			public float totalCost = 0;
-			public LinkedList<TimeStepStateResult> timeStepList = new LinkedList<TimeStepStateResult>();
-			
-			
-			public TimeStepStateResult addTimeStepStateResult(){
-				TimeStepStateResult aResult = new TimeStepStateResult();
-				timeStepList.add(aResult);
-				return aResult;
-			}
-			
-			
-			public class TimeStepStateResult{
-				public int amountOfProducer = 0;
-				public int amountOfConsumer = 0;
-				public int amountOfPassiv = 0;
-				public int amountOfConsumerOverSupplied = 0;
-				public int amountOfConsumerSupplied = 0;
-				public int amountOfConsumerPartiallySupplied = 0;
-				public int amountOfConsumerUnSupplied= 0;
-				
-				public float getProportionWithState(HolonObjectState state) {
-					float amountOfObjects = amountOfProducer + amountOfConsumer + amountOfPassiv;
-					switch(state) {
-					case NOT_SUPPLIED:
-						return (float) amountOfConsumerUnSupplied / amountOfObjects;
-					case NO_ENERGY:
-						return (float) amountOfPassiv / amountOfObjects;
-					case OVER_SUPPLIED:
-						return (float) amountOfConsumerOverSupplied / amountOfObjects;
-					case PARTIALLY_SUPPLIED:
-						return (float) amountOfConsumerPartiallySupplied / amountOfObjects;
-					case PRODUCER:
-						return (float) amountOfProducer / amountOfObjects;
-					case SUPPLIED:
-						return (float) amountOfConsumerSupplied / amountOfObjects;
-					default:
-						return 0.f;
-					}
-				}
-			}
-			public float getAvergaeProportionWithState(HolonObjectState state) {
-				return timeStepList.stream().map(step -> step.getProportionWithState(state)).reduce((a,b) -> (a + b)).orElse(0.f) / (float) 100;
-			}
-		}
-		
-		private   class  Handle<T>{
-			public T object;
-			Handle(T object){
-				this.object = object;
-			}
-			public String toString() {
-				return object.toString();
-			}
-		}
+  }
+
+  private void calculateAllResults(RunResult result) {
+    println("----------");
+    println("Average producer proportion: " + result.getAvergaeProportionWithState(
+        HolonObjectState.PRODUCER));
+    println("Average producer OverSupplied: " + result.getAvergaeProportionWithState(
+        HolonObjectState.OVER_SUPPLIED));
+    println("Average producer Supplied: " + result.getAvergaeProportionWithState(
+        HolonObjectState.SUPPLIED));
+    println("Average producer PartiallySupplied: " + result.getAvergaeProportionWithState(
+        HolonObjectState.PARTIALLY_SUPPLIED));
+    println("Average producer NotSupplied: " + result.getAvergaeProportionWithState(
+        HolonObjectState.NOT_SUPPLIED));
+    println("Average producer NoEnergy: " + result.getAvergaeProportionWithState(
+        HolonObjectState.NO_ENERGY));
+  }
+
+
+  private float shutDownAllConsumerElementsWithPriority(
+      Set<HolonElement> allHolonElemntsInThisNetwork,
+      Priority emergencyShutDownPriority, RunResult result) {
+
+    List<HolonElement> elementsOfPriorityToShutdown = allHolonElemntsInThisNetwork.stream().filter(
+        hElement -> hElement.isConsumer() && hElement.getPriority() == emergencyShutDownPriority
+            && !hElement.isFlexActive() && hElement.active).collect(Collectors.toList());
+    //.forEach(hElement -> hElement.setActive(false));
+    float energyGained = elementsOfPriorityToShutdown.stream()
+        .map(hElement -> -hElement.getEnergy()).reduce(0.0f, (a, b) -> a + b);
+    elementsOfPriorityToShutdown.forEach(hElement -> hElement.active = false);
+    int shutdownCount = elementsOfPriorityToShutdown.size();
+    result.deactivatedElements += shutdownCount;
+    println(
+        "Gained " + energyGained + "Energy from Shutdown with Priority:" + emergencyShutDownPriority
+            + " AmountOfShutDowned HolonElements: " + shutdownCount);
+    return energyGained;
+  }
+
+
+  private float sumEnergyAvailable(List<Flexibility> flexList) {
+    HashMap<HolonElement, Flexibility> dublicateFilter = new HashMap<HolonElement, Flexibility>();
+    flexList.stream().forEach(flex -> dublicateFilter.put(flex.getElement(), flex));
+    return dublicateFilter.values().stream().map(flex -> flex.energyReleased())
+        .reduce(0.0f, Float::sum);
+  }
+
+  private List<Priority> createPriorityListASC() {
+    List<Priority> priorityASC = new ArrayList<Priority>();
+    priorityASC.add(Priority.Low);
+    priorityASC.add(Priority.Medium);
+    priorityASC.add(Priority.High);
+    priorityASC.add(Priority.Essential);
+    return priorityASC;
+  }
+
+  /**
+   * Method to get the current Position alias a ListOf Booleans for aktive settings on the Objects
+   * on the Canvas. Also initialize the Access Hashmap to swap faster positions.
+   *
+   * @return
+   */
+  private List<Boolean> extractPositionAndAccess() {
+    Model model = control.getModel();
+    switchList = new ArrayList<HolonSwitch>();
+    objectList = new ArrayList<HolonObject>();
+    initialState = new ArrayList<Boolean>();
+    access = new HashMap<Integer, AccessWrapper>();
+    rollOutNodes((useGroupNode && (groupnode.isPresent())) ? groupnode.get().getObjectsInThisLayer()
+        : model.getCanvas().getObjectsInThisLayer(), initialState, model.getCurrentIteration());
+    resetChain.add(initialState);
+    return initialState;
+  }
+
+  /**
+   * Method to extract the Informations recursively out of the Model.
+   *
+   * @param nodes
+   * @param positionToInit
+   * @param timeStep
+   */
+  private void rollOutNodes(Stream<AbstractCanvasObject> nodes, List<Boolean> positionToInit,
+      int timeStep) {
+    nodes.forEach(aCps -> {
+      if (aCps instanceof HolonObject hO) {
+        hO.elementsStream().forEach(hE -> {
+          positionToInit.add(hE.active);
+          access.put(positionToInit.size() - 1, new AccessWrapper(hE));
+        });
+        objectList.add(hO);
+      } else if (aCps instanceof HolonSwitch sw) {
+        positionToInit.add(sw.getState().isClosed());
+        switchList.add(sw);
+        access.put(positionToInit.size() - 1, new AccessWrapper(sw));
+      } else if (aCps instanceof GroupNode groupnode) {
+        rollOutGroupNode(groupnode, positionToInit, timeStep);
+      }
+    });
+
+  }
+
+
+  private void rollOutGroupNode(GroupNode groupNode, List<Boolean> positionToInit, int timeStep) {
+    groupNode.getAllHolonObjectsRecursive().forEach(hObject -> {
+      hObject.elementsStream().forEach(hE -> {
+        positionToInit.add(hE.active);
+        access.put(positionToInit.size() - 1, new AccessWrapper(hE));
+      });
+      objectList.add(hObject);
+    });
+    groupNode.getAllSwitchObjectsRecursive().forEach(sw -> {
+      positionToInit.add(sw.getState().isClosed());
+      switchList.add(sw);
+      access.put(positionToInit.size() - 1, new AccessWrapper(sw));
+    });
+
+  }
+
+  /**
+   * To let the User See the current state without touching the Canvas.
+   */
+  private void updateVisual() {
+    control.calculateStateForCurrentIteration();
+    //control.updateCanvas();
+    //control.getGui().triggerUpdateController(null);
+  }
+
+  /**
+   * Sets the Model back to its original State before the LAST run.
+   */
+  private void resetState() {
+    setState(resetChain.getLast());
+  }
+
+  /**
+   * Sets the State out of the given position for calculation or to show the user.
+   *
+   * @param position
+   */
+  private void setState(List<Boolean> position) {
+    for (int i = 0; i < position.size(); i++) {
+      access.get(i).setState(position.get(i));
+    }
+  }
+
+
+  /**
+   * A Wrapper Class for Access HolonElement and HolonSwitch in one Element and not have to split
+   * the List.
+   */
+  private class AccessWrapper {
+
+    public static final int HOLONELEMENT = 0;
+    public static final int SWITCH = 1;
+    private int type;
+    private HolonSwitch hSwitch;
+    private HolonElement hElement;
+
+    public AccessWrapper(HolonSwitch hSwitch) {
+      type = SWITCH;
+      this.hSwitch = hSwitch;
+    }
+
+    public AccessWrapper(HolonElement hElement) {
+      type = HOLONELEMENT;
+      this.hElement = hElement;
+    }
+
+    public void setState(boolean state) {
+      if (type == HOLONELEMENT) {
+        hElement.active = state;
+      } else {//is switch
+        hSwitch.setMode(SwitchMode.Manual);
+        hSwitch.setManualState(state ? SwitchState.Closed : SwitchState.Open);
+      }
+
+    }
+  }
+
+
+  private class RunResult {
+
+    public int activatedFlex = 0;
+    public int deactivatedElements = 0;
+    public float totalCost = 0;
+    public LinkedList<TimeStepStateResult> timeStepList = new LinkedList<TimeStepStateResult>();
+
+
+    public TimeStepStateResult addTimeStepStateResult() {
+      TimeStepStateResult aResult = new TimeStepStateResult();
+      timeStepList.add(aResult);
+      return aResult;
+    }
+
+    public float getAvergaeProportionWithState(HolonObjectState state) {
+      return timeStepList.stream().map(step -> step.getProportionWithState(state))
+          .reduce((a, b) -> (a + b)).orElse(0.f) / (float) 100;
+    }
+
+    public class TimeStepStateResult {
+
+      public int amountOfProducer = 0;
+      public int amountOfConsumer = 0;
+      public int amountOfPassiv = 0;
+      public int amountOfConsumerOverSupplied = 0;
+      public int amountOfConsumerSupplied = 0;
+      public int amountOfConsumerPartiallySupplied = 0;
+      public int amountOfConsumerUnSupplied = 0;
+
+      public float getProportionWithState(HolonObjectState state) {
+        float amountOfObjects = amountOfProducer + amountOfConsumer + amountOfPassiv;
+        switch (state) {
+          case NOT_SUPPLIED:
+            return (float) amountOfConsumerUnSupplied / amountOfObjects;
+          case NO_ENERGY:
+            return (float) amountOfPassiv / amountOfObjects;
+          case OVER_SUPPLIED:
+            return (float) amountOfConsumerOverSupplied / amountOfObjects;
+          case PARTIALLY_SUPPLIED:
+            return (float) amountOfConsumerPartiallySupplied / amountOfObjects;
+          case PRODUCER:
+            return (float) amountOfProducer / amountOfObjects;
+          case SUPPLIED:
+            return (float) amountOfConsumerSupplied / amountOfObjects;
+          default:
+            return 0.f;
+        }
+      }
+    }
+  }
+
+  private class Handle<T> {
+
+    public T object;
+
+    Handle(T object) {
+      this.object = object;
+    }
+
+    public String toString() {
+      return object.toString();
+    }
+  }
 
 
 }
 }

+ 120 - 119
src/holeg/algorithm/objective_function/Evaluation.java

@@ -2,99 +2,99 @@ package holeg.algorithm.objective_function;
 
 
 import holeg.model.Flexibility;
 import holeg.model.Flexibility;
 import holeg.model.Holon;
 import holeg.model.Holon;
+import holeg.model.HolonElement.Priority;
 import holeg.model.HolonObject;
 import holeg.model.HolonObject;
 import holeg.model.HolonObject.HolonObjectState;
 import holeg.model.HolonObject.HolonObjectState;
-import holeg.model.HolonElement.Priority;
 import holeg.model.Model;
 import holeg.model.Model;
-
 import java.util.List;
 import java.util.List;
 
 
 public class Evaluation {
 public class Evaluation {
-	
-	/**
-	 * Calculate the Fitness(Penelty) Value for a state (alias the calculated Position).
-	 * @return
-	 */
-	public static double getFitnessValueForState(Model model) {
-		double fitness = 0.0;
-		double nw_fitness =0.0;
-		double object_fitness = 0.0;
-		double flexFitness = 0.0;
-		
-		double sigma = 9;
-
-		// calculate network_fitness
-		for(Holon holon : model.holons) {
-			float production = holon.getTotalProduction();
-			float consumption = holon.getTotalConsumption();
-			nw_fitness += Math.abs((production - consumption)/100); //Energy is now everywhere positive
-		}
-
-
-
-		// calculate object_fitness
-		for(Holon holon : model.holons) {
-
-			object_fitness += holon.holonObjects.stream().filter(HolonObject::isConsumer).map(con -> holonObjectSupplyPenaltyFunction(con.getSupplyBarPercentage()) /*+ inactiveHolonElementPenalty(con.getModel())*/).reduce(0.0, Double::sum);
-			object_fitness += holon.holonObjects.stream().filter(HolonObject::isConsumer).map(con -> StateToDouble(con.getState())).reduce(0.0, Double::sum);
-		}
-		List<Flexibility> getAllFlexInUse = model.getAllFlexibilities().stream().filter(flex -> flex.getState().equals(Flexibility.FlexState.IN_USE)).toList();
-		for(Flexibility flex : getAllFlexInUse) {
-			flexFitness += Math.pow(sigma, (double)priorityToInt(flex.getElement().getPriority())) - 1;
-		}
-
-		fitness = nw_fitness + object_fitness + flexFitness;
-		return fitness;
-	}
-
-	
-	
-	
-	
-	private static int priorityToInt(Priority priority) {
-		switch(priority) {
-		case Essential:
-			return 3;
-		case High:
-			return 2;
-		case Medium:
-			return 1;
-		case Low:
-		default:		
-			return 0;
-		}
-	}
-
-
-
-
-
-	/**
-	 * Untouched:
-	 * Function that returns the fitness depending on the number of elements deactivated in a single holon object
-	 * @param obj Holon Object that contains Holon Elements
-	 * @return fitness value for that object depending on the number of deactivated holon elements
-	 */
-	@SuppressWarnings("unused")
-	private static double inactiveHolonElementPenalty(HolonObject obj) {
-		float result = 0;
-		int activeElements = obj.getNumberOfActiveElements();
-		int maxElements = (int)obj.elementsStream().count();
-		
-		//result = (float) Math.pow((maxElements -activeElements),2)*10;
-		result = (float) Math.pow(5, 4* ( (float) maxElements - (float) activeElements)/ (float) maxElements) - 1;
-		//System.out.console.println("max: " + maxElements + " active: " + activeElements + " results in penalty: " + result);
-	return result;
-		
-	}
-	/**
-	 * Untouched:
-	 * Calculates a penalty value based on the HOs current supply percentage
-	 * @param supplyPercentage
-	 * @return
-	 */
-	private static double holonObjectSupplyPenaltyFunction(float supplyPercentage) {
-		double result = 0;
+
+  /**
+   * Calculate the Fitness(Penelty) Value for a state (alias the calculated Position).
+   *
+   * @return
+   */
+  public static double getFitnessValueForState(Model model) {
+    double fitness = 0.0;
+    double nw_fitness = 0.0;
+    double object_fitness = 0.0;
+    double flexFitness = 0.0;
+
+    double sigma = 9;
+
+    // calculate network_fitness
+    for (Holon holon : model.holons) {
+      float production = holon.getTotalProduction();
+      float consumption = holon.getTotalConsumption();
+      nw_fitness += Math.abs((production - consumption) / 100); //Energy is now everywhere positive
+    }
+
+    // calculate object_fitness
+    for (Holon holon : model.holons) {
+
+      object_fitness += holon.holonObjects.stream().filter(HolonObject::isConsumer).map(
+              con -> holonObjectSupplyPenaltyFunction(
+                  con.getSupplyBarPercentage()) /*+ inactiveHolonElementPenalty(con.getModel())*/)
+          .reduce(0.0, Double::sum);
+      object_fitness += holon.holonObjects.stream().filter(HolonObject::isConsumer)
+          .map(con -> StateToDouble(con.getState())).reduce(0.0, Double::sum);
+    }
+    List<Flexibility> getAllFlexInUse = model.getAllFlexibilities().stream()
+        .filter(flex -> flex.getState().equals(Flexibility.FlexState.IN_USE)).toList();
+    for (Flexibility flex : getAllFlexInUse) {
+      flexFitness += Math.pow(sigma, (double) priorityToInt(flex.getElement().getPriority())) - 1;
+    }
+
+    fitness = nw_fitness + object_fitness + flexFitness;
+    return fitness;
+  }
+
+
+  private static int priorityToInt(Priority priority) {
+    switch (priority) {
+      case Essential:
+        return 3;
+      case High:
+        return 2;
+      case Medium:
+        return 1;
+      case Low:
+      default:
+        return 0;
+    }
+  }
+
+
+  /**
+   * Untouched: Function that returns the fitness depending on the number of elements deactivated in
+   * a single holon object
+   *
+   * @param obj Holon Object that contains Holon Elements
+   * @return fitness value for that object depending on the number of deactivated holon elements
+   */
+  @SuppressWarnings("unused")
+  private static double inactiveHolonElementPenalty(HolonObject obj) {
+    float result = 0;
+    int activeElements = obj.getNumberOfActiveElements();
+    int maxElements = (int) obj.elementsStream().count();
+
+    //result = (float) Math.pow((maxElements -activeElements),2)*10;
+    result = (float) Math.pow(5,
+        4 * ((float) maxElements - (float) activeElements) / (float) maxElements) - 1;
+    //System.out.console.println("max: " + maxElements + " active: " + activeElements + " results in penalty: " + result);
+    return result;
+
+  }
+
+  /**
+   * Untouched: Calculates a penalty value based on the HOs current supply percentage
+   *
+   * @param supplyPercentage
+   * @return
+   */
+  private static double holonObjectSupplyPenaltyFunction(float supplyPercentage) {
+    double result = 0;
 		/*if(supplyPercentage == 1)
 		/*if(supplyPercentage == 1)
 			return result;
 			return result;
 		else if(supplyPercentage < 1 && supplyPercentage >= 0.25) // undersupplied inbetween 25% and 100%
 		else if(supplyPercentage < 1 && supplyPercentage >= 0.25) // undersupplied inbetween 25% and 100%
@@ -109,36 +109,37 @@ public class Evaluation {
 		if(Float.isInfinite(result) || Float.isNaN(result))
 		if(Float.isInfinite(result) || Float.isNaN(result))
 			result = 1000;
 			result = 1000;
 	*/
 	*/
-		if(supplyPercentage <= 1.0) {
-			result = Math.pow(5,(Math.abs((100 - (supplyPercentage*100)))/50 + 2)) - Math.pow(5, 2);
-		}
-		else {
-			result = Math.pow(6,(Math.abs((100 - (supplyPercentage*100)))/50 + 2)) - Math.pow(6, 2);
-		}
-		
-		return result;
-	}
-	/**
-	 * If you want to get in touch with a reliable state? Working function not in use currently.
-	 * @param state
-	 * @return
-	 */
-	private static double StateToDouble(HolonObjectState state) {
-		switch (state) {
-		case NOT_SUPPLIED:
-			return 150.0;
-		case NO_ENERGY:
-			return 150.0;
-		case OVER_SUPPLIED:
-			return 100.0;
-		case PARTIALLY_SUPPLIED:
-			return 100.0;
-		case PRODUCER:
-			return 0;
-		case SUPPLIED:
-			return 0;
-		default:
-			return 0;
-		}
-	}
+    if (supplyPercentage <= 1.0) {
+      result = Math.pow(5, (Math.abs((100 - (supplyPercentage * 100))) / 50 + 2)) - Math.pow(5, 2);
+    } else {
+      result = Math.pow(6, (Math.abs((100 - (supplyPercentage * 100))) / 50 + 2)) - Math.pow(6, 2);
+    }
+
+    return result;
+  }
+
+  /**
+   * If you want to get in touch with a reliable state? Working function not in use currently.
+   *
+   * @param state
+   * @return
+   */
+  private static double StateToDouble(HolonObjectState state) {
+    switch (state) {
+      case NOT_SUPPLIED:
+        return 150.0;
+      case NO_ENERGY:
+        return 150.0;
+      case OVER_SUPPLIED:
+        return 100.0;
+      case PARTIALLY_SUPPLIED:
+        return 100.0;
+      case PRODUCER:
+        return 0;
+      case SUPPLIED:
+        return 0;
+      default:
+        return 0;
+    }
+  }
 }
 }

+ 448 - 427
src/holeg/algorithm/objective_function/GraphMetrics.java

@@ -1,440 +1,461 @@
 package holeg.algorithm.objective_function;
 package holeg.algorithm.objective_function;
 
 
-import java.util.*;
+import holeg.model.AbstractCanvasObject;
+import holeg.model.Holon;
+import holeg.model.HolonObject;
+import holeg.model.HolonSwitch;
+import holeg.model.Model;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
 
 
-import holeg.model.*;
-
 public class GraphMetrics {
 public class GraphMetrics {
-	private static final Logger log = Logger.getLogger(GraphMetrics.class.getName());
-	
-	
-	public static class Vertex{
-		public int id = 0;
-		public Vertex(int id){
-			this.id = id;
-		}
-		public String toString() {
-			return "" + id;
-		}
-	}
-	private static class Edge{
-		public int idA, idB;
-		public double weight;
-		public Edge(int idA, int idB, double weight){
-			this.idA = idA;
-			this.idB = idB;
-			this.weight = weight;
-		}
-	}
-	
-	public static class Graph{
-		Vertex[] V;
-		Edge[] E;
-		/**Only the Sources/Trains for disjoint Path no Switch or Node**/
-		Vertex[] S;
-		
-		public String toString() {
-			String vList = "V" + Arrays.toString(V);
-			String sList = "S" + Arrays.toString(S);
-			return vList + ", " + sList;
-		}
-	}
-	
-	
-	
-	/**
-	 * Convert a DecoratedNetwork to a Graph
-	 * @return a equivalent Graph to the DecoratedNetwork
-	 */
-	public static Graph convertDecoratedNetworkToGraph(Model model, Holon holon) {
-		Graph G = new Graph();
-		HashMap<AbstractCanvasObject, Integer> objectToId = new HashMap<>();
-		List<Integer> sourcesList = new ArrayList<Integer>();
-		int count = 0;
-
-		for(HolonObject con: holon.holonObjects) {
-			objectToId.put(con, count);
-			sourcesList.add(count);
-			count++;
-		}
-		
-		//Generate EdgeList 
-		List<Edge> edgeList = new ArrayList<Edge>();
-		for(holeg.model.Edge cable : model.getEdgesOnCanvas()){
-
-			AbstractCanvasObject objectA = cable.getA();
-			AbstractCanvasObject objectB = cable.getB();
-			if(objectA == null) {
-				log.warning("Edge: " + cable + "objectA == null");
-				continue;
-			}
-			if(objectB == null) {
-				log.warning("Edge: " + cable + "objectB == null");
-				continue;
-			}
-
-			//SpecialCase for open switches
-			if(objectA instanceof HolonSwitch sw && !sw.getState().isOpen()) {
-				continue;
-			}
-			if(objectB instanceof HolonSwitch sw && !sw.getState().isOpen()) {
-				continue;
-			}
-
-			int idA = -1;
-			if(objectToId.containsKey(objectA)) {
-				idA = objectToId.get(objectA);
-			}else {
-				idA = count;
-				objectToId.put(objectA, count++);
-			}
-			int idB = -1;
-			if(objectToId.containsKey(objectB)) {
-				idB = objectToId.get(objectB);
-			}else {
-				idB = count;
-				objectToId.put(objectB, count++);
-			}
-			double length = cable.getLength();
-			edgeList.add(new Edge(idA, idB, length));
-		}
-		//Generate EdgeArray
-		G.E = new Edge[edgeList.size()];
-		for(int i=0;i<edgeList.size();i++)
-	    {
-				G.E[i] =  edgeList.get(i);
-	    }
-		//Generate VertexArray
-		G.V = new Vertex[objectToId.size()];
-		int entryCount = 0;
-		for(Map.Entry<AbstractCanvasObject, Integer> entry : objectToId.entrySet()) {
-			G.V[entryCount] =  new Vertex(entry.getValue());
-			entryCount++;
-		}
-		//Generate Sources Array
-		int sourceCount = 0;
-		G.S = new Vertex[sourcesList.size()];
-		for(int source : sourcesList) {
-			G.S[sourceCount] = new Vertex(source);
-			sourceCount++;
-		}
-		return G;
-	}
-	
-	
-// Example Test
-	 public static void main(String[] args){
-		 Graph G = new Graph();
-		 G.V = new Vertex[4];
-		 for(int i=0;i<G.V.length;i++)
-	     {
-				G.V[i] =  new Vertex(i);
-	     }
-		 G.E = new Edge[4];
-		 
-		 G.E[0] = new Edge(0, 1, 1);
-		 G.E[1] = new Edge(1, 2, 1);
-		 G.E[2] = new Edge(2, 3, 1);
-		 G.E[3] = new Edge(3, 0, 1);
-		 
-		 G.S = new Vertex[4];
-		 G.S[0] = new Vertex(0);
-		 G.S[1] = new Vertex(1);
-		 G.S[2] = new Vertex(2);
-		 G.S[3] = new Vertex(3);
-		 log.info(G.toString());
-		 log.info("minimumCut: " + minimumCut(G.V, G.E));
-		 log.info("AvgShortestDistance " + averageShortestDistance(G));
-		 log.info("DisjointPath " + averageEdgeDisjointPathProblem(G));
-	 }
-	 
-	 static int[][] generateDisjointWeightMatrix(Vertex[] V, Edge[] E){
-			int[][] L = new int[V.length][V.length];
-			for(int i = 0; i < E.length; i++) {
-				L[E[i].idA][E[i].idB] = 1;
-				L[E[i].idB][E[i].idA] = 1;
-			}
-			return L;
-		}
-	 
-	 /** find the average s_t disjoint paths between all pairs of s and t **/
-	 static double averageEdgeDisjointPathProblem(Graph G) {
-		 //This matrix indicates if a Edge is existent between two vertices
-		int[][] L = generateDisjointWeightMatrix(G.V, G.E);
-		double disjointPathSum = 0.0;
-		 for(int s = 0; s < G.S.length; s++) {
-			 for(int t = s; t < G.S.length; t++) {
-				 disjointPathSum += s_t_EdgeDisjointPath(G.S[s].id, G.S[t].id, L);					 
-			 }
-		 }
-		 //Returns the Average
-		 return disjointPathSum / ((G.S.length * (G.S.length - 1)) / 2);
-	 }
-	 
-	 
-	 
-	 /** find the amount of s_t disjoint paths between s and t **/
-	 private static double s_t_EdgeDisjointPath(int s, int t, int[][] L_input) {
-		 if(s == t) return 0;
-		 //Make Copy of L
-		int [][] L = makeCopyOfMatrix(L_input);
-		double foundPaths = 0;
-		//RepeatBreathFirst search till no path is found
-		boolean b_foundpath = true;
-		while(b_foundpath) {
-			b_foundpath = breathFirstSearch(s,t,L);
-			if(b_foundpath) {
-				foundPaths++;
-			}
-		}
-		return foundPaths;
-	}
-
-	 /** execute one breathFirstSearch to find a path between s and t **/
-	 private static boolean breathFirstSearch(int s, int t, int[][] L) {
-		 //Visited Notes 
-		 Set<Integer> visitedNotes = new HashSet<Integer>();
-		 //Queue to check which node to search next
-		 LinkedList<Integer> queue = new LinkedList<Integer>();
-		 //Map to traverse the path back when found a path 
-		 HashMap<Integer,Integer> noteBeforeMap = new HashMap<Integer,Integer>();
-		 //Add starting Point
-		 queue.add(s);
-		 //Visit all neighbours of the next point in queue
-		 while(!queue.isEmpty()) {
-			 int id = queue.pollFirst();
-			 visitedNotes.add(id);
-			 //For all neighbors add to queue
-			 for(int i = 0; i < L[id].length; i++) {
-				 //Check if edge exist and not visited before
-				 if(L[id][i] != 0 && !visitedNotes.contains(i)) {
-					 
-					 queue.add(i);
-					 noteBeforeMap.putIfAbsent(i, id);
-					 //check if train is found
-					 if(i == t) {
-						 //update connectionMatrix l and remove the found path
-						 int actualID = t;
-						 while(actualID != s) {
-							 int nextID = noteBeforeMap.get(actualID);
-							 //remove edge
-							 L[nextID][actualID] = 0;
-							 L[actualID][nextID] = 0;
-							 actualID = nextID; 
-						 }
-						 return true;
-					 }
-				 }
-				 
-			 }
-		 }
-		 //if last queue element is searched but t is not reachable 
-		 return false;
-	}
-
-	/**
-	  * Makes a deep Copy of a Integer Matrix
-	  * @return
-	  */
-	private static int[][] makeCopyOfMatrix(int[][] matrix) {
-		int[][] copyMatrix = new int[matrix.length][matrix[0].length];
-		for(int i = 0; i < matrix.length; i++) {
-			for(int j = 0; j < matrix[0].length; j++) {
-				copyMatrix[i][j] = matrix[i][j];
-			}
-		}
-		return copyMatrix;
-	}
-
-	/**
-	  * Stoer Wagner Minimal Cut Algo
-	  * Source from
-	  * <a href="https://github.com/hunglvosu/algorithm/blob/master/algorithm/src/Stoer-Wagner.c">
-	  * https://github.com/hunglvosu/algorithm/blob/master/algorithm/src/Stoer-Wagner.c</a> <br>
-	  * in C formatted written in java
-	  * @param V Vertex Array
-	  * @param E Edge Array
-	  * @return
-	  */
-	 
-	 static int minimumCut(Vertex[] V, Edge[] E) {
-		 int[][] W = generateDisjointWeightMatrix(V, E); 
-		 boolean[] Del = new boolean[V.length];
-		 int n = V.length;				// the number of veritces
-		 int m = E.length;
-		return StoerWagner(n, m, W, Del);
-		 
-	 }
-	 
-	 static int StoerWagner(int n, int m, int[][] W, boolean[] Del){
-			int C = Integer.MAX_VALUE;
-			for(int V = n; V > 1; V--){
-				int cutValue = minCutPhase(V, W, Del, n, m);
-				C = (C < cutValue ? C: cutValue);	
-			}
-			return C;
-		}
-	 
-	 static int minCutPhase(int V, int[][] W, boolean[] Del, int n, int m){
-			int i = 0, j = 0;
-			int[] s = new int[2];
-			if(V  == 2) {
-				for( i = 0; i < n; i++){
-					if(Del[i] == false){
-						s[j] = i; j++;
-					}
-				}
-				return W[s[0]][s[1]];
-			}
-			int[] L = new int[n];
-			boolean[] T = new boolean[n];
-			
-			i = 1;	// the number of vertices in the tree T
-			j = 0;
-			int v,u;
-			while( i <= V){
-				v = maxStickiness(T,L, Del, n);
-				T[v] = true;
-				for(u = 0; u < n; u++){
-					if(W[v][u] != 0 && Del[u] == false && T[u] == false){
-						L[u] = L[u] + W[u][v];
-					}
-				}
-				if( i >= V-1){
-					s[j] = v; j++;
-				}
-				i++;
-			}
-			merge(s[0], s[1], n, W, Del);
-			return L[s[1]];	
-		}
-	 
-
-		static int maxStickiness(boolean[] T, int[] L, boolean[] Del, int n){
-			int i = 0;
-			int v = 0;
-			int max = 0;
-			for(i = 0; i < n; i++){
-				if(Del[i] == false && T[i] == false && max < L[i]){
-					v = i;
-					max = L[i];
-				} 
-			}
-			return v;
-		}
-	 
-
-		static void merge(int s, int t, int n, int[][] W, boolean[] Del){
-			int v = 0;
-			for(v = 0; v < n; v++){
-				if(Del[v] == false && v != s && v!= t){
-					W[s][v] = W[s][v] + W[v][t];
-					W[v][s] = W[s][v];
-				}
-			}
-			Del[t] = true;	
-		}
-
-
-
-
-
-	static double[][] basicAllPairsShortestPath(Vertex[] V, Edge[] E){
-		 double[][] L = generateWeightMatrix(V, E);
-		 double[][] D = generateDistanceMatrix(V);
-		 boolean[] flag = generateFlagList(V);
-		 for(int i=0;i<V.length;i++) {
-			 modifiedDikstra(V[i].id, L, D, flag);
-		 }
-		 return D;
-	 }
-	 static double averageShortestDistance(Graph G) {
-		 if(G.V.length <= 1) return 0.0;
-		 double[][] D = basicAllPairsShortestPath(G.V, G.E);
-		 double sum = 0.0;
-		 for(int s = 0; s < G.S.length; s++) {
-			 for(int t = s; t < G.S.length; t++) {
-				sum += D[G.S[s].id][G.S[t].id];					 
-			 }
-		 }
-		 //Returns the Average
-		 return sum / ((G.S.length * (G.S.length - 1)) / 2);
-	 } 
-	/** 
-	 * @return Updated Distance Matrix D and flag List 
-	 */
-	static void modifiedDikstra(int source, double[][] L, double[][] D, boolean[] flag) {
-		D[source][source] = 0;
-		LinkedList<Integer> visitedNotes = new LinkedList<Integer>(); 
-		LinkedList<Integer> minPriorityQueue = new LinkedList<Integer>(); 
-		minPriorityQueue.add(source);
-		
-		
-		
-		while(!minPriorityQueue.isEmpty()) {
-			minPriorityQueue.sort((a,b) -> Double.compare(D[source][a],  D[source][b]));
-			int target =  minPriorityQueue.pop();
-			if(flag[source] == true) {
-				for(int outgoingID = 0; outgoingID < L.length; outgoingID++) {
-					if(D[source][target] + L[target][outgoingID] < D[source][outgoingID]) {
-						D[source][outgoingID] = D[source][target] + L[target][outgoingID];
-					}
-				}
-			}else {
-				for(int outgoingID = 0; outgoingID < L.length; outgoingID++) {
-					if(L[target][outgoingID] == Double.POSITIVE_INFINITY) continue;
-					if(D[source][target] + L[target][outgoingID] < D[source][outgoingID]) {
-						D[source][outgoingID] = D[source][target] + L[target][outgoingID];
-						if(!visitedNotes.contains(outgoingID)) {
-							minPriorityQueue.add(outgoingID);
-						}
-					}
-				}
-			}
-			visitedNotes.add(target);
-		}
-		flag[source] = true;
-	}
-	
-	static double[][] generateWeightMatrix(Vertex[] V, Edge[] E){
-		double[][] L = new double[V.length][V.length];
-		for(int i = 0; i < E.length; i++) {
-			try {
-			L[E[i].idA][E[i].idB] = E[i].weight;
-			L[E[i].idB][E[i].idA] = E[i].weight;
-			}catch(java.lang.NullPointerException e) {
-				log.info("E[i].idA:" + E[i].idA + " E[i].idB:" + E[i].idB + " E[i].weight:" + E[i].weight);
-			}
-		}
-		for(int i=0;i<L.length;i++)
-        {
-            for(int j=0;j<L.length;j++)
-            {
-                if(L[i][j]==0.0) L[i][j] = Double.POSITIVE_INFINITY;
+
+  private static final Logger log = Logger.getLogger(GraphMetrics.class.getName());
+
+  /**
+   * Convert a DecoratedNetwork to a Graph
+   *
+   * @return a equivalent Graph to the DecoratedNetwork
+   */
+  public static Graph convertDecoratedNetworkToGraph(Model model, Holon holon) {
+    Graph G = new Graph();
+    HashMap<AbstractCanvasObject, Integer> objectToId = new HashMap<>();
+    List<Integer> sourcesList = new ArrayList<Integer>();
+    int count = 0;
+
+    for (HolonObject con : holon.holonObjects) {
+      objectToId.put(con, count);
+      sourcesList.add(count);
+      count++;
+    }
+
+    //Generate EdgeList
+    List<Edge> edgeList = new ArrayList<Edge>();
+    for (holeg.model.Edge cable : model.getEdgesOnCanvas()) {
+
+      AbstractCanvasObject objectA = cable.getA();
+      AbstractCanvasObject objectB = cable.getB();
+      if (objectA == null) {
+        log.warning("Edge: " + cable + "objectA == null");
+        continue;
+      }
+      if (objectB == null) {
+        log.warning("Edge: " + cable + "objectB == null");
+        continue;
+      }
+
+      //SpecialCase for open switches
+      if (objectA instanceof HolonSwitch sw && !sw.getState().isOpen()) {
+        continue;
+      }
+      if (objectB instanceof HolonSwitch sw && !sw.getState().isOpen()) {
+        continue;
+      }
+
+      int idA = -1;
+      if (objectToId.containsKey(objectA)) {
+        idA = objectToId.get(objectA);
+      } else {
+        idA = count;
+        objectToId.put(objectA, count++);
+      }
+      int idB = -1;
+      if (objectToId.containsKey(objectB)) {
+        idB = objectToId.get(objectB);
+      } else {
+        idB = count;
+        objectToId.put(objectB, count++);
+      }
+      double length = cable.getLength();
+      edgeList.add(new Edge(idA, idB, length));
+    }
+    //Generate EdgeArray
+    G.E = new Edge[edgeList.size()];
+    for (int i = 0; i < edgeList.size(); i++) {
+      G.E[i] = edgeList.get(i);
+    }
+    //Generate VertexArray
+    G.V = new Vertex[objectToId.size()];
+    int entryCount = 0;
+    for (Map.Entry<AbstractCanvasObject, Integer> entry : objectToId.entrySet()) {
+      G.V[entryCount] = new Vertex(entry.getValue());
+      entryCount++;
+    }
+    //Generate Sources Array
+    int sourceCount = 0;
+    G.S = new Vertex[sourcesList.size()];
+    for (int source : sourcesList) {
+      G.S[sourceCount] = new Vertex(source);
+      sourceCount++;
+    }
+    return G;
+  }
+
+  // Example Test
+  public static void main(String[] args) {
+    Graph G = new Graph();
+    G.V = new Vertex[4];
+    for (int i = 0; i < G.V.length; i++) {
+      G.V[i] = new Vertex(i);
+    }
+    G.E = new Edge[4];
+
+    G.E[0] = new Edge(0, 1, 1);
+    G.E[1] = new Edge(1, 2, 1);
+    G.E[2] = new Edge(2, 3, 1);
+    G.E[3] = new Edge(3, 0, 1);
+
+    G.S = new Vertex[4];
+    G.S[0] = new Vertex(0);
+    G.S[1] = new Vertex(1);
+    G.S[2] = new Vertex(2);
+    G.S[3] = new Vertex(3);
+    log.info(G.toString());
+    log.info("minimumCut: " + minimumCut(G.V, G.E));
+    log.info("AvgShortestDistance " + averageShortestDistance(G));
+    log.info("DisjointPath " + averageEdgeDisjointPathProblem(G));
+  }
+
+  static int[][] generateDisjointWeightMatrix(Vertex[] V, Edge[] E) {
+    int[][] L = new int[V.length][V.length];
+    for (int i = 0; i < E.length; i++) {
+      L[E[i].idA][E[i].idB] = 1;
+      L[E[i].idB][E[i].idA] = 1;
+    }
+    return L;
+  }
+
+  /**
+   * find the average s_t disjoint paths between all pairs of s and t
+   **/
+  static double averageEdgeDisjointPathProblem(Graph G) {
+    //This matrix indicates if a Edge is existent between two vertices
+    int[][] L = generateDisjointWeightMatrix(G.V, G.E);
+    double disjointPathSum = 0.0;
+    for (int s = 0; s < G.S.length; s++) {
+      for (int t = s; t < G.S.length; t++) {
+        disjointPathSum += s_t_EdgeDisjointPath(G.S[s].id, G.S[t].id, L);
+      }
+    }
+    //Returns the Average
+    return disjointPathSum / ((G.S.length * (G.S.length - 1)) / 2);
+  }
+
+  /**
+   * find the amount of s_t disjoint paths between s and t
+   **/
+  private static double s_t_EdgeDisjointPath(int s, int t, int[][] L_input) {
+    if (s == t) {
+      return 0;
+    }
+    //Make Copy of L
+    int[][] L = makeCopyOfMatrix(L_input);
+    double foundPaths = 0;
+    //RepeatBreathFirst search till no path is found
+    boolean b_foundpath = true;
+    while (b_foundpath) {
+      b_foundpath = breathFirstSearch(s, t, L);
+      if (b_foundpath) {
+        foundPaths++;
+      }
+    }
+    return foundPaths;
+  }
+
+  /**
+   * execute one breathFirstSearch to find a path between s and t
+   **/
+  private static boolean breathFirstSearch(int s, int t, int[][] L) {
+    //Visited Notes
+    Set<Integer> visitedNotes = new HashSet<Integer>();
+    //Queue to check which node to search next
+    LinkedList<Integer> queue = new LinkedList<Integer>();
+    //Map to traverse the path back when found a path
+    HashMap<Integer, Integer> noteBeforeMap = new HashMap<Integer, Integer>();
+    //Add starting Point
+    queue.add(s);
+    //Visit all neighbours of the next point in queue
+    while (!queue.isEmpty()) {
+      int id = queue.pollFirst();
+      visitedNotes.add(id);
+      //For all neighbors add to queue
+      for (int i = 0; i < L[id].length; i++) {
+        //Check if edge exist and not visited before
+        if (L[id][i] != 0 && !visitedNotes.contains(i)) {
+
+          queue.add(i);
+          noteBeforeMap.putIfAbsent(i, id);
+          //check if train is found
+          if (i == t) {
+            //update connectionMatrix l and remove the found path
+            int actualID = t;
+            while (actualID != s) {
+              int nextID = noteBeforeMap.get(actualID);
+              //remove edge
+              L[nextID][actualID] = 0;
+              L[actualID][nextID] = 0;
+              actualID = nextID;
             }
             }
+            return true;
+          }
+        }
+
+      }
+    }
+    //if last queue element is searched but t is not reachable
+    return false;
+  }
+
+  /**
+   * Makes a deep Copy of a Integer Matrix
+   *
+   * @return
+   */
+  private static int[][] makeCopyOfMatrix(int[][] matrix) {
+    int[][] copyMatrix = new int[matrix.length][matrix[0].length];
+    for (int i = 0; i < matrix.length; i++) {
+      for (int j = 0; j < matrix[0].length; j++) {
+        copyMatrix[i][j] = matrix[i][j];
+      }
+    }
+    return copyMatrix;
+  }
+
+  /**
+   * Stoer Wagner Minimal Cut Algo Source from
+   * <a href="https://github.com/hunglvosu/algorithm/blob/master/algorithm/src/Stoer-Wagner.c">
+   * https://github.com/hunglvosu/algorithm/blob/master/algorithm/src/Stoer-Wagner.c</a> <br> in C
+   * formatted written in java
+   *
+   * @param V Vertex Array
+   * @param E Edge Array
+   * @return
+   */
+
+  static int minimumCut(Vertex[] V, Edge[] E) {
+    int[][] W = generateDisjointWeightMatrix(V, E);
+    boolean[] Del = new boolean[V.length];
+    int n = V.length;        // the number of veritces
+    int m = E.length;
+    return StoerWagner(n, m, W, Del);
+
+  }
+
+  static int StoerWagner(int n, int m, int[][] W, boolean[] Del) {
+    int C = Integer.MAX_VALUE;
+    for (int V = n; V > 1; V--) {
+      int cutValue = minCutPhase(V, W, Del, n, m);
+      C = (C < cutValue ? C : cutValue);
+    }
+    return C;
+  }
+
+  static int minCutPhase(int V, int[][] W, boolean[] Del, int n, int m) {
+    int i = 0, j = 0;
+    int[] s = new int[2];
+    if (V == 2) {
+      for (i = 0; i < n; i++) {
+        if (Del[i] == false) {
+          s[j] = i;
+          j++;
+        }
+      }
+      return W[s[0]][s[1]];
+    }
+    int[] L = new int[n];
+    boolean[] T = new boolean[n];
+
+    i = 1;  // the number of vertices in the tree T
+    j = 0;
+    int v, u;
+    while (i <= V) {
+      v = maxStickiness(T, L, Del, n);
+      T[v] = true;
+      for (u = 0; u < n; u++) {
+        if (W[v][u] != 0 && Del[u] == false && T[u] == false) {
+          L[u] = L[u] + W[u][v];
         }
         }
-		for(int i=0;i<L.length;i++)
-        {
-			L[i][i] = 0.0;
+      }
+      if (i >= V - 1) {
+        s[j] = v;
+        j++;
+      }
+      i++;
+    }
+    merge(s[0], s[1], n, W, Del);
+    return L[s[1]];
+  }
+
+  static int maxStickiness(boolean[] T, int[] L, boolean[] Del, int n) {
+    int i = 0;
+    int v = 0;
+    int max = 0;
+    for (i = 0; i < n; i++) {
+      if (Del[i] == false && T[i] == false && max < L[i]) {
+        v = i;
+        max = L[i];
+      }
+    }
+    return v;
+  }
+
+  static void merge(int s, int t, int n, int[][] W, boolean[] Del) {
+    int v = 0;
+    for (v = 0; v < n; v++) {
+      if (Del[v] == false && v != s && v != t) {
+        W[s][v] = W[s][v] + W[v][t];
+        W[v][s] = W[s][v];
+      }
+    }
+    Del[t] = true;
+  }
+
+  static double[][] basicAllPairsShortestPath(Vertex[] V, Edge[] E) {
+    double[][] L = generateWeightMatrix(V, E);
+    double[][] D = generateDistanceMatrix(V);
+    boolean[] flag = generateFlagList(V);
+    for (int i = 0; i < V.length; i++) {
+      modifiedDikstra(V[i].id, L, D, flag);
+    }
+    return D;
+  }
+
+  static double averageShortestDistance(Graph G) {
+    if (G.V.length <= 1) {
+      return 0.0;
+    }
+    double[][] D = basicAllPairsShortestPath(G.V, G.E);
+    double sum = 0.0;
+    for (int s = 0; s < G.S.length; s++) {
+      for (int t = s; t < G.S.length; t++) {
+        sum += D[G.S[s].id][G.S[t].id];
+      }
+    }
+    //Returns the Average
+    return sum / ((G.S.length * (G.S.length - 1)) / 2);
+  }
+
+  /**
+   * @return Updated Distance Matrix D and flag List
+   */
+  static void modifiedDikstra(int source, double[][] L, double[][] D, boolean[] flag) {
+    D[source][source] = 0;
+    LinkedList<Integer> visitedNotes = new LinkedList<Integer>();
+    LinkedList<Integer> minPriorityQueue = new LinkedList<Integer>();
+    minPriorityQueue.add(source);
+
+    while (!minPriorityQueue.isEmpty()) {
+      minPriorityQueue.sort((a, b) -> Double.compare(D[source][a], D[source][b]));
+      int target = minPriorityQueue.pop();
+      if (flag[source] == true) {
+        for (int outgoingID = 0; outgoingID < L.length; outgoingID++) {
+          if (D[source][target] + L[target][outgoingID] < D[source][outgoingID]) {
+            D[source][outgoingID] = D[source][target] + L[target][outgoingID];
+          }
         }
         }
-		return L;
-	}
-	static double[][] generateDistanceMatrix(Vertex[] V) {
-		double[][] D = new double[V.length][V.length];
-		for(int i=0;i<D.length;i++)
-        {
-            for(int j=0;j<D.length;j++)
-            {
-                D[i][j] = Double.POSITIVE_INFINITY;
+      } else {
+        for (int outgoingID = 0; outgoingID < L.length; outgoingID++) {
+          if (L[target][outgoingID] == Double.POSITIVE_INFINITY) {
+            continue;
+          }
+          if (D[source][target] + L[target][outgoingID] < D[source][outgoingID]) {
+            D[source][outgoingID] = D[source][target] + L[target][outgoingID];
+            if (!visitedNotes.contains(outgoingID)) {
+              minPriorityQueue.add(outgoingID);
             }
             }
+          }
         }
         }
-		return D;
-	}
-	private static boolean[] generateFlagList(Vertex[] V) {
-		boolean[] flag = new boolean[V.length];
-		return flag;
-	}
+      }
+      visitedNotes.add(target);
+    }
+    flag[source] = true;
+  }
+
+  static double[][] generateWeightMatrix(Vertex[] V, Edge[] E) {
+    double[][] L = new double[V.length][V.length];
+    for (int i = 0; i < E.length; i++) {
+      try {
+        L[E[i].idA][E[i].idB] = E[i].weight;
+        L[E[i].idB][E[i].idA] = E[i].weight;
+      } catch (java.lang.NullPointerException e) {
+        log.info("E[i].idA:" + E[i].idA + " E[i].idB:" + E[i].idB + " E[i].weight:" + E[i].weight);
+      }
+    }
+    for (int i = 0; i < L.length; i++) {
+      for (int j = 0; j < L.length; j++) {
+        if (L[i][j] == 0.0) {
+          L[i][j] = Double.POSITIVE_INFINITY;
+        }
+      }
+    }
+    for (int i = 0; i < L.length; i++) {
+      L[i][i] = 0.0;
+    }
+    return L;
+  }
+
+  static double[][] generateDistanceMatrix(Vertex[] V) {
+    double[][] D = new double[V.length][V.length];
+    for (int i = 0; i < D.length; i++) {
+      for (int j = 0; j < D.length; j++) {
+        D[i][j] = Double.POSITIVE_INFINITY;
+      }
+    }
+    return D;
+  }
+
+  private static boolean[] generateFlagList(Vertex[] V) {
+    boolean[] flag = new boolean[V.length];
+    return flag;
+  }
+
+  public static class Vertex {
+
+    public int id = 0;
+
+    public Vertex(int id) {
+      this.id = id;
+    }
+
+    public String toString() {
+      return "" + id;
+    }
+  }
+
+  private static class Edge {
+
+    public int idA, idB;
+    public double weight;
+
+    public Edge(int idA, int idB, double weight) {
+      this.idA = idA;
+      this.idB = idB;
+      this.weight = weight;
+    }
+  }
+
+  public static class Graph {
+
+    Vertex[] V;
+    Edge[] E;
+    /**
+     * Only the Sources/Trains for disjoint Path no Switch or Node
+     **/
+    Vertex[] S;
+
+    public String toString() {
+      String vList = "V" + Arrays.toString(V);
+      String sList = "S" + Arrays.toString(S);
+      return vList + ", " + sList;
+    }
+  }
 
 
 
 
 }
 }

+ 192 - 188
src/holeg/algorithm/objective_function/ObjectiveFunctionByCarlos.java

@@ -1,199 +1,203 @@
 package holeg.algorithm.objective_function;
 package holeg.algorithm.objective_function;
 
 
-import java.util.logging.Logger;
-
 import holeg.model.Flexibility;
 import holeg.model.Flexibility;
 import holeg.model.Holon;
 import holeg.model.Holon;
 import holeg.model.HolonElement.Priority;
 import holeg.model.HolonElement.Priority;
 import holeg.model.HolonObject;
 import holeg.model.HolonObject;
 import holeg.model.Model;
 import holeg.model.Model;
+import java.util.logging.Logger;
 
 
 public class ObjectiveFunctionByCarlos {
 public class ObjectiveFunctionByCarlos {
-	// Parameters
-	private static final Logger log = Logger.getLogger(ObjectiveFunctionByCarlos.class.getName());
-	static double w_eb = .3, w_state = .3, w_pro = .2, w_perf = .1, w_holon = .1;
-
-	static double k_eb = 750000.f, k_state = 20000, k_pro = 3000, k_perf = 15000, k_holon = 200000;
-
-	// theta for f_pro
-	static double theta = 3;
-
-	// kappas for f_perf:
-	static double kappa_f_unre = 120;
-	static double kappa_f_cool = 60 * 60 * 24;
-	static double kappa_f_dur = 60 * 60;
-
-	// lambdas for f_perf:
-	static double lambda_f_unre = 10;
-	static double lambda_f_cool = 10;
-	static double lambda_f_dur = 10;
-
-	static double lambda_f_change = 1000;
-
-	// pre-calculated parameters for partial function terms:
-	/**
-	 * Pre calculated for the squash function <br>
-	 * {@link ObjectiveFunctionByCarlos#squash}
-	 */
-	static double squash_subtract = 100.f / (1.f + (float) Math.exp(5.0));
-	static double range_for_kappa_f_unre = range(kappa_f_unre);
-	static double range_for_kappa_f_cool = range(kappa_f_cool);
-	static double range_for_kappa_f_dur = range(kappa_f_dur);
-
-	static {
-		// init
-		checkParameter();
-	}
-
-	/**
-	 * Check parameter Setting and print error when wrong values are put in. Here
-	 * should all invariants be placed to be checked on initialization.
-	 */
-	private static void checkParameter() {
-		boolean parameterSumOne = Math.abs(w_eb + w_state + w_pro + w_perf + w_holon - 1) < 0.001;
-		if (!parameterSumOne) {
-			log.warning("ParameterError in ObjectiveFunction: w1 + w2 + w3 + w4 + w5 should be 1");
-		}
-	}
-
-	/**
-	 * ObjectifeFunction by Carlos. Function computes f_g: f_g = w1 * squash(f_eb,
-	 * k1) + w2 * squash(f_state, k2) + w3 * squash(f_pro, k3) + w4 * squash(f_perf,
-	 * k4) + w5 * squash(f_holon, k5)
-	 * 
-	 * 
-	 * squash is the squashing function {@link ObjectiveFunctionByCarlos#squash}
-	 * 
-	 *
-	 * @return f_g value between 0 and 100
-	 */
-	static public double getFitnessValueForState(Model model) {
-
-		// Calculate f_eb the penalty for unbalenced energy in the network
-		double f_eb = 0;
-		// sum over all objects
-		for (Holon holon : model.holons) {
-			double netEnergyDifference = holon.holonObjects.stream().map(hO -> Math.abs(hO.getActualEnergy())).reduce(0.0f, Float::sum);
-			f_eb += netEnergyDifference;
-		}
-
-		// Calculate f_state the penalty function for the supply state
-		double f_state = 0;
-		for (Holon holon : model.holons) {
-			f_state += holon.holonObjects.stream().filter(hO -> hO.getState() != HolonObject.HolonObjectState.PRODUCER)
-					.map(HolonObject::getSupplyBarPercentage).reduce(0.f, Float::sum);
-		}
-
-		// calculate f_pro the penalty function for priority usage
-		// for each active flexibility punish
-
-		double f_pro = model.getAllFlexibilities().stream().filter(flex -> flex.getState().equals(Flexibility.FlexState.IN_USE))
-				.map(flex -> Math.pow(theta, priorityToDouble(flex.getElement().getPriority())) - 1.0)
-				.reduce(0.0, Double::sum);
-
-
-		// calculate f_perf the penalty function for the quality of a flexibility used
-
-
-		// and the subfuction f_unre, f_cool, f_dur
-		double f_perf = 0;
-		for (Flexibility flex : model.getAllFlexibilities().stream().filter(flex -> flex.getState().equals(Flexibility.FlexState.IN_USE)).toList()) {
-			double f_unre = unresponsivnessPenalty(flex.getSpeed());
-			double f_cool = cooldownPenalty(flex.getCooldown());
-			double f_dur = durationPenalty(flex.getDuration());
-			f_perf += f_unre + f_cool + f_dur;
-		}
-
-		// calculate f_holon
-		double f_holon = 0;
-		for (Holon net : model.holons) {
-			double f_elements_deviation_production = net.getDeviationInProductionInNetworkForHolonObjects();
-			double f_elements_deviation_consumption = net.getDeviationInProductionInNetworkForHolonObjects();
-			double f_flexibility_deviation_consumption = net.getDeviationInFlexibilityConsumption();
-			double f_flexibility_deviation_production = net.getDeviationInFlexibilityProduction();
-
-			double con = net.getTotalConsumption();
-			double prod = net.getTotalProduction();
-			double flexcapProd = net.getFlexibilityProductionCapacity();
-			double flexcapCon = net.getFlexibilityConsumptionCapacity();
-			double f_change_positive = lambda_f_change
-					- lambda_f_change * Math.min(1, (con > 0.0) ? flexcapProd / con : 1.0);
-			double f_change_negativ = lambda_f_change
-					- lambda_f_change * Math.min(1, (prod > 0.0) ? flexcapCon / prod : 1.0);
-
-			double f_element = f_elements_deviation_production + f_elements_deviation_consumption;
-			double f_flexibility = f_flexibility_deviation_consumption + f_flexibility_deviation_production;
-			double f_change = f_change_positive + f_change_negativ;
-
-			f_holon += f_element + f_flexibility + f_change;
-		}
-		double q1 = squash(f_eb, k_eb);
-		double q2 = squash(f_state, k_state);
-		double q3 = squash(f_pro, k_pro);
-		double q4 = squash(f_perf, k_perf);
-		double q5 = squash(f_holon, k_holon);
-		log.finer("f_eb= " + f_eb + " f_state= " + f_state + " f_pro= " + f_pro + " f_perf= " + f_perf + " f_holon= "
-				+ f_holon + " q1= " + q1 + " q2= " + q2 + " q3= " + q3 + " q4= " + q4 + " q5= " + q5);
-
-		return w_eb * q1 + w_state * q2 + w_pro * q3 + w_perf * q4 + w_holon * q5;
-	}
-
-	/**
-	 * The squashing function in paper
-	 * 
-	 * @param x     the input
-	 * @param kappa the corresponding kappa
-	 */
-	static public double squash(double x, double kappa) {
-		return 100.f / (1.0f + Math.exp(-(10.f * (x - kappa / 2.f)) / kappa)) - squash_subtract;
-	}
-
-	/**
-	 * f_sup in paper
-	 * 
-	 * @param supply from 0 to 1
-	 */
-	static public double supplyPenalty(double supply) {
-		double supplyPercentage = 100 * supply;
-		// double test = (supplyPercentage < 100) ? -0.5 * supplyPercentage + 50:
-		// supplyPercentage - 100;
-		return (supplyPercentage < 100) ? -0.5 * supplyPercentage + 50 : supplyPercentage - 100;
-	}
-
-	private static double priorityToDouble(Priority priority) {
-		return switch (priority) {
-			case Essential -> 3.;
-			case High -> 2.;
-			case Medium -> 1.;
-			default -> 0.;
-		};
-	}
-
-	/**
-	 * Attention Math.log calcultae ln not log
-	 */
-	private static double range(double kappa) {
-		return -kappa / Math.log(Math.pow(2.0, 0.05) - 1.0);
-	}
-
-	/**
-	 * f_unre
-
-	 */
-	private static double unresponsivnessPenalty(double unresponsiv) {
-		return (2.0 * lambda_f_unre) / (1 + Math.exp(-unresponsiv / range_for_kappa_f_unre)) - lambda_f_unre;
-	}
-
-	/**
-	 * f_cool
-	 */
-	private static double cooldownPenalty(double cooldown) {
-		return (2.0 * lambda_f_cool) / (1 + Math.exp(-cooldown / range_for_kappa_f_cool)) - lambda_f_cool;
-	}
-
-	private static double durationPenalty(double duration) {
-		double lambda_dur_times2 = 2.0 * lambda_f_dur;
-		return -lambda_dur_times2 / (1 + Math.exp(-duration / range_for_kappa_f_dur)) + lambda_dur_times2;
-	}
+
+  // Parameters
+  private static final Logger log = Logger.getLogger(ObjectiveFunctionByCarlos.class.getName());
+  static double w_eb = .3, w_state = .3, w_pro = .2, w_perf = .1, w_holon = .1;
+
+  static double k_eb = 750000.f, k_state = 20000, k_pro = 3000, k_perf = 15000, k_holon = 200000;
+
+  // theta for f_pro
+  static double theta = 3;
+
+  // kappas for f_perf:
+  static double kappa_f_unre = 120;
+  static double kappa_f_cool = 60 * 60 * 24;
+  static double kappa_f_dur = 60 * 60;
+
+  // lambdas for f_perf:
+  static double lambda_f_unre = 10;
+  static double lambda_f_cool = 10;
+  static double lambda_f_dur = 10;
+
+  static double lambda_f_change = 1000;
+
+  // pre-calculated parameters for partial function terms:
+  /**
+   * Pre calculated for the squash function <br> {@link ObjectiveFunctionByCarlos#squash}
+   */
+  static double squash_subtract = 100.f / (1.f + (float) Math.exp(5.0));
+  static double range_for_kappa_f_unre = range(kappa_f_unre);
+  static double range_for_kappa_f_cool = range(kappa_f_cool);
+  static double range_for_kappa_f_dur = range(kappa_f_dur);
+
+  static {
+    // init
+    checkParameter();
+  }
+
+  /**
+   * Check parameter Setting and print error when wrong values are put in. Here should all
+   * invariants be placed to be checked on initialization.
+   */
+  private static void checkParameter() {
+    boolean parameterSumOne = Math.abs(w_eb + w_state + w_pro + w_perf + w_holon - 1) < 0.001;
+    if (!parameterSumOne) {
+      log.warning("ParameterError in ObjectiveFunction: w1 + w2 + w3 + w4 + w5 should be 1");
+    }
+  }
+
+  /**
+   * ObjectifeFunction by Carlos. Function computes f_g: f_g = w1 * squash(f_eb, k1) + w2 *
+   * squash(f_state, k2) + w3 * squash(f_pro, k3) + w4 * squash(f_perf, k4) + w5 * squash(f_holon,
+   * k5)
+   * <p>
+   * <p>
+   * squash is the squashing function {@link ObjectiveFunctionByCarlos#squash}
+   *
+   * @return f_g value between 0 and 100
+   */
+  static public double getFitnessValueForState(Model model) {
+
+    // Calculate f_eb the penalty for unbalenced energy in the network
+    double f_eb = 0;
+    // sum over all objects
+    for (Holon holon : model.holons) {
+      double netEnergyDifference = holon.holonObjects.stream()
+          .map(hO -> Math.abs(hO.getActualEnergy())).reduce(0.0f, Float::sum);
+      f_eb += netEnergyDifference;
+    }
+
+    // Calculate f_state the penalty function for the supply state
+    double f_state = 0;
+    for (Holon holon : model.holons) {
+      f_state += holon.holonObjects.stream()
+          .filter(hO -> hO.getState() != HolonObject.HolonObjectState.PRODUCER)
+          .map(HolonObject::getSupplyBarPercentage).reduce(0.f, Float::sum);
+    }
+
+    // calculate f_pro the penalty function for priority usage
+    // for each active flexibility punish
+
+    double f_pro = model.getAllFlexibilities().stream()
+        .filter(flex -> flex.getState().equals(Flexibility.FlexState.IN_USE))
+        .map(flex -> Math.pow(theta, priorityToDouble(flex.getElement().getPriority())) - 1.0)
+        .reduce(0.0, Double::sum);
+
+    // calculate f_perf the penalty function for the quality of a flexibility used
+
+    // and the subfuction f_unre, f_cool, f_dur
+    double f_perf = 0;
+    for (Flexibility flex : model.getAllFlexibilities().stream()
+        .filter(flex -> flex.getState().equals(Flexibility.FlexState.IN_USE)).toList()) {
+      double f_unre = unresponsivnessPenalty(flex.getSpeed());
+      double f_cool = cooldownPenalty(flex.getCooldown());
+      double f_dur = durationPenalty(flex.getDuration());
+      f_perf += f_unre + f_cool + f_dur;
+    }
+
+    // calculate f_holon
+    double f_holon = 0;
+    for (Holon net : model.holons) {
+      double f_elements_deviation_production = net.getDeviationInProductionInNetworkForHolonObjects();
+      double f_elements_deviation_consumption = net.getDeviationInProductionInNetworkForHolonObjects();
+      double f_flexibility_deviation_consumption = net.getDeviationInFlexibilityConsumption();
+      double f_flexibility_deviation_production = net.getDeviationInFlexibilityProduction();
+
+      double con = net.getTotalConsumption();
+      double prod = net.getTotalProduction();
+      double flexcapProd = net.getFlexibilityProductionCapacity();
+      double flexcapCon = net.getFlexibilityConsumptionCapacity();
+      double f_change_positive = lambda_f_change
+          - lambda_f_change * Math.min(1, (con > 0.0) ? flexcapProd / con : 1.0);
+      double f_change_negativ = lambda_f_change
+          - lambda_f_change * Math.min(1, (prod > 0.0) ? flexcapCon / prod : 1.0);
+
+      double f_element = f_elements_deviation_production + f_elements_deviation_consumption;
+      double f_flexibility =
+          f_flexibility_deviation_consumption + f_flexibility_deviation_production;
+      double f_change = f_change_positive + f_change_negativ;
+
+      f_holon += f_element + f_flexibility + f_change;
+    }
+    double q1 = squash(f_eb, k_eb);
+    double q2 = squash(f_state, k_state);
+    double q3 = squash(f_pro, k_pro);
+    double q4 = squash(f_perf, k_perf);
+    double q5 = squash(f_holon, k_holon);
+    log.finer("f_eb= " + f_eb + " f_state= " + f_state + " f_pro= " + f_pro + " f_perf= " + f_perf
+        + " f_holon= "
+        + f_holon + " q1= " + q1 + " q2= " + q2 + " q3= " + q3 + " q4= " + q4 + " q5= " + q5);
+
+    return w_eb * q1 + w_state * q2 + w_pro * q3 + w_perf * q4 + w_holon * q5;
+  }
+
+  /**
+   * The squashing function in paper
+   *
+   * @param x     the input
+   * @param kappa the corresponding kappa
+   */
+  static public double squash(double x, double kappa) {
+    return 100.f / (1.0f + Math.exp(-(10.f * (x - kappa / 2.f)) / kappa)) - squash_subtract;
+  }
+
+  /**
+   * f_sup in paper
+   *
+   * @param supply from 0 to 1
+   */
+  static public double supplyPenalty(double supply) {
+    double supplyPercentage = 100 * supply;
+    // double test = (supplyPercentage < 100) ? -0.5 * supplyPercentage + 50:
+    // supplyPercentage - 100;
+    return (supplyPercentage < 100) ? -0.5 * supplyPercentage + 50 : supplyPercentage - 100;
+  }
+
+  private static double priorityToDouble(Priority priority) {
+    return switch (priority) {
+      case Essential -> 3.;
+      case High -> 2.;
+      case Medium -> 1.;
+      default -> 0.;
+    };
+  }
+
+  /**
+   * Attention Math.log calcultae ln not log
+   */
+  private static double range(double kappa) {
+    return -kappa / Math.log(Math.pow(2.0, 0.05) - 1.0);
+  }
+
+  /**
+   * f_unre
+   */
+  private static double unresponsivnessPenalty(double unresponsiv) {
+    return (2.0 * lambda_f_unre) / (1 + Math.exp(-unresponsiv / range_for_kappa_f_unre))
+        - lambda_f_unre;
+  }
+
+  /**
+   * f_cool
+   */
+  private static double cooldownPenalty(double cooldown) {
+    return (2.0 * lambda_f_cool) / (1 + Math.exp(-cooldown / range_for_kappa_f_cool))
+        - lambda_f_cool;
+  }
+
+  private static double durationPenalty(double duration) {
+    double lambda_dur_times2 = 2.0 * lambda_f_dur;
+    return -lambda_dur_times2 / (1 + Math.exp(-duration / range_for_kappa_f_dur))
+        + lambda_dur_times2;
+  }
 
 
 }
 }

+ 50 - 47
src/holeg/algorithm/objective_function/SwitchObjectiveFunction.java

@@ -5,51 +5,54 @@ import holeg.model.HolonObject;
 import holeg.model.Model;
 import holeg.model.Model;
 
 
 public class SwitchObjectiveFunction {
 public class SwitchObjectiveFunction {
-	
-	//weights
-	static double w_eb = .5, w_state = .5;
-	static double k_eb = 1050000.f, k_state = 10000;
-	
-	static double squash_subtract = 1.0f / (1.f + (float) Math.exp(5.0));
-
-	static public float getFitnessValueForState(Model model) {
-		double f_eb = 0;
-		double f_state = 0;
-		double elementCountInNetwork = model.getAllHolonElements().size();
-		//sum over all objects
-		for(Holon holon : model.holons) {
-
-			//weigt
-			double w_network = holon.getAmountOfElements()/elementCountInNetwork;
-
-			//f_eb
-			double netEnergyDifference = holon.holonObjects.stream().map(hO -> Math.abs(hO.getActualEnergy())).reduce(0.0f, Float::sum);
-			//abs
-			f_eb += w_network * Math.abs(netEnergyDifference);
-
-
-			//f_state
-			f_state += w_network * holon.holonObjects.stream().filter(HolonObject::isConsumer).map(con -> supplyPenalty(con.getSupplyBarPercentage())).reduce(0., Double::sum);
-		}
-		return (float) (w_eb*squash(f_eb, k_eb) + w_state*squash(f_state, k_state));
-	}
-	
-	
-	/**
-	 * f_sup in paper
-	 * @param supply from 0 to 1
-	 */
-	static public double supplyPenalty(double supply) {
-		double supplyPercentage = 100 * supply;
-		return (supplyPercentage < 100) ? -0.5 * supplyPercentage + 50: supplyPercentage - 100;
-	}
-	
-	/**
-	 * The squashing function in paper
-	 * @param x the input
-	 * @param kappa the corresponding kappa
-	 */
-	static public double squash(double x, double kappa) {
-		return 100.f/(1.0f + Math.exp(-(10.f * (x - kappa/2.f))/ kappa)) - squash_subtract;
-	}
+
+  //weights
+  static double w_eb = .5, w_state = .5;
+  static double k_eb = 1050000.f, k_state = 10000;
+
+  static double squash_subtract = 1.0f / (1.f + (float) Math.exp(5.0));
+
+  static public float getFitnessValueForState(Model model) {
+    double f_eb = 0;
+    double f_state = 0;
+    double elementCountInNetwork = model.getAllHolonElements().size();
+    //sum over all objects
+    for (Holon holon : model.holons) {
+
+      //weigt
+      double w_network = holon.getAmountOfElements() / elementCountInNetwork;
+
+      //f_eb
+      double netEnergyDifference = holon.holonObjects.stream()
+          .map(hO -> Math.abs(hO.getActualEnergy())).reduce(0.0f, Float::sum);
+      //abs
+      f_eb += w_network * Math.abs(netEnergyDifference);
+
+      //f_state
+      f_state += w_network * holon.holonObjects.stream().filter(HolonObject::isConsumer)
+          .map(con -> supplyPenalty(con.getSupplyBarPercentage())).reduce(0., Double::sum);
+    }
+    return (float) (w_eb * squash(f_eb, k_eb) + w_state * squash(f_state, k_state));
+  }
+
+
+  /**
+   * f_sup in paper
+   *
+   * @param supply from 0 to 1
+   */
+  static public double supplyPenalty(double supply) {
+    double supplyPercentage = 100 * supply;
+    return (supplyPercentage < 100) ? -0.5 * supplyPercentage + 50 : supplyPercentage - 100;
+  }
+
+  /**
+   * The squashing function in paper
+   *
+   * @param x     the input
+   * @param kappa the corresponding kappa
+   */
+  static public double squash(double x, double kappa) {
+    return 100.f / (1.0f + Math.exp(-(10.f * (x - kappa / 2.f)) / kappa)) - squash_subtract;
+  }
 }
 }

+ 283 - 280
src/holeg/algorithm/objective_function/TopologieObjectiveFunction.java

@@ -1,292 +1,295 @@
 package holeg.algorithm.objective_function;
 package holeg.algorithm.objective_function;
 
 
 
 
-import java.util.Locale;
-import java.util.logging.Logger;
-
 import holeg.model.Holon;
 import holeg.model.Holon;
 import holeg.model.HolonObject;
 import holeg.model.HolonObject;
 import holeg.model.Model;
 import holeg.model.Model;
 import holeg.utility.math.decimal.Sampler;
 import holeg.utility.math.decimal.Sampler;
+import java.util.Locale;
+import java.util.logging.Logger;
 
 
 public class TopologieObjectiveFunction {
 public class TopologieObjectiveFunction {
-	private static final Logger log = Logger.getLogger(TopologieObjectiveFunction.class.getName());
-	//Parameters
-	//weight for f_g(H)
-	static double w_eb = 0.2, w_max = 0.5, w_holon= 0.1, w_selection = .1, w_grid = 0.1;
-	
-	
-	//--> f_eb parameter
-	/**
-	 * Maximum Energie Difference(kappa)
-	 */
-	static double k_eb = 5000.f;
-	/**
-	 * Maximum when all on Energie Difference(kappa)
-	 */
-	static double k_max = 10.f;
-	static double lambda_max = 10.;
-	
-	//--> f_holon parameter
-	/**
-	 * maximum penalty from holon element distribution
-	 */
-	static double k_holon= 4000;
-	
-	
-	//--> f_selection paramaeter;
-	/**
-	 *  average Maximum Cost for selction(kappa) of switch and elements.
-	 */
-	static double k_selection = 200000;
-	static double cost_switch = 3000;
-	private static double cost_of_cable_per_meter = 6;
-
-	//--> f_grid parameter
-	
-	
-	
-	/**
-	 * The avergae shortest path maximum length -> kappa for the squash function
-	 */
-	static double k_avg_shortest_path = 1600;
-	//Disjpijoint path cant have zero as output it starts with the value 1
-	static double centerValue_disjoint_path = 1.0; 
-	static double k_disjoint_path = 2.4;
-	static double lambda_avg_shortest_path = 10;
-	static double lambda_disjoint_path = 10;
-	static double k_grid = lambda_avg_shortest_path;// + lambda_disjoint_path;
-	
-	
-	
-	//pre-calculated parameters for partial function terms:
-	/** 
-	 * Pre calculated for the squash function
-	 * <br>
-	 *  {@link TopologieObjectiveFunction#squash}
-	 */
-	static double squash_subtract = 1.0f / (1.f + (float) Math.exp(5.0));
-	static double range_for_k_avg_shortest_path = range(k_avg_shortest_path);
-	static double range_for_k_disjoint_path = range(k_disjoint_path - centerValue_disjoint_path);
-
-	public static Sampler averageLog = new Sampler();
-	static boolean useLog = false;
-	static {
-        //init
-		checkParameter();
+
+  private static final Logger log = Logger.getLogger(TopologieObjectiveFunction.class.getName());
+  public static Sampler averageLog = new Sampler();
+
+  //--> f_eb parameter
+  //Parameters
+  //weight for f_g(H)
+  static double w_eb = 0.2, w_max = 0.5, w_holon = 0.1, w_selection = .1, w_grid = 0.1;
+  /**
+   * Maximum Energie Difference(kappa)
+   */
+  static double k_eb = 5000.f;
+  /**
+   * Maximum when all on Energie Difference(kappa)
+   */
+  static double k_max = 10.f;
+
+  //--> f_holon parameter
+  static double lambda_max = 10.;
+
+  //--> f_selection paramaeter;
+  /**
+   * maximum penalty from holon element distribution
+   */
+  static double k_holon = 4000;
+  /**
+   * average Maximum Cost for selction(kappa) of switch and elements.
+   */
+  static double k_selection = 200000;
+  static double cost_switch = 3000;
+
+  //--> f_grid parameter
+  /**
+   * The avergae shortest path maximum length -> kappa for the squash function
+   */
+  static double k_avg_shortest_path = 1600;
+  //Disjpijoint path cant have zero as output it starts with the value 1
+  static double centerValue_disjoint_path = 1.0;
+  static double k_disjoint_path = 2.4;
+  static double lambda_avg_shortest_path = 10;
+  static double lambda_disjoint_path = 10;
+  static double k_grid = lambda_avg_shortest_path;// + lambda_disjoint_path;
+
+  //pre-calculated parameters for partial function terms:
+  /**
+   * Pre calculated for the squash function
+   * <br>
+   * {@link TopologieObjectiveFunction#squash}
+   */
+  static double squash_subtract = 1.0f / (1.f + (float) Math.exp(5.0));
+  static double range_for_k_avg_shortest_path = range(k_avg_shortest_path);
+  static double range_for_k_disjoint_path = range(k_disjoint_path - centerValue_disjoint_path);
+  static boolean useLog = false;
+  private static double cost_of_cable_per_meter = 6;
+
+  static {
+    //init
+    checkParameter();
+  }
+
+  /**
+   * Check parameter Setting and print error when wrong values are put in. Here should all
+   * invariants be placed to be checked on initialization.
+   */
+  private static void checkParameter() {
+    if (!(Math.abs(w_eb + w_holon + w_selection + w_grid + w_max - 1) < 0.001)) {
+      System.err.println("ParameterError in ObjectiveFunction: Sum of all weights should be 1");
+    }
+  }
+
+  /**
+   * ObjectifeFunction by Carlos. Function computes f_g: f_g = w1 * squash(f_eb, k1) + w2 *
+   * squash(f_state, k2) + w3 * squash(f_pro, k3) + w4 * squash(f_perf, k4) + w5 * squash(f_holon,
+   * k5)
+   * <p>
+   * <p>
+   * squash is the squashing function {@link TopologieObjectiveFunction#squash}
+   *
+   * @param moreInformation if more prints should be made
+   * @return f_g value between 0 and 100
+   */
+  static public float getFitnessValueForState(Model model, int amountOfAddedSwitch,
+      double addedCableMeters, boolean moreInformation) {
+
+    int holonCount = model.holons.size();
+    //Calculate f_eb the penalty for unbalenced energy in the network
+    double f_eb = 0;
+    for (Holon holon : model.holons) {
+      //abs
+      f_eb += Math.abs(holon.getTotalConsumption() - holon.getTotalProduction());
     }
     }
-	
-	/**
-	 * Check parameter Setting and print error when wrong values are put in.
-	 * Here should all invariants be placed to be checked on initialization.
-	 */
-	private static void checkParameter() {
-		if(!(Math.abs(w_eb + w_holon + w_selection + w_grid + w_max - 1) < 0.001)) {
-			System.err.println("ParameterError in ObjectiveFunction: Sum of all weights should be 1");
-		}
-	}
-	
-	/**
-	 * ObjectifeFunction by Carlos.
-	 * Function computes f_g:
-	 * f_g = w1 * squash(f_eb, k1) + w2 * squash(f_state, k2) + w3 * squash(f_pro, k3) + w4 * squash(f_perf, k4) + w5 * squash(f_holon, k5) 
-	 * 
-	 * 
-	 * squash is the squashing function {@link TopologieObjectiveFunction#squash}
-	 * 
-	 *
-	 * @param moreInformation if more prints should be made
-	 * @return f_g value between 0 and 100
-	 */
-	static public float getFitnessValueForState(Model model, int amountOfAddedSwitch, double addedCableMeters, boolean moreInformation) {
-
-
-		int holonCount = model.holons.size();
-		//Calculate f_eb the penalty for unbalenced energy in the network
-		double f_eb = 0;
-		for(Holon holon : model.holons) {
-			//abs
-			f_eb += Math.abs(holon.getTotalConsumption() - holon.getTotalProduction());
-		}
-		//Average
-		f_eb /= holonCount;
-
-
-
-
-		double f_maximum = 0;
-		for(Holon net : model.holons) {
-			double prod = net.getTotalProduction();
-			double con = net.getTotalConsumption();
-			if(prod == 0 || con == 0) {
-				f_maximum += lambda_max;
-			}else {
-				f_maximum += lambda_max * (Math.abs(prod - con)/Math.max(prod, con));
-			}
-		}
-		//Average?
-		f_maximum /= holonCount;
-
-		//calculate f_holon
-		double f_holon = 0;
-		for(Holon net : model.holons) {
-			double f_elements_deviation_production = net.getDeviationInProductionInNetworkForHolonObjects();
-			double f_elements_deviation_consumption = net.getDeviationInConsumptionInNetworkForHolonObjects();
-			double f_element = f_elements_deviation_production+f_elements_deviation_consumption;
-			f_holon += f_element;
-		}
-		f_holon /= holonCount;
-
-		//calculating f_selection
-		double f_selection = calculateTopologieCost(model, amountOfAddedSwitch, addedCableMeters);
-		//if(moreInformation)LOGGER.info("CostForWildcards:" + cost + ", CostSwitches(#" + amountOfAddedSwitch +"):" + cost_switch * amountOfAddedSwitch + ", CostCables(" +addedCableMeters+ "m):" + cost_of_cable_per_meter * addedCableMeters);
-
-
-		//calculating f_grid
-		double f_grid = 0;
-		//each network is a holon
-		for(Holon net : model.holons) {
-			GraphMetrics.Graph G = GraphMetrics.convertDecoratedNetworkToGraph(model, net);
-			//We have to penalize single Networks;
-			if(G.V.length <= 1 || G.S.length <= 1) {
-				f_grid += lambda_avg_shortest_path;// + lambda_disjoint_path;
-				continue;
-			}
-
-			double avgShortestPath = GraphMetrics.averageShortestDistance(G);
-			//double disjpointPaths = GraphMetrics.averageEdgeDisjointPathProblem(G);
-			if(useLog) {
-				averageLog.addSample("avgShortestPath", (float)avgShortestPath);
-			}
-			f_grid += avgShortestPathPenalty(avgShortestPath);// + disjoinPathPenalty(disjpointPaths);
-		}
-		//take average to encourage splitting
-		f_grid /= holonCount;
-
-
-
-
-		if(moreInformation) {
-			printWeightedValues(f_eb, f_maximum, f_holon, f_selection, f_grid);
-			if(useLog) {
-				log.info(averageLog.toString());
-			}
-		}
-		//printUnsquashedValues(f_eb, f_maximum, f_holon, f_selection, f_grid);
-		if(useLog) {
-			averageLog.addSample("Unsquashed f_eb", (float)f_eb);
-			averageLog.addSample("Unsquashed f_maximum", (float)f_maximum);
-			averageLog.addSample("Unsquashed f_holon", (float)f_holon);
-			averageLog.addSample("Unsquashed f_selection", (float)f_selection);
-			averageLog.addSample("Unsquashed f_grid", (float)f_grid);
-		}
-		return (float) (w_eb * squash(f_eb, k_eb)
-				+ w_max * squash(f_maximum, k_max)
-				+ w_holon * squash(f_holon, k_holon)
-				+ w_selection * squash(f_selection, k_selection)
-				+ w_grid * squash(f_grid, k_grid));
-	}
-	public static double calculateTopologieCost(Model model, int amountOfAddedSwitch,
-			double addedCableMeters) {
-		double cost = calculateWildcardCost(model);
-		cost += calculateAddedSwitchCost(amountOfAddedSwitch);
-		cost += calculateAddedCableCost(addedCableMeters);
-		return cost;
-	}
-
-	public static double calculateAddedCableCost(double addedCableMeters) {
-		return cost_of_cable_per_meter * addedCableMeters;
-	}
-
-	public static double calculateAddedSwitchCost(int amountOfAddedSwitch) {
-		return cost_switch * amountOfAddedSwitch;
-	}
-
-	public static double calculateWildcardCost(Model model) {
-		double cost = 0;
-		for(Holon net : model.holons) {
-			for(HolonObject hO : net.holonObjects) {
-				if(hO.getName().contains("Wildcard")){
-					if(hO.getName().length() > 9) {
-						String costString = hO.getName().substring(9);
-						cost += Double.parseDouble(costString);
-					}
-				}
-			}
-		}
-		return cost;
-	}
-
-	private static String doubleToString(double value) {
-		return String.format (Locale.US, "%.2f", value);
-	}
-	
-
-	@SuppressWarnings("unused")
-	private static double disjoinPathPenalty(double value) {
-		return -(2.0 * lambda_disjoint_path) / (1 + Math.exp(- (value - centerValue_disjoint_path)/ range_for_k_disjoint_path)) + (2.0 * lambda_disjoint_path);
-	}
-	private static double avgShortestPathPenalty(double value) {
-		return (2.0 * lambda_avg_shortest_path) / (1 + Math.exp(- value/ range_for_k_avg_shortest_path)) - lambda_avg_shortest_path;
-	}
-	/**
-	 * Attention Math.log calcultae ln not log
-	 * @param kappa
-	 * @return
-	 */
-	private static double range(double kappa) {
-		return - kappa / Math.log(Math.pow(2.0, 0.05) - 1.0 );
-	}
-	
-	/**
-	 * The squashing function in paper
-	 * @param x the input
-	 * @param kappa the corresponding kappa
-	 * @return
-	 */
-	static public double squash(double x, double kappa) {
-		return 100.f/(1.0f + Math.exp(-(10.f * (x - kappa/2.f))/ kappa)) - squash_subtract;
-	}
-	
-	/**
-	 * f_sup in paper
-	 * @param supply from 0 to 1
-	 * @return
-	 */
-	static public double supplyPenalty(double supply) {
-		double supplyPercentage = 100 * supply;
-		return (supplyPercentage < 100) ? -0.5 * supplyPercentage + 50: supplyPercentage - 100;
-	}
-	
-	static void printWeightedValues(double f_eb, double f_maximum, double f_holon, double f_selection, double f_grid){
-		 log.info("===================================================================");
-		 log.info(" f_eb: " + f_eb + ", k_eb: " + k_eb + ", w_eb: " + w_eb); 
-		 log.info(" squash(f_eb, k_eb): " + doubleToString(squash(f_eb, k_eb))); 
-		 log.info(" w_eb * squash(f_eb, k_eb): " + doubleToString(w_eb * squash(f_eb, k_eb))); 
-		 log.info("===================================================================");
-		 log.info(" f_maximum: " + f_maximum + ", k_max: " + k_max + ", w_max: " + w_max); 
-		 log.info(" squash(f_maximum, k_max): " + doubleToString(squash(f_maximum, k_max))); 
-		 log.info(" w_max * squash(f_maximum, k_max): " + doubleToString(w_max * squash(f_maximum, k_max))); 
-		 log.info("===================================================================");
-		 log.info(" f_selection: " + f_selection + ", k_selection: " + k_selection + ", w_selection: " + w_selection); 
-		 log.info(" squash(f_selection, k_selection): " + doubleToString(squash(f_selection, k_selection))); 
-		 log.info(" w_selection * squash(f_selection, k_selection): " + doubleToString(w_selection * squash(f_selection, k_selection))); 
-		 log.info("===================================================================");
-		 log.info(" f_holon: " + f_holon + ", k_holon: " + k_holon + ", w_holon: " + w_holon); 
-		 log.info(" squash(f_holon, k_holon): " + doubleToString(squash(f_holon, k_holon))); 
-		 log.info(" w_holon * squash(f_holon, k_holon): " + doubleToString(w_holon * squash(f_holon, k_holon))); 
-		 log.info("===================================================================");
-		 log.info(" f_grid: " + f_grid + ", k_grid: " + k_grid + ", w_grid: " + w_grid); 
-		 log.info(" squash(f_grid, k_grid): " + doubleToString(squash(f_grid, k_grid))); 
-		 log.info(" w_grid * squash(f_grid, k_grid): " + doubleToString(w_grid * squash(f_grid, k_grid))); 
-		 log.info("===================================================================");
-	}
-	static void printUnsquashedValues(double f_eb, double f_maximum, double f_holon, double f_selection, double f_grid){
-		 System.out.print(" f_eb(" + f_eb + ") ");
-		 System.out.print(" f_maximum(" + f_maximum + ") ");
-		 System.out.print(" f_holon(" + f_holon + ") ");
-		 System.out.print(" f_selection(" + f_selection + ") ");
-		 log.info(" f_grid(" + f_grid + ") ");
-	}
+    //Average
+    f_eb /= holonCount;
+
+    double f_maximum = 0;
+    for (Holon net : model.holons) {
+      double prod = net.getTotalProduction();
+      double con = net.getTotalConsumption();
+      if (prod == 0 || con == 0) {
+        f_maximum += lambda_max;
+      } else {
+        f_maximum += lambda_max * (Math.abs(prod - con) / Math.max(prod, con));
+      }
+    }
+    //Average?
+    f_maximum /= holonCount;
+
+    //calculate f_holon
+    double f_holon = 0;
+    for (Holon net : model.holons) {
+      double f_elements_deviation_production = net.getDeviationInProductionInNetworkForHolonObjects();
+      double f_elements_deviation_consumption = net.getDeviationInConsumptionInNetworkForHolonObjects();
+      double f_element = f_elements_deviation_production + f_elements_deviation_consumption;
+      f_holon += f_element;
+    }
+    f_holon /= holonCount;
+
+    //calculating f_selection
+    double f_selection = calculateTopologieCost(model, amountOfAddedSwitch, addedCableMeters);
+    //if(moreInformation)LOGGER.info("CostForWildcards:" + cost + ", CostSwitches(#" + amountOfAddedSwitch +"):" + cost_switch * amountOfAddedSwitch + ", CostCables(" +addedCableMeters+ "m):" + cost_of_cable_per_meter * addedCableMeters);
+
+    //calculating f_grid
+    double f_grid = 0;
+    //each network is a holon
+    for (Holon net : model.holons) {
+      GraphMetrics.Graph G = GraphMetrics.convertDecoratedNetworkToGraph(model, net);
+      //We have to penalize single Networks;
+      if (G.V.length <= 1 || G.S.length <= 1) {
+        f_grid += lambda_avg_shortest_path;// + lambda_disjoint_path;
+        continue;
+      }
+
+      double avgShortestPath = GraphMetrics.averageShortestDistance(G);
+      //double disjpointPaths = GraphMetrics.averageEdgeDisjointPathProblem(G);
+      if (useLog) {
+        averageLog.addSample("avgShortestPath", (float) avgShortestPath);
+      }
+      f_grid += avgShortestPathPenalty(avgShortestPath);// + disjoinPathPenalty(disjpointPaths);
+    }
+    //take average to encourage splitting
+    f_grid /= holonCount;
+
+    if (moreInformation) {
+      printWeightedValues(f_eb, f_maximum, f_holon, f_selection, f_grid);
+      if (useLog) {
+        log.info(averageLog.toString());
+      }
+    }
+    //printUnsquashedValues(f_eb, f_maximum, f_holon, f_selection, f_grid);
+    if (useLog) {
+      averageLog.addSample("Unsquashed f_eb", (float) f_eb);
+      averageLog.addSample("Unsquashed f_maximum", (float) f_maximum);
+      averageLog.addSample("Unsquashed f_holon", (float) f_holon);
+      averageLog.addSample("Unsquashed f_selection", (float) f_selection);
+      averageLog.addSample("Unsquashed f_grid", (float) f_grid);
+    }
+    return (float) (w_eb * squash(f_eb, k_eb)
+        + w_max * squash(f_maximum, k_max)
+        + w_holon * squash(f_holon, k_holon)
+        + w_selection * squash(f_selection, k_selection)
+        + w_grid * squash(f_grid, k_grid));
+  }
+
+  public static double calculateTopologieCost(Model model, int amountOfAddedSwitch,
+      double addedCableMeters) {
+    double cost = calculateWildcardCost(model);
+    cost += calculateAddedSwitchCost(amountOfAddedSwitch);
+    cost += calculateAddedCableCost(addedCableMeters);
+    return cost;
+  }
+
+  public static double calculateAddedCableCost(double addedCableMeters) {
+    return cost_of_cable_per_meter * addedCableMeters;
+  }
+
+  public static double calculateAddedSwitchCost(int amountOfAddedSwitch) {
+    return cost_switch * amountOfAddedSwitch;
+  }
+
+  public static double calculateWildcardCost(Model model) {
+    double cost = 0;
+    for (Holon net : model.holons) {
+      for (HolonObject hO : net.holonObjects) {
+        if (hO.getName().contains("Wildcard")) {
+          if (hO.getName().length() > 9) {
+            String costString = hO.getName().substring(9);
+            cost += Double.parseDouble(costString);
+          }
+        }
+      }
+    }
+    return cost;
+  }
+
+  private static String doubleToString(double value) {
+    return String.format(Locale.US, "%.2f", value);
+  }
+
+
+  @SuppressWarnings("unused")
+  private static double disjoinPathPenalty(double value) {
+    return -(2.0 * lambda_disjoint_path) / (1 + Math.exp(
+        -(value - centerValue_disjoint_path) / range_for_k_disjoint_path)) + (2.0
+        * lambda_disjoint_path);
+  }
+
+  private static double avgShortestPathPenalty(double value) {
+    return (2.0 * lambda_avg_shortest_path) / (1 + Math.exp(-value / range_for_k_avg_shortest_path))
+        - lambda_avg_shortest_path;
+  }
+
+  /**
+   * Attention Math.log calcultae ln not log
+   *
+   * @param kappa
+   * @return
+   */
+  private static double range(double kappa) {
+    return -kappa / Math.log(Math.pow(2.0, 0.05) - 1.0);
+  }
+
+  /**
+   * The squashing function in paper
+   *
+   * @param x     the input
+   * @param kappa the corresponding kappa
+   * @return
+   */
+  static public double squash(double x, double kappa) {
+    return 100.f / (1.0f + Math.exp(-(10.f * (x - kappa / 2.f)) / kappa)) - squash_subtract;
+  }
+
+  /**
+   * f_sup in paper
+   *
+   * @param supply from 0 to 1
+   * @return
+   */
+  static public double supplyPenalty(double supply) {
+    double supplyPercentage = 100 * supply;
+    return (supplyPercentage < 100) ? -0.5 * supplyPercentage + 50 : supplyPercentage - 100;
+  }
+
+  static void printWeightedValues(double f_eb, double f_maximum, double f_holon, double f_selection,
+      double f_grid) {
+    log.info("===================================================================");
+    log.info(" f_eb: " + f_eb + ", k_eb: " + k_eb + ", w_eb: " + w_eb);
+    log.info(" squash(f_eb, k_eb): " + doubleToString(squash(f_eb, k_eb)));
+    log.info(" w_eb * squash(f_eb, k_eb): " + doubleToString(w_eb * squash(f_eb, k_eb)));
+    log.info("===================================================================");
+    log.info(" f_maximum: " + f_maximum + ", k_max: " + k_max + ", w_max: " + w_max);
+    log.info(" squash(f_maximum, k_max): " + doubleToString(squash(f_maximum, k_max)));
+    log.info(
+        " w_max * squash(f_maximum, k_max): " + doubleToString(w_max * squash(f_maximum, k_max)));
+    log.info("===================================================================");
+    log.info(" f_selection: " + f_selection + ", k_selection: " + k_selection + ", w_selection: "
+        + w_selection);
+    log.info(
+        " squash(f_selection, k_selection): " + doubleToString(squash(f_selection, k_selection)));
+    log.info(" w_selection * squash(f_selection, k_selection): " + doubleToString(
+        w_selection * squash(f_selection, k_selection)));
+    log.info("===================================================================");
+    log.info(" f_holon: " + f_holon + ", k_holon: " + k_holon + ", w_holon: " + w_holon);
+    log.info(" squash(f_holon, k_holon): " + doubleToString(squash(f_holon, k_holon)));
+    log.info(" w_holon * squash(f_holon, k_holon): " + doubleToString(
+        w_holon * squash(f_holon, k_holon)));
+    log.info("===================================================================");
+    log.info(" f_grid: " + f_grid + ", k_grid: " + k_grid + ", w_grid: " + w_grid);
+    log.info(" squash(f_grid, k_grid): " + doubleToString(squash(f_grid, k_grid)));
+    log.info(
+        " w_grid * squash(f_grid, k_grid): " + doubleToString(w_grid * squash(f_grid, k_grid)));
+    log.info("===================================================================");
+  }
+
+  static void printUnsquashedValues(double f_eb, double f_maximum, double f_holon,
+      double f_selection, double f_grid) {
+    System.out.print(" f_eb(" + f_eb + ") ");
+    System.out.print(" f_maximum(" + f_maximum + ") ");
+    System.out.print(" f_holon(" + f_holon + ") ");
+    System.out.print(" f_selection(" + f_selection + ") ");
+    log.info(" f_grid(" + f_grid + ") ");
+  }
 
 
 }
 }

+ 200 - 174
src/holeg/algorithm/topologie/AcoAlgorithm.java

@@ -1,185 +1,211 @@
 package holeg.algorithm.topologie;
 package holeg.algorithm.topologie;
 
 
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.ListIterator;
-
 import holeg.algorithm.objective_function.TopologieObjectiveFunction;
 import holeg.algorithm.objective_function.TopologieObjectiveFunction;
 import holeg.api.TopologieAlgorithmFramework;
 import holeg.api.TopologieAlgorithmFramework;
 import holeg.model.Model;
 import holeg.model.Model;
 import holeg.utility.math.Random;
 import holeg.utility.math.Random;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
 
 
 public class AcoAlgorithm extends TopologieAlgorithmFramework {
 public class AcoAlgorithm extends TopologieAlgorithmFramework {
 
 
-	private int popsize = 20;
-	private int maxGenerations = 100;
-	private boolean moreInformation = false;
-	/**
-	 * The vaporization factor;
-	 */
-	private double p = 0.05;
-	private double convergenceFactorReset = 0.90;
-	
-	public AcoAlgorithm(){
-		addIntParameter("popsize", popsize, intValue -> popsize = intValue, () -> popsize, 1);
-		addIntParameter("maxGenerations", maxGenerations, intValue -> maxGenerations = intValue, () -> maxGenerations, 1);
-		addSeperator();
-		addDoubleParameter("Vaporization", p, doubleValue -> p = doubleValue, () -> p, true, 0.0, 1.0);
-		addDoubleParameter("FactorReset", convergenceFactorReset, doubleValue -> convergenceFactorReset = doubleValue, () -> convergenceFactorReset, true, 0.0, 1.0);
-		addSeperator();
-		addBooleanParameter("moreInformation", moreInformation, booleanValue -> moreInformation = booleanValue, new LinkedList<String>(), new LinkedList<String>());
-
-	}
-	@Override
-	protected double evaluateState(Model model, int amountOfAddedSwitch, double addedCableMeters, boolean moreInformation) {
-		return TopologieObjectiveFunction.getFitnessValueForState(model, amountOfAddedSwitch, addedCableMeters, moreInformation);
-	}
-
-	@Override
-	protected Individual executeAlgo() {
-		resetWildcards();
-		Individual best = new Individual();
-		best.position = extractPositionAndAccess();
-		int problemSize =  best.position.size();
-		best.fitness = evaluatePosition(best.position);
-		List<Double> runList = new ArrayList<Double>();
-		runList.add(best.fitness);
-		console.println("Integer_Array_length: " + best.position.size());
-		List<List<Double>> pheromones = initPheromones(problemSize);
-		List<Individual> population = new ArrayList<Individual>();
-		if(moreInformation)console.println("Size To Test:" + population.size());
-		for(int generation = 0; generation< maxGenerations; generation++) {
-			population.clear();
-			population = constructSolutionsBiasedBy(pheromones);
-			if(moreInformation)console.println("Generation" + generation + " start with Fitness: " + best.fitness);
-			for(Individual i : population) {
-				i.fitness = evaluatePosition(i.position);
-				if(moreInformation)console.println("Fitness" + i.fitness);
-				if(i.fitness < best.fitness) best = i;	
-			}
-			runList.add(best.fitness);
-			if(moreInformation)console.println("________________");
-			vaporizeIntensifiePheromons(pheromones, best.position, problemSize);
-			double cf = calculateConvergenceFactor(pheromones, problemSize);
-			if(moreInformation)console.println("ConvergenceFactor = " + cf);
-			if(moreInformation)console.println("pheromones:" + pheromones);
-			if(cf > this.convergenceFactorReset) {
-				pheromones = initPheromones(problemSize);
-			}
-			if(cancel)return null;
-		}
-		console.println("   End with:" + best.fitness);
-		this.runList = runList;
-		return best;
-	}
-
-	@Override
-	protected int getProgressBarMaxCount() {
-		return rounds * maxGenerations * popsize + 1;
-	}
-
-	@Override
-	protected String algoInformationToPrint() {
-		return "Aco for Topologie "+ " Rounds:" + rounds 
-				+ " maxGenerations:" + maxGenerations 
-				+ " popsize:" +  popsize
-				+ " vaporization:" +  p
-				+ " convergenceFactorReset:" +  convergenceFactorReset;
-	}
-
-	@Override
-	protected String plottFileName() {
-		return "aco-topologie.txt";
-	}
-	/**
-	 * tj1 is the pheromon level in the j position
-	 * cf is the convergence factor cf e [0;1]
-	 * 
-	 * 
-	 * 
-	 * @param pheromones
-	 * @return cf
-	 */
-	private double calculateConvergenceFactor(List<List<Double>> pheromones,int problemSize) {
-		double sumofmax = pheromones.stream().map(listPheromons -> listPheromons.stream().max((a,b) -> Double.compare(a,b)).get()).reduce(0.0, Double::sum);
-		double cf = sumofmax / (double)problemSize;
-		return cf;
-	}
-	/**
-	 * pheromone <- (1-p) * pheromone;
-	 * if(best is true at this position) pheromone <- pheromone + p;
-	 * @param pheromones
-	 * @param position
-	 */
-	private void vaporizeIntensifiePheromons(List<List<Double>> pheromones, List<Integer> position, int problemSize) {
-		ListIterator<List<Double>> iterPheromone = pheromones.listIterator();
-		ListIterator<Integer> iterBest = position.listIterator();
-		for(int i = 0; i < problemSize; i++) {
-			List<Double> tauList = iterPheromone.next();
-			int bestDecision = iterBest.next();
-			ListIterator<Double> tauListiter = tauList.listIterator();
-			for(int k = 0; tauListiter.hasNext(); k++) {
-				double value = tauListiter.next();
-				tauListiter.set((1.0 - p) * value + (k == bestDecision?p:0.0));
-			}
-		}
-	}
-	/**
-	 * 
-	 * @param pheromones
-	 * @return
-	 */
-	private List<Individual> constructSolutionsBiasedBy(List<List<Double>> pheromones) {
-		List<Individual> population =  new ArrayList<Individual>();
-		for(int i = 0; i < popsize; i++) {
-			population.add(constructASolutionBiasedBy(pheromones));
-		}
-		return population;
-	}
-	
-	
-	/**
-	 * Walks the path with a ant and decide by pheromones if should take true or false;
-	 * A pheromone have a level of 0 < pheromone < 1.
-	 * A Pheromone is  equal to the probability.
-	 * @param pheromones
-	 * @return
-	 */
-	private Individual constructASolutionBiasedBy(List<List<Double>> pheromones) {
-		Individual result = new Individual();
-		result.position = new ArrayList<Integer>();
-		for(List<Double> pheromoneList : pheromones) {
-			ListIterator<Double> tauListiter = pheromoneList.listIterator();
-			double radnomValue = Random.nextDouble();
-			for(int i = 0;tauListiter.hasNext(); i++) {
-				double actualtau = tauListiter.next();
-				if(radnomValue > actualtau) {
-					radnomValue -= actualtau;
-				}else {
-					result.position.add(i);
-					break;
-				}
-			}
-		}
-		return result;
-	}
-	/**
-	 * Initialize Pheromons with 1.0 / maxIndex;
-	 */
-	private List<List<Double>> initPheromones(int problemSize) {
-		List<List<Double>> result = new ArrayList<List<Double>>();
-		for(int i = 0; i < problemSize;i++) {
-			//generate list equal tau values with max Int
-			int maxIndex = this.getMaximumIndexObjects(i);
-			double tauValue = 1.0 / (double) (maxIndex + 1);
-			List<Double> tauList = new ArrayList<Double>();
-			for(int tau= 0; tau < maxIndex + 1; tau++) {
-				tauList.add(tauValue);				
-			}
-			result.add(tauList);
-		}
-		return result;
-	}
+  private int popsize = 20;
+  private int maxGenerations = 100;
+  private boolean moreInformation = false;
+  /**
+   * The vaporization factor;
+   */
+  private double p = 0.05;
+  private double convergenceFactorReset = 0.90;
+
+  public AcoAlgorithm() {
+    addIntParameter("popsize", popsize, intValue -> popsize = intValue, () -> popsize, 1);
+    addIntParameter("maxGenerations", maxGenerations, intValue -> maxGenerations = intValue,
+        () -> maxGenerations, 1);
+    addSeperator();
+    addDoubleParameter("Vaporization", p, doubleValue -> p = doubleValue, () -> p, true, 0.0, 1.0);
+    addDoubleParameter("FactorReset", convergenceFactorReset,
+        doubleValue -> convergenceFactorReset = doubleValue, () -> convergenceFactorReset, true,
+        0.0, 1.0);
+    addSeperator();
+    addBooleanParameter("moreInformation", moreInformation,
+        booleanValue -> moreInformation = booleanValue, new LinkedList<String>(),
+        new LinkedList<String>());
+
+  }
+
+  @Override
+  protected double evaluateState(Model model, int amountOfAddedSwitch, double addedCableMeters,
+      boolean moreInformation) {
+    return TopologieObjectiveFunction.getFitnessValueForState(model, amountOfAddedSwitch,
+        addedCableMeters, moreInformation);
+  }
+
+  @Override
+  protected Individual executeAlgo() {
+    resetWildcards();
+    Individual best = new Individual();
+    best.position = extractPositionAndAccess();
+    int problemSize = best.position.size();
+    best.fitness = evaluatePosition(best.position);
+    List<Double> runList = new ArrayList<Double>();
+    runList.add(best.fitness);
+    console.println("Integer_Array_length: " + best.position.size());
+    List<List<Double>> pheromones = initPheromones(problemSize);
+    List<Individual> population = new ArrayList<Individual>();
+    if (moreInformation) {
+      console.println("Size To Test:" + population.size());
+    }
+    for (int generation = 0; generation < maxGenerations; generation++) {
+      population.clear();
+      population = constructSolutionsBiasedBy(pheromones);
+      if (moreInformation) {
+        console.println("Generation" + generation + " start with Fitness: " + best.fitness);
+      }
+      for (Individual i : population) {
+        i.fitness = evaluatePosition(i.position);
+        if (moreInformation) {
+          console.println("Fitness" + i.fitness);
+        }
+        if (i.fitness < best.fitness) {
+          best = i;
+        }
+      }
+      runList.add(best.fitness);
+      if (moreInformation) {
+        console.println("________________");
+      }
+      vaporizeIntensifiePheromons(pheromones, best.position, problemSize);
+      double cf = calculateConvergenceFactor(pheromones, problemSize);
+      if (moreInformation) {
+        console.println("ConvergenceFactor = " + cf);
+      }
+      if (moreInformation) {
+        console.println("pheromones:" + pheromones);
+      }
+      if (cf > this.convergenceFactorReset) {
+        pheromones = initPheromones(problemSize);
+      }
+      if (cancel) {
+        return null;
+      }
+    }
+    console.println("   End with:" + best.fitness);
+    this.runList = runList;
+    return best;
+  }
+
+  @Override
+  protected int getProgressBarMaxCount() {
+    return rounds * maxGenerations * popsize + 1;
+  }
+
+  @Override
+  protected String algoInformationToPrint() {
+    return "Aco for Topologie " + " Rounds:" + rounds
+        + " maxGenerations:" + maxGenerations
+        + " popsize:" + popsize
+        + " vaporization:" + p
+        + " convergenceFactorReset:" + convergenceFactorReset;
+  }
+
+  @Override
+  protected String plottFileName() {
+    return "aco-topologie.txt";
+  }
+
+  /**
+   * tj1 is the pheromon level in the j position cf is the convergence factor cf e [0;1]
+   *
+   * @param pheromones
+   * @return cf
+   */
+  private double calculateConvergenceFactor(List<List<Double>> pheromones, int problemSize) {
+    double sumofmax = pheromones.stream()
+        .map(listPheromons -> listPheromons.stream().max((a, b) -> Double.compare(a, b)).get())
+        .reduce(0.0, Double::sum);
+    double cf = sumofmax / (double) problemSize;
+    return cf;
+  }
+
+  /**
+   * pheromone <- (1-p) * pheromone; if(best is true at this position) pheromone <- pheromone + p;
+   *
+   * @param pheromones
+   * @param position
+   */
+  private void vaporizeIntensifiePheromons(List<List<Double>> pheromones, List<Integer> position,
+      int problemSize) {
+    ListIterator<List<Double>> iterPheromone = pheromones.listIterator();
+    ListIterator<Integer> iterBest = position.listIterator();
+    for (int i = 0; i < problemSize; i++) {
+      List<Double> tauList = iterPheromone.next();
+      int bestDecision = iterBest.next();
+      ListIterator<Double> tauListiter = tauList.listIterator();
+      for (int k = 0; tauListiter.hasNext(); k++) {
+        double value = tauListiter.next();
+        tauListiter.set((1.0 - p) * value + (k == bestDecision ? p : 0.0));
+      }
+    }
+  }
+
+  /**
+   * @param pheromones
+   * @return
+   */
+  private List<Individual> constructSolutionsBiasedBy(List<List<Double>> pheromones) {
+    List<Individual> population = new ArrayList<Individual>();
+    for (int i = 0; i < popsize; i++) {
+      population.add(constructASolutionBiasedBy(pheromones));
+    }
+    return population;
+  }
+
+
+  /**
+   * Walks the path with a ant and decide by pheromones if should take true or false; A pheromone
+   * have a level of 0 < pheromone < 1. A Pheromone is  equal to the probability.
+   *
+   * @param pheromones
+   * @return
+   */
+  private Individual constructASolutionBiasedBy(List<List<Double>> pheromones) {
+    Individual result = new Individual();
+    result.position = new ArrayList<Integer>();
+    for (List<Double> pheromoneList : pheromones) {
+      ListIterator<Double> tauListiter = pheromoneList.listIterator();
+      double radnomValue = Random.nextDouble();
+      for (int i = 0; tauListiter.hasNext(); i++) {
+        double actualtau = tauListiter.next();
+        if (radnomValue > actualtau) {
+          radnomValue -= actualtau;
+        } else {
+          result.position.add(i);
+          break;
+        }
+      }
+    }
+    return result;
+  }
+
+  /**
+   * Initialize Pheromons with 1.0 / maxIndex;
+   */
+  private List<List<Double>> initPheromones(int problemSize) {
+    List<List<Double>> result = new ArrayList<List<Double>>();
+    for (int i = 0; i < problemSize; i++) {
+      //generate list equal tau values with max Int
+      int maxIndex = this.getMaximumIndexObjects(i);
+      double tauValue = 1.0 / (double) (maxIndex + 1);
+      List<Double> tauList = new ArrayList<Double>();
+      for (int tau = 0; tau < maxIndex + 1; tau++) {
+        tauList.add(tauValue);
+      }
+      result.add(tauList);
+    }
+    return result;
+  }
 }
 }
  
  

+ 269 - 216
src/holeg/algorithm/topologie/GaAlgorithm.java

@@ -1,5 +1,9 @@
 package holeg.algorithm.topologie;
 package holeg.algorithm.topologie;
 
 
+import holeg.algorithm.objective_function.TopologieObjectiveFunction;
+import holeg.api.TopologieAlgorithmFramework;
+import holeg.model.Model;
+import holeg.utility.math.Random;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.LinkedList;
@@ -7,222 +11,271 @@ import java.util.List;
 import java.util.ListIterator;
 import java.util.ListIterator;
 import java.util.TreeSet;
 import java.util.TreeSet;
 
 
-import holeg.algorithm.objective_function.TopologieObjectiveFunction;
-import holeg.api.TopologieAlgorithmFramework;
-import holeg.model.Model;
-import holeg.utility.math.Random;
-
 public class GaAlgorithm extends TopologieAlgorithmFramework {
 public class GaAlgorithm extends TopologieAlgorithmFramework {
 
 
-	private int popsize = 20;
-	private int maxGenerations = 100;
-	private double tournamentSize = 2.0;
-	private double fixedSwapProbability = 0.02;
-	private boolean useFixedSpawProbability = false;
-	private double fixedMutateProbability = 0.02;
-	private boolean useFixedMutateProbability = false;
-	private boolean useIntervalMutation = false;
-	private double mutateProbabilityInterval = 0.01;
-	private double maxMutationPercent = 0.01;
-	private boolean moreInformation = false;
-	
-	public GaAlgorithm(){
-		addIntParameter("popsize", popsize, intValue -> popsize = intValue, () -> popsize, 1);
-		addIntParameter("maxGenerations", maxGenerations, intValue -> maxGenerations = intValue, () -> maxGenerations, 1);
-		addDoubleParameter("tournamentSize", tournamentSize, doubleValue -> tournamentSize = doubleValue, () -> tournamentSize, 1.0);
-		addBooleanParameter("useFixedSpawProbability", useFixedSpawProbability, booleanValue -> useFixedSpawProbability = booleanValue, Arrays.asList("fixedSwapProbability"), new LinkedList<String>());
-		addDoubleParameter("fixedSwapProbability", fixedSwapProbability, doubleValue -> fixedSwapProbability = doubleValue, () -> fixedSwapProbability, useFixedSpawProbability, 0.0, 1.0);
-		addSeperator();
-		addBooleanParameter("Use Interval Mutation", useIntervalMutation, booleanValue -> useIntervalMutation = booleanValue, Arrays.asList("Probability for Frequency Mutation", "Scope of Mutation"), Arrays.asList("Probability for Bit-wise Mutation"));
-		addDoubleParameter("Probability for Frequency Mutation", mutateProbabilityInterval, doubleValue -> mutateProbabilityInterval = doubleValue, () -> mutateProbabilityInterval, useIntervalMutation, 0.0, 1.0);
-		addDoubleParameter("Probability for Bit-wise Mutation", fixedMutateProbability, doubleValue -> fixedMutateProbability = doubleValue, () -> fixedMutateProbability, !useIntervalMutation, 0.0, 1.0);
-		addDoubleParameter("Scope of Mutation", maxMutationPercent, doubleValue -> maxMutationPercent = doubleValue, () -> maxMutationPercent, useIntervalMutation, 0.0, 1.0);
-		addSeperator();
-		addBooleanParameter("Print Auxiliary Information", moreInformation, booleanValue -> moreInformation = booleanValue, new LinkedList<String>(), new LinkedList<String>());
-	
-	}
-	@Override
-	protected double evaluateState(Model model, int amountOfAddedSwitch, double addedCableMeters, boolean moreInformation) {
-		return TopologieObjectiveFunction.getFitnessValueForState(model, amountOfAddedSwitch, addedCableMeters, moreInformation);
-	}
-
-	@Override
-	protected Individual executeAlgo() {
-		resetWildcards();
-		Individual best = new Individual();
-		best.position = extractPositionAndAccess();
-		int problemSize =  best.position.size();
-		best.fitness = evaluatePosition(best.position);
-		List<Double> runList = new ArrayList<Double>();
-		runList.add(best.fitness);
-		console.println("Integer_Array_length: " + best.position.size());
-		List<Individual> population = initPopuluationRandom(problemSize, best);
-		for(int generation = 0; generation< maxGenerations; generation++) {
-			if(moreInformation)console.println("Generation" + generation + " start with Fitness: " + best.fitness);
-			for(Individual i : population) {
-				i.fitness = evaluatePosition(i.position);
-				if(moreInformation)console.println("Fitness" + i.fitness);
-				if(i.fitness < best.fitness) best = i;
-			}
-			runList.add(best.fitness);
-			List<Individual> childList = new ArrayList<Individual>();
-			for(int k = 0; k<popsize/2; k++) {
-				Individual parentA = selectAParent(population, popsize);
-				Individual parentB = selectAParent(population, popsize);
-				Individual childA = new Individual(parentA);
-				Individual childB = new Individual(parentB);
-				crossover(childA, childB, problemSize);
-				if(useIntervalMutation)mutateInterval(childA, problemSize);else mutate(childA, problemSize);
-				if(useIntervalMutation)mutateInterval(childB, problemSize);else mutate(childB, problemSize);
-				childList.add(childA);
-				childList.add(childB);
-			}
-			population = childList;
-			if(moreInformation)console.println("________________");
-			if(cancel)return null;
-		}
-		
-		console.println("   End with:" + best.fitness);
-		this.runList = runList;
-		return best;
-	}
-
-	@Override
-	protected int getProgressBarMaxCount() {
-		return rounds * maxGenerations * popsize + 1;
-	}
-
-	@Override
-	protected String algoInformationToPrint() {
-		return "GaAlgo"+ " Rounds:" + rounds 
-				+ " maxGenerations:" + maxGenerations
-				+ " popsize:" + popsize
-				+ " tournamentSize:" +  tournamentSize
-				+ (useFixedSpawProbability? " fixedSwapProbability:" +  fixedSwapProbability:" swapProbability:" + "1.0f/problemsize")
-				+ (useIntervalMutation? 
-						(" mutateProbabilityInterval:" +  mutateProbabilityInterval
-						+ " maxMutationPercent:" +  maxMutationPercent)
-						: 
-						(useFixedMutateProbability? " fixedMutateProbability:" +  fixedMutateProbability:" mutateProbability:" + "1.0f/problemsize"));
-	}
-
-	@Override
-	protected String plottFileName() {
-		return "ga-topologie.txt";
-	}
-	/**
-	 * Initialize the Population with Individuals that have a random Position.
-	 */
-	private List<Individual> initPopuluationRandom(int problemSize, Individual startIndidual){
-		List<Individual> population =  new ArrayList<Individual>();
-		for(int i = 0; i < popsize -1; i++) {
-			population.add(createRandomIndividualWithoutFitness(problemSize));
-		}
-		//Add Start Position
-		population.add(new Individual(startIndidual));
-		return population;
-	}
-	
-	private Individual createRandomIndividualWithoutFitness(int problemSize) {
-		//create Random Individual Without Fitness
-		Individual result = new Individual();
-		result.position = new ArrayList<Integer>();
-		for (int index = 0; index < problemSize; index++){
-			result.position.add(Random.nextIntegerInRange(0, this.getMaximumIndexObjects(index) + 1));
-		}
-		//console.println("[" +result.position.stream().map(Object::toString).collect(Collectors.joining(", ")) + "]");
-		return result;
-	}
-	
-	/**
-	 * Algorithm 32 Tournament Selection.
-	 * The fitnessValues are calculated for the Population List.
-	 * PseudoCode
-	 */
-	private Individual selectAParent(List<Individual> population,int popsize) {
-		Individual tournamentBest = population.get(Random.nextIntegerInRange(0, popsize));
-		double participants;
-		for(participants = tournamentSize ; participants >= 2; participants -= 1.0) {
-			Individual next = population.get(Random.nextIntegerInRange(0, popsize));
-			if(next.fitness < tournamentBest.fitness) tournamentBest = next;
-		}
-		//if tournament size is not a whole number like 2.5 or 3.6
-		//the remaining part is the chance to fight another time; 2.7 -> 70% chance to fight a second time
-		if( participants > 1) {		
-			if(Random.nextDouble() < participants - 1.0) {
-				//println("Chance to find a match");
-				Individual next = population.get(Random.nextIntegerInRange(0, popsize));
-				if(next.fitness < tournamentBest.fitness) tournamentBest = next;
-			}
-		}
-		return tournamentBest;
-	}
-	/** 
-	 * Algorithm 25 Uniform Crossover.
-	 * Probability is set to 1/Problemsize when not changed.
-	 */
-	private void crossover(Individual childA, Individual childB, int problemSize) {
-		double probability = (this.useFixedSpawProbability) ? this.fixedSwapProbability : 1.0/(double)problemSize;
-		ListIterator<Integer> iterA = childA.position.listIterator();
-		ListIterator<Integer> iterB = childB.position.listIterator();
-		for(int i= 0; i < problemSize; i++) {
-			int intA = iterA.next();
-			int intB = iterB.next();
-			if(Random.nextDouble() <=  probability ) {
-				//Swap 
-				iterA.set(intB);
-				iterB.set(intA);
-			}
-		}
-	}
-	/**
-	 * Algorithm 22 Bit-Flip Mutation.
-	 * 
-	 */
-	private void mutate(Individual child, int problemSize) {
-		double probability = (this.useFixedMutateProbability) ? this.fixedMutateProbability : 1.0/(double)problemSize;
-		ListIterator<Integer> iter = child.position.listIterator();
-		while(iter.hasNext()) {
-			int index = iter.nextIndex();
-			Integer intValue = iter.next();
-			if(Random.nextDouble() <=  probability) {
-				iter.set(Random.nextIntegerInRangeExcept(0, this.getMaximumIndexObjects(index), intValue));
-			}
-		}
-	}
-	/**
-	 * Algorithm rolf
-	 * 
-	 */
-	private void mutateInterval(Individual child, int problemSize) {
-		//If not mutate skip
-		if(Random.nextDouble() >  this.mutateProbabilityInterval) {
-			return;
-		}
-		//println("problemSize:" + problemSize + "    maxMutationPercent:" + maxMutationPercent);
-		int maximumAmountOfMutatedBits = Math.max(1, (int)Math.round(((double) problemSize) * this.maxMutationPercent));
-		int randomUniformAmountOfMutatedValues = Random.nextIntegerInRange(1,maximumAmountOfMutatedBits + 1);
-		
-		//println("max:" + maximumAmountOfMutatedBits + "   actual:" + randomUniformAmountOfMutatedValues);
-		TreeSet<Integer> mutationLocation = new TreeSet<Integer>(); //sortedSet
-		//Choose the location to mutate
-		for(int i = 0; i< randomUniformAmountOfMutatedValues; i++) {
-			boolean success = mutationLocation.add(Random.nextIntegerInRange(0, problemSize));
-			if(!success) i--; //can be add up to some series long loops if maximumAmountOfMutatedBits get closed to problemsize.
-		}
-		//println("Set:" + mutationLocation);
-		ListIterator<Integer> iter = child.position.listIterator();
-		if(mutationLocation.isEmpty()) return;
-		int firstindex = mutationLocation.pollFirst();
-		while(iter.hasNext()) {
-			int index = iter.nextIndex();
-			int intValue = iter.next();
-			if(index == firstindex) {
-				iter.set(Random.nextIntegerInRangeExcept(0, this.getMaximumIndexObjects(index), intValue));
-				//println("changed Value["+ index +"]");
-				if(mutationLocation.isEmpty()) break;
-				firstindex = mutationLocation.pollFirst();
-			}
-		}
-	}
+  private int popsize = 20;
+  private int maxGenerations = 100;
+  private double tournamentSize = 2.0;
+  private double fixedSwapProbability = 0.02;
+  private boolean useFixedSpawProbability = false;
+  private double fixedMutateProbability = 0.02;
+  private boolean useFixedMutateProbability = false;
+  private boolean useIntervalMutation = false;
+  private double mutateProbabilityInterval = 0.01;
+  private double maxMutationPercent = 0.01;
+  private boolean moreInformation = false;
+
+  public GaAlgorithm() {
+    addIntParameter("popsize", popsize, intValue -> popsize = intValue, () -> popsize, 1);
+    addIntParameter("maxGenerations", maxGenerations, intValue -> maxGenerations = intValue,
+        () -> maxGenerations, 1);
+    addDoubleParameter("tournamentSize", tournamentSize,
+        doubleValue -> tournamentSize = doubleValue, () -> tournamentSize, 1.0);
+    addBooleanParameter("useFixedSpawProbability", useFixedSpawProbability,
+        booleanValue -> useFixedSpawProbability = booleanValue,
+        Arrays.asList("fixedSwapProbability"), new LinkedList<String>());
+    addDoubleParameter("fixedSwapProbability", fixedSwapProbability,
+        doubleValue -> fixedSwapProbability = doubleValue, () -> fixedSwapProbability,
+        useFixedSpawProbability, 0.0, 1.0);
+    addSeperator();
+    addBooleanParameter("Use Interval Mutation", useIntervalMutation,
+        booleanValue -> useIntervalMutation = booleanValue,
+        Arrays.asList("Probability for Frequency Mutation", "Scope of Mutation"),
+        Arrays.asList("Probability for Bit-wise Mutation"));
+    addDoubleParameter("Probability for Frequency Mutation", mutateProbabilityInterval,
+        doubleValue -> mutateProbabilityInterval = doubleValue, () -> mutateProbabilityInterval,
+        useIntervalMutation, 0.0, 1.0);
+    addDoubleParameter("Probability for Bit-wise Mutation", fixedMutateProbability,
+        doubleValue -> fixedMutateProbability = doubleValue, () -> fixedMutateProbability,
+        !useIntervalMutation, 0.0, 1.0);
+    addDoubleParameter("Scope of Mutation", maxMutationPercent,
+        doubleValue -> maxMutationPercent = doubleValue, () -> maxMutationPercent,
+        useIntervalMutation, 0.0, 1.0);
+    addSeperator();
+    addBooleanParameter("Print Auxiliary Information", moreInformation,
+        booleanValue -> moreInformation = booleanValue, new LinkedList<String>(),
+        new LinkedList<String>());
+
+  }
+
+  @Override
+  protected double evaluateState(Model model, int amountOfAddedSwitch, double addedCableMeters,
+      boolean moreInformation) {
+    return TopologieObjectiveFunction.getFitnessValueForState(model, amountOfAddedSwitch,
+        addedCableMeters, moreInformation);
+  }
+
+  @Override
+  protected Individual executeAlgo() {
+    resetWildcards();
+    Individual best = new Individual();
+    best.position = extractPositionAndAccess();
+    int problemSize = best.position.size();
+    best.fitness = evaluatePosition(best.position);
+    List<Double> runList = new ArrayList<Double>();
+    runList.add(best.fitness);
+    console.println("Integer_Array_length: " + best.position.size());
+    List<Individual> population = initPopuluationRandom(problemSize, best);
+    for (int generation = 0; generation < maxGenerations; generation++) {
+      if (moreInformation) {
+        console.println("Generation" + generation + " start with Fitness: " + best.fitness);
+      }
+      for (Individual i : population) {
+        i.fitness = evaluatePosition(i.position);
+        if (moreInformation) {
+          console.println("Fitness" + i.fitness);
+        }
+        if (i.fitness < best.fitness) {
+          best = i;
+        }
+      }
+      runList.add(best.fitness);
+      List<Individual> childList = new ArrayList<Individual>();
+      for (int k = 0; k < popsize / 2; k++) {
+        Individual parentA = selectAParent(population, popsize);
+        Individual parentB = selectAParent(population, popsize);
+        Individual childA = new Individual(parentA);
+        Individual childB = new Individual(parentB);
+        crossover(childA, childB, problemSize);
+        if (useIntervalMutation) {
+          mutateInterval(childA, problemSize);
+        } else {
+          mutate(childA, problemSize);
+        }
+        if (useIntervalMutation) {
+          mutateInterval(childB, problemSize);
+        } else {
+          mutate(childB, problemSize);
+        }
+        childList.add(childA);
+        childList.add(childB);
+      }
+      population = childList;
+      if (moreInformation) {
+        console.println("________________");
+      }
+      if (cancel) {
+        return null;
+      }
+    }
+
+    console.println("   End with:" + best.fitness);
+    this.runList = runList;
+    return best;
+  }
+
+  @Override
+  protected int getProgressBarMaxCount() {
+    return rounds * maxGenerations * popsize + 1;
+  }
+
+  @Override
+  protected String algoInformationToPrint() {
+    return "GaAlgo" + " Rounds:" + rounds
+        + " maxGenerations:" + maxGenerations
+        + " popsize:" + popsize
+        + " tournamentSize:" + tournamentSize
+        + (useFixedSpawProbability ? " fixedSwapProbability:" + fixedSwapProbability
+        : " swapProbability:" + "1.0f/problemsize")
+        + (useIntervalMutation ?
+        (" mutateProbabilityInterval:" + mutateProbabilityInterval
+            + " maxMutationPercent:" + maxMutationPercent)
+        :
+            (useFixedMutateProbability ? " fixedMutateProbability:" + fixedMutateProbability
+                : " mutateProbability:" + "1.0f/problemsize"));
+  }
+
+  @Override
+  protected String plottFileName() {
+    return "ga-topologie.txt";
+  }
+
+  /**
+   * Initialize the Population with Individuals that have a random Position.
+   */
+  private List<Individual> initPopuluationRandom(int problemSize, Individual startIndidual) {
+    List<Individual> population = new ArrayList<Individual>();
+    for (int i = 0; i < popsize - 1; i++) {
+      population.add(createRandomIndividualWithoutFitness(problemSize));
+    }
+    //Add Start Position
+    population.add(new Individual(startIndidual));
+    return population;
+  }
+
+  private Individual createRandomIndividualWithoutFitness(int problemSize) {
+    //create Random Individual Without Fitness
+    Individual result = new Individual();
+    result.position = new ArrayList<Integer>();
+    for (int index = 0; index < problemSize; index++) {
+      result.position.add(Random.nextIntegerInRange(0, this.getMaximumIndexObjects(index) + 1));
+    }
+    //console.println("[" +result.position.stream().map(Object::toString).collect(Collectors.joining(", ")) + "]");
+    return result;
+  }
+
+  /**
+   * Algorithm 32 Tournament Selection. The fitnessValues are calculated for the Population List.
+   * PseudoCode
+   */
+  private Individual selectAParent(List<Individual> population, int popsize) {
+    Individual tournamentBest = population.get(Random.nextIntegerInRange(0, popsize));
+    double participants;
+    for (participants = tournamentSize; participants >= 2; participants -= 1.0) {
+      Individual next = population.get(Random.nextIntegerInRange(0, popsize));
+      if (next.fitness < tournamentBest.fitness) {
+        tournamentBest = next;
+      }
+    }
+    //if tournament size is not a whole number like 2.5 or 3.6
+    //the remaining part is the chance to fight another time; 2.7 -> 70% chance to fight a second time
+    if (participants > 1) {
+      if (Random.nextDouble() < participants - 1.0) {
+        //println("Chance to find a match");
+        Individual next = population.get(Random.nextIntegerInRange(0, popsize));
+        if (next.fitness < tournamentBest.fitness) {
+          tournamentBest = next;
+        }
+      }
+    }
+    return tournamentBest;
+  }
+
+  /**
+   * Algorithm 25 Uniform Crossover. Probability is set to 1/Problemsize when not changed.
+   */
+  private void crossover(Individual childA, Individual childB, int problemSize) {
+    double probability =
+        (this.useFixedSpawProbability) ? this.fixedSwapProbability : 1.0 / (double) problemSize;
+    ListIterator<Integer> iterA = childA.position.listIterator();
+    ListIterator<Integer> iterB = childB.position.listIterator();
+    for (int i = 0; i < problemSize; i++) {
+      int intA = iterA.next();
+      int intB = iterB.next();
+      if (Random.nextDouble() <= probability) {
+        //Swap
+        iterA.set(intB);
+        iterB.set(intA);
+      }
+    }
+  }
+
+  /**
+   * Algorithm 22 Bit-Flip Mutation.
+   */
+  private void mutate(Individual child, int problemSize) {
+    double probability =
+        (this.useFixedMutateProbability) ? this.fixedMutateProbability : 1.0 / (double) problemSize;
+    ListIterator<Integer> iter = child.position.listIterator();
+    while (iter.hasNext()) {
+      int index = iter.nextIndex();
+      Integer intValue = iter.next();
+      if (Random.nextDouble() <= probability) {
+        iter.set(Random.nextIntegerInRangeExcept(0, this.getMaximumIndexObjects(index), intValue));
+      }
+    }
+  }
+
+  /**
+   * Algorithm rolf
+   */
+  private void mutateInterval(Individual child, int problemSize) {
+    //If not mutate skip
+    if (Random.nextDouble() > this.mutateProbabilityInterval) {
+      return;
+    }
+    //println("problemSize:" + problemSize + "    maxMutationPercent:" + maxMutationPercent);
+    int maximumAmountOfMutatedBits = Math.max(1,
+        (int) Math.round(((double) problemSize) * this.maxMutationPercent));
+    int randomUniformAmountOfMutatedValues = Random.nextIntegerInRange(1,
+        maximumAmountOfMutatedBits + 1);
+
+    //println("max:" + maximumAmountOfMutatedBits + "   actual:" + randomUniformAmountOfMutatedValues);
+    TreeSet<Integer> mutationLocation = new TreeSet<Integer>(); //sortedSet
+    //Choose the location to mutate
+    for (int i = 0; i < randomUniformAmountOfMutatedValues; i++) {
+      boolean success = mutationLocation.add(Random.nextIntegerInRange(0, problemSize));
+      if (!success) {
+        i--; //can be add up to some series long loops if maximumAmountOfMutatedBits get closed to problemsize.
+      }
+    }
+    //println("Set:" + mutationLocation);
+    ListIterator<Integer> iter = child.position.listIterator();
+    if (mutationLocation.isEmpty()) {
+      return;
+    }
+    int firstindex = mutationLocation.pollFirst();
+    while (iter.hasNext()) {
+      int index = iter.nextIndex();
+      int intValue = iter.next();
+      if (index == firstindex) {
+        iter.set(Random.nextIntegerInRangeExcept(0, this.getMaximumIndexObjects(index), intValue));
+        //println("changed Value["+ index +"]");
+        if (mutationLocation.isEmpty()) {
+          break;
+        }
+        firstindex = mutationLocation.pollFirst();
+      }
+    }
+  }
 }
 }

+ 360 - 310
src/holeg/algorithm/topologie/PsoAlgorithm.java

@@ -1,5 +1,10 @@
 package holeg.algorithm.topologie;
 package holeg.algorithm.topologie;
 
 
+import holeg.algorithm.objective_function.TopologieObjectiveFunction;
+import holeg.api.TopologieAlgorithmFramework;
+import holeg.model.Model;
+import holeg.utility.math.Maths;
+import holeg.utility.math.Random;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.LinkedList;
@@ -7,316 +12,361 @@ import java.util.List;
 import java.util.TreeSet;
 import java.util.TreeSet;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
-import holeg.algorithm.objective_function.TopologieObjectiveFunction;
-import holeg.api.TopologieAlgorithmFramework;
-import holeg.model.Model;
-import holeg.utility.math.Maths;
-import holeg.utility.math.Random;
-
 public class PsoAlgorithm extends TopologieAlgorithmFramework {
 public class PsoAlgorithm extends TopologieAlgorithmFramework {
 
 
-	private int popsize = 20;
-	private int maxGenerations = 500;
-	private double dependency = 2.07; 
-	private double c1, c2, w;
-	private double maxVelocity = 10.0;
-	private double deviation = 0.5;
-	//mutation
-	private int mutationInterval = 1;
-	private boolean useIntervalMutation = false;
-	private double mutationRate = 0.005;
-	private double mutateProbabilityInterval = 0.01;
-	private double maxMutationPercent = 0.01;
-	
-	private boolean moreInformation = false;
-	
-	public PsoAlgorithm(){
-		addIntParameter("Swarmsize", popsize, intValue -> popsize = intValue, () -> popsize, 1);
-		addIntParameter("Iterations", maxGenerations, intValue -> maxGenerations = intValue, () -> maxGenerations, 1);
-		addSeperator();
-		addDoubleParameter("Deviation", deviation, doubleValue -> deviation = doubleValue, () -> deviation, 0);
-		addDoubleParameter("Dependency", dependency, doubleValue -> dependency = doubleValue, () -> dependency, true, 2.001, 2.4);
-		addDoubleParameter("Particle Max-Velocity", maxVelocity, doubleValue -> maxVelocity = doubleValue, () -> maxVelocity, 0.0);
-		addSeperator();
-		addIntParameter("Mutation Frequency (Iteration)", mutationInterval, intValue -> mutationInterval = intValue, () -> mutationInterval, 0);
-		addBooleanParameter("Use Interval Mutation", useIntervalMutation, booleanValue -> useIntervalMutation = booleanValue, Arrays.asList("Probability for Frequency Mutation", "Scope of Mutation"), Arrays.asList("Probability for Bit-wise Mutation"));
-		addDoubleParameter("Probability for Frequency Mutation", mutateProbabilityInterval, doubleValue -> mutateProbabilityInterval = doubleValue, () -> mutateProbabilityInterval, useIntervalMutation, 0.0, 1.0);
-		addDoubleParameter("Probability for Bit-wise Mutation", mutationRate, doubleValue -> mutationRate = doubleValue, () -> mutationRate, !useIntervalMutation, 0.0, 1.0);
-		addDoubleParameter("Scope of Mutation", maxMutationPercent, doubleValue -> maxMutationPercent = doubleValue, () -> maxMutationPercent, useIntervalMutation, 0.0, 1.0);
-		addSeperator();
-		addBooleanParameter("Print Auxiliary Information", moreInformation, booleanValue -> moreInformation = booleanValue, new LinkedList<String>(), new LinkedList<String>());
-	}
-	
-	
-
-	
-	@Override
-	protected double evaluateState(Model model, int amountOfAddedSwitch, double addedCableMeters, boolean moreInformation) {
-		return TopologieObjectiveFunction.getFitnessValueForState(model, amountOfAddedSwitch, addedCableMeters, moreInformation);
-	}
-
-	@Override
-	/**
-	 *  <p>Algo from Paper:</p><font size="3"><pre>
-	 *  
-	 *  Begin
-	 *  	t = 0; {t: generation index}
-	 *  	initialize particles x<sub>p,i,j</sub>(t);
-	 *  	evaluation x<sub>p,i,j</sub>(t);
-	 *  	while (termination condition &ne; true) do
-	 *  		v<sub>i,j</sub>(t) = update v<sub>i,j</sub>(t); {by Eq. (6)}
-	 *  		x<sub>g,i,j</sub>(t) = update x<sub>g,i,j</sub>(t); {by Eq. (7)}
-	 *  		x<sub>g,i,j</sub>(t) = mutation x<sub>g,i,j</sub>(t); {by Eq. (11)}
-	 *  		x<sub>p,i,j</sub>(t) = decode x<sub>g,i,j</sub>(t); {by Eqs. (8) and (9)}
-	 *  		evaluate x<sub>p,i,j</sub>(t);
-	 *  		t = t + 1;
-	 *  	end while
-	 *  End</pre></font>
-	 *  <p>with:</p><font size="3">
-	 *  
-	 *  x<sub>g,i,j</sub>: genotype ->genetic information -> in continuous space<br>
-	 *  x<sub>p,i,j</sub>: phenotype -> observable characteristics-> in binary space<br>
-	 *  X<sub>g,max</sub>: is the Maximum here set to 4.<br>
-	 *  Eq. (6):v<sub>i,j</sub>(t + 1) = wv<sub>i,j</sub>+c<sub>1</sub>R<sub>1</sub>(P<sub>best,i,j</sub>-x<sub>p,i,j</sub>(t))+c<sub>2</sub>R<sub>2</sub>(g<sub>best,i,j</sub>-x<sub>p,i,j</sub>(t))<br>
-	 *  Eq. (7):x<sub>g,i,j</sub>(t + 1) = x<sub>g,i,j</sub>(t) + v<sub>i,j</sub>(t + 1)<br>
-	 *  Eq. (11):<b>if(</b>rand()&lt;r<sub>mu</sub><b>)then</b> x<sub>g,i,j</sub>(t + 1) = -x<sub>g,i,j</sub>(t + 1)<br>
-	 *  Eq. (8):x<sub>p,i,j</sub>(t + 1) = <b>(</b>rand() &lt; S(x<sub>g,i,j</sub>(t + 1))<b>) ?</b> 1 <b>:</b> 0<br>
-	 *  Eq. (9) Sigmoid:S(x<sub>g,i,j</sub>(t + 1)) := 1/(1 + e<sup>-x<sub>g,i,j</sub>(t + 1)</sup>)<br></font>
-	 *  <p>Parameter:</p>
-	 *  w inertia, calculated from phi(Variable:{@link #dependency})<br>
-	 *  c1:	influence, calculated from phi(Variable:{@link #dependency}) <br>
-	 *  c2:	influence, calculated from phi(Variable:{@link #dependency})<br>
-	 *  r<sub>mu</sub>: probability that the proposed operation is conducted defined by limit(Variable:{@link #limit})<br>
-	 *  
-	 *  
-	 */
-	protected Individual executeAlgo() {
-		resetWildcards();
-		initDependentParameter();
-		Individual globalBest = new Individual();
-		globalBest.position = extractPositionAndAccess();
-		globalBest.fitness = evaluatePosition(globalBest.position);
-		console.println("Start Value:" + globalBest.fitness);
-		int dimensions = globalBest.position.size();
-		List<Particle> swarm= initializeParticles(dimensions);
-		List<Double> runList = new ArrayList<Double>();
-		runList.add(globalBest.fitness);
-		evaluation(globalBest, swarm);
-		runList.add(globalBest.fitness);
-		for (int iteration = 0; iteration < this.maxGenerations ; iteration++) {
-			int mutationAllowed = iteration % mutationInterval;
-			double bitsFlipped = 0;
-			for (int particleNumber = 0; particleNumber < this.popsize; particleNumber++) {
-				Particle particle = swarm.get(particleNumber);		
-				
-				if(this.useIntervalMutation) {
-					boolean allowMutation = (Random.nextDouble() <  this.mutateProbabilityInterval);
-					TreeSet<Integer> mutationLocationSet = null;
-					if(allowMutation)mutationLocationSet = locationsToMutate(dimensions);
-					for(int index = 0; index < dimensions; index++) {
-						updateVelocity(particle, index, globalBest);
-						updateGenotype(particle, index);
-						if(allowMutation &&mutationAllowed == 0 && iteration != 0 && mutationLocationSet.contains(index))mutation(particle, index);
-						decode(particle, index);
-					}
-				}else {				
-					int count = 0;
-					for(int index = 0; index < dimensions; index++) {
-						updateVelocity(particle, index, globalBest);
-						updateGenotype(particle, index);
-						if(mutationAllowed == 0 && iteration != 0 && Random.nextDouble() < mutationRate) {
-							count++;
-							mutation(particle, index);
-						}
-						decode(particle, index);
-					}
-					bitsFlipped += count;
-				}
-			}
-			if(moreInformation) console.println("\t\t\t\t\t\tAvgBitsMutate: " + (bitsFlipped / (double)popsize));
-			if(cancel)return null;
-			evaluation(globalBest, swarm);
-			runList.add(globalBest.fitness);
-			if(moreInformation) console.println("------------------------");
-		}
-		console.println(" End Value:" + globalBest.fitness);
-		this.runList = runList;
-		return globalBest;
-	}
-
-	@Override
-	protected int getProgressBarMaxCount() {
-		return rounds * maxGenerations * popsize + 1;
-	}
-
-	@Override
-	protected String algoInformationToPrint() {
-		return "PsoAlgo"+ " Rounds:" + rounds 
-				+ " maxIterations:" + maxGenerations
-				+ " swarmSize:" + popsize
-				+ " dependency:" +  dependency
-				+ " mutationInterval:" +  mutationInterval
-				+ " maxVelocity: " + maxVelocity
-				+ " deviation: " + deviation
-				+ (useIntervalMutation? 
-						(" mutateProbabilityInterval:" +  mutateProbabilityInterval
-						+ " maxMutationPercent:" +  maxMutationPercent) : " mutationRate:" + mutationRate);
-	}
-
-	@Override
-	protected String plottFileName() {
-		return "pso-topologie.txt";
-	}
-	
-	
-	/**
-	 * 
-	 * @param problemSize maximum index of position in the particle
-	 * @return
-	 */
-	private List<Particle> initializeParticles(int problemSize) {
-		List<Particle> swarm = new ArrayList<Particle>();
-		//Create The Particle
-		for (int particleNumber = 0; particleNumber < popsize; particleNumber++){
-			//Create a Random position
-			List<Integer> aRandomPosition = new ArrayList<Integer>();
-			for (int index = 0; index < problemSize; index++){
-				aRandomPosition.add(Random.nextIntegerInRange(0, this.getMaximumIndexObjects(index) + 1));
-			}
-			swarm.add(new Particle(aRandomPosition));
-		}
-		return swarm;
-	}
-	/**
-	 * Calculate w, c1, c2
-	 */
-	private void initDependentParameter() {
-		w = 1.0 / (dependency - 1 + Math.sqrt(dependency * dependency - 2 * dependency));
-		c1 = c2 = dependency * w;
-	}
-	/**
-	 * Evaluate each particle and update the global Best position;
-	 * @param globalBest
-	 * @param swarm
-	 */
-	private void evaluation(Individual globalBest, List<Particle> swarm) {
-		for(Particle p: swarm) {
-			double localEvaluationValue = evaluatePosition(p.xPhenotype);
-			if(moreInformation) console.println("Fitness " + localEvaluationValue);
-			p.checkNewEvaluationValue(localEvaluationValue);
-			if(localEvaluationValue < globalBest.fitness) {
-				globalBest.fitness = localEvaluationValue;
-				globalBest.position = p.localBest.position;
-			}
-		}
-	}
-	/**
-	 * 	Eq. (6):v<sub>i,j</sub>(t + 1) = wv<sub>i,j</sub>+c<sub>1</sub>R<sub>1</sub>(P<sub>best,i,j</sub>-x<sub>p,i,j</sub>(t))+c<sub>2</sub>R<sub>2</sub>(g<sub>best,i,j</sub>-x<sub>p,i,j</sub>(t))<br>
-	 * @param particle
-	 * @param index
-	 * @param globalBest
-	 */
-	private void updateVelocity(Particle particle, int index, Individual globalBest) {
-		double r1 = Random.nextDouble();
-		double r2 =	Random.nextDouble();
-		double posValue = particle.xPhenotype.get(index);
-		particle.velocity.set(index, clamp(w*particle.velocity.get(index) + c1*r1*((particle.localBest.position.get(index))  - posValue) + c2*r2*((globalBest.position.get(index))- posValue)) );
-	}
-	/**
-	 * Eq. (7):x<sub>g,i,j</sub>(t + 1) = x<sub>g,i,j</sub>(t) + v<sub>i,j</sub>(t + 1)<br>
-	 * @param particle
-	 * @param index
-	 */
-	private void updateGenotype(Particle particle, int index) {
-		particle.xGenotype.set(index, clamp(particle.xGenotype.get(index) + particle.velocity.get(index)));
-	}
-	/**
-	 * Eq. (11):<b>if(</b>rand()&lt;r<sub>mu</sub><b>)then</b> x<sub>g,i,j</sub>(t + 1) = -x<sub>g,i,j</sub>(t + 1)<br>
-	 * @param particle
-	 * @param index
-	 */
-	private void mutation(Particle particle, int index) {
-		//if(Random.nextDouble() < limit) 
-			particle.xGenotype.set(index, -particle.xGenotype.get(index));
-	}
-	/**
-	 * Eq. (8):x<sub>p,i,j</sub>(t + 1) = <b>(</b>rand() &lt; S(x<sub>g,i,j</sub>(t + 1))<b>) ?</b> 1 <b>:</b> 0<br>
-	 * @param particle
-	 * @param index
-	 */
-	private void decode(Particle particle, int index) {
-		double value = clamp(Random.nextGaussian(particle.xGenotype.get(index), deviation));
-		double alpha = Maths.invLerp(-maxVelocity, +maxVelocity, value);
-		double result = Maths.lerp(0, this.getMaximumIndexObjects(index), alpha);
-		particle.xPhenotype.set(index, (int)Math.round(result));
-	}
-
-	/**
-	 * To clamp X<sub>g,j,i</sub> and v<sub>i,j</sub> in Range [-X<sub>g,max</sub>|+X<sub>g,max</sub>] with {X<sub>g,max</sub>= 4}
-	 * @param value
-	 * @return
-	 */
-	private double clamp(double value) {
-		return Math.max(-maxVelocity, Math.min(maxVelocity, value));
-	}
-	private TreeSet<Integer> locationsToMutate(int dimensions) {
-		TreeSet<Integer> mutationLocation = new TreeSet<Integer>(); //sortedSet
-		int maximumAmountOfMutatedBits = Math.max(1, (int)Math.round(((double) dimensions) * this.maxMutationPercent));
-		int randomUniformAmountOfMutatedValues = Random.nextIntegerInRange(1,maximumAmountOfMutatedBits + 1);
-		for(int i = 0; i< randomUniformAmountOfMutatedValues; i++) {
-			boolean success = mutationLocation.add(Random.nextIntegerInRange(0, dimensions));
-			if(!success) i--; //can be add up to some series long loops if maximumAmountOfMutatedBits get closed to problemsize.
-		}
-		return mutationLocation;
-	}
-	
-	
-	
-	
-	
-	
-	/**
-	 * Class to represent a Particle.
-	 */
-	private class Particle{
-		/**
-		 * The velocity of a particle.
-		 */
-		public List<Double> velocity;
-		/**
-		 * The positions genotype.
-		 */
-		public List<Double> xGenotype;
-		/**
-		 * The positions phenotype. Alias the current position.
-		 */
-		public List<Integer> xPhenotype;
-		
-		public Individual localBest;
-		
-		Particle(List<Integer> position){
-			this.xPhenotype = position;
-			//Init velocity, xGenotype with 0.0 values.
-			this.velocity = position.stream().map(bool -> 0.0).collect(Collectors.toList());
-			this.xGenotype = position.stream().map(bool -> 0.0).collect(Collectors.toList());
-			localBest = new Individual();
-			localBest.fitness = Double.MAX_VALUE;
-		}
-		public void checkNewEvaluationValue(double newEvaluationValue) {
-			if(newEvaluationValue < localBest.fitness) {
-				localBest.fitness = newEvaluationValue;
-				localBest.position = xPhenotype.stream().collect(Collectors.toList());
-			}
-		}
-		public String toString() {
-			return "Particle with xPhenotype(Position), xGenotype, velocity:[" 
-					+ listToString(xPhenotype) + "],[" + listToString(xGenotype) + "],[" 
-					+ listToString(velocity) + "]";
-		}
-		private <Type> String listToString(List<Type> list) {
-			return list.stream().map(Object::toString).collect(Collectors.joining(", "));
-		}
-		
-	}
-	
+  private int popsize = 20;
+  private int maxGenerations = 500;
+  private double dependency = 2.07;
+  private double c1, c2, w;
+  private double maxVelocity = 10.0;
+  private double deviation = 0.5;
+  //mutation
+  private int mutationInterval = 1;
+  private boolean useIntervalMutation = false;
+  private double mutationRate = 0.005;
+  private double mutateProbabilityInterval = 0.01;
+  private double maxMutationPercent = 0.01;
+
+  private boolean moreInformation = false;
+
+  public PsoAlgorithm() {
+    addIntParameter("Swarmsize", popsize, intValue -> popsize = intValue, () -> popsize, 1);
+    addIntParameter("Iterations", maxGenerations, intValue -> maxGenerations = intValue,
+        () -> maxGenerations, 1);
+    addSeperator();
+    addDoubleParameter("Deviation", deviation, doubleValue -> deviation = doubleValue,
+        () -> deviation, 0);
+    addDoubleParameter("Dependency", dependency, doubleValue -> dependency = doubleValue,
+        () -> dependency, true, 2.001, 2.4);
+    addDoubleParameter("Particle Max-Velocity", maxVelocity,
+        doubleValue -> maxVelocity = doubleValue, () -> maxVelocity, 0.0);
+    addSeperator();
+    addIntParameter("Mutation Frequency (Iteration)", mutationInterval,
+        intValue -> mutationInterval = intValue, () -> mutationInterval, 0);
+    addBooleanParameter("Use Interval Mutation", useIntervalMutation,
+        booleanValue -> useIntervalMutation = booleanValue,
+        Arrays.asList("Probability for Frequency Mutation", "Scope of Mutation"),
+        Arrays.asList("Probability for Bit-wise Mutation"));
+    addDoubleParameter("Probability for Frequency Mutation", mutateProbabilityInterval,
+        doubleValue -> mutateProbabilityInterval = doubleValue, () -> mutateProbabilityInterval,
+        useIntervalMutation, 0.0, 1.0);
+    addDoubleParameter("Probability for Bit-wise Mutation", mutationRate,
+        doubleValue -> mutationRate = doubleValue, () -> mutationRate, !useIntervalMutation, 0.0,
+        1.0);
+    addDoubleParameter("Scope of Mutation", maxMutationPercent,
+        doubleValue -> maxMutationPercent = doubleValue, () -> maxMutationPercent,
+        useIntervalMutation, 0.0, 1.0);
+    addSeperator();
+    addBooleanParameter("Print Auxiliary Information", moreInformation,
+        booleanValue -> moreInformation = booleanValue, new LinkedList<String>(),
+        new LinkedList<String>());
+  }
+
+
+  @Override
+  protected double evaluateState(Model model, int amountOfAddedSwitch, double addedCableMeters,
+      boolean moreInformation) {
+    return TopologieObjectiveFunction.getFitnessValueForState(model, amountOfAddedSwitch,
+        addedCableMeters, moreInformation);
+  }
+
+  @Override
+  /**
+   *  <p>Algo from Paper:</p><font size="3"><pre>
+   *
+   *  Begin
+   *  	t = 0; {t: generation index}
+   *  	initialize particles x<sub>p,i,j</sub>(t);
+   *  	evaluation x<sub>p,i,j</sub>(t);
+   *  	while (termination condition &ne; true) do
+   *  		v<sub>i,j</sub>(t) = update v<sub>i,j</sub>(t); {by Eq. (6)}
+   *  		x<sub>g,i,j</sub>(t) = update x<sub>g,i,j</sub>(t); {by Eq. (7)}
+   *  		x<sub>g,i,j</sub>(t) = mutation x<sub>g,i,j</sub>(t); {by Eq. (11)}
+   *  		x<sub>p,i,j</sub>(t) = decode x<sub>g,i,j</sub>(t); {by Eqs. (8) and (9)}
+   *  		evaluate x<sub>p,i,j</sub>(t);
+   *  		t = t + 1;
+   *  	end while
+   *  End</pre></font>
+   *  <p>with:</p><font size="3">
+   *
+   *  x<sub>g,i,j</sub>: genotype ->genetic information -> in continuous space<br>
+   *  x<sub>p,i,j</sub>: phenotype -> observable characteristics-> in binary space<br>
+   *  X<sub>g,max</sub>: is the Maximum here set to 4.<br>
+   *  Eq. (6):v<sub>i,j</sub>(t + 1) = wv<sub>i,j</sub>+c<sub>1</sub>R<sub>1</sub>(P<sub>best,i,j</sub>-x<sub>p,i,j</sub>(t))+c<sub>2</sub>R<sub>2</sub>(g<sub>best,i,j</sub>-x<sub>p,i,j</sub>(t))<br>
+   *  Eq. (7):x<sub>g,i,j</sub>(t + 1) = x<sub>g,i,j</sub>(t) + v<sub>i,j</sub>(t + 1)<br>
+   *  Eq. (11):<b>if(</b>rand()&lt;r<sub>mu</sub><b>)then</b> x<sub>g,i,j</sub>(t + 1) = -x<sub>g,i,j</sub>(t + 1)<br>
+   *  Eq. (8):x<sub>p,i,j</sub>(t + 1) = <b>(</b>rand() &lt; S(x<sub>g,i,j</sub>(t + 1))<b>) ?</b> 1 <b>:</b> 0<br>
+   *  Eq. (9) Sigmoid:S(x<sub>g,i,j</sub>(t + 1)) := 1/(1 + e<sup>-x<sub>g,i,j</sub>(t + 1)</sup>)<br></font>
+   *  <p>Parameter:</p>
+   *  w inertia, calculated from phi(Variable:{@link #dependency})<br>
+   *  c1:	influence, calculated from phi(Variable:{@link #dependency}) <br>
+   *  c2:	influence, calculated from phi(Variable:{@link #dependency})<br>
+   *  r<sub>mu</sub>: probability that the proposed operation is conducted defined by limit(Variable:{@link #limit})<br>
+   *
+   *
+   */
+  protected Individual executeAlgo() {
+    resetWildcards();
+    initDependentParameter();
+    Individual globalBest = new Individual();
+    globalBest.position = extractPositionAndAccess();
+    globalBest.fitness = evaluatePosition(globalBest.position);
+    console.println("Start Value:" + globalBest.fitness);
+    int dimensions = globalBest.position.size();
+    List<Particle> swarm = initializeParticles(dimensions);
+    List<Double> runList = new ArrayList<Double>();
+    runList.add(globalBest.fitness);
+    evaluation(globalBest, swarm);
+    runList.add(globalBest.fitness);
+    for (int iteration = 0; iteration < this.maxGenerations; iteration++) {
+      int mutationAllowed = iteration % mutationInterval;
+      double bitsFlipped = 0;
+      for (int particleNumber = 0; particleNumber < this.popsize; particleNumber++) {
+        Particle particle = swarm.get(particleNumber);
+
+        if (this.useIntervalMutation) {
+          boolean allowMutation = (Random.nextDouble() < this.mutateProbabilityInterval);
+          TreeSet<Integer> mutationLocationSet = null;
+          if (allowMutation) {
+            mutationLocationSet = locationsToMutate(dimensions);
+          }
+          for (int index = 0; index < dimensions; index++) {
+            updateVelocity(particle, index, globalBest);
+            updateGenotype(particle, index);
+            if (allowMutation && mutationAllowed == 0 && iteration != 0
+                && mutationLocationSet.contains(index)) {
+              mutation(particle, index);
+            }
+            decode(particle, index);
+          }
+        } else {
+          int count = 0;
+          for (int index = 0; index < dimensions; index++) {
+            updateVelocity(particle, index, globalBest);
+            updateGenotype(particle, index);
+            if (mutationAllowed == 0 && iteration != 0 && Random.nextDouble() < mutationRate) {
+              count++;
+              mutation(particle, index);
+            }
+            decode(particle, index);
+          }
+          bitsFlipped += count;
+        }
+      }
+      if (moreInformation) {
+        console.println("\t\t\t\t\t\tAvgBitsMutate: " + (bitsFlipped / (double) popsize));
+      }
+      if (cancel) {
+        return null;
+      }
+      evaluation(globalBest, swarm);
+      runList.add(globalBest.fitness);
+      if (moreInformation) {
+        console.println("------------------------");
+      }
+    }
+    console.println(" End Value:" + globalBest.fitness);
+    this.runList = runList;
+    return globalBest;
+  }
+
+  @Override
+  protected int getProgressBarMaxCount() {
+    return rounds * maxGenerations * popsize + 1;
+  }
+
+  @Override
+  protected String algoInformationToPrint() {
+    return "PsoAlgo" + " Rounds:" + rounds
+        + " maxIterations:" + maxGenerations
+        + " swarmSize:" + popsize
+        + " dependency:" + dependency
+        + " mutationInterval:" + mutationInterval
+        + " maxVelocity: " + maxVelocity
+        + " deviation: " + deviation
+        + (useIntervalMutation ?
+        (" mutateProbabilityInterval:" + mutateProbabilityInterval
+            + " maxMutationPercent:" + maxMutationPercent) : " mutationRate:" + mutationRate);
+  }
+
+  @Override
+  protected String plottFileName() {
+    return "pso-topologie.txt";
+  }
+
+
+  /**
+   * @param problemSize maximum index of position in the particle
+   * @return
+   */
+  private List<Particle> initializeParticles(int problemSize) {
+    List<Particle> swarm = new ArrayList<Particle>();
+    //Create The Particle
+    for (int particleNumber = 0; particleNumber < popsize; particleNumber++) {
+      //Create a Random position
+      List<Integer> aRandomPosition = new ArrayList<Integer>();
+      for (int index = 0; index < problemSize; index++) {
+        aRandomPosition.add(Random.nextIntegerInRange(0, this.getMaximumIndexObjects(index) + 1));
+      }
+      swarm.add(new Particle(aRandomPosition));
+    }
+    return swarm;
+  }
+
+  /**
+   * Calculate w, c1, c2
+   */
+  private void initDependentParameter() {
+    w = 1.0 / (dependency - 1 + Math.sqrt(dependency * dependency - 2 * dependency));
+    c1 = c2 = dependency * w;
+  }
+
+  /**
+   * Evaluate each particle and update the global Best position;
+   *
+   * @param globalBest
+   * @param swarm
+   */
+  private void evaluation(Individual globalBest, List<Particle> swarm) {
+    for (Particle p : swarm) {
+      double localEvaluationValue = evaluatePosition(p.xPhenotype);
+      if (moreInformation) {
+        console.println("Fitness " + localEvaluationValue);
+      }
+      p.checkNewEvaluationValue(localEvaluationValue);
+      if (localEvaluationValue < globalBest.fitness) {
+        globalBest.fitness = localEvaluationValue;
+        globalBest.position = p.localBest.position;
+      }
+    }
+  }
+
+  /**
+   * Eq. (6):v<sub>i,j</sub>(t + 1) = wv<sub>i,j</sub>+c<sub>1</sub>R<sub>1</sub>(P<sub>best,i,j</sub>-x<sub>p,i,j</sub>(t))+c<sub>2</sub>R<sub>2</sub>(g<sub>best,i,j</sub>-x<sub>p,i,j</sub>(t))<br>
+   *
+   * @param particle
+   * @param index
+   * @param globalBest
+   */
+  private void updateVelocity(Particle particle, int index, Individual globalBest) {
+    double r1 = Random.nextDouble();
+    double r2 = Random.nextDouble();
+    double posValue = particle.xPhenotype.get(index);
+    particle.velocity.set(index, clamp(
+        w * particle.velocity.get(index) + c1 * r1 * ((particle.localBest.position.get(index))
+            - posValue) + c2 * r2 * ((globalBest.position.get(index)) - posValue)));
+  }
+
+  /**
+   * Eq. (7):x<sub>g,i,j</sub>(t + 1) = x<sub>g,i,j</sub>(t) + v<sub>i,j</sub>(t + 1)<br>
+   *
+   * @param particle
+   * @param index
+   */
+  private void updateGenotype(Particle particle, int index) {
+    particle.xGenotype.set(index,
+        clamp(particle.xGenotype.get(index) + particle.velocity.get(index)));
+  }
+
+  /**
+   * Eq. (11):<b>if(</b>rand()&lt;r<sub>mu</sub><b>)then</b> x<sub>g,i,j</sub>(t + 1) =
+   * -x<sub>g,i,j</sub>(t + 1)<br>
+   *
+   * @param particle
+   * @param index
+   */
+  private void mutation(Particle particle, int index) {
+    //if(Random.nextDouble() < limit)
+    particle.xGenotype.set(index, -particle.xGenotype.get(index));
+  }
+
+  /**
+   * Eq. (8):x<sub>p,i,j</sub>(t + 1) = <b>(</b>rand() &lt; S(x<sub>g,i,j</sub>(t + 1))<b>) ?</b> 1
+   * <b>:</b> 0<br>
+   *
+   * @param particle
+   * @param index
+   */
+  private void decode(Particle particle, int index) {
+    double value = clamp(Random.nextGaussian(particle.xGenotype.get(index), deviation));
+    double alpha = Maths.invLerp(-maxVelocity, +maxVelocity, value);
+    double result = Maths.lerp(0, this.getMaximumIndexObjects(index), alpha);
+    particle.xPhenotype.set(index, (int) Math.round(result));
+  }
+
+  /**
+   * To clamp X<sub>g,j,i</sub> and v<sub>i,j</sub> in Range [-X<sub>g,max</sub>|+X<sub>g,max</sub>]
+   * with {X<sub>g,max</sub>= 4}
+   *
+   * @param value
+   * @return
+   */
+  private double clamp(double value) {
+    return Math.max(-maxVelocity, Math.min(maxVelocity, value));
+  }
+
+  private TreeSet<Integer> locationsToMutate(int dimensions) {
+    TreeSet<Integer> mutationLocation = new TreeSet<Integer>(); //sortedSet
+    int maximumAmountOfMutatedBits = Math.max(1,
+        (int) Math.round(((double) dimensions) * this.maxMutationPercent));
+    int randomUniformAmountOfMutatedValues = Random.nextIntegerInRange(1,
+        maximumAmountOfMutatedBits + 1);
+    for (int i = 0; i < randomUniformAmountOfMutatedValues; i++) {
+      boolean success = mutationLocation.add(Random.nextIntegerInRange(0, dimensions));
+      if (!success) {
+        i--; //can be add up to some series long loops if maximumAmountOfMutatedBits get closed to problemsize.
+      }
+    }
+    return mutationLocation;
+  }
+
+
+  /**
+   * Class to represent a Particle.
+   */
+  private class Particle {
+
+    /**
+     * The velocity of a particle.
+     */
+    public List<Double> velocity;
+    /**
+     * The positions genotype.
+     */
+    public List<Double> xGenotype;
+    /**
+     * The positions phenotype. Alias the current position.
+     */
+    public List<Integer> xPhenotype;
+
+    public Individual localBest;
+
+    Particle(List<Integer> position) {
+      this.xPhenotype = position;
+      //Init velocity, xGenotype with 0.0 values.
+      this.velocity = position.stream().map(bool -> 0.0).collect(Collectors.toList());
+      this.xGenotype = position.stream().map(bool -> 0.0).collect(Collectors.toList());
+      localBest = new Individual();
+      localBest.fitness = Double.MAX_VALUE;
+    }
+
+    public void checkNewEvaluationValue(double newEvaluationValue) {
+      if (newEvaluationValue < localBest.fitness) {
+        localBest.fitness = newEvaluationValue;
+        localBest.position = xPhenotype.stream().collect(Collectors.toList());
+      }
+    }
+
+    public String toString() {
+      return "Particle with xPhenotype(Position), xGenotype, velocity:["
+          + listToString(xPhenotype) + "],[" + listToString(xGenotype) + "],["
+          + listToString(velocity) + "]";
+    }
+
+    private <Type> String listToString(List<Type> list) {
+      return list.stream().map(Object::toString).collect(Collectors.joining(", "));
+    }
+
+  }
+
 }
 }

+ 7 - 5
src/holeg/api/AddOn.java

@@ -1,14 +1,16 @@
 package holeg.api;
 package holeg.api;
 
 
-import javax.swing.JPanel;
-
 import holeg.ui.controller.Control;
 import holeg.ui.controller.Control;
+import javax.swing.JPanel;
 
 
 /**
 /**
  * Interface for a Standart Addon.
  * Interface for a Standart Addon.
+ *
  * @author Tom Troppmann
  * @author Tom Troppmann
  */
  */
-public interface AddOn  {
-	public JPanel getPanel();
-	public void setController(Control control);
+public interface AddOn {
+
+  public JPanel getPanel();
+
+  public void setController(Control control);
 }
 }

+ 1325 - 1276
src/holeg/api/AlgorithmFrameworkFlex.java

@@ -1,5 +1,22 @@
 package holeg.api;
 package holeg.api;
 
 
+import holeg.addon.helper.EmailNotification;
+import holeg.algorithm.objective_function.ObjectiveFunctionByCarlos;
+import holeg.algorithm.objective_function.SwitchObjectiveFunction;
+import holeg.model.Flexibility;
+import holeg.model.Flexibility.FlexState;
+import holeg.model.GroupNode;
+import holeg.model.HolonElement;
+import holeg.model.HolonObject;
+import holeg.model.HolonSwitch;
+import holeg.model.HolonSwitch.SwitchMode;
+import holeg.model.HolonSwitch.SwitchState;
+import holeg.model.Model;
+import holeg.preferences.ImagePreference;
+import holeg.ui.controller.Control;
+import holeg.ui.view.component.Console;
+import holeg.ui.view.image.Import;
+import holeg.utility.math.decimal.Format;
 import java.awt.BorderLayout;
 import java.awt.BorderLayout;
 import java.awt.Component;
 import java.awt.Component;
 import java.awt.Dimension;
 import java.awt.Dimension;
@@ -12,13 +29,21 @@ import java.io.IOException;
 import java.io.OutputStreamWriter;
 import java.io.OutputStreamWriter;
 import java.math.RoundingMode;
 import java.math.RoundingMode;
 import java.text.NumberFormat;
 import java.text.NumberFormat;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.DoubleSummaryStatistics;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
 import java.util.function.BiFunction;
 import java.util.function.BiFunction;
 import java.util.function.Consumer;
 import java.util.function.Consumer;
 import java.util.function.Supplier;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import java.util.stream.Stream;
-
 import javax.swing.BorderFactory;
 import javax.swing.BorderFactory;
 import javax.swing.Box;
 import javax.swing.Box;
 import javax.swing.BoxLayout;
 import javax.swing.BoxLayout;
@@ -36,1302 +61,1326 @@ import javax.swing.JScrollPane;
 import javax.swing.JSplitPane;
 import javax.swing.JSplitPane;
 import javax.swing.text.NumberFormatter;
 import javax.swing.text.NumberFormatter;
 
 
-import holeg.addon.helper.EmailNotification;
-import holeg.algorithm.objective_function.ObjectiveFunctionByCarlos;
-import holeg.algorithm.objective_function.SwitchObjectiveFunction;
-import holeg.model.*;
-import holeg.preferences.ImagePreference;
-import holeg.model.Flexibility.FlexState;
-import holeg.model.HolonSwitch.SwitchMode;
-import holeg.model.HolonSwitch.SwitchState;
-import holeg.ui.controller.Control;
-import holeg.ui.view.component.Console;
-import holeg.ui.view.image.Import;
-import holeg.utility.math.decimal.Format;
+public abstract class AlgorithmFrameworkFlex implements AddOn {
 
 
-public abstract class AlgorithmFrameworkFlex implements AddOn{
-	//Algo
-	protected int rounds = 1;
-	
-	
-	
-	//Panel
-	private JPanel content = new JPanel();
-	protected Console console = new Console();
-	private JPanel borderPanel = new JPanel();
-	
-	
-	//Settings groupNode
-	private Optional<GroupNode> groupNode = Optional.empty();
-	
-	
-	//access
-	private ArrayList<AccessWrapper> access;
-	private HashMap<HolonObject, AccessWrapper> accessKillSwitch = new HashMap<HolonObject, AccessWrapper>();
-	LinkedList<List<Boolean>> resetChain = new LinkedList<List<Boolean>>();
-	boolean algoUseElements = false, algoUseSwitches = true, algoUseFlexes = true, algoUseKillSwitch = true;
-	
-	//time
-	private long startTime;
-	
-	
-	private RunProgressBar runProgressbar = new RunProgressBar();
-	
-	
-	
-	//concurrency
-	private Thread runThread = new Thread();
-	protected boolean cancel = false;
-
-	//holeg interaction
-	protected Control  control;
-
-	
-	//printing
-	private Printer runPrinter = new Printer(plottFileName());
-	protected List<Double> runList = new LinkedList<Double>();
-	private RunAverage avg = new RunAverage();
-
-	//Parameter
-	@SuppressWarnings("rawtypes")
-	LinkedList<ParameterStepping> parameterSteppingList= new LinkedList<ParameterStepping>();
-	protected boolean useStepping = false;
-
-	//Email
-	private boolean useEmailNotification = false;
-	
-	
-	//ObjectiveFunction
-	enum ObjectiveFunction {Normal, Switch};
-	ObjectiveFunction evaluationFunction = ObjectiveFunction.Normal;
-	
-	public AlgorithmFrameworkFlex(){
-		content.setLayout(new BorderLayout());
-		JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
-				createOptionPanel() , console);
-		splitPane.setResizeWeight(0.0);
-		content.add(splitPane, BorderLayout.CENTER);
-		content.setPreferredSize(new Dimension(1200,800));
-	}
-	
-	
-	
-	
-	
-	
-	private JPanel createOptionPanel() {
-		JPanel optionPanel = new JPanel(new BorderLayout());
-		JScrollPane scrollPane = new JScrollPane(createParameterPanel());
-		scrollPane.setBorder(BorderFactory.createTitledBorder("Parameter"));
-		optionPanel.add(scrollPane,  BorderLayout.CENTER);
-		optionPanel.add(createButtonPanel(), BorderLayout.PAGE_END);
-		return optionPanel;
-	}
-	
-	private Component createParameterPanel() {
-		JPanel parameterPanel = new JPanel(null);
-		parameterPanel.setPreferredSize(new Dimension(510,300));
-		borderPanel.setLayout(new BoxLayout(borderPanel, BoxLayout.PAGE_AXIS));
-		addIntParameter("Rounds", rounds, intInput -> rounds = intInput, () -> rounds, 1);
-		JScrollPane scrollPane = new JScrollPane(borderPanel);
-		scrollPane.setBounds(10, 0, 850, 292);
-		scrollPane.setBorder(BorderFactory.createEmptyBorder());
-		parameterPanel.add(scrollPane);	
-		
-		
-		
-		JButton selectGroupNodeButton = new JButton("Select GroupNode");
-		selectGroupNodeButton.setBounds(900, 0, 185, 30);
-		selectGroupNodeButton.addActionListener(actionEvent -> selectGroupNode());
-		parameterPanel.add(selectGroupNodeButton);	
-		JProgressBar progressBar = runProgressbar.getJProgressBar();
-		progressBar.setBounds(900, 35, 185, 20);
-		progressBar.setStringPainted(true);
-		parameterPanel.add(progressBar);
-		
-		JCheckBox useElements = new JCheckBox("Elements");
-		useElements.setSelected(algoUseElements);
-		useElements.setBounds(900, 70, 185, 20);
-		useElements.addActionListener(actionEvent -> algoUseElements = useElements.isSelected());
-		parameterPanel.add(useElements);
-		
-		JCheckBox useSwitches = new JCheckBox("Switches");
-		useSwitches.setSelected(algoUseSwitches);
-		useSwitches.setBounds(900, 90, 185, 20);
-		useSwitches.addActionListener(actionEvent -> algoUseSwitches = useSwitches.isSelected());
-		parameterPanel.add(useSwitches);
-		
-		
-		JCheckBox useFlexes = new JCheckBox("Flexibilities");
-		useFlexes.setSelected(algoUseFlexes);
-		useFlexes.setBounds(900, 110, 185, 20);
-		useFlexes.addActionListener(actionEvent -> algoUseFlexes = useFlexes.isSelected());
-		parameterPanel.add(useFlexes);
-		
-		JCheckBox useSmartMeter = new JCheckBox("SmartMeter");
-		useSmartMeter.setSelected(algoUseFlexes);
-		useSmartMeter.setBounds(900, 130, 185, 20);
-		useSmartMeter.addActionListener(actionEvent -> 
-				{
-					cancel();
-					reset();
-					algoUseKillSwitch = useSmartMeter.isSelected();
-				});
-		parameterPanel.add(useSmartMeter);
-		
-		String[] objectiveFunctionStrings = { "Normal", "Switch"};
-		JLabel fitnessLabel = new JLabel("FitnessFunction:");
-		fitnessLabel.setBounds(910, 160, 90, 20);
-		parameterPanel.add(fitnessLabel);
-		JComboBox<String> ofBox = new JComboBox<String>(objectiveFunctionStrings);
-		ofBox.addActionListener(actionEvent -> 
-		{
-			boolean pickNormal = ((String)ofBox.getSelectedItem()).equals("Normal");
-			evaluationFunction = pickNormal?ObjectiveFunction.Normal:ObjectiveFunction.Switch;
-		});
-		ofBox.setBounds(1000, 160, 70, 20);
-		parameterPanel.add(ofBox);
-		
-		
-		
-		
-		JCheckBox emailNotificationCheckbox = new JCheckBox("EmailNotification");
-		emailNotificationCheckbox.setSelected(this.useEmailNotification);
-		emailNotificationCheckbox.setBounds(900, 200, 130, 20);
-		emailNotificationCheckbox.addActionListener(actionEvent -> useEmailNotification = emailNotificationCheckbox.isSelected());
-		parameterPanel.add(emailNotificationCheckbox);
-		
-		JButton emailSettingsButton = new JButton("", new ImageIcon(Import.loadImage(ImagePreference.Button.Settings, 16,16)));
-		emailSettingsButton.setBounds(1030, 200, 20, 20);
-		emailSettingsButton.addActionListener(event -> {
-			EmailNotification.OpenEmailSettings(content);
-		});
-		parameterPanel.add(emailSettingsButton);
-		
-		
-		
-		
-		return parameterPanel;
-	}
-	private JPanel createButtonPanel() {
-		JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
-		
-		JButton resetButton =  new JButton("Reset");
-		resetButton.setToolTipText("Resets the state to the initial grid configuration.");
-		resetButton.addActionListener(actionEvent -> reset());
-		buttonPanel.add(resetButton);
-		
-		JButton cancelButton =  new JButton("Cancel Run");
-		cancelButton.addActionListener(actionEvent -> cancel());
-		buttonPanel.add(cancelButton);
-		
-		JButton fitnessButton =  new JButton("Evaluate");
-		fitnessButton.setToolTipText("Evaluate the current grid configuration.");
-		fitnessButton.addActionListener(actionEvent -> fitness());
-		buttonPanel.add(fitnessButton);
-		
-		JButton runButton =  new JButton("Run");
-		runButton.addActionListener(actionEvent -> {
-			Runnable task = () -> run();
-			runThread = new Thread(task);
-			runThread.start();
-		});
-		buttonPanel.add(runButton);
-		
-		
-		
-		return buttonPanel;
-	}
-	
-	
-	
-	//ParameterImports
-	
-	//int
-	protected void addIntParameter(String parameterName, int parameterValue, Consumer<Integer> setter, Supplier<Integer> getter) {
-		this.addIntParameter(parameterName, parameterValue, setter, getter, Integer.MIN_VALUE, Integer.MAX_VALUE);
-	}
-	
-	protected void addIntParameter(String parameterName, int parameterValue, Consumer<Integer> setter, Supplier<Integer> getter, int parameterMinValue) {
-		this.addIntParameter(parameterName, parameterValue, setter, getter, parameterMinValue, Integer.MAX_VALUE);
-	}
-	
-	protected void addIntParameter(String parameterName, int parameterValue, Consumer<Integer> setter, Supplier<Integer> getter, int parameterMinValue, int parameterMaxValue) {
-		JPanel singleParameterPanel = new JPanel();
-		singleParameterPanel.setLayout(new BoxLayout(singleParameterPanel, BoxLayout.LINE_AXIS));
-		singleParameterPanel.setAlignmentX(0.0f);
-		singleParameterPanel.add(new JLabel(parameterName + ": "));
-		singleParameterPanel.add(Box.createHorizontalGlue());
-		NumberFormat format = NumberFormat.getIntegerInstance();
-		format.setGroupingUsed(false);
-		format.setParseIntegerOnly(true);
-		NumberFormatter integerFormatter = new NumberFormatter(format);
-		integerFormatter.setMinimum(parameterMinValue);
-		integerFormatter.setMaximum(parameterMaxValue);
-		integerFormatter.setCommitsOnValidEdit(true);
-		JFormattedTextField singleParameterTextField = new  JFormattedTextField(integerFormatter);
-		singleParameterTextField.setValue(parameterValue);
-		String minValue = (parameterMinValue == Integer.MIN_VALUE)?"Integer.MIN_VALUE":String.valueOf(parameterMinValue);
-		String maxValue = (parameterMaxValue == Integer.MAX_VALUE)?"Integer.MAX_VALUE":String.valueOf(parameterMaxValue);
-		singleParameterTextField.setToolTipText("Only integer \u2208 [" + minValue + "," + maxValue + "]");
-		singleParameterTextField.addPropertyChangeListener(actionEvent -> setter.accept(Integer.parseInt(singleParameterTextField.getValue().toString())));
-		singleParameterTextField.setMaximumSize(new Dimension(200, 30));
-		singleParameterTextField.setPreferredSize(new Dimension(200, 30));
-		singleParameterPanel.add(singleParameterTextField);
-		
-		
-		ParameterStepping<Integer> intParameterStepping = new ParameterStepping<Integer>(setter, getter, Integer::sum , (a,b) -> a * b, 1, 1);
-		intParameterStepping.useThisParameter = false;
-		parameterSteppingList.add(intParameterStepping);
-		
-		JCheckBox useSteppingCheckBox = new JCheckBox();
-		useSteppingCheckBox.setSelected(false);
-		singleParameterPanel.add(useSteppingCheckBox);
-		
-		
-		
-		JLabel stepsLabel = new JLabel("Steps: ");
-		stepsLabel.setEnabled(false);
-		singleParameterPanel.add(stepsLabel);
-		
-		NumberFormatter stepFormatter = new NumberFormatter(format);
-		stepFormatter.setMinimum(1);
-		stepFormatter.setMaximum(Integer.MAX_VALUE);
-		stepFormatter.setCommitsOnValidEdit(true);
-		
-		
-		JFormattedTextField stepsTextField = new  JFormattedTextField(stepFormatter);
-		stepsTextField.setEnabled(false);
-		stepsTextField.setValue(1);
-		stepsTextField.setToolTipText("Only integer \u2208 [" + 1 + "," + Integer.MAX_VALUE + "]");
-		stepsTextField.addPropertyChangeListener(actionEvent -> intParameterStepping.stepps = Integer.parseInt(stepsTextField.getValue().toString()));
-		stepsTextField.setMaximumSize(new Dimension(40, 30));
-		stepsTextField.setPreferredSize(new Dimension(40, 30));
-		singleParameterPanel.add(stepsTextField);
-		
-		JLabel stepsSizeLabel = new JLabel("Step size: ");
-		stepsSizeLabel.setEnabled(false);
-		singleParameterPanel.add(stepsSizeLabel);
-		
-		JFormattedTextField stepsSizeTextField = new  JFormattedTextField(stepFormatter);
-		stepsSizeTextField.setEnabled(false);
-		stepsSizeTextField.setValue(1);
-		stepsSizeTextField.setToolTipText("Only integer \u2208 [" + 1 + "," + Integer.MAX_VALUE + "]");
-		stepsSizeTextField.addPropertyChangeListener(actionEvent -> intParameterStepping.stepSize = Integer.parseInt(stepsSizeTextField.getValue().toString()));
-		stepsSizeTextField.setMaximumSize(new Dimension(40, 30));
-		stepsSizeTextField.setPreferredSize(new Dimension(40, 30));
-		singleParameterPanel.add(stepsSizeTextField);
-		
-		useSteppingCheckBox.addActionListener(actionEvent -> {
-			boolean enabled = useSteppingCheckBox.isSelected();
-			intParameterStepping.useThisParameter = enabled;
-			this.useStepping = this.parameterSteppingList.stream().anyMatch(parameter -> parameter.useThisParameter);
-			stepsLabel.setEnabled(enabled);
-			stepsTextField.setEnabled(enabled);
-			stepsSizeLabel.setEnabled(enabled);
-			stepsSizeTextField.setEnabled(enabled);
-		});
-		
-		borderPanel.add(singleParameterPanel);
-	}
-	
-	
-	//double
-	protected void addDoubleParameter(String parameterName, double parameterValue, Consumer<Double> setter, Supplier<Double> getter) {
-		this.addDoubleParameter(parameterName, parameterValue, setter, getter, Double.MIN_VALUE, Double.MAX_VALUE);
-	}
-	
-	
-	protected void addDoubleParameter(String parameterName, double parameterValue, Consumer<Double> setter, Supplier<Double> getter, double parameterMinValue) {
-		this.addDoubleParameter(parameterName, parameterValue, setter, getter, parameterMinValue, Double.MAX_VALUE);
-	}
-	
-	
-	protected void addDoubleParameter(String parameterName, double parameterValue, Consumer<Double> setter, Supplier<Double> getter, double parameterMinValue, double parameterMaxValue) {
-		JPanel singleParameterPanel = new JPanel();
-		singleParameterPanel.setLayout(new BoxLayout(singleParameterPanel, BoxLayout.LINE_AXIS));
-		singleParameterPanel.setAlignmentX(0.0f);
-		singleParameterPanel.add(new JLabel(parameterName + ": "));
-		singleParameterPanel.add(Box.createHorizontalGlue());
-		NumberFormat doubleFormat = NumberFormat.getNumberInstance(Locale.US);
-		doubleFormat.setMinimumFractionDigits(1);
-		doubleFormat.setMaximumFractionDigits(10);
-		doubleFormat.setRoundingMode(RoundingMode.HALF_UP);
-		NumberFormatter doubleFormatter = new NumberFormatter(doubleFormat);
-		doubleFormatter.setMinimum(parameterMinValue);
-		doubleFormatter.setMaximum(parameterMaxValue);
-		doubleFormatter.setCommitsOnValidEdit(true);
-		JFormattedTextField singleParameterTextField = new  JFormattedTextField(doubleFormatter);
-		singleParameterTextField.setValue(parameterValue);
-		String minValue = (parameterMinValue == Double.MIN_VALUE)?"Double.MIN_VALUE":String.valueOf(parameterMinValue);
-		String maxValue = (parameterMaxValue == Double.MAX_VALUE)?"Double.MAX_VALUE":String.valueOf(parameterMaxValue);
-		singleParameterTextField.setToolTipText("Only double \u2208 [" + minValue + "," + maxValue + "]");
-		singleParameterTextField.addPropertyChangeListener(actionEvent -> setter.accept(Double.parseDouble(singleParameterTextField.getValue().toString())));
-		singleParameterTextField.setMaximumSize(new Dimension(200, 30));
-		singleParameterTextField.setPreferredSize(new Dimension(200, 30));
-		singleParameterPanel.add(singleParameterTextField);
-		
-		ParameterStepping<Double> doubleParameterStepping = new ParameterStepping<Double>(setter, getter, (a,b) -> a+b , (a,b) -> a * b, 1.0, 1);
-		doubleParameterStepping.useThisParameter = false;
-		parameterSteppingList.add(doubleParameterStepping);
-		
-		JCheckBox useSteppingCheckBox = new JCheckBox();
-		useSteppingCheckBox.setSelected(false);
-		singleParameterPanel.add(useSteppingCheckBox);
-		
-		
-		
-		JLabel stepsLabel = new JLabel("Steps: ");
-		stepsLabel.setEnabled(false);
-		singleParameterPanel.add(stepsLabel);
-		NumberFormat format = NumberFormat.getIntegerInstance();
-		format.setGroupingUsed(false);
-		format.setParseIntegerOnly(true);
-		NumberFormatter integerFormatter = new NumberFormatter(format);
-		integerFormatter.setMinimum(1);
-		integerFormatter.setMaximum(Integer.MAX_VALUE);
-		integerFormatter.setCommitsOnValidEdit(true);
-	
-		
-		
-		JFormattedTextField stepsTextField = new  JFormattedTextField(integerFormatter);
-		stepsTextField.setEnabled(false);
-		stepsTextField.setValue(1);
-		stepsTextField.setToolTipText("Only integer \u2208 [" + 1 + "," + Integer.MAX_VALUE + "]");
-		stepsTextField.addPropertyChangeListener(actionEvent -> doubleParameterStepping.stepps = Integer.parseInt(stepsTextField.getValue().toString()));
-		stepsTextField.setMaximumSize(new Dimension(40, 30));
-		stepsTextField.setPreferredSize(new Dimension(40, 30));
-		singleParameterPanel.add(stepsTextField);
-		
-		JLabel stepsSizeLabel = new JLabel("Step size: ");
-		stepsSizeLabel.setEnabled(false);
-		singleParameterPanel.add(stepsSizeLabel);
-		
-		NumberFormatter doubleFormatterForStepping = new NumberFormatter(doubleFormat);
-		doubleFormatterForStepping.setCommitsOnValidEdit(true);
-		JFormattedTextField stepsSizeTextField = new  JFormattedTextField(doubleFormatterForStepping);
-		stepsSizeTextField.setEnabled(false);
-		stepsSizeTextField.setValue(1.0);
-		stepsSizeTextField.setToolTipText("Only double");
-		stepsSizeTextField.addPropertyChangeListener(actionEvent -> doubleParameterStepping.stepSize = Double.parseDouble(stepsSizeTextField.getValue().toString()));
-		stepsSizeTextField.setMaximumSize(new Dimension(40, 30));
-		stepsSizeTextField.setPreferredSize(new Dimension(40, 30));
-		singleParameterPanel.add(stepsSizeTextField);
-		
-		useSteppingCheckBox.addActionListener(actionEvent -> {
-			boolean enabled = useSteppingCheckBox.isSelected();
-			doubleParameterStepping.useThisParameter = enabled;
-			this.useStepping = this.parameterSteppingList.stream().anyMatch(parameter -> parameter.useThisParameter);
-			stepsLabel.setEnabled(enabled);
-			stepsTextField.setEnabled(enabled);
-			stepsSizeLabel.setEnabled(enabled);
-			stepsSizeTextField.setEnabled(enabled);
-		});
-		
-		borderPanel.add(singleParameterPanel);
-	}
-	//boolean
-	protected void addBooleanParameter(String parameterName, boolean parameterValue, Consumer<Boolean> setter){
-		JPanel singleParameterPanel = new JPanel();
-		singleParameterPanel.setLayout(new BoxLayout(singleParameterPanel, BoxLayout.LINE_AXIS));
-		singleParameterPanel.setAlignmentX(0.0f);
-		singleParameterPanel.add(new JLabel(parameterName + ": "));
-		singleParameterPanel.add(Box.createHorizontalGlue());
-		JCheckBox useGroupNodeCheckBox = new JCheckBox();
-		useGroupNodeCheckBox.setSelected(parameterValue);
-		useGroupNodeCheckBox.addActionListener(actionEvent -> setter.accept(useGroupNodeCheckBox.isSelected()));
-		singleParameterPanel.add(useGroupNodeCheckBox);
-		borderPanel.add(singleParameterPanel);
-	}
-	
-
-	private void startTimer(){
-		startTime = System.currentTimeMillis();
-	}
-	private long printElapsedTime(){
-		long elapsedMilliSeconds = System.currentTimeMillis() - startTime;
-		console.println("Execution Time in Milliseconds:" + elapsedMilliSeconds);
-		return elapsedMilliSeconds;
-	}
-	
-	
-	
-	private void cancel() {
-		if(runThread.isAlive()) {
-			console.println("Cancel run.");
-			cancel = true;
-			runProgressbar.cancel();
-		} else {
-			console.println("Nothing to cancel.");
-		}
-	}
-	
-	
-	private void fitness() {
-		if(runThread.isAlive()) {
-			console.println("Run have to be cancelled first.");
-			return;
-		}
-		double currentFitness = evaluatePosition(extractPositionAndAccess());
-		resetChain.removeLast();
-		console.println("Actual Fitnessvalue: " + currentFitness);
-	}
-	
-	
-	private void selectGroupNode() {
-		Object[] possibilities = control.getModel().getCanvas().getAllGroupNodeObjectsRecursive().toArray();
-		@SuppressWarnings("unchecked")
-		GroupNode selected = (GroupNode) JOptionPane.showInputDialog(content, "Select GroupNode:", "GroupNode?",  JOptionPane.OK_OPTION,new ImageIcon(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)) , possibilities, "");
-		if(selected != null) {
-			console.println("Selected: " + selected);
-			groupNode = Optional.of(selected);
-		}
-	}
-	
-	protected double evaluatePosition(List<Boolean> positionToEvaluate) {
-		runProgressbar.step();
-		setState(positionToEvaluate); // execution time critical
-		double result = evaluateState();
-		return result;
-	}
-
-	private double evaluateState() {
-		switch(this.evaluationFunction) {
-		case Switch:
-			return SwitchObjectiveFunction.getFitnessValueForState(control.getModel());
-		case Normal:
-		default:
-			return ObjectiveFunctionByCarlos.getFitnessValueForState(control.getModel());
-		}
-		
-	}
-
-	
-	private void run() {
-		cancel = false;
-		control.guiSetEnabled(false);
-		runPrinter.openStream();
-		runPrinter.println("");
-		runPrinter.println("Start:" + stringStatFromRunValues(getRunValuesFromActualState()));
-		runPrinter.closeStream();
-		if(this.useStepping) {
-			initParameterStepping();
-			do {
-					executeAlgoWithParameter();
-					if(cancel) break;
-					resetState();
-			}while(updateOneParameter());
-			resetParameterStepping();
-		}else {
-			executeAlgoWithParameter();
-			
-		}
-		updateVisual();
-		runProgressbar.finishedCancel();
-		control.guiSetEnabled(true);
-		if(this.useEmailNotification && !cancel) {
-			EmailNotification.sendEmail(this.getClass().getName() + " finished", "Execution done.");
-		}
-	}
-	@SuppressWarnings("rawtypes")
-	private void initParameterStepping() {
-		for(ParameterStepping param :this.parameterSteppingList) {
-			param.init();
-		}
-		
-	}
-	@SuppressWarnings("rawtypes")
-	private void resetParameterStepping() {
-		for(ParameterStepping param :this.parameterSteppingList) {
-			param.reset();
-		}
-		
-	}
-
-
-
-
-	@SuppressWarnings("rawtypes")
-	private boolean updateOneParameter() {
-		List<ParameterStepping> parameterInUseList = this.parameterSteppingList.stream().filter(param -> param.useThisParameter).collect(Collectors.toList());
-		Collections.reverse(parameterInUseList);
-		int lastParameter = parameterInUseList.size() - 1 ;
-		int actualParameter = 0;
-		for(ParameterStepping param : parameterInUseList) {
-			
-			if(param.canUpdate()) {
-				param.update();
-				return true;
-			}else {
-				if(actualParameter == lastParameter) break;
-				param.reset();
-			}
-			actualParameter++;
-		}
-		//No Param can be updated 
-		return false;
-	}
-
-
-
-
-
-
-	private void executeAlgoWithParameter(){
-		double startFitness = evaluatePosition(extractPositionAndAccess());
-		console.println("BitLength: " + access.size());
-		resetChain.removeLast();
-		runPrinter.openStream();
-		runPrinter.println(algoInformationToPrint());
-		console.println(algoInformationToPrint());
-		runPrinter.closeStream();
-		runProgressbar.start();
-		Individual runBest = new Individual();
-		runBest.fitness = Double.MAX_VALUE;
-		this.avg = new RunAverage();
-		for(int r = 0; r < rounds; r++)
-		{	
-			startTimer();	
-			Individual  roundBest = executeAlgo();
-			if(cancel)return;
-			long executionTime = printElapsedTime();
-			setState(roundBest.position);
-			runPrinter.openStream();
-			runPrinter.println(runList.stream().map(value -> Format.doubleFixedPlaces(2,value)).collect(Collectors.joining(", ")));
-			RunValues val = getRunValuesFromActualState();
-			val.result = roundBest.fitness;
-			val.executionTime = executionTime;
-			avg.addRun(val);
-			runPrinter.println("Result: " + Format.doubleFixedPlaces(2,roundBest.fitness) + " ExecutionTime:" + executionTime + " " + stringStatFromRunValues(val));
-			runPrinter.closeStream();
-			resetState();
-			if(roundBest.fitness < runBest.fitness) runBest = roundBest;
-		}
-		
-		this.extractPositionAndAccess();
-		setState(runBest.position);
-		updateVisual();
-		console.println("Start: " + Format.doubleFixedPlaces(2,startFitness));
-		console.println("AlgoResult: " + Format.doubleFixedPlaces(2,runBest.fitness));
-		if(this.algoUseFlexes)calculateAndPrintFlexInfos();
-		runPrinter.openStream();
-		if(rounds > 1) {
-			RunValues avgRun = avg.getAverage();
-			
-			runPrinter.println("Average.Result: " + Format.doubleFixedPlaces(2, avgRun.result) + " Average.ExecutionTime:" + avgRun.executionTime + " "  + avg.getAverage().stringStatFromRunValues("Average."));
-		}
-		runPrinter.println("");
-		runPrinter.closeStream();
-	}
-	
-	
-	private void calculateAndPrintFlexInfos() {
-		int amountOfUsedFlex = 0;
-		List<Flexibility> allFlex = control.getModel().getAllFlexibilities();
-		int amountOfFlex = allFlex.size(); 
-		float cost = 0;
-		int consumingFlex = 0;
-		float consumingFlexEnergy = 0.0f;
-		int producingFlex = 0;
-		float producingFlexEnergy = 0.0f;
-		int maxCooldown = 0;
-		int amountEssential = 0;
-		int amountHigh = 0;
-		int amountMedium = 0;
-		int amountLow = 0;
-		Stream<Flexibility> allFlexInUse = allFlex.stream().filter(flex -> flex.getState().equals(FlexState.IN_USE));
-		Iterator<Flexibility> iterInUseFlex =  allFlexInUse.iterator();
-		while(iterInUseFlex.hasNext()) {
-			Flexibility flex = iterInUseFlex.next();
-			amountOfUsedFlex++;
-			cost += flex.cost;
-			float energy = flex.energyReleased();
-			if(energy < 0) {
-				consumingFlex++;
-				consumingFlexEnergy += -energy;
-			}else {
-				producingFlex++;
-				producingFlexEnergy += energy;
-			}
-			if(flex.getCooldown() > maxCooldown) maxCooldown = flex.getCooldown();
-			switch(flex.getElement().getPriority()) {
-			case Essential:
-				amountEssential++;
-				break;
-			case High:
-				amountHigh++;
-				break;
-			case Low:
-				amountLow++;
-				break;
-			case Medium:
-				amountMedium++;
-				break;
-			default:
-				break;
-			
-			}
-		}
-		
-		
-		//Total Flexibilities:
-		//Used Flexibilities:
-		console.println("Used Flex [" + amountOfUsedFlex + "/" + amountOfFlex + "]");
-		
-		//Consuming Flexibilities:
-		console.println(consumingFlex + " consuimg flexibilities that consumed " + consumingFlexEnergy + "Energy.");
-		//Producing Flexibilities
-		console.println(producingFlex + " producing flexibilities that produce " + producingFlexEnergy + "Energy.");
-		console.println("Flex in use:\t" + "Low= " + amountLow + "\tMedium= " + amountMedium + "\tHigh= " + amountHigh + "\tEssential= " + amountEssential);
-		//Total cost:
-		console.println("Total Cost: "+ cost);
-		//Longest Cooldown
-		console.println("Max Cooldown: "+ maxCooldown);
-		//
-		
-	}
+  //Algo
+  protected int rounds = 1;
+  protected Console console = new Console();
+  protected boolean cancel = false;
+  //holeg interaction
+  protected Control control;
+  protected List<Double> runList = new LinkedList<Double>();
+  protected boolean useStepping = false;
+  LinkedList<List<Boolean>> resetChain = new LinkedList<List<Boolean>>();
+  boolean algoUseElements = false, algoUseSwitches = true, algoUseFlexes = true, algoUseKillSwitch = true;
+  //Parameter
+  @SuppressWarnings("rawtypes")
+  LinkedList<ParameterStepping> parameterSteppingList = new LinkedList<ParameterStepping>();
+  ObjectiveFunction evaluationFunction = ObjectiveFunction.Normal;
+  //Panel
+  private JPanel content = new JPanel();
+  private JPanel borderPanel = new JPanel();
+  //Settings groupNode
+  private Optional<GroupNode> groupNode = Optional.empty();
+  //access
+  private ArrayList<AccessWrapper> access;
+  private HashMap<HolonObject, AccessWrapper> accessKillSwitch = new HashMap<HolonObject, AccessWrapper>();
+  //time
+  private long startTime;
+  private RunProgressBar runProgressbar = new RunProgressBar();
+  //concurrency
+  private Thread runThread = new Thread();
+  //printing
+  private Printer runPrinter = new Printer(plottFileName());
+  private RunAverage avg = new RunAverage();
+  //Email
+  private boolean useEmailNotification = false;
 
 
+  ;
+  public AlgorithmFrameworkFlex() {
+    content.setLayout(new BorderLayout());
+    JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
+        createOptionPanel(), console);
+    splitPane.setResizeWeight(0.0);
+    content.add(splitPane, BorderLayout.CENTER);
+    content.setPreferredSize(new Dimension(1200, 800));
+  }
 
 
+  private JPanel createOptionPanel() {
+    JPanel optionPanel = new JPanel(new BorderLayout());
+    JScrollPane scrollPane = new JScrollPane(createParameterPanel());
+    scrollPane.setBorder(BorderFactory.createTitledBorder("Parameter"));
+    optionPanel.add(scrollPane, BorderLayout.CENTER);
+    optionPanel.add(createButtonPanel(), BorderLayout.PAGE_END);
+    return optionPanel;
+  }
 
 
+  private Component createParameterPanel() {
+    JPanel parameterPanel = new JPanel(null);
+    parameterPanel.setPreferredSize(new Dimension(510, 300));
+    borderPanel.setLayout(new BoxLayout(borderPanel, BoxLayout.PAGE_AXIS));
+    addIntParameter("Rounds", rounds, intInput -> rounds = intInput, () -> rounds, 1);
+    JScrollPane scrollPane = new JScrollPane(borderPanel);
+    scrollPane.setBounds(10, 0, 850, 292);
+    scrollPane.setBorder(BorderFactory.createEmptyBorder());
+    parameterPanel.add(scrollPane);
 
 
+    JButton selectGroupNodeButton = new JButton("Select GroupNode");
+    selectGroupNodeButton.setBounds(900, 0, 185, 30);
+    selectGroupNodeButton.addActionListener(actionEvent -> selectGroupNode());
+    parameterPanel.add(selectGroupNodeButton);
+    JProgressBar progressBar = runProgressbar.getJProgressBar();
+    progressBar.setBounds(900, 35, 185, 20);
+    progressBar.setStringPainted(true);
+    parameterPanel.add(progressBar);
 
 
+    JCheckBox useElements = new JCheckBox("Elements");
+    useElements.setSelected(algoUseElements);
+    useElements.setBounds(900, 70, 185, 20);
+    useElements.addActionListener(actionEvent -> algoUseElements = useElements.isSelected());
+    parameterPanel.add(useElements);
 
 
-	protected abstract Individual executeAlgo();
+    JCheckBox useSwitches = new JCheckBox("Switches");
+    useSwitches.setSelected(algoUseSwitches);
+    useSwitches.setBounds(900, 90, 185, 20);
+    useSwitches.addActionListener(actionEvent -> algoUseSwitches = useSwitches.isSelected());
+    parameterPanel.add(useSwitches);
 
 
+    JCheckBox useFlexes = new JCheckBox("Flexibilities");
+    useFlexes.setSelected(algoUseFlexes);
+    useFlexes.setBounds(900, 110, 185, 20);
+    useFlexes.addActionListener(actionEvent -> algoUseFlexes = useFlexes.isSelected());
+    parameterPanel.add(useFlexes);
 
 
+    JCheckBox useSmartMeter = new JCheckBox("SmartMeter");
+    useSmartMeter.setSelected(algoUseFlexes);
+    useSmartMeter.setBounds(900, 130, 185, 20);
+    useSmartMeter.addActionListener(actionEvent ->
+    {
+      cancel();
+      reset();
+      algoUseKillSwitch = useSmartMeter.isSelected();
+    });
+    parameterPanel.add(useSmartMeter);
 
 
+    String[] objectiveFunctionStrings = {"Normal", "Switch"};
+    JLabel fitnessLabel = new JLabel("FitnessFunction:");
+    fitnessLabel.setBounds(910, 160, 90, 20);
+    parameterPanel.add(fitnessLabel);
+    JComboBox<String> ofBox = new JComboBox<String>(objectiveFunctionStrings);
+    ofBox.addActionListener(actionEvent ->
+    {
+      boolean pickNormal = ((String) ofBox.getSelectedItem()).equals("Normal");
+      evaluationFunction = pickNormal ? ObjectiveFunction.Normal : ObjectiveFunction.Switch;
+    });
+    ofBox.setBounds(1000, 160, 70, 20);
+    parameterPanel.add(ofBox);
 
 
+    JCheckBox emailNotificationCheckbox = new JCheckBox("EmailNotification");
+    emailNotificationCheckbox.setSelected(this.useEmailNotification);
+    emailNotificationCheckbox.setBounds(900, 200, 130, 20);
+    emailNotificationCheckbox.addActionListener(
+        actionEvent -> useEmailNotification = emailNotificationCheckbox.isSelected());
+    parameterPanel.add(emailNotificationCheckbox);
 
 
+    JButton emailSettingsButton = new JButton("",
+        new ImageIcon(Import.loadImage(ImagePreference.Button.Settings, 16, 16)));
+    emailSettingsButton.setBounds(1030, 200, 20, 20);
+    emailSettingsButton.addActionListener(event -> {
+      EmailNotification.OpenEmailSettings(content);
+    });
+    parameterPanel.add(emailSettingsButton);
 
 
-	private void reset() {
-		if(runThread.isAlive()) {
-			console.println("Run have to be cancelled First.");
-			return;
-		}
-		if(!resetChain.isEmpty()) {
-			console.println("Resetting..");
-			setState(resetChain.getFirst());
-			resetChain.clear();
-			control.resetSimulation();
-			control.getModel().setCurrentIteration(0);
-			updateVisual();
-		}else {
-			console.println("No run inistialized.");
-		}
-	}
-
-
-	/**
-	 * To let the User See the current state without touching the Canvas.
-	 */
-	private void updateVisual() {
-		control.calculateStateForCurrentIteration();
-	}
-	/**
-	 * Sets the Model back to its original State before the LAST run.
-	 */
-	private void resetState() {
-		setState(resetChain.getLast());
-	}
-
-
-	/**
-	 * Sets the State out of the given position for calculation or to show the user.
-	 * @param position
-	 */
-	private void setState(List<Boolean> position) {
-		control.resetSimulation();
-		int i = 0;
-		for(Boolean bool: position) {
-			access.get(i++).setState(bool);
-		}
-		control.calculateStateForCurrentIteration();
-}
+    return parameterPanel;
+  }
 
 
+  private JPanel createButtonPanel() {
+    JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
 
 
-	/**
-	 * Method to get the current Position alias a ListOf Booleans for aktive settings on the Objects on the Canvas.
-	 * Also initialize the Access Hashmap to swap faster positions.
-	 * @return
-	 */
-	protected List<Boolean> extractPositionAndAccess() {
-		Model model = control.getModel();
-		this.accessKillSwitch = new HashMap<HolonObject, AccessWrapper>();
-		access= new ArrayList<AccessWrapper>();
-		List<Boolean> initialState = new ArrayList<Boolean>();
-		rollOutNodes(initialState);			
-		resetChain.add(initialState);
-		if(algoUseFlexes) {		
-			List<Flexibility> flexList = model.getAllFlexibilities();
-			List<Flexibility> allOfferedFLex = flexList.stream().filter(flex -> flex.getState() == FlexState.OFFERED).toList();
-			for(Flexibility flex :allOfferedFLex){
-				//flex.getFlex().getElement().parentObject;
-				AccessWrapper killSwitchAccess = this.algoUseKillSwitch ? this.accessKillSwitch.get(flex.getElement().parentObject): null;;
-				access.add(new AccessWrapper(flex, killSwitchAccess));
-				initialState.add(false);
-			}
-			List<Flexibility> allInUseFLex = flexList.stream().filter(flex -> flex.getState() == FlexState.IN_USE).toList();
-			for(Flexibility flex : allInUseFLex){
-				AccessWrapper killSwitchAccess = this.algoUseKillSwitch ? this.accessKillSwitch.get(flex.getElement().parentObject): null;
-				access.add(new AccessWrapper(flex, killSwitchAccess));
-				initialState.add(true);
-			}
-		}
-		//console.println(access.stream().map(Object::toString).collect(Collectors.joining(", ")));
-		return initialState;
-	}
-	
-	
-	
-
-	private void rollOutNodes(List<Boolean> positionToInit) {
-		boolean groupNodeSelected = groupNode.isPresent();
-		int timeStep = control.getModel().getCurrentIteration();
-		Stream<HolonObject> holonObjects = groupNodeSelected ? groupNode.get().getAllHolonObjectsRecursive() : control.getModel().getCanvas().getAllHolonObjectsRecursive();
-		Stream<HolonSwitch> holonSwitches = groupNodeSelected ? groupNode.get().getAllSwitchObjectsRecursive(): control.getModel().getCanvas().getAllSwitchObjectsRecursive();
-		holonObjects.forEach(hObject -> {
-			AccessWrapper killSwitchAccess = new AccessWrapper(hObject);
-			if(this.algoUseKillSwitch) {
-				positionToInit.add(false);
-				access.add(killSwitchAccess);
-				accessKillSwitch.put(hObject, killSwitchAccess);					
-			}
-			if(this.algoUseElements) {
-				hObject.elementsStream().forEach(hE -> {
-					positionToInit.add(hE.active);
-					access.add(new AccessWrapper(hE, killSwitchAccess));
-				});
-			}
-		});
-		
-		holonSwitches.forEach(sw -> {
-			positionToInit.add(sw.getState().isClosed());
-			access.add(new AccessWrapper(sw));
-		});
-	}
-	
-
-	
-
-	private RunValues getRunValuesFromActualState() {
-		RunValues val = new RunValues();
-
-		GroupNode canvas = control.getModel().getCanvas();
-		List<HolonObject> holonObjectList = canvas.getAllHolonObjectsRecursive().toList();
-		Map<HolonObject.HolonObjectState, Long> stateMap = holonObjectList.stream().collect(Collectors.groupingBy(HolonObject::getState, Collectors.counting()));
-		// UPDATE SUPPLY STATE
-		val.producer = Math.toIntExact(stateMap.getOrDefault(HolonObject.HolonObjectState.PRODUCER, 0L));
-		val.overSupplied = Math.toIntExact(stateMap.getOrDefault(HolonObject.HolonObjectState.OVER_SUPPLIED, 0L));
-		val.supplied = Math.toIntExact(stateMap.getOrDefault(HolonObject.HolonObjectState.SUPPLIED, 0L));
-		val.partiallySupplied = Math.toIntExact(stateMap.getOrDefault(HolonObject.HolonObjectState.PARTIALLY_SUPPLIED, 0L));
-		val.unsupplied = Math.toIntExact(stateMap.getOrDefault(HolonObject.HolonObjectState.NOT_SUPPLIED, 0L));
-		val.passiv = Math.toIntExact(stateMap.getOrDefault(HolonObject.HolonObjectState.NO_ENERGY, 0L));
-		val.consumer = val.overSupplied + val.supplied + val.partiallySupplied + val.unsupplied;
-		val.objects = val.consumer + val.producer + val.passiv;
-
-		List<HolonElement> holonElementList = canvas.getAllHolonElements().toList();
-		val.elements = holonElementList.size();
-		// UPDATE ActiveInActive
-		val.activeElements = holonElementList.stream().filter(HolonElement::isOn).count();
-		val.consumption = canvas.getTotalConsumption();
-		val.production = canvas.getTotalProduction();
-		val.difference= Math.abs(val.production - val.consumption);
-
-		List<Flexibility> activeFlex = holonElementList.stream().flatMap(ele -> ele.flexList.stream()).filter(flex -> flex.getState().equals(FlexState.IN_USE)).toList();
-		Map<HolonElement.Priority, Long> priorityCounts = activeFlex.stream().collect(Collectors.groupingBy(flex -> flex.getElement().priority, Collectors.counting()));
-		val.essentialFlex = priorityCounts.getOrDefault(HolonElement.Priority.Essential, 0L);
-		val.highFlex = priorityCounts.getOrDefault(HolonElement.Priority.High, 0L);
-		val.mediumFlex = priorityCounts.getOrDefault(HolonElement.Priority.Medium, 0L);
-		val.lowFlex = priorityCounts.getOrDefault(HolonElement.Priority.Low, 0L);
-
-		val.flexebilities = activeFlex.size();
-		val.holon = control.getModel().holons.size();
-		List<HolonSwitch> switchList = canvas.getAllSwitchObjectsRecursive().toList();
-		val.switches = switchList.size();
-		val.activeSwitches = (int)switchList.stream().filter(HolonSwitch::isClosed).count();
-
-		DoubleSummaryStatistics overStat = holonObjectList.stream().filter(con -> con.getState().equals(HolonObject.HolonObjectState.OVER_SUPPLIED))
-				.mapToDouble(HolonObject::getSupplyBarPercentage).summaryStatistics();
-
-		DoubleSummaryStatistics partiallyStat = holonObjectList.stream().filter(con -> con.getState().equals(HolonObject.HolonObjectState.PARTIALLY_SUPPLIED))
-				.mapToDouble(HolonObject::getSupplyBarPercentage).summaryStatistics();
-
-		val.partiallyMin = RunValues.filterInf(partiallyStat.getMin());
-		val.partiallyMax = RunValues.filterInf(partiallyStat.getMax());
-		val.partiallyAverage = RunValues.filterInf(partiallyStat.getAverage());
-
-		val.overMin = RunValues.filterInf(overStat.getMin());
-		val.overMax = RunValues.filterInf(overStat.getMax());
-		val.overAverage = RunValues.filterInf(overStat.getAverage());
-		return val;
-	}
-	
-	
-
-	
-	private String stringStatFromRunValues(RunValues val){
-		return val.stringStatFromRunValues("");
-	}
-	
-
-	
-	
-
-	
-
-	
-	@Override
-	public JPanel getPanel() {
-		return content;
-	}
-
-	@Override
-	public void setController(Control control) {
-		this.control = control;
-	}
-	
-	
-	
-	private class RunProgressBar{
-		//progressbar
-		private JProgressBar progressBar = new JProgressBar();
-		private int count = 0;
-		private boolean isActive = false;
-		
-		public void step() {
-			if(isActive) progressBar.setValue(count++);
-		}
-		public void start() {
-			progressBar.setIndeterminate(false);
-			count = 0;
-			isActive = true;
-			progressBar.setValue(0);
-			progressBar.setMaximum(getProgressBarMaxCount());
-		}
-		public void cancel() {
-			isActive = false;
-			progressBar.setIndeterminate(true);
-		}
-		public void finishedCancel() {
-			progressBar.setIndeterminate(false);
-			progressBar.setValue(0);
-		}
-		public JProgressBar getJProgressBar(){
-			return progressBar;
-		}
-	}
-	
-	protected abstract int getProgressBarMaxCount();
-	
-	protected abstract String algoInformationToPrint();
-	protected abstract String plottFileName();
-	
-	
-	
-	public class Printer{
-		private JFileChooser fileChooser = new JFileChooser();
-		private BufferedWriter out;
-		public Printer(String filename){
-			fileChooser.setCurrentDirectory(new File(System.getProperty("user.dir")));
-			fileChooser.setSelectedFile(new File(filename));
-		}
-		public void openStream() {
-			File file = fileChooser.getSelectedFile();
-			try {
-				file.createNewFile();
-				out = new BufferedWriter(new OutputStreamWriter(
-					    new FileOutputStream(file, true), "UTF-8"));
-			} catch (IOException e) {
-				System.out.println(e.getMessage());
-			}
-		}
-		
-		
-		public void println(String stringToPrint) {
-			try {
-				out.write(stringToPrint);
-				out.newLine();
-			} catch (IOException e) {
-				System.out.println(e.getMessage());
-			}
-		}
-		public void closeStream() {
-			try {
-				out.close();
-			} catch (IOException e) {
-				System.out.println(e.getMessage());
-			}
-		}
-	}
-		
-	
-	static class RunValues{
-		public double result;
-		public double executionTime;
-		
-		public double objects;
-		public double passiv;
-		public double consumer;
-		public double supplied;
-		public double producer;
-		public double unsupplied;
-		public double partiallySupplied;
-		public double overSupplied;
-
-		public double partiallyMin;
-		public double partiallyMax;
-		public double partiallyAverage;
-		public double overMin;
-		public double overMax;
-		public double overAverage;
-		
-		public double activeElements;
-		public double elements;
-		
-		public double essentialFlex;
-		public double highFlex;
-		public double mediumFlex;
-		public double lowFlex;
-		public double flexebilities;
-		
-		public double switches;
-		public double activeSwitches;
-		
-		public double holon;
-		public double consumption;
-		public double production;
-		public double difference;
-
-		public static double filterInf(double value) {
-			if(value == Double.NEGATIVE_INFINITY || value == Double.POSITIVE_INFINITY || Double.isNaN(value)) {
-				return 0;
-			}else {
-				return value;
-			}
-		}
-		public static String percentage(double numerator , double denominator) {
-			if((int)denominator == 0) {
-				return "-%";
-			}
-			return  Format.doubleTwoPlaces(numerator)   + "/" + Format.doubleTwoPlaces(denominator) + " "+ Format.doubleFixedPlaces(2,(float)numerator /(float)denominator * 100) + "%";
-		}
+    JButton resetButton = new JButton("Reset");
+    resetButton.setToolTipText("Resets the state to the initial grid configuration.");
+    resetButton.addActionListener(actionEvent -> reset());
+    buttonPanel.add(resetButton);
 
 
-		public String stringStatFromRunValues(String prefix) {
-			return	prefix +"Passiv: " + percentage(passiv, objects)
-					+ " " + prefix +"Producer: " + percentage(producer, objects)
-					+ " " +	prefix +"Consumer: " + percentage(consumer, objects)
-					+ " " +	prefix +"Unsupplied: " + percentage(unsupplied, objects)
-					+ " " +	prefix +"Partially: " + percentage(partiallySupplied, objects)
-					+ " " +	prefix +"Over: " + percentage(overSupplied, objects)
-					+ " " +	prefix +"Supplied: " + percentage(supplied, objects)
-					+ " " +	prefix +"Partially.SupplyPercentage.Min: " + Format.doubleFixedPlaces(2, partiallyMin)
-					+ " " +	prefix +"Partially.SupplyPercentage.Max: "+ Format.doubleFixedPlaces(2, partiallyMax)
-					+ " " +	prefix +"Partially.SupplyPercentage.Average: " + Format.doubleFixedPlaces(2, partiallyAverage)
-					+ " " + prefix +"Over.SupplyPercentage.Min: " + Format.doubleFixedPlaces(2, overMin)
-					+ " " +	prefix +"Over.SupplyPercentage.Max: "+ Format.doubleFixedPlaces(2, overMax)
-					+ " " +	prefix +"Over.SupplyPercentage.Average: " + Format.doubleFixedPlaces(2, overAverage)
-					+ " " +	prefix +"HolonElemnts.Active:" + percentage(activeElements, elements)
-					+ " " +	prefix +"Flexibilities.Essential: " + percentage(essentialFlex, flexebilities)
-					+ " " + prefix +"Flexibilities.High: " + percentage(highFlex, flexebilities)
-					+ " " +	prefix +"Flexibilities.Medium: " + percentage(mediumFlex, flexebilities)
-					+ " " +	prefix +"Flexibilities.Low: " + percentage(lowFlex, flexebilities)
-					+ " " +	prefix +"Switches.Active:" + percentage(activeSwitches,switches)
-					+ " " +	prefix +"Holons: " + holon
-					+ " " + prefix +"TotalConsumption: " + consumption
-					+ " " + prefix +"TotalProduction: " + production
-					+ " " + prefix +"Difference: " + difference;
+    JButton cancelButton = new JButton("Cancel Run");
+    cancelButton.addActionListener(actionEvent -> cancel());
+    buttonPanel.add(cancelButton);
 
 
-		}
-	}
-	
-	
-	private class RunAverage{
-		private int runCount = 0;
-		//Values
-		private RunValues sum = new RunValues();
-		
-		public void addRun(RunValues val) {
-			sum.result += val.result;
-			sum.executionTime += val.executionTime;
-			sum.passiv += val.passiv;
-			sum.consumer += val.consumer;
-			sum.producer += val.producer;
-			sum.unsupplied += val.unsupplied;
-			sum.partiallySupplied += val.partiallySupplied;
-			sum.overSupplied += val.overSupplied;
-			sum.activeElements += val.activeElements;
-			sum.elements += val.elements;
-			sum.essentialFlex += val.essentialFlex;
-			sum.highFlex += val.highFlex;
-			sum.mediumFlex += val.mediumFlex;
-			sum.lowFlex += val.lowFlex;
-			sum.flexebilities += val.flexebilities;
-			sum.holon += val.holon;
-			sum.switches += val.switches;
-			sum.activeSwitches += val.activeSwitches;
-			sum.consumption += val.consumption;
-			sum.production += val.production;
-			sum.difference += val.difference;
-			sum.objects += val.objects;
-			sum.supplied += val.supplied;
-			sum.partiallyMin += val.partiallyMin;
-			sum.partiallyMax += val.partiallyMax;
-			sum.partiallyAverage += val.partiallyAverage;
-			sum.overMin += val.overMin;
-			sum.overMax += val.overMax;
-			sum.overAverage += val.overAverage;
-			
-			runCount++;
-		}
-		public RunValues getAverage() {
-			RunValues avg = new RunValues();
-			if(runCount == 0) {
-				return avg;
-			}
-			avg.result = sum.result / runCount;
-			avg.executionTime = sum.executionTime / runCount;
-			avg.passiv = sum.passiv / runCount;
-			avg.consumer = sum.consumer / runCount;
-			avg.producer = sum.producer / runCount;
-			avg.unsupplied = sum.unsupplied / runCount;
-			avg.partiallySupplied = sum.partiallySupplied / runCount;
-			avg.overSupplied = sum.overSupplied / runCount;
-			avg.activeElements = sum.activeElements / runCount;
-			avg.elements = sum.elements / runCount;
-			avg.essentialFlex = sum.essentialFlex / runCount;
-			avg.highFlex = sum.highFlex / runCount;
-			avg.mediumFlex = sum.mediumFlex / runCount;
-			avg.lowFlex = sum.lowFlex / runCount;
-			avg.flexebilities = sum.flexebilities / runCount;
-			avg.holon = sum.holon / runCount;
-			avg.switches = sum.switches / runCount;
-			avg.activeSwitches = sum.activeSwitches / runCount;
-			avg.consumption = sum.consumption / runCount;
-			avg.production = sum.production / runCount;
-			avg.difference = sum.difference / runCount;
-			avg.objects = sum.objects / runCount;
-			avg.supplied = sum.supplied / runCount;
-			avg.supplied = sum.supplied / runCount;	
-			avg.partiallyMin = sum.partiallyMin / runCount;
-			avg.partiallyMax = sum.partiallyMax / runCount;
-			avg.partiallyAverage = sum.partiallyAverage / runCount;
-			avg.overMin = sum.overMin / runCount;
-			avg.overMax = sum.overMax / runCount;
-			avg.overAverage = sum.overAverage / runCount;		
-			return avg;
-		}
-	}
-	
-	
-	private enum AccessType {None, HolonElement, Switch, Flexibility, KillSwitch};
-	/**
-	 * A Wrapper Class for Access HolonElement and HolonSwitch in one Element and not have to split the List.
-	 */
-	private class AccessWrapper {
-		private AccessType type;
-		private List<Boolean> intialStatesOfElementForKilllSwitch;
-		
-		private HolonObject hObject;
-		private HolonSwitch hSwitch;
-		
-		private HolonElement hElement;
-		private Flexibility flex;
-		private AccessWrapper correspondingKillSwitch;
-		
-		private boolean lastState;
-		
-		
-		public AccessWrapper(HolonObject hObject){
-			type = AccessType.KillSwitch;
-			this.hObject = hObject;
-			intialStatesOfElementForKilllSwitch = new ArrayList<Boolean>();
-			hObject.elementsStream().forEach(hE -> {
-				intialStatesOfElementForKilllSwitch.add(hE.active);
-			});
-		}
-		public AccessWrapper(HolonSwitch hSwitch){
-			type = AccessType.Switch;
-			this.hSwitch = hSwitch;
-		}
-		public AccessWrapper(HolonElement hElement, AccessWrapper correspondingKillSwitch){
-			type = AccessType.HolonElement;
-			this.hElement = hElement;
-			this.correspondingKillSwitch = correspondingKillSwitch;
-		}
-		
-		public AccessWrapper(Flexibility flex, AccessWrapper correspondingKillSwitch){
-			type = AccessType.Flexibility;
-			this.flex = flex;
-			this.correspondingKillSwitch = correspondingKillSwitch;
-		}
-		
-		public void setState(boolean state) {
-			lastState = state;
-			switch(type) {
-				case  HolonElement:
-					if(!algoUseKillSwitch || (algoUseKillSwitch && !correspondingKillSwitch.getLastState())) {
-						hElement.active = state;
-					}
-					break;
-				case Switch:
-					hSwitch.setMode(SwitchMode.Manual);
-					hSwitch.setManualState(state ? SwitchState.Closed: SwitchState.Open);
-					break;
-				case Flexibility:
-					if(state && (!algoUseKillSwitch || (algoUseKillSwitch && !correspondingKillSwitch.getLastState()))) {
-						flex.order();
-					}
-					break;
-				case KillSwitch:
-					if(state) {
-						hObject.elementsStream().forEach(hE -> {
-							hE.active = false;
-						});
-					}else {
-						List<HolonElement> eleList = hObject.elementsStream().toList();
-						for(int i = 0; i < eleList.size(); i++) {
-							eleList.get(i).active = intialStatesOfElementForKilllSwitch.get(i);
-						}
-					}
+    JButton fitnessButton = new JButton("Evaluate");
+    fitnessButton.setToolTipText("Evaluate the current grid configuration.");
+    fitnessButton.addActionListener(actionEvent -> fitness());
+    buttonPanel.add(fitnessButton);
+
+    JButton runButton = new JButton("Run");
+    runButton.addActionListener(actionEvent -> {
+      Runnable task = () -> run();
+      runThread = new Thread(task);
+      runThread.start();
+    });
+    buttonPanel.add(runButton);
+
+    return buttonPanel;
+  }
+
+  //int
+  protected void addIntParameter(String parameterName, int parameterValue, Consumer<Integer> setter,
+      Supplier<Integer> getter) {
+    this.addIntParameter(parameterName, parameterValue, setter, getter, Integer.MIN_VALUE,
+        Integer.MAX_VALUE);
+  }
+
+  //ParameterImports
+
+  protected void addIntParameter(String parameterName, int parameterValue, Consumer<Integer> setter,
+      Supplier<Integer> getter, int parameterMinValue) {
+    this.addIntParameter(parameterName, parameterValue, setter, getter, parameterMinValue,
+        Integer.MAX_VALUE);
+  }
+
+  protected void addIntParameter(String parameterName, int parameterValue, Consumer<Integer> setter,
+      Supplier<Integer> getter, int parameterMinValue, int parameterMaxValue) {
+    JPanel singleParameterPanel = new JPanel();
+    singleParameterPanel.setLayout(new BoxLayout(singleParameterPanel, BoxLayout.LINE_AXIS));
+    singleParameterPanel.setAlignmentX(0.0f);
+    singleParameterPanel.add(new JLabel(parameterName + ": "));
+    singleParameterPanel.add(Box.createHorizontalGlue());
+    NumberFormat format = NumberFormat.getIntegerInstance();
+    format.setGroupingUsed(false);
+    format.setParseIntegerOnly(true);
+    NumberFormatter integerFormatter = new NumberFormatter(format);
+    integerFormatter.setMinimum(parameterMinValue);
+    integerFormatter.setMaximum(parameterMaxValue);
+    integerFormatter.setCommitsOnValidEdit(true);
+    JFormattedTextField singleParameterTextField = new JFormattedTextField(integerFormatter);
+    singleParameterTextField.setValue(parameterValue);
+    String minValue = (parameterMinValue == Integer.MIN_VALUE) ? "Integer.MIN_VALUE"
+        : String.valueOf(parameterMinValue);
+    String maxValue = (parameterMaxValue == Integer.MAX_VALUE) ? "Integer.MAX_VALUE"
+        : String.valueOf(parameterMaxValue);
+    singleParameterTextField.setToolTipText(
+        "Only integer \u2208 [" + minValue + "," + maxValue + "]");
+    singleParameterTextField.addPropertyChangeListener(actionEvent -> setter.accept(
+        Integer.parseInt(singleParameterTextField.getValue().toString())));
+    singleParameterTextField.setMaximumSize(new Dimension(200, 30));
+    singleParameterTextField.setPreferredSize(new Dimension(200, 30));
+    singleParameterPanel.add(singleParameterTextField);
+
+    ParameterStepping<Integer> intParameterStepping = new ParameterStepping<Integer>(setter, getter,
+        Integer::sum, (a, b) -> a * b, 1, 1);
+    intParameterStepping.useThisParameter = false;
+    parameterSteppingList.add(intParameterStepping);
+
+    JCheckBox useSteppingCheckBox = new JCheckBox();
+    useSteppingCheckBox.setSelected(false);
+    singleParameterPanel.add(useSteppingCheckBox);
+
+    JLabel stepsLabel = new JLabel("Steps: ");
+    stepsLabel.setEnabled(false);
+    singleParameterPanel.add(stepsLabel);
+
+    NumberFormatter stepFormatter = new NumberFormatter(format);
+    stepFormatter.setMinimum(1);
+    stepFormatter.setMaximum(Integer.MAX_VALUE);
+    stepFormatter.setCommitsOnValidEdit(true);
+
+    JFormattedTextField stepsTextField = new JFormattedTextField(stepFormatter);
+    stepsTextField.setEnabled(false);
+    stepsTextField.setValue(1);
+    stepsTextField.setToolTipText("Only integer \u2208 [" + 1 + "," + Integer.MAX_VALUE + "]");
+    stepsTextField.addPropertyChangeListener(
+        actionEvent -> intParameterStepping.stepps = Integer.parseInt(
+            stepsTextField.getValue().toString()));
+    stepsTextField.setMaximumSize(new Dimension(40, 30));
+    stepsTextField.setPreferredSize(new Dimension(40, 30));
+    singleParameterPanel.add(stepsTextField);
+
+    JLabel stepsSizeLabel = new JLabel("Step size: ");
+    stepsSizeLabel.setEnabled(false);
+    singleParameterPanel.add(stepsSizeLabel);
+
+    JFormattedTextField stepsSizeTextField = new JFormattedTextField(stepFormatter);
+    stepsSizeTextField.setEnabled(false);
+    stepsSizeTextField.setValue(1);
+    stepsSizeTextField.setToolTipText("Only integer \u2208 [" + 1 + "," + Integer.MAX_VALUE + "]");
+    stepsSizeTextField.addPropertyChangeListener(
+        actionEvent -> intParameterStepping.stepSize = Integer.parseInt(
+            stepsSizeTextField.getValue().toString()));
+    stepsSizeTextField.setMaximumSize(new Dimension(40, 30));
+    stepsSizeTextField.setPreferredSize(new Dimension(40, 30));
+    singleParameterPanel.add(stepsSizeTextField);
+
+    useSteppingCheckBox.addActionListener(actionEvent -> {
+      boolean enabled = useSteppingCheckBox.isSelected();
+      intParameterStepping.useThisParameter = enabled;
+      this.useStepping = this.parameterSteppingList.stream()
+          .anyMatch(parameter -> parameter.useThisParameter);
+      stepsLabel.setEnabled(enabled);
+      stepsTextField.setEnabled(enabled);
+      stepsSizeLabel.setEnabled(enabled);
+      stepsSizeTextField.setEnabled(enabled);
+    });
+
+    borderPanel.add(singleParameterPanel);
+  }
+
+  //double
+  protected void addDoubleParameter(String parameterName, double parameterValue,
+      Consumer<Double> setter, Supplier<Double> getter) {
+    this.addDoubleParameter(parameterName, parameterValue, setter, getter, Double.MIN_VALUE,
+        Double.MAX_VALUE);
+  }
+
+  protected void addDoubleParameter(String parameterName, double parameterValue,
+      Consumer<Double> setter, Supplier<Double> getter, double parameterMinValue) {
+    this.addDoubleParameter(parameterName, parameterValue, setter, getter, parameterMinValue,
+        Double.MAX_VALUE);
+  }
+
+  protected void addDoubleParameter(String parameterName, double parameterValue,
+      Consumer<Double> setter, Supplier<Double> getter, double parameterMinValue,
+      double parameterMaxValue) {
+    JPanel singleParameterPanel = new JPanel();
+    singleParameterPanel.setLayout(new BoxLayout(singleParameterPanel, BoxLayout.LINE_AXIS));
+    singleParameterPanel.setAlignmentX(0.0f);
+    singleParameterPanel.add(new JLabel(parameterName + ": "));
+    singleParameterPanel.add(Box.createHorizontalGlue());
+    NumberFormat doubleFormat = NumberFormat.getNumberInstance(Locale.US);
+    doubleFormat.setMinimumFractionDigits(1);
+    doubleFormat.setMaximumFractionDigits(10);
+    doubleFormat.setRoundingMode(RoundingMode.HALF_UP);
+    NumberFormatter doubleFormatter = new NumberFormatter(doubleFormat);
+    doubleFormatter.setMinimum(parameterMinValue);
+    doubleFormatter.setMaximum(parameterMaxValue);
+    doubleFormatter.setCommitsOnValidEdit(true);
+    JFormattedTextField singleParameterTextField = new JFormattedTextField(doubleFormatter);
+    singleParameterTextField.setValue(parameterValue);
+    String minValue = (parameterMinValue == Double.MIN_VALUE) ? "Double.MIN_VALUE"
+        : String.valueOf(parameterMinValue);
+    String maxValue = (parameterMaxValue == Double.MAX_VALUE) ? "Double.MAX_VALUE"
+        : String.valueOf(parameterMaxValue);
+    singleParameterTextField.setToolTipText(
+        "Only double \u2208 [" + minValue + "," + maxValue + "]");
+    singleParameterTextField.addPropertyChangeListener(actionEvent -> setter.accept(
+        Double.parseDouble(singleParameterTextField.getValue().toString())));
+    singleParameterTextField.setMaximumSize(new Dimension(200, 30));
+    singleParameterTextField.setPreferredSize(new Dimension(200, 30));
+    singleParameterPanel.add(singleParameterTextField);
+
+    ParameterStepping<Double> doubleParameterStepping = new ParameterStepping<Double>(setter,
+        getter, (a, b) -> a + b, (a, b) -> a * b, 1.0, 1);
+    doubleParameterStepping.useThisParameter = false;
+    parameterSteppingList.add(doubleParameterStepping);
+
+    JCheckBox useSteppingCheckBox = new JCheckBox();
+    useSteppingCheckBox.setSelected(false);
+    singleParameterPanel.add(useSteppingCheckBox);
+
+    JLabel stepsLabel = new JLabel("Steps: ");
+    stepsLabel.setEnabled(false);
+    singleParameterPanel.add(stepsLabel);
+    NumberFormat format = NumberFormat.getIntegerInstance();
+    format.setGroupingUsed(false);
+    format.setParseIntegerOnly(true);
+    NumberFormatter integerFormatter = new NumberFormatter(format);
+    integerFormatter.setMinimum(1);
+    integerFormatter.setMaximum(Integer.MAX_VALUE);
+    integerFormatter.setCommitsOnValidEdit(true);
+
+    JFormattedTextField stepsTextField = new JFormattedTextField(integerFormatter);
+    stepsTextField.setEnabled(false);
+    stepsTextField.setValue(1);
+    stepsTextField.setToolTipText("Only integer \u2208 [" + 1 + "," + Integer.MAX_VALUE + "]");
+    stepsTextField.addPropertyChangeListener(
+        actionEvent -> doubleParameterStepping.stepps = Integer.parseInt(
+            stepsTextField.getValue().toString()));
+    stepsTextField.setMaximumSize(new Dimension(40, 30));
+    stepsTextField.setPreferredSize(new Dimension(40, 30));
+    singleParameterPanel.add(stepsTextField);
+
+    JLabel stepsSizeLabel = new JLabel("Step size: ");
+    stepsSizeLabel.setEnabled(false);
+    singleParameterPanel.add(stepsSizeLabel);
+
+    NumberFormatter doubleFormatterForStepping = new NumberFormatter(doubleFormat);
+    doubleFormatterForStepping.setCommitsOnValidEdit(true);
+    JFormattedTextField stepsSizeTextField = new JFormattedTextField(doubleFormatterForStepping);
+    stepsSizeTextField.setEnabled(false);
+    stepsSizeTextField.setValue(1.0);
+    stepsSizeTextField.setToolTipText("Only double");
+    stepsSizeTextField.addPropertyChangeListener(
+        actionEvent -> doubleParameterStepping.stepSize = Double.parseDouble(
+            stepsSizeTextField.getValue().toString()));
+    stepsSizeTextField.setMaximumSize(new Dimension(40, 30));
+    stepsSizeTextField.setPreferredSize(new Dimension(40, 30));
+    singleParameterPanel.add(stepsSizeTextField);
+
+    useSteppingCheckBox.addActionListener(actionEvent -> {
+      boolean enabled = useSteppingCheckBox.isSelected();
+      doubleParameterStepping.useThisParameter = enabled;
+      this.useStepping = this.parameterSteppingList.stream()
+          .anyMatch(parameter -> parameter.useThisParameter);
+      stepsLabel.setEnabled(enabled);
+      stepsTextField.setEnabled(enabled);
+      stepsSizeLabel.setEnabled(enabled);
+      stepsSizeTextField.setEnabled(enabled);
+    });
+
+    borderPanel.add(singleParameterPanel);
+  }
+
+  //boolean
+  protected void addBooleanParameter(String parameterName, boolean parameterValue,
+      Consumer<Boolean> setter) {
+    JPanel singleParameterPanel = new JPanel();
+    singleParameterPanel.setLayout(new BoxLayout(singleParameterPanel, BoxLayout.LINE_AXIS));
+    singleParameterPanel.setAlignmentX(0.0f);
+    singleParameterPanel.add(new JLabel(parameterName + ": "));
+    singleParameterPanel.add(Box.createHorizontalGlue());
+    JCheckBox useGroupNodeCheckBox = new JCheckBox();
+    useGroupNodeCheckBox.setSelected(parameterValue);
+    useGroupNodeCheckBox.addActionListener(
+        actionEvent -> setter.accept(useGroupNodeCheckBox.isSelected()));
+    singleParameterPanel.add(useGroupNodeCheckBox);
+    borderPanel.add(singleParameterPanel);
+  }
+
+  private void startTimer() {
+    startTime = System.currentTimeMillis();
+  }
+
+  private long printElapsedTime() {
+    long elapsedMilliSeconds = System.currentTimeMillis() - startTime;
+    console.println("Execution Time in Milliseconds:" + elapsedMilliSeconds);
+    return elapsedMilliSeconds;
+  }
+
+  private void cancel() {
+    if (runThread.isAlive()) {
+      console.println("Cancel run.");
+      cancel = true;
+      runProgressbar.cancel();
+    } else {
+      console.println("Nothing to cancel.");
+    }
+  }
+
+  private void fitness() {
+    if (runThread.isAlive()) {
+      console.println("Run have to be cancelled first.");
+      return;
+    }
+    double currentFitness = evaluatePosition(extractPositionAndAccess());
+    resetChain.removeLast();
+    console.println("Actual Fitnessvalue: " + currentFitness);
+  }
+
+  private void selectGroupNode() {
+    Object[] possibilities = control.getModel().getCanvas().getAllGroupNodeObjectsRecursive()
+        .toArray();
+    @SuppressWarnings("unchecked")
+    GroupNode selected = (GroupNode) JOptionPane.showInputDialog(content, "Select GroupNode:",
+        "GroupNode?", JOptionPane.OK_OPTION,
+        new ImageIcon(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)), possibilities, "");
+    if (selected != null) {
+      console.println("Selected: " + selected);
+      groupNode = Optional.of(selected);
+    }
+  }
+
+  protected double evaluatePosition(List<Boolean> positionToEvaluate) {
+    runProgressbar.step();
+    setState(positionToEvaluate); // execution time critical
+    double result = evaluateState();
+    return result;
+  }
+
+  private double evaluateState() {
+    switch (this.evaluationFunction) {
+      case Switch:
+        return SwitchObjectiveFunction.getFitnessValueForState(control.getModel());
+      case Normal:
+      default:
+        return ObjectiveFunctionByCarlos.getFitnessValueForState(control.getModel());
+    }
+
+  }
+
+  private void run() {
+    cancel = false;
+    control.guiSetEnabled(false);
+    runPrinter.openStream();
+    runPrinter.println("");
+    runPrinter.println("Start:" + stringStatFromRunValues(getRunValuesFromActualState()));
+    runPrinter.closeStream();
+    if (this.useStepping) {
+      initParameterStepping();
+      do {
+        executeAlgoWithParameter();
+				if (cancel) {
 					break;
 					break;
-				default:
+				}
+        resetState();
+      } while (updateOneParameter());
+      resetParameterStepping();
+    } else {
+      executeAlgoWithParameter();
+
+    }
+    updateVisual();
+    runProgressbar.finishedCancel();
+    control.guiSetEnabled(true);
+    if (this.useEmailNotification && !cancel) {
+      EmailNotification.sendEmail(this.getClass().getName() + " finished", "Execution done.");
+    }
+  }
+
+  @SuppressWarnings("rawtypes")
+  private void initParameterStepping() {
+    for (ParameterStepping param : this.parameterSteppingList) {
+      param.init();
+    }
+
+  }
+
+  @SuppressWarnings("rawtypes")
+  private void resetParameterStepping() {
+    for (ParameterStepping param : this.parameterSteppingList) {
+      param.reset();
+    }
+
+  }
+
+  @SuppressWarnings("rawtypes")
+  private boolean updateOneParameter() {
+    List<ParameterStepping> parameterInUseList = this.parameterSteppingList.stream()
+        .filter(param -> param.useThisParameter).collect(Collectors.toList());
+    Collections.reverse(parameterInUseList);
+    int lastParameter = parameterInUseList.size() - 1;
+    int actualParameter = 0;
+    for (ParameterStepping param : parameterInUseList) {
+
+      if (param.canUpdate()) {
+        param.update();
+        return true;
+      } else {
+				if (actualParameter == lastParameter) {
 					break;
 					break;
-				
+				}
+        param.reset();
+      }
+      actualParameter++;
+    }
+    //No Param can be updated
+    return false;
+  }
+
+  private void executeAlgoWithParameter() {
+    double startFitness = evaluatePosition(extractPositionAndAccess());
+    console.println("BitLength: " + access.size());
+    resetChain.removeLast();
+    runPrinter.openStream();
+    runPrinter.println(algoInformationToPrint());
+    console.println(algoInformationToPrint());
+    runPrinter.closeStream();
+    runProgressbar.start();
+    Individual runBest = new Individual();
+    runBest.fitness = Double.MAX_VALUE;
+    this.avg = new RunAverage();
+    for (int r = 0; r < rounds; r++) {
+      startTimer();
+      Individual roundBest = executeAlgo();
+			if (cancel) {
+				return;
 			}
 			}
-		}
-		
-		public boolean getLastState() {
-			return lastState;
-		}
-		
-		public String typeString() {
-			switch(type) {
-				case HolonElement:
-					return "HolonElement";
-				case Switch:
-					return "Switch";
-				case Flexibility:
-					return "Flexibility";
-				case KillSwitch:
-					return "KillSwitch";
-				default:
-					return "unknown";
+      long executionTime = printElapsedTime();
+      setState(roundBest.position);
+      runPrinter.openStream();
+      runPrinter.println(runList.stream().map(value -> Format.doubleFixedPlaces(2, value))
+          .collect(Collectors.joining(", ")));
+      RunValues val = getRunValuesFromActualState();
+      val.result = roundBest.fitness;
+      val.executionTime = executionTime;
+      avg.addRun(val);
+      runPrinter.println(
+          "Result: " + Format.doubleFixedPlaces(2, roundBest.fitness) + " ExecutionTime:"
+              + executionTime + " " + stringStatFromRunValues(val));
+      runPrinter.closeStream();
+      resetState();
+			if (roundBest.fitness < runBest.fitness) {
+				runBest = roundBest;
 			}
 			}
+    }
+
+    this.extractPositionAndAccess();
+    setState(runBest.position);
+    updateVisual();
+    console.println("Start: " + Format.doubleFixedPlaces(2, startFitness));
+    console.println("AlgoResult: " + Format.doubleFixedPlaces(2, runBest.fitness));
+		if (this.algoUseFlexes) {
+			calculateAndPrintFlexInfos();
 		}
 		}
-		
-		public String toString() {
-			return "[" +  typeString() + "]";
-		}
-	}
-	
-	
-	
-	
-	/**
-	* To create Random and maybe switch the random generation in the future.
-	*/
-	protected static class Random{
-		private static java.util.Random random = new java.util.Random();
-		/**
-		 * True or false
-		 * @return the random boolean.
-		 */
-		public static boolean nextBoolean(){
-			return random.nextBoolean();
-		}
-		/**
-		 * Between 0.0(inclusive) and 1.0 (exclusive)
-		 * @return the random double.
-		 */
-		public static double nextDouble() {
-			return random.nextDouble();
-		}
-		
-		/**
-		 * Random Int in Range [min;max[ with UniformDistirbution
-		 * @param min
-		 * @param max
-		 * @return
-		 */
-		public static int nextIntegerInRange(int min, int max) {
-			int result = min;
-			try {
-				result = min + random.nextInt(max - min);
-			}catch(java.lang.IllegalArgumentException e){
-				System.err.println("min : " + min + " max : " + max);
-				System.err.println("max should be more then min");
+    runPrinter.openStream();
+    if (rounds > 1) {
+      RunValues avgRun = avg.getAverage();
+
+      runPrinter.println("Average.Result: " + Format.doubleFixedPlaces(2, avgRun.result)
+          + " Average.ExecutionTime:" + avgRun.executionTime + " " + avg.getAverage()
+          .stringStatFromRunValues("Average."));
+    }
+    runPrinter.println("");
+    runPrinter.closeStream();
+  }
+
+  private void calculateAndPrintFlexInfos() {
+    int amountOfUsedFlex = 0;
+    List<Flexibility> allFlex = control.getModel().getAllFlexibilities();
+    int amountOfFlex = allFlex.size();
+    float cost = 0;
+    int consumingFlex = 0;
+    float consumingFlexEnergy = 0.0f;
+    int producingFlex = 0;
+    float producingFlexEnergy = 0.0f;
+    int maxCooldown = 0;
+    int amountEssential = 0;
+    int amountHigh = 0;
+    int amountMedium = 0;
+    int amountLow = 0;
+    Stream<Flexibility> allFlexInUse = allFlex.stream()
+        .filter(flex -> flex.getState().equals(FlexState.IN_USE));
+    Iterator<Flexibility> iterInUseFlex = allFlexInUse.iterator();
+    while (iterInUseFlex.hasNext()) {
+      Flexibility flex = iterInUseFlex.next();
+      amountOfUsedFlex++;
+      cost += flex.cost;
+      float energy = flex.energyReleased();
+      if (energy < 0) {
+        consumingFlex++;
+        consumingFlexEnergy += -energy;
+      } else {
+        producingFlex++;
+        producingFlexEnergy += energy;
+      }
+			if (flex.getCooldown() > maxCooldown) {
+				maxCooldown = flex.getCooldown();
 			}
 			}
-			return result;
-		}
-	}
-	
-	private   class  Handle<T>{
-		public T object;
-		Handle(T object){
-			this.object = object;
-		}
-		public String toString() {
-			return object.toString();
-		}
-	}
-	public class Individual {
-		public double fitness;
-		public  List<Boolean> position;
-		
-		public Individual(){};
-		/**
-		 *  Copy Constructor
-		 */
-		public Individual(Individual c){
-			position = c.position.stream().collect(Collectors.toList());
-			fitness = c.fitness;
-		}
-		
-		String positionToString() {
-			return position.stream().map(bool -> (bool?"1":"0")).collect(Collectors.joining());
-		}
-	}
-	
-	protected class ParameterStepping<T>{
-		boolean useThisParameter = false;
-		String paramaterName;
-		private int count = 0;
-		int stepps;
-		T stepSize;
-		T startValue;
-		Consumer<T> setter;
-		Supplier<T> getter;
-		BiFunction<Integer,T,T> multyply;
-		BiFunction<T,T,T> add;
-		ParameterStepping(Consumer<T> setter, Supplier<T> getter, BiFunction<T,T,T> add, BiFunction<Integer,T,T> multyply, T stepSize, int stepps){
-			this.setter = setter;
-			this.getter = getter;
-			this.multyply = multyply;
-			this.add = add;
-			this.stepSize = stepSize;
-			this.stepps = stepps;
-		}
-		
-		void init() {
-			startValue = getter.get();
-		}
-		
-		boolean canUpdate() {
-			return count  < stepps;
-		}
-		
-		void update(){
-			if(canUpdate()) {
-				setter.accept(add.apply(startValue, multyply.apply(count + 1, stepSize)));
-				count ++;
+      switch (flex.getElement().getPriority()) {
+        case Essential:
+          amountEssential++;
+          break;
+        case High:
+          amountHigh++;
+          break;
+        case Low:
+          amountLow++;
+          break;
+        case Medium:
+          amountMedium++;
+          break;
+        default:
+          break;
+
+      }
+    }
+
+    //Total Flexibilities:
+    //Used Flexibilities:
+    console.println("Used Flex [" + amountOfUsedFlex + "/" + amountOfFlex + "]");
+
+    //Consuming Flexibilities:
+    console.println(
+        consumingFlex + " consuimg flexibilities that consumed " + consumingFlexEnergy + "Energy.");
+    //Producing Flexibilities
+    console.println(
+        producingFlex + " producing flexibilities that produce " + producingFlexEnergy + "Energy.");
+    console.println(
+        "Flex in use:\t" + "Low= " + amountLow + "\tMedium= " + amountMedium + "\tHigh= "
+            + amountHigh + "\tEssential= " + amountEssential);
+    //Total cost:
+    console.println("Total Cost: " + cost);
+    //Longest Cooldown
+    console.println("Max Cooldown: " + maxCooldown);
+    //
+
+  }
+
+  protected abstract Individual executeAlgo();
+
+  private void reset() {
+    if (runThread.isAlive()) {
+      console.println("Run have to be cancelled First.");
+      return;
+    }
+    if (!resetChain.isEmpty()) {
+      console.println("Resetting..");
+      setState(resetChain.getFirst());
+      resetChain.clear();
+      control.resetSimulation();
+      control.getModel().setCurrentIteration(0);
+      updateVisual();
+    } else {
+      console.println("No run inistialized.");
+    }
+  }
+
+  /**
+   * To let the User See the current state without touching the Canvas.
+   */
+  private void updateVisual() {
+    control.updateStateForCurrentIteration();
+  }
+
+  /**
+   * Sets the Model back to its original State before the LAST run.
+   */
+  private void resetState() {
+    setState(resetChain.getLast());
+  }
+
+  /**
+   * Sets the State out of the given position for calculation or to show the user.
+   *
+   * @param position
+   */
+  private void setState(List<Boolean> position) {
+    control.resetSimulation();
+    int i = 0;
+    for (Boolean bool : position) {
+      access.get(i++).setState(bool);
+    }
+    control.calculateStateForCurrentIteration();
+  }
+
+  /**
+   * Method to get the current Position alias a ListOf Booleans for aktive settings on the Objects
+   * on the Canvas. Also initialize the Access Hashmap to swap faster positions.
+   *
+   * @return
+   */
+  protected List<Boolean> extractPositionAndAccess() {
+    Model model = control.getModel();
+    this.accessKillSwitch = new HashMap<HolonObject, AccessWrapper>();
+    access = new ArrayList<AccessWrapper>();
+    List<Boolean> initialState = new ArrayList<Boolean>();
+    rollOutNodes(initialState);
+    resetChain.add(initialState);
+    if (algoUseFlexes) {
+      List<Flexibility> flexList = model.getAllFlexibilities();
+      List<Flexibility> allOfferedFLex = flexList.stream()
+          .filter(flex -> flex.getState() == FlexState.OFFERED).toList();
+      for (Flexibility flex : allOfferedFLex) {
+        //flex.getFlex().getElement().parentObject;
+        AccessWrapper killSwitchAccess =
+            this.algoUseKillSwitch ? this.accessKillSwitch.get(flex.getElement().parentObject)
+                : null;
+        ;
+        access.add(new AccessWrapper(flex, killSwitchAccess));
+        initialState.add(false);
+      }
+      List<Flexibility> allInUseFLex = flexList.stream()
+          .filter(flex -> flex.getState() == FlexState.IN_USE).toList();
+      for (Flexibility flex : allInUseFLex) {
+        AccessWrapper killSwitchAccess =
+            this.algoUseKillSwitch ? this.accessKillSwitch.get(flex.getElement().parentObject)
+                : null;
+        access.add(new AccessWrapper(flex, killSwitchAccess));
+        initialState.add(true);
+      }
+    }
+    //console.println(access.stream().map(Object::toString).collect(Collectors.joining(", ")));
+    return initialState;
+  }
+
+  private void rollOutNodes(List<Boolean> positionToInit) {
+    boolean groupNodeSelected = groupNode.isPresent();
+    int timeStep = control.getModel().getCurrentIteration();
+    Stream<HolonObject> holonObjects =
+        groupNodeSelected ? groupNode.get().getAllHolonObjectsRecursive()
+            : control.getModel().getCanvas().getAllHolonObjectsRecursive();
+    Stream<HolonSwitch> holonSwitches =
+        groupNodeSelected ? groupNode.get().getAllSwitchObjectsRecursive()
+            : control.getModel().getCanvas().getAllSwitchObjectsRecursive();
+    holonObjects.forEach(hObject -> {
+      AccessWrapper killSwitchAccess = new AccessWrapper(hObject);
+      if (this.algoUseKillSwitch) {
+        positionToInit.add(false);
+        access.add(killSwitchAccess);
+        accessKillSwitch.put(hObject, killSwitchAccess);
+      }
+      if (this.algoUseElements) {
+        hObject.elementsStream().forEach(hE -> {
+          positionToInit.add(hE.active);
+          access.add(new AccessWrapper(hE, killSwitchAccess));
+        });
+      }
+    });
+
+    holonSwitches.forEach(sw -> {
+      positionToInit.add(sw.getState().isClosed());
+      access.add(new AccessWrapper(sw));
+    });
+  }
+
+  private RunValues getRunValuesFromActualState() {
+    RunValues val = new RunValues();
+
+    GroupNode canvas = control.getModel().getCanvas();
+    List<HolonObject> holonObjectList = canvas.getAllHolonObjectsRecursive().toList();
+    Map<HolonObject.HolonObjectState, Long> stateMap = holonObjectList.stream()
+        .collect(Collectors.groupingBy(HolonObject::getState, Collectors.counting()));
+    // UPDATE SUPPLY STATE
+    val.producer = Math.toIntExact(
+        stateMap.getOrDefault(HolonObject.HolonObjectState.PRODUCER, 0L));
+    val.overSupplied = Math.toIntExact(
+        stateMap.getOrDefault(HolonObject.HolonObjectState.OVER_SUPPLIED, 0L));
+    val.supplied = Math.toIntExact(
+        stateMap.getOrDefault(HolonObject.HolonObjectState.SUPPLIED, 0L));
+    val.partiallySupplied = Math.toIntExact(
+        stateMap.getOrDefault(HolonObject.HolonObjectState.PARTIALLY_SUPPLIED, 0L));
+    val.unsupplied = Math.toIntExact(
+        stateMap.getOrDefault(HolonObject.HolonObjectState.NOT_SUPPLIED, 0L));
+    val.passiv = Math.toIntExact(stateMap.getOrDefault(HolonObject.HolonObjectState.NO_ENERGY, 0L));
+    val.consumer = val.overSupplied + val.supplied + val.partiallySupplied + val.unsupplied;
+    val.objects = val.consumer + val.producer + val.passiv;
+
+    List<HolonElement> holonElementList = canvas.getAllHolonElements().toList();
+    val.elements = holonElementList.size();
+    // UPDATE ActiveInActive
+    val.activeElements = holonElementList.stream().filter(HolonElement::isOn).count();
+    val.consumption = canvas.getTotalConsumption();
+    val.production = canvas.getTotalProduction();
+    val.difference = Math.abs(val.production - val.consumption);
+
+    List<Flexibility> activeFlex = holonElementList.stream().flatMap(ele -> ele.flexList.stream())
+        .filter(flex -> flex.getState().equals(FlexState.IN_USE)).toList();
+    Map<HolonElement.Priority, Long> priorityCounts = activeFlex.stream()
+        .collect(Collectors.groupingBy(flex -> flex.getElement().priority, Collectors.counting()));
+    val.essentialFlex = priorityCounts.getOrDefault(HolonElement.Priority.Essential, 0L);
+    val.highFlex = priorityCounts.getOrDefault(HolonElement.Priority.High, 0L);
+    val.mediumFlex = priorityCounts.getOrDefault(HolonElement.Priority.Medium, 0L);
+    val.lowFlex = priorityCounts.getOrDefault(HolonElement.Priority.Low, 0L);
+
+    val.flexebilities = activeFlex.size();
+    val.holon = control.getModel().holons.size();
+    List<HolonSwitch> switchList = canvas.getAllSwitchObjectsRecursive().toList();
+    val.switches = switchList.size();
+    val.activeSwitches = (int) switchList.stream().filter(HolonSwitch::isClosed).count();
+
+    DoubleSummaryStatistics overStat = holonObjectList.stream()
+        .filter(con -> con.getState().equals(HolonObject.HolonObjectState.OVER_SUPPLIED))
+        .mapToDouble(HolonObject::getSupplyBarPercentage).summaryStatistics();
+
+    DoubleSummaryStatistics partiallyStat = holonObjectList.stream()
+        .filter(con -> con.getState().equals(HolonObject.HolonObjectState.PARTIALLY_SUPPLIED))
+        .mapToDouble(HolonObject::getSupplyBarPercentage).summaryStatistics();
+
+    val.partiallyMin = RunValues.filterInf(partiallyStat.getMin());
+    val.partiallyMax = RunValues.filterInf(partiallyStat.getMax());
+    val.partiallyAverage = RunValues.filterInf(partiallyStat.getAverage());
+
+    val.overMin = RunValues.filterInf(overStat.getMin());
+    val.overMax = RunValues.filterInf(overStat.getMax());
+    val.overAverage = RunValues.filterInf(overStat.getAverage());
+    return val;
+  }
+
+  private String stringStatFromRunValues(RunValues val) {
+    return val.stringStatFromRunValues("");
+  }
+
+  @Override
+  public JPanel getPanel() {
+    return content;
+  }
+
+  @Override
+  public void setController(Control control) {
+    this.control = control;
+  }
+
+  protected abstract int getProgressBarMaxCount();
+
+  protected abstract String algoInformationToPrint();
+
+  protected abstract String plottFileName();
+
+  //ObjectiveFunction
+  enum ObjectiveFunction {Normal, Switch}
+
+  private enum AccessType {None, HolonElement, Switch, Flexibility, KillSwitch}
+
+  static class RunValues {
+
+    public double result;
+    public double executionTime;
+
+    public double objects;
+    public double passiv;
+    public double consumer;
+    public double supplied;
+    public double producer;
+    public double unsupplied;
+    public double partiallySupplied;
+    public double overSupplied;
+
+    public double partiallyMin;
+    public double partiallyMax;
+    public double partiallyAverage;
+    public double overMin;
+    public double overMax;
+    public double overAverage;
+
+    public double activeElements;
+    public double elements;
+
+    public double essentialFlex;
+    public double highFlex;
+    public double mediumFlex;
+    public double lowFlex;
+    public double flexebilities;
+
+    public double switches;
+    public double activeSwitches;
+
+    public double holon;
+    public double consumption;
+    public double production;
+    public double difference;
+
+    public static double filterInf(double value) {
+      if (value == Double.NEGATIVE_INFINITY || value == Double.POSITIVE_INFINITY || Double.isNaN(
+          value)) {
+        return 0;
+      } else {
+        return value;
+      }
+    }
+
+    public static String percentage(double numerator, double denominator) {
+      if ((int) denominator == 0) {
+        return "-%";
+      }
+      return Format.doubleTwoPlaces(numerator) + "/" + Format.doubleTwoPlaces(denominator) + " "
+          + Format.doubleFixedPlaces(2, (float) numerator / (float) denominator * 100) + "%";
+    }
+
+    public String stringStatFromRunValues(String prefix) {
+      return prefix + "Passiv: " + percentage(passiv, objects)
+          + " " + prefix + "Producer: " + percentage(producer, objects)
+          + " " + prefix + "Consumer: " + percentage(consumer, objects)
+          + " " + prefix + "Unsupplied: " + percentage(unsupplied, objects)
+          + " " + prefix + "Partially: " + percentage(partiallySupplied, objects)
+          + " " + prefix + "Over: " + percentage(overSupplied, objects)
+          + " " + prefix + "Supplied: " + percentage(supplied, objects)
+          + " " + prefix + "Partially.SupplyPercentage.Min: " + Format.doubleFixedPlaces(2,
+          partiallyMin)
+          + " " + prefix + "Partially.SupplyPercentage.Max: " + Format.doubleFixedPlaces(2,
+          partiallyMax)
+          + " " + prefix + "Partially.SupplyPercentage.Average: " + Format.doubleFixedPlaces(2,
+          partiallyAverage)
+          + " " + prefix + "Over.SupplyPercentage.Min: " + Format.doubleFixedPlaces(2, overMin)
+          + " " + prefix + "Over.SupplyPercentage.Max: " + Format.doubleFixedPlaces(2, overMax)
+          + " " + prefix + "Over.SupplyPercentage.Average: " + Format.doubleFixedPlaces(2,
+          overAverage)
+          + " " + prefix + "HolonElemnts.Active:" + percentage(activeElements, elements)
+          + " " + prefix + "Flexibilities.Essential: " + percentage(essentialFlex, flexebilities)
+          + " " + prefix + "Flexibilities.High: " + percentage(highFlex, flexebilities)
+          + " " + prefix + "Flexibilities.Medium: " + percentage(mediumFlex, flexebilities)
+          + " " + prefix + "Flexibilities.Low: " + percentage(lowFlex, flexebilities)
+          + " " + prefix + "Switches.Active:" + percentage(activeSwitches, switches)
+          + " " + prefix + "Holons: " + holon
+          + " " + prefix + "TotalConsumption: " + consumption
+          + " " + prefix + "TotalProduction: " + production
+          + " " + prefix + "Difference: " + difference;
+
+    }
+  }
+
+  /**
+   * To create Random and maybe switch the random generation in the future.
+   */
+  protected static class Random {
+
+    private static java.util.Random random = new java.util.Random();
+
+    /**
+     * True or false
+     *
+     * @return the random boolean.
+     */
+    public static boolean nextBoolean() {
+      return random.nextBoolean();
+    }
+
+    /**
+     * Between 0.0(inclusive) and 1.0 (exclusive)
+     *
+     * @return the random double.
+     */
+    public static double nextDouble() {
+      return random.nextDouble();
+    }
+
+    /**
+     * Random Int in Range [min;max[ with UniformDistirbution
+     *
+     * @param min
+     * @param max
+     * @return
+     */
+    public static int nextIntegerInRange(int min, int max) {
+      int result = min;
+      try {
+        result = min + random.nextInt(max - min);
+      } catch (java.lang.IllegalArgumentException e) {
+        System.err.println("min : " + min + " max : " + max);
+        System.err.println("max should be more then min");
+      }
+      return result;
+    }
+  }
+
+  private class RunProgressBar {
+
+    //progressbar
+    private JProgressBar progressBar = new JProgressBar();
+    private int count = 0;
+    private boolean isActive = false;
+
+    public void step() {
+			if (isActive) {
+				progressBar.setValue(count++);
 			}
 			}
-		}
-		
-		void reset() {
-			setter.accept(startValue);
-			count = 0;
-		}
-	}
-	
-	
+    }
+
+    public void start() {
+      progressBar.setIndeterminate(false);
+      count = 0;
+      isActive = true;
+      progressBar.setValue(0);
+      progressBar.setMaximum(getProgressBarMaxCount());
+    }
+
+    public void cancel() {
+      isActive = false;
+      progressBar.setIndeterminate(true);
+    }
+
+    public void finishedCancel() {
+      progressBar.setIndeterminate(false);
+      progressBar.setValue(0);
+    }
+
+    public JProgressBar getJProgressBar() {
+      return progressBar;
+    }
+  }
+
+  public class Printer {
+
+    private JFileChooser fileChooser = new JFileChooser();
+    private BufferedWriter out;
+
+    public Printer(String filename) {
+      fileChooser.setCurrentDirectory(new File(System.getProperty("user.dir")));
+      fileChooser.setSelectedFile(new File(filename));
+    }
+
+    public void openStream() {
+      File file = fileChooser.getSelectedFile();
+      try {
+        file.createNewFile();
+        out = new BufferedWriter(new OutputStreamWriter(
+            new FileOutputStream(file, true), "UTF-8"));
+      } catch (IOException e) {
+        System.out.println(e.getMessage());
+      }
+    }
+
+
+    public void println(String stringToPrint) {
+      try {
+        out.write(stringToPrint);
+        out.newLine();
+      } catch (IOException e) {
+        System.out.println(e.getMessage());
+      }
+    }
+
+    public void closeStream() {
+      try {
+        out.close();
+      } catch (IOException e) {
+        System.out.println(e.getMessage());
+      }
+    }
+  }
+
+  ;
+
+  private class RunAverage {
+
+    private int runCount = 0;
+    //Values
+    private RunValues sum = new RunValues();
+
+    public void addRun(RunValues val) {
+      sum.result += val.result;
+      sum.executionTime += val.executionTime;
+      sum.passiv += val.passiv;
+      sum.consumer += val.consumer;
+      sum.producer += val.producer;
+      sum.unsupplied += val.unsupplied;
+      sum.partiallySupplied += val.partiallySupplied;
+      sum.overSupplied += val.overSupplied;
+      sum.activeElements += val.activeElements;
+      sum.elements += val.elements;
+      sum.essentialFlex += val.essentialFlex;
+      sum.highFlex += val.highFlex;
+      sum.mediumFlex += val.mediumFlex;
+      sum.lowFlex += val.lowFlex;
+      sum.flexebilities += val.flexebilities;
+      sum.holon += val.holon;
+      sum.switches += val.switches;
+      sum.activeSwitches += val.activeSwitches;
+      sum.consumption += val.consumption;
+      sum.production += val.production;
+      sum.difference += val.difference;
+      sum.objects += val.objects;
+      sum.supplied += val.supplied;
+      sum.partiallyMin += val.partiallyMin;
+      sum.partiallyMax += val.partiallyMax;
+      sum.partiallyAverage += val.partiallyAverage;
+      sum.overMin += val.overMin;
+      sum.overMax += val.overMax;
+      sum.overAverage += val.overAverage;
+
+      runCount++;
+    }
+
+    public RunValues getAverage() {
+      RunValues avg = new RunValues();
+      if (runCount == 0) {
+        return avg;
+      }
+      avg.result = sum.result / runCount;
+      avg.executionTime = sum.executionTime / runCount;
+      avg.passiv = sum.passiv / runCount;
+      avg.consumer = sum.consumer / runCount;
+      avg.producer = sum.producer / runCount;
+      avg.unsupplied = sum.unsupplied / runCount;
+      avg.partiallySupplied = sum.partiallySupplied / runCount;
+      avg.overSupplied = sum.overSupplied / runCount;
+      avg.activeElements = sum.activeElements / runCount;
+      avg.elements = sum.elements / runCount;
+      avg.essentialFlex = sum.essentialFlex / runCount;
+      avg.highFlex = sum.highFlex / runCount;
+      avg.mediumFlex = sum.mediumFlex / runCount;
+      avg.lowFlex = sum.lowFlex / runCount;
+      avg.flexebilities = sum.flexebilities / runCount;
+      avg.holon = sum.holon / runCount;
+      avg.switches = sum.switches / runCount;
+      avg.activeSwitches = sum.activeSwitches / runCount;
+      avg.consumption = sum.consumption / runCount;
+      avg.production = sum.production / runCount;
+      avg.difference = sum.difference / runCount;
+      avg.objects = sum.objects / runCount;
+      avg.supplied = sum.supplied / runCount;
+      avg.supplied = sum.supplied / runCount;
+      avg.partiallyMin = sum.partiallyMin / runCount;
+      avg.partiallyMax = sum.partiallyMax / runCount;
+      avg.partiallyAverage = sum.partiallyAverage / runCount;
+      avg.overMin = sum.overMin / runCount;
+      avg.overMax = sum.overMax / runCount;
+      avg.overAverage = sum.overAverage / runCount;
+      return avg;
+    }
+  }
+
+  /**
+   * A Wrapper Class for Access HolonElement and HolonSwitch in one Element and not have to split
+   * the List.
+   */
+  private class AccessWrapper {
+
+    private AccessType type;
+    private List<Boolean> intialStatesOfElementForKilllSwitch;
+
+    private HolonObject hObject;
+    private HolonSwitch hSwitch;
+
+    private HolonElement hElement;
+    private Flexibility flex;
+    private AccessWrapper correspondingKillSwitch;
+
+    private boolean lastState;
+
+
+    public AccessWrapper(HolonObject hObject) {
+      type = AccessType.KillSwitch;
+      this.hObject = hObject;
+      intialStatesOfElementForKilllSwitch = new ArrayList<Boolean>();
+      hObject.elementsStream().forEach(hE -> {
+        intialStatesOfElementForKilllSwitch.add(hE.active);
+      });
+    }
+
+    public AccessWrapper(HolonSwitch hSwitch) {
+      type = AccessType.Switch;
+      this.hSwitch = hSwitch;
+    }
+
+    public AccessWrapper(HolonElement hElement, AccessWrapper correspondingKillSwitch) {
+      type = AccessType.HolonElement;
+      this.hElement = hElement;
+      this.correspondingKillSwitch = correspondingKillSwitch;
+    }
+
+    public AccessWrapper(Flexibility flex, AccessWrapper correspondingKillSwitch) {
+      type = AccessType.Flexibility;
+      this.flex = flex;
+      this.correspondingKillSwitch = correspondingKillSwitch;
+    }
+
+    public void setState(boolean state) {
+      lastState = state;
+      switch (type) {
+        case HolonElement:
+          if (!algoUseKillSwitch || (algoUseKillSwitch
+              && !correspondingKillSwitch.getLastState())) {
+            hElement.active = state;
+          }
+          break;
+        case Switch:
+          hSwitch.setMode(SwitchMode.Manual);
+          hSwitch.setManualState(state ? SwitchState.Closed : SwitchState.Open);
+          break;
+        case Flexibility:
+          if (state && (!algoUseKillSwitch || (algoUseKillSwitch
+              && !correspondingKillSwitch.getLastState()))) {
+            flex.order();
+          }
+          break;
+        case KillSwitch:
+          if (state) {
+            hObject.elementsStream().forEach(hE -> {
+              hE.active = false;
+            });
+          } else {
+            List<HolonElement> eleList = hObject.elementsStream().toList();
+            for (int i = 0; i < eleList.size(); i++) {
+              eleList.get(i).active = intialStatesOfElementForKilllSwitch.get(i);
+            }
+          }
+          break;
+        default:
+          break;
+
+      }
+    }
+
+    public boolean getLastState() {
+      return lastState;
+    }
+
+    public String typeString() {
+      switch (type) {
+        case HolonElement:
+          return "HolonElement";
+        case Switch:
+          return "Switch";
+        case Flexibility:
+          return "Flexibility";
+        case KillSwitch:
+          return "KillSwitch";
+        default:
+          return "unknown";
+      }
+    }
+
+    public String toString() {
+      return "[" + typeString() + "]";
+    }
+  }
+
+  private class Handle<T> {
+
+    public T object;
+
+    Handle(T object) {
+      this.object = object;
+    }
+
+    public String toString() {
+      return object.toString();
+    }
+  }
+
+  public class Individual {
+
+    public double fitness;
+    public List<Boolean> position;
+
+    public Individual() {
+    }
+
+    ;
+
+    /**
+     * Copy Constructor
+     */
+    public Individual(Individual c) {
+      position = c.position.stream().collect(Collectors.toList());
+      fitness = c.fitness;
+    }
+
+    String positionToString() {
+      return position.stream().map(bool -> (bool ? "1" : "0")).collect(Collectors.joining());
+    }
+  }
+
+  protected class ParameterStepping<T> {
+
+    boolean useThisParameter = false;
+    String paramaterName;
+    int stepps;
+    T stepSize;
+    T startValue;
+    Consumer<T> setter;
+    Supplier<T> getter;
+    BiFunction<Integer, T, T> multyply;
+    BiFunction<T, T, T> add;
+    private int count = 0;
+
+    ParameterStepping(Consumer<T> setter, Supplier<T> getter, BiFunction<T, T, T> add,
+        BiFunction<Integer, T, T> multyply, T stepSize, int stepps) {
+      this.setter = setter;
+      this.getter = getter;
+      this.multyply = multyply;
+      this.add = add;
+      this.stepSize = stepSize;
+      this.stepps = stepps;
+    }
+
+    void init() {
+      startValue = getter.get();
+    }
+
+    boolean canUpdate() {
+      return count < stepps;
+    }
+
+    void update() {
+      if (canUpdate()) {
+        setter.accept(add.apply(startValue, multyply.apply(count + 1, stepSize)));
+        count++;
+      }
+    }
+
+    void reset() {
+      setter.accept(startValue);
+      count = 0;
+    }
+  }
+
+
 }
 }

+ 1211 - 1171
src/holeg/api/TopologieAlgorithmFramework.java

@@ -1,5 +1,21 @@
 package holeg.api;
 package holeg.api;
 
 
+import holeg.algorithm.objective_function.TopologieObjectiveFunction;
+import holeg.model.AbstractCanvasObject;
+import holeg.model.Edge;
+import holeg.model.Flexibility;
+import holeg.model.GroupNode;
+import holeg.model.HolonElement;
+import holeg.model.HolonObject;
+import holeg.model.HolonSwitch;
+import holeg.model.HolonSwitch.SwitchMode;
+import holeg.model.HolonSwitch.SwitchState;
+import holeg.model.Model;
+import holeg.model.Node;
+import holeg.preferences.ImagePreference;
+import holeg.ui.controller.Control;
+import holeg.ui.view.category.Category;
+import holeg.ui.view.component.Console;
 import java.awt.BorderLayout;
 import java.awt.BorderLayout;
 import java.awt.Dimension;
 import java.awt.Dimension;
 import java.awt.FlowLayout;
 import java.awt.FlowLayout;
@@ -10,13 +26,23 @@ import java.io.IOException;
 import java.io.OutputStreamWriter;
 import java.io.OutputStreamWriter;
 import java.math.RoundingMode;
 import java.math.RoundingMode;
 import java.text.NumberFormat;
 import java.text.NumberFormat;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.DoubleSummaryStatistics;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
 import java.util.function.BiFunction;
 import java.util.function.BiFunction;
 import java.util.function.Consumer;
 import java.util.function.Consumer;
 import java.util.function.Supplier;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import java.util.stream.Stream;
-
 import javax.swing.BorderFactory;
 import javax.swing.BorderFactory;
 import javax.swing.Box;
 import javax.swing.Box;
 import javax.swing.BoxLayout;
 import javax.swing.BoxLayout;
@@ -32,1182 +58,1196 @@ import javax.swing.JSeparator;
 import javax.swing.JSplitPane;
 import javax.swing.JSplitPane;
 import javax.swing.text.NumberFormatter;
 import javax.swing.text.NumberFormatter;
 
 
-import holeg.algorithm.objective_function.TopologieObjectiveFunction;
-import holeg.model.*;
-import holeg.model.HolonSwitch.SwitchMode;
-import holeg.model.HolonSwitch.SwitchState;
-import holeg.preferences.ImagePreference;
-import holeg.ui.controller.Control;
-import holeg.ui.view.component.Console;
-import holeg.ui.view.category.Category;
-
-public abstract class TopologieAlgorithmFramework implements AddOn{
-	//Algo
-	protected int rounds = 1;
-	protected int amountOfNewCables = 20;
-	
-	
-	//Panel
-	private JPanel content = new JPanel();
-	protected Console console = new Console();
-	private JPanel borderPanel = new JPanel();
-	private HashMap<String, JPanel> panelMap = new HashMap<String, JPanel>();
-	
-	
-	
-	
-	//Settings groupNode
-	private Optional<GroupNode> groupNode = Optional.empty();
-	
-	
-	//access
-	private ArrayList<AccessWrapper> accessWildcards = new ArrayList<>();
-	LinkedList<List<Integer>> resetChain = new LinkedList<>();
-	
-	
-	private final HashMap<Integer, AbstractCanvasObject> accessIntToObject = new HashMap<>();
-	private final HashMap<AbstractCanvasObject, Integer> accessObjectToInt = new HashMap<>();
-	private final HashMap<Integer, AbstractCanvasObject> accessIntegerToWildcard = new HashMap<>();
-	private final HashMap<AbstractCanvasObject, GroupNode> accessGroupNode = new HashMap<>();
-	
-	private final HashSet<IndexCable> cableSet = new HashSet<>();
-	private final ArrayList<IndexCable> cableList = new ArrayList<>();
-	private final HashMap<IndexCable, Double> addedIndexCable = new HashMap<>();
-	private int countForAccessMap = 0;
-	private int amountOfExistingCables = 0;
-	private final ArrayList<HolonSwitch> switchList = new ArrayList<>();
-	private final HashMap<HolonSwitch, GroupNode> accessSwitchGroupNode = new HashMap<>();
-	private final ArrayList<Edge> edgeList = new ArrayList<>();
-	
-	boolean algoUseElements = false, algoUseSwitches = true, algoUseFlexes = true;
-	
-	//time
-	private long startTime;
-	
-	
-	private final RunProgressBar runProgressbar = new RunProgressBar();
-	
-	
-	
-	//concurrency
-	private Thread runThread = new Thread();
-	protected boolean cancel = false;
-
-	//holeg interaction
-	protected Control  control;
-
-	
-	//printing
-	private final Printer runPrinter = new Printer(plottFileName());
-	protected List<Double> runList = new LinkedList<>();
-
-	//Parameter
-	@SuppressWarnings("rawtypes")
-	LinkedList<ParameterStepping> parameterSteppingList= new LinkedList<ParameterStepping>();
-	protected boolean useStepping = false;
-	//SwitchButton
-	
-
-	
-	
-	public TopologieAlgorithmFramework(){
-		content.setLayout(new BorderLayout());
-		JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
-				createOptionPanel() , console);
-		splitPane.setResizeWeight(0.0);
-		content.add(splitPane, BorderLayout.CENTER);
-		content.setPreferredSize(new Dimension(1200,800));
-	}
-	
-	
-	
-	
-	
-	
-	private JPanel createOptionPanel() {
-		JPanel optionPanel = new JPanel(new BorderLayout());
-		JScrollPane scrollPane = new JScrollPane(createParameterPanel());
-		scrollPane.setBorder(BorderFactory.createTitledBorder("Parameters"));
-		optionPanel.add(scrollPane,  BorderLayout.CENTER);
-		optionPanel.add(createButtonPanel(), BorderLayout.PAGE_END);
-		return optionPanel;
-	}
-	
-	private JPanel createParameterPanel() {
-		JPanel parameterPanel = new JPanel(null);
-		parameterPanel.setPreferredSize(new Dimension(510,300));
-		borderPanel.setLayout(new BoxLayout(borderPanel, BoxLayout.PAGE_AXIS));
-		addIntParameter("Number of New Cables", amountOfNewCables, intInput -> amountOfNewCables = intInput, () -> amountOfNewCables, 0);
-		addSeperator();
-		addIntParameter("Repetitions", rounds, intInput -> rounds = intInput, () -> rounds, 1);
-		JScrollPane scrollPane = new JScrollPane(borderPanel);
-		scrollPane.setBounds(10, 0, 850, 292);
-		scrollPane.setBorder(BorderFactory.createEmptyBorder());
-		parameterPanel.add(scrollPane);	
-		
-		
-		JProgressBar progressBar = runProgressbar.getJProgressBar();
-		progressBar.setBounds(900, 35, 185, 20);
-		progressBar.setStringPainted(true);
-		parameterPanel.add(progressBar);
-		
-		JButton addCategoryButton = new JButton("Add Category");
-		addCategoryButton.setBounds(900, 65, 185, 30);
-		addCategoryButton.addActionListener(clicked -> createWildcardsCategory());
-		parameterPanel.add(addCategoryButton);
-		return parameterPanel;
-	}
-	private JPanel createButtonPanel() {
-		JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
-		
-		JButton toggleSwitchesButton =  new JButton("Toggle Switches");
-		toggleSwitchesButton.setToolTipText("Set all switches active or inactive.");
-		toggleSwitchesButton.addActionListener(actionEvent -> toggleSwitches());
-		buttonPanel.add(toggleSwitchesButton);
-		
-		
-		
-		JButton resetButton =  new JButton("Reset");
-		resetButton.setToolTipText("Resets the State to before the Algorithm has runed.");
-		resetButton.addActionListener(actionEvent -> reset());
-		buttonPanel.add(resetButton);
-		
-		JButton cancelButton =  new JButton("Cancel Run");
-		cancelButton.addActionListener(actionEvent -> cancel());
-		buttonPanel.add(cancelButton);
-		
-		JButton fitnessButton =  new JButton("Fitness");
-		fitnessButton.setToolTipText("Fitness for the current state.");
-		fitnessButton.addActionListener(actionEvent -> fitness());
-		buttonPanel.add(fitnessButton);
-		
-		JButton runButton =  new JButton("Run");
-		runButton.addActionListener(actionEvent -> {
-			if(runThread.isAlive()) {
-				return;
-			}
-			reset();
-			this.resetAllList();
-			resetChain.clear();
-			Runnable task = () -> run();
-			runThread = new Thread(task);
-			runThread.start();
-		});
-		buttonPanel.add(runButton);
-		
-		
-		
-		return buttonPanel;
-	}
-	
-	
-	
-	//ParameterImports
-	
-	private void toggleSwitches() {
-		List<HolonSwitch> allSwitchList = control.getModel().getCanvas().getAllSwitchObjectsRecursive().toList();
-		if(allSwitchList.isEmpty()) return;
-		SwitchState set = allSwitchList.get(0).getManualState();
-		allSwitchList.forEach(hSwitch -> {
-			hSwitch.setMode(SwitchMode.Manual);
-			hSwitch.setManualState(SwitchState.opposite(set));
-		});
-		updateVisual();
-	}
-
-
-
-	//addSeperator
-	protected void addSeperator() {
-		borderPanel.add(Box.createRigidArea(new Dimension(5, 5)));
-		borderPanel.add(new JSeparator());
-		borderPanel.add(Box.createRigidArea(new Dimension(5, 5)));
-	}
-
-
-	//int
-	protected void addIntParameter(String parameterName, int parameterValue, Consumer<Integer> setter, Supplier<Integer> getter) {
-		this.addIntParameter(parameterName, parameterValue, setter, getter, true, Integer.MIN_VALUE, Integer.MAX_VALUE);
-	}
-	
-	protected void addIntParameter(String parameterName, int parameterValue, Consumer<Integer> setter, Supplier<Integer> getter, int parameterMinValue) {
-		this.addIntParameter(parameterName, parameterValue, setter, getter, true, parameterMinValue, Integer.MAX_VALUE);
-	}
-	
-	protected void addIntParameter(String parameterName, int parameterValue, Consumer<Integer> setter, Supplier<Integer> getter, boolean visible, int parameterMinValue, int parameterMaxValue) {
-		JPanel singleParameterPanel = new JPanel();
-		singleParameterPanel.setLayout(new BoxLayout(singleParameterPanel, BoxLayout.LINE_AXIS));
-		singleParameterPanel.setAlignmentX(0.0f);
-		singleParameterPanel.add(new JLabel(parameterName + ": "));
-		singleParameterPanel.add(Box.createHorizontalGlue());
-		NumberFormat format = NumberFormat.getIntegerInstance();
-		format.setGroupingUsed(false);
-		format.setParseIntegerOnly(true);
-		NumberFormatter integerFormatter = new NumberFormatter(format);
-		integerFormatter.setMinimum(parameterMinValue);
-		integerFormatter.setMaximum(parameterMaxValue);
-		integerFormatter.setCommitsOnValidEdit(true);
-		JFormattedTextField singleParameterTextField = new  JFormattedTextField(integerFormatter);
-		singleParameterTextField.setValue(parameterValue);
-		String minValue = (parameterMinValue == Integer.MIN_VALUE)?"Integer.MIN_VALUE":String.valueOf(parameterMinValue);
-		String maxValue = (parameterMaxValue == Integer.MAX_VALUE)?"Integer.MAX_VALUE":String.valueOf(parameterMaxValue);
-		singleParameterTextField.setToolTipText("Only integer \u2208 [" + minValue + "," + maxValue + "]");
-		singleParameterTextField.addPropertyChangeListener(actionEvent -> setter.accept(Integer.parseInt(singleParameterTextField.getValue().toString())));
-		singleParameterTextField.setMaximumSize(new Dimension(200, 30));
-		singleParameterTextField.setPreferredSize(new Dimension(200, 30));
-		singleParameterPanel.add(singleParameterTextField);
-		
-		
-		ParameterStepping<Integer> intParameterStepping = new ParameterStepping<Integer>(setter, getter, Integer::sum , (a,b) -> a * b, 1, 1);
-		intParameterStepping.useThisParameter = false;
-		parameterSteppingList.add(intParameterStepping);
-		
-		JCheckBox useSteppingCheckBox = new JCheckBox();
-		useSteppingCheckBox.setSelected(false);
-		singleParameterPanel.add(useSteppingCheckBox);
-		
-		
-		
-		JLabel stepsLabel = new JLabel("Steps: ");
-		stepsLabel.setEnabled(false);
-		singleParameterPanel.add(stepsLabel);
-		
-		NumberFormatter stepFormatter = new NumberFormatter(format);
-		stepFormatter.setMinimum(1);
-		stepFormatter.setMaximum(Integer.MAX_VALUE);
-		stepFormatter.setCommitsOnValidEdit(true);
-		
-		
-		JFormattedTextField stepsTextField = new  JFormattedTextField(stepFormatter);
-		stepsTextField.setEnabled(false);
-		stepsTextField.setValue(1);
-		stepsTextField.setToolTipText("Only integer \u2208 [" + 1 + "," + Integer.MAX_VALUE + "]");
-		stepsTextField.addPropertyChangeListener(actionEvent -> intParameterStepping.stepps = Integer.parseInt(stepsTextField.getValue().toString()));
-		stepsTextField.setMaximumSize(new Dimension(40, 30));
-		stepsTextField.setPreferredSize(new Dimension(40, 30));
-		singleParameterPanel.add(stepsTextField);
-		
-		JLabel stepsSizeLabel = new JLabel("StepsSize: ");
-		stepsSizeLabel.setEnabled(false);
-		singleParameterPanel.add(stepsSizeLabel);
-		
-		JFormattedTextField stepsSizeTextField = new  JFormattedTextField(stepFormatter);
-		stepsSizeTextField.setEnabled(false);
-		stepsSizeTextField.setValue(1);
-		stepsSizeTextField.setToolTipText("Only integer \u2208 [" + 1 + "," + Integer.MAX_VALUE + "]");
-		stepsSizeTextField.addPropertyChangeListener(actionEvent -> intParameterStepping.stepSize = Integer.parseInt(stepsSizeTextField.getValue().toString()));
-		stepsSizeTextField.setMaximumSize(new Dimension(40, 30));
-		stepsSizeTextField.setPreferredSize(new Dimension(40, 30));
-		singleParameterPanel.add(stepsSizeTextField);
-		
-		useSteppingCheckBox.addActionListener(actionEvent -> {
-			boolean enabled = useSteppingCheckBox.isSelected();
-			intParameterStepping.useThisParameter = enabled;
-			this.useStepping = this.parameterSteppingList.stream().anyMatch(parameter -> parameter.useThisParameter);
-			stepsLabel.setEnabled(enabled);
-			stepsTextField.setEnabled(enabled);
-			stepsSizeLabel.setEnabled(enabled);
-			stepsSizeTextField.setEnabled(enabled);
-		});
-		panelMap.put(parameterName, singleParameterPanel);
-		singleParameterPanel.setVisible(visible);
-		borderPanel.add(singleParameterPanel);
-	}
-	
-	
-	//double
-	protected void addDoubleParameter(String parameterName, double parameterValue, Consumer<Double> setter, Supplier<Double> getter) {
-		this.addDoubleParameter(parameterName, parameterValue, setter, getter, true, Double.MIN_VALUE, Double.MAX_VALUE);
-	}
-	
-	
-	protected void addDoubleParameter(String parameterName, double parameterValue, Consumer<Double> setter, Supplier<Double> getter, double parameterMinValue) {
-		this.addDoubleParameter(parameterName, parameterValue, setter, getter, true, parameterMinValue, Double.MAX_VALUE);
-	}
-	
-	
-	protected void addDoubleParameter(String parameterName, double parameterValue, Consumer<Double> setter, Supplier<Double> getter, boolean visible, double parameterMinValue, double parameterMaxValue) {
-		JPanel singleParameterPanel = new JPanel();
-		singleParameterPanel.setLayout(new BoxLayout(singleParameterPanel, BoxLayout.LINE_AXIS));
-		singleParameterPanel.setAlignmentX(0.0f);
-		singleParameterPanel.add(new JLabel(parameterName + ": "));
-		singleParameterPanel.add(Box.createHorizontalGlue());
-		NumberFormat doubleFormat = NumberFormat.getNumberInstance(Locale.US);
-		doubleFormat.setMinimumFractionDigits(1);
-		doubleFormat.setMaximumFractionDigits(10);
-		doubleFormat.setRoundingMode(RoundingMode.HALF_UP);
-		NumberFormatter doubleFormatter = new NumberFormatter(doubleFormat);
-		doubleFormatter.setMinimum(parameterMinValue);
-		doubleFormatter.setMaximum(parameterMaxValue);
-		doubleFormatter.setCommitsOnValidEdit(true);
-		JFormattedTextField singleParameterTextField = new  JFormattedTextField(doubleFormatter);
-		singleParameterTextField.setValue(parameterValue);
-		String minValue = (parameterMinValue == Double.MIN_VALUE)?"Double.MIN_VALUE":String.valueOf(parameterMinValue);
-		String maxValue = (parameterMaxValue == Double.MAX_VALUE)?"Double.MAX_VALUE":String.valueOf(parameterMaxValue);
-		singleParameterTextField.setToolTipText("Only double \u2208 [" + minValue + "," + maxValue + "]");
-		singleParameterTextField.addPropertyChangeListener(actionEvent -> setter.accept(Double.parseDouble(singleParameterTextField.getValue().toString())));
-		singleParameterTextField.setMaximumSize(new Dimension(200, 30));
-		singleParameterTextField.setPreferredSize(new Dimension(200, 30));
-		singleParameterPanel.add(singleParameterTextField);
-		
-		ParameterStepping<Double> doubleParameterStepping = new ParameterStepping<Double>(setter, getter, (a,b) -> a+b , (a,b) -> a * b, 1.0, 1);
-		doubleParameterStepping.useThisParameter = false;
-		parameterSteppingList.add(doubleParameterStepping);
-		
-		JCheckBox useSteppingCheckBox = new JCheckBox();
-		useSteppingCheckBox.setSelected(false);
-		singleParameterPanel.add(useSteppingCheckBox);
-		
-		
-		
-		JLabel stepsLabel = new JLabel("Steps: ");
-		stepsLabel.setEnabled(false);
-		singleParameterPanel.add(stepsLabel);
-		NumberFormat format = NumberFormat.getIntegerInstance();
-		format.setGroupingUsed(false);
-		format.setParseIntegerOnly(true);
-		NumberFormatter integerFormatter = new NumberFormatter(format);
-		integerFormatter.setMinimum(1);
-		integerFormatter.setMaximum(Integer.MAX_VALUE);
-		integerFormatter.setCommitsOnValidEdit(true);
-	
-		
-		
-		JFormattedTextField stepsTextField = new  JFormattedTextField(integerFormatter);
-		stepsTextField.setEnabled(false);
-		stepsTextField.setValue(1);
-		stepsTextField.setToolTipText("Only integer \u2208 [" + 1 + "," + Integer.MAX_VALUE + "]");
-		stepsTextField.addPropertyChangeListener(actionEvent -> doubleParameterStepping.stepps = Integer.parseInt(stepsTextField.getValue().toString()));
-		stepsTextField.setMaximumSize(new Dimension(40, 30));
-		stepsTextField.setPreferredSize(new Dimension(40, 30));
-		singleParameterPanel.add(stepsTextField);
-		
-		JLabel stepsSizeLabel = new JLabel("StepsSize: ");
-		stepsSizeLabel.setEnabled(false);
-		singleParameterPanel.add(stepsSizeLabel);
-		
-		NumberFormatter doubleFormatterForStepping = new NumberFormatter(doubleFormat);
-		doubleFormatterForStepping.setCommitsOnValidEdit(true);
-		JFormattedTextField stepsSizeTextField = new  JFormattedTextField(doubleFormatterForStepping);
-		stepsSizeTextField.setEnabled(false);
-		stepsSizeTextField.setValue(1.0);
-		stepsSizeTextField.setToolTipText("Only double");
-		stepsSizeTextField.addPropertyChangeListener(actionEvent -> doubleParameterStepping.stepSize = Double.parseDouble(stepsSizeTextField.getValue().toString()));
-		stepsSizeTextField.setMaximumSize(new Dimension(40, 30));
-		stepsSizeTextField.setPreferredSize(new Dimension(40, 30));
-		singleParameterPanel.add(stepsSizeTextField);
-		
-		useSteppingCheckBox.addActionListener(actionEvent -> {
-			boolean enabled = useSteppingCheckBox.isSelected();
-			doubleParameterStepping.useThisParameter = enabled;
-			this.useStepping = this.parameterSteppingList.stream().anyMatch(parameter -> parameter.useThisParameter);
-			stepsLabel.setEnabled(enabled);
-			stepsTextField.setEnabled(enabled);
-			stepsSizeLabel.setEnabled(enabled);
-			stepsSizeTextField.setEnabled(enabled);
-		});
-		panelMap.put(parameterName, singleParameterPanel);
-		singleParameterPanel.setVisible(visible);
-		borderPanel.add(singleParameterPanel);
-	}
-	//boolean
-	protected void addBooleanParameter(String parameterName, boolean parameterValue, Consumer<Boolean> setter, List<String> showParameterNames, List<String> hideParameterNames){
-		JPanel singleParameterPanel = new JPanel();
-		panelMap.put(parameterName, singleParameterPanel);
-		singleParameterPanel.setLayout(new BoxLayout(singleParameterPanel, BoxLayout.LINE_AXIS));
-		singleParameterPanel.setAlignmentX(0.0f);
-		singleParameterPanel.add(new JLabel(parameterName + ": "));
-		singleParameterPanel.add(Box.createHorizontalGlue());
-		JCheckBox useGroupNodeCheckBox = new JCheckBox();
-		useGroupNodeCheckBox.addActionListener(actionEvent -> {
-			setter.accept(useGroupNodeCheckBox.isSelected());
-			showParameterNames.forEach(string -> panelMap.get(string).setVisible(useGroupNodeCheckBox.isSelected()));
-			hideParameterNames.forEach(string -> panelMap.get(string).setVisible(!useGroupNodeCheckBox.isSelected()));
-		});
-		useGroupNodeCheckBox.setSelected(parameterValue);
-		singleParameterPanel.add(useGroupNodeCheckBox);
-		borderPanel.add(singleParameterPanel);
-	}
-	
-
-	private void startTimer(){
-		startTime = System.currentTimeMillis();
-	}
-	private long printElapsedTime(){
-		long elapsedMilliSeconds = System.currentTimeMillis() - startTime;
-		console.println("Execution Time of Algo in Milliseconds:" + elapsedMilliSeconds);
-		return elapsedMilliSeconds;
-	}
-	
-	
-	
-	private void cancel() {
-		if(runThread.isAlive()) {
-			console.println("Cancel run.");
-			cancel = true;
-			runProgressbar.cancel();
-		} else {
-			console.println("Nothing to cancel.");
-		}
-	}
-	private void createWildcardsCategory() {
-		Optional<Category> category = control.findCategoryWithName("Wildcards");
-		if(category.isEmpty()) {
-			control.createCategoryWithName("Wildcards");
-		}
-	}
-	
-	private void fitness() {
-		if(runThread.isAlive()) {
-			console.println("Run have to be cancelled First.");
+public abstract class TopologieAlgorithmFramework implements AddOn {
+
+  private final HashMap<Integer, AbstractCanvasObject> accessIntToObject = new HashMap<>();
+  private final HashMap<AbstractCanvasObject, Integer> accessObjectToInt = new HashMap<>();
+  private final HashMap<Integer, AbstractCanvasObject> accessIntegerToWildcard = new HashMap<>();
+  private final HashMap<AbstractCanvasObject, GroupNode> accessGroupNode = new HashMap<>();
+  private final HashSet<IndexCable> cableSet = new HashSet<>();
+  private final ArrayList<IndexCable> cableList = new ArrayList<>();
+  private final HashMap<IndexCable, Double> addedIndexCable = new HashMap<>();
+  private final ArrayList<HolonSwitch> switchList = new ArrayList<>();
+  private final HashMap<HolonSwitch, GroupNode> accessSwitchGroupNode = new HashMap<>();
+  private final ArrayList<Edge> edgeList = new ArrayList<>();
+  private final RunProgressBar runProgressbar = new RunProgressBar();
+  //printing
+  private final Printer runPrinter = new Printer(plottFileName());
+  //Algo
+  protected int rounds = 1;
+  protected int amountOfNewCables = 20;
+  protected Console console = new Console();
+  protected boolean cancel = false;
+  //holeg interaction
+  protected Control control;
+  protected List<Double> runList = new LinkedList<>();
+  protected boolean useStepping = false;
+  LinkedList<List<Integer>> resetChain = new LinkedList<>();
+  boolean algoUseElements = false, algoUseSwitches = true, algoUseFlexes = true;
+  //Parameter
+  @SuppressWarnings("rawtypes")
+  LinkedList<ParameterStepping> parameterSteppingList = new LinkedList<ParameterStepping>();
+  //Panel
+  private JPanel content = new JPanel();
+  private JPanel borderPanel = new JPanel();
+  private HashMap<String, JPanel> panelMap = new HashMap<String, JPanel>();
+  //Settings groupNode
+  private Optional<GroupNode> groupNode = Optional.empty();
+  //access
+  private ArrayList<AccessWrapper> accessWildcards = new ArrayList<>();
+  private int countForAccessMap = 0;
+  private int amountOfExistingCables = 0;
+  //time
+  private long startTime;
+  //concurrency
+  private Thread runThread = new Thread();
+  //SwitchButton
+
+
+  public TopologieAlgorithmFramework() {
+    content.setLayout(new BorderLayout());
+    JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
+        createOptionPanel(), console);
+    splitPane.setResizeWeight(0.0);
+    content.add(splitPane, BorderLayout.CENTER);
+    content.setPreferredSize(new Dimension(1200, 800));
+  }
+
+
+  private JPanel createOptionPanel() {
+    JPanel optionPanel = new JPanel(new BorderLayout());
+    JScrollPane scrollPane = new JScrollPane(createParameterPanel());
+    scrollPane.setBorder(BorderFactory.createTitledBorder("Parameters"));
+    optionPanel.add(scrollPane, BorderLayout.CENTER);
+    optionPanel.add(createButtonPanel(), BorderLayout.PAGE_END);
+    return optionPanel;
+  }
+
+  private JPanel createParameterPanel() {
+    JPanel parameterPanel = new JPanel(null);
+    parameterPanel.setPreferredSize(new Dimension(510, 300));
+    borderPanel.setLayout(new BoxLayout(borderPanel, BoxLayout.PAGE_AXIS));
+    addIntParameter("Number of New Cables", amountOfNewCables,
+        intInput -> amountOfNewCables = intInput, () -> amountOfNewCables, 0);
+    addSeperator();
+    addIntParameter("Repetitions", rounds, intInput -> rounds = intInput, () -> rounds, 1);
+    JScrollPane scrollPane = new JScrollPane(borderPanel);
+    scrollPane.setBounds(10, 0, 850, 292);
+    scrollPane.setBorder(BorderFactory.createEmptyBorder());
+    parameterPanel.add(scrollPane);
+
+    JProgressBar progressBar = runProgressbar.getJProgressBar();
+    progressBar.setBounds(900, 35, 185, 20);
+    progressBar.setStringPainted(true);
+    parameterPanel.add(progressBar);
+
+    JButton addCategoryButton = new JButton("Add Category");
+    addCategoryButton.setBounds(900, 65, 185, 30);
+    addCategoryButton.addActionListener(clicked -> createWildcardsCategory());
+    parameterPanel.add(addCategoryButton);
+    return parameterPanel;
+  }
+
+  private JPanel createButtonPanel() {
+    JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+
+    JButton toggleSwitchesButton = new JButton("Toggle Switches");
+    toggleSwitchesButton.setToolTipText("Set all switches active or inactive.");
+    toggleSwitchesButton.addActionListener(actionEvent -> toggleSwitches());
+    buttonPanel.add(toggleSwitchesButton);
+
+    JButton resetButton = new JButton("Reset");
+    resetButton.setToolTipText("Resets the State to before the Algorithm has runed.");
+    resetButton.addActionListener(actionEvent -> reset());
+    buttonPanel.add(resetButton);
+
+    JButton cancelButton = new JButton("Cancel Run");
+    cancelButton.addActionListener(actionEvent -> cancel());
+    buttonPanel.add(cancelButton);
+
+    JButton fitnessButton = new JButton("Fitness");
+    fitnessButton.setToolTipText("Fitness for the current state.");
+    fitnessButton.addActionListener(actionEvent -> fitness());
+    buttonPanel.add(fitnessButton);
+
+    JButton runButton = new JButton("Run");
+    runButton.addActionListener(actionEvent -> {
+      if (runThread.isAlive()) {
+        return;
+      }
+      reset();
+      this.resetAllList();
+      resetChain.clear();
+      Runnable task = () -> run();
+      runThread = new Thread(task);
+      runThread.start();
+    });
+    buttonPanel.add(runButton);
+
+    return buttonPanel;
+  }
+
+  //ParameterImports
+
+  private void toggleSwitches() {
+    List<HolonSwitch> allSwitchList = control.getModel().getCanvas().getAllSwitchObjectsRecursive()
+        .toList();
+		if (allSwitchList.isEmpty()) {
 			return;
 			return;
 		}
 		}
+    SwitchState set = allSwitchList.get(0).getManualState();
+    allSwitchList.forEach(hSwitch -> {
+      hSwitch.setMode(SwitchMode.Manual);
+      hSwitch.setManualState(SwitchState.opposite(set));
+    });
+    updateVisual();
+  }
+
+
+  //addSeperator
+  protected void addSeperator() {
+    borderPanel.add(Box.createRigidArea(new Dimension(5, 5)));
+    borderPanel.add(new JSeparator());
+    borderPanel.add(Box.createRigidArea(new Dimension(5, 5)));
+  }
+
+
+  //int
+  protected void addIntParameter(String parameterName, int parameterValue, Consumer<Integer> setter,
+      Supplier<Integer> getter) {
+    this.addIntParameter(parameterName, parameterValue, setter, getter, true, Integer.MIN_VALUE,
+        Integer.MAX_VALUE);
+  }
+
+  protected void addIntParameter(String parameterName, int parameterValue, Consumer<Integer> setter,
+      Supplier<Integer> getter, int parameterMinValue) {
+    this.addIntParameter(parameterName, parameterValue, setter, getter, true, parameterMinValue,
+        Integer.MAX_VALUE);
+  }
+
+  protected void addIntParameter(String parameterName, int parameterValue, Consumer<Integer> setter,
+      Supplier<Integer> getter, boolean visible, int parameterMinValue, int parameterMaxValue) {
+    JPanel singleParameterPanel = new JPanel();
+    singleParameterPanel.setLayout(new BoxLayout(singleParameterPanel, BoxLayout.LINE_AXIS));
+    singleParameterPanel.setAlignmentX(0.0f);
+    singleParameterPanel.add(new JLabel(parameterName + ": "));
+    singleParameterPanel.add(Box.createHorizontalGlue());
+    NumberFormat format = NumberFormat.getIntegerInstance();
+    format.setGroupingUsed(false);
+    format.setParseIntegerOnly(true);
+    NumberFormatter integerFormatter = new NumberFormatter(format);
+    integerFormatter.setMinimum(parameterMinValue);
+    integerFormatter.setMaximum(parameterMaxValue);
+    integerFormatter.setCommitsOnValidEdit(true);
+    JFormattedTextField singleParameterTextField = new JFormattedTextField(integerFormatter);
+    singleParameterTextField.setValue(parameterValue);
+    String minValue = (parameterMinValue == Integer.MIN_VALUE) ? "Integer.MIN_VALUE"
+        : String.valueOf(parameterMinValue);
+    String maxValue = (parameterMaxValue == Integer.MAX_VALUE) ? "Integer.MAX_VALUE"
+        : String.valueOf(parameterMaxValue);
+    singleParameterTextField.setToolTipText(
+        "Only integer \u2208 [" + minValue + "," + maxValue + "]");
+    singleParameterTextField.addPropertyChangeListener(actionEvent -> setter.accept(
+        Integer.parseInt(singleParameterTextField.getValue().toString())));
+    singleParameterTextField.setMaximumSize(new Dimension(200, 30));
+    singleParameterTextField.setPreferredSize(new Dimension(200, 30));
+    singleParameterPanel.add(singleParameterTextField);
+
+    ParameterStepping<Integer> intParameterStepping = new ParameterStepping<Integer>(setter, getter,
+        Integer::sum, (a, b) -> a * b, 1, 1);
+    intParameterStepping.useThisParameter = false;
+    parameterSteppingList.add(intParameterStepping);
+
+    JCheckBox useSteppingCheckBox = new JCheckBox();
+    useSteppingCheckBox.setSelected(false);
+    singleParameterPanel.add(useSteppingCheckBox);
+
+    JLabel stepsLabel = new JLabel("Steps: ");
+    stepsLabel.setEnabled(false);
+    singleParameterPanel.add(stepsLabel);
+
+    NumberFormatter stepFormatter = new NumberFormatter(format);
+    stepFormatter.setMinimum(1);
+    stepFormatter.setMaximum(Integer.MAX_VALUE);
+    stepFormatter.setCommitsOnValidEdit(true);
+
+    JFormattedTextField stepsTextField = new JFormattedTextField(stepFormatter);
+    stepsTextField.setEnabled(false);
+    stepsTextField.setValue(1);
+    stepsTextField.setToolTipText("Only integer \u2208 [" + 1 + "," + Integer.MAX_VALUE + "]");
+    stepsTextField.addPropertyChangeListener(
+        actionEvent -> intParameterStepping.stepps = Integer.parseInt(
+            stepsTextField.getValue().toString()));
+    stepsTextField.setMaximumSize(new Dimension(40, 30));
+    stepsTextField.setPreferredSize(new Dimension(40, 30));
+    singleParameterPanel.add(stepsTextField);
+
+    JLabel stepsSizeLabel = new JLabel("StepsSize: ");
+    stepsSizeLabel.setEnabled(false);
+    singleParameterPanel.add(stepsSizeLabel);
+
+    JFormattedTextField stepsSizeTextField = new JFormattedTextField(stepFormatter);
+    stepsSizeTextField.setEnabled(false);
+    stepsSizeTextField.setValue(1);
+    stepsSizeTextField.setToolTipText("Only integer \u2208 [" + 1 + "," + Integer.MAX_VALUE + "]");
+    stepsSizeTextField.addPropertyChangeListener(
+        actionEvent -> intParameterStepping.stepSize = Integer.parseInt(
+            stepsSizeTextField.getValue().toString()));
+    stepsSizeTextField.setMaximumSize(new Dimension(40, 30));
+    stepsSizeTextField.setPreferredSize(new Dimension(40, 30));
+    singleParameterPanel.add(stepsSizeTextField);
+
+    useSteppingCheckBox.addActionListener(actionEvent -> {
+      boolean enabled = useSteppingCheckBox.isSelected();
+      intParameterStepping.useThisParameter = enabled;
+      this.useStepping = this.parameterSteppingList.stream()
+          .anyMatch(parameter -> parameter.useThisParameter);
+      stepsLabel.setEnabled(enabled);
+      stepsTextField.setEnabled(enabled);
+      stepsSizeLabel.setEnabled(enabled);
+      stepsSizeTextField.setEnabled(enabled);
+    });
+    panelMap.put(parameterName, singleParameterPanel);
+    singleParameterPanel.setVisible(visible);
+    borderPanel.add(singleParameterPanel);
+  }
+
+
+  //double
+  protected void addDoubleParameter(String parameterName, double parameterValue,
+      Consumer<Double> setter, Supplier<Double> getter) {
+    this.addDoubleParameter(parameterName, parameterValue, setter, getter, true, Double.MIN_VALUE,
+        Double.MAX_VALUE);
+  }
+
+
+  protected void addDoubleParameter(String parameterName, double parameterValue,
+      Consumer<Double> setter, Supplier<Double> getter, double parameterMinValue) {
+    this.addDoubleParameter(parameterName, parameterValue, setter, getter, true, parameterMinValue,
+        Double.MAX_VALUE);
+  }
+
+
+  protected void addDoubleParameter(String parameterName, double parameterValue,
+      Consumer<Double> setter, Supplier<Double> getter, boolean visible, double parameterMinValue,
+      double parameterMaxValue) {
+    JPanel singleParameterPanel = new JPanel();
+    singleParameterPanel.setLayout(new BoxLayout(singleParameterPanel, BoxLayout.LINE_AXIS));
+    singleParameterPanel.setAlignmentX(0.0f);
+    singleParameterPanel.add(new JLabel(parameterName + ": "));
+    singleParameterPanel.add(Box.createHorizontalGlue());
+    NumberFormat doubleFormat = NumberFormat.getNumberInstance(Locale.US);
+    doubleFormat.setMinimumFractionDigits(1);
+    doubleFormat.setMaximumFractionDigits(10);
+    doubleFormat.setRoundingMode(RoundingMode.HALF_UP);
+    NumberFormatter doubleFormatter = new NumberFormatter(doubleFormat);
+    doubleFormatter.setMinimum(parameterMinValue);
+    doubleFormatter.setMaximum(parameterMaxValue);
+    doubleFormatter.setCommitsOnValidEdit(true);
+    JFormattedTextField singleParameterTextField = new JFormattedTextField(doubleFormatter);
+    singleParameterTextField.setValue(parameterValue);
+    String minValue = (parameterMinValue == Double.MIN_VALUE) ? "Double.MIN_VALUE"
+        : String.valueOf(parameterMinValue);
+    String maxValue = (parameterMaxValue == Double.MAX_VALUE) ? "Double.MAX_VALUE"
+        : String.valueOf(parameterMaxValue);
+    singleParameterTextField.setToolTipText(
+        "Only double \u2208 [" + minValue + "," + maxValue + "]");
+    singleParameterTextField.addPropertyChangeListener(actionEvent -> setter.accept(
+        Double.parseDouble(singleParameterTextField.getValue().toString())));
+    singleParameterTextField.setMaximumSize(new Dimension(200, 30));
+    singleParameterTextField.setPreferredSize(new Dimension(200, 30));
+    singleParameterPanel.add(singleParameterTextField);
+
+    ParameterStepping<Double> doubleParameterStepping = new ParameterStepping<Double>(setter,
+        getter, (a, b) -> a + b, (a, b) -> a * b, 1.0, 1);
+    doubleParameterStepping.useThisParameter = false;
+    parameterSteppingList.add(doubleParameterStepping);
+
+    JCheckBox useSteppingCheckBox = new JCheckBox();
+    useSteppingCheckBox.setSelected(false);
+    singleParameterPanel.add(useSteppingCheckBox);
+
+    JLabel stepsLabel = new JLabel("Steps: ");
+    stepsLabel.setEnabled(false);
+    singleParameterPanel.add(stepsLabel);
+    NumberFormat format = NumberFormat.getIntegerInstance();
+    format.setGroupingUsed(false);
+    format.setParseIntegerOnly(true);
+    NumberFormatter integerFormatter = new NumberFormatter(format);
+    integerFormatter.setMinimum(1);
+    integerFormatter.setMaximum(Integer.MAX_VALUE);
+    integerFormatter.setCommitsOnValidEdit(true);
+
+    JFormattedTextField stepsTextField = new JFormattedTextField(integerFormatter);
+    stepsTextField.setEnabled(false);
+    stepsTextField.setValue(1);
+    stepsTextField.setToolTipText("Only integer \u2208 [" + 1 + "," + Integer.MAX_VALUE + "]");
+    stepsTextField.addPropertyChangeListener(
+        actionEvent -> doubleParameterStepping.stepps = Integer.parseInt(
+            stepsTextField.getValue().toString()));
+    stepsTextField.setMaximumSize(new Dimension(40, 30));
+    stepsTextField.setPreferredSize(new Dimension(40, 30));
+    singleParameterPanel.add(stepsTextField);
+
+    JLabel stepsSizeLabel = new JLabel("StepsSize: ");
+    stepsSizeLabel.setEnabled(false);
+    singleParameterPanel.add(stepsSizeLabel);
+
+    NumberFormatter doubleFormatterForStepping = new NumberFormatter(doubleFormat);
+    doubleFormatterForStepping.setCommitsOnValidEdit(true);
+    JFormattedTextField stepsSizeTextField = new JFormattedTextField(doubleFormatterForStepping);
+    stepsSizeTextField.setEnabled(false);
+    stepsSizeTextField.setValue(1.0);
+    stepsSizeTextField.setToolTipText("Only double");
+    stepsSizeTextField.addPropertyChangeListener(
+        actionEvent -> doubleParameterStepping.stepSize = Double.parseDouble(
+            stepsSizeTextField.getValue().toString()));
+    stepsSizeTextField.setMaximumSize(new Dimension(40, 30));
+    stepsSizeTextField.setPreferredSize(new Dimension(40, 30));
+    singleParameterPanel.add(stepsSizeTextField);
+
+    useSteppingCheckBox.addActionListener(actionEvent -> {
+      boolean enabled = useSteppingCheckBox.isSelected();
+      doubleParameterStepping.useThisParameter = enabled;
+      this.useStepping = this.parameterSteppingList.stream()
+          .anyMatch(parameter -> parameter.useThisParameter);
+      stepsLabel.setEnabled(enabled);
+      stepsTextField.setEnabled(enabled);
+      stepsSizeLabel.setEnabled(enabled);
+      stepsSizeTextField.setEnabled(enabled);
+    });
+    panelMap.put(parameterName, singleParameterPanel);
+    singleParameterPanel.setVisible(visible);
+    borderPanel.add(singleParameterPanel);
+  }
+
+  //boolean
+  protected void addBooleanParameter(String parameterName, boolean parameterValue,
+      Consumer<Boolean> setter, List<String> showParameterNames, List<String> hideParameterNames) {
+    JPanel singleParameterPanel = new JPanel();
+    panelMap.put(parameterName, singleParameterPanel);
+    singleParameterPanel.setLayout(new BoxLayout(singleParameterPanel, BoxLayout.LINE_AXIS));
+    singleParameterPanel.setAlignmentX(0.0f);
+    singleParameterPanel.add(new JLabel(parameterName + ": "));
+    singleParameterPanel.add(Box.createHorizontalGlue());
+    JCheckBox useGroupNodeCheckBox = new JCheckBox();
+    useGroupNodeCheckBox.addActionListener(actionEvent -> {
+      setter.accept(useGroupNodeCheckBox.isSelected());
+      showParameterNames.forEach(
+          string -> panelMap.get(string).setVisible(useGroupNodeCheckBox.isSelected()));
+      hideParameterNames.forEach(
+          string -> panelMap.get(string).setVisible(!useGroupNodeCheckBox.isSelected()));
+    });
+    useGroupNodeCheckBox.setSelected(parameterValue);
+    singleParameterPanel.add(useGroupNodeCheckBox);
+    borderPanel.add(singleParameterPanel);
+  }
+
+
+  private void startTimer() {
+    startTime = System.currentTimeMillis();
+  }
+
+  private long printElapsedTime() {
+    long elapsedMilliSeconds = System.currentTimeMillis() - startTime;
+    console.println("Execution Time of Algo in Milliseconds:" + elapsedMilliSeconds);
+    return elapsedMilliSeconds;
+  }
+
+
+  private void cancel() {
+    if (runThread.isAlive()) {
+      console.println("Cancel run.");
+      cancel = true;
+      runProgressbar.cancel();
+    } else {
+      console.println("Nothing to cancel.");
+    }
+  }
+
+  private void createWildcardsCategory() {
+    Optional<Category> category = control.findCategoryWithName("Wildcards");
+    if (category.isEmpty()) {
+      control.createCategoryWithName("Wildcards");
+    }
+  }
+
+  private void fitness() {
+    if (runThread.isAlive()) {
+      console.println("Run have to be cancelled First.");
+      return;
+    }
 //		reset();
 //		reset();
 //		this.extractPositionAndAccess();
 //		this.extractPositionAndAccess();
-		double currentFitness = evaluateNetworkAndPrint();
-		console.println("Actual Fitnessvalue: " + currentFitness);
-	}
-	
-	
-	protected double evaluatePosition(List<Integer> positionToEvaluate) {
-		setState(positionToEvaluate); // execution time critical
-		return evaluateNetwork();
-	}
-
-	private double evaluateNetwork() {
-		runProgressbar.step();
-		return evaluateState(control.getModel(), calculateAmountOfAddedSwitches(), addedCableMeter(), false);
-	}
-	private double evaluateNetworkAndPrint() {
-		runProgressbar.step();
-		openAllSwitchInSwitchList();
-		control.calculateStateForCurrentIteration();
-		return evaluateState(control.getModel() ,calculateAmountOfAddedSwitches(), addedCableMeter(), true);
-	}
-	
-	private void openAllSwitchInSwitchList() {
-		for(HolonSwitch hSwitch: switchList) {
-			hSwitch.setMode(SwitchMode.Manual);
-			hSwitch.setManualState(SwitchState.Open);
-		}	
-	}
-	
-	
-	
-	private double addedCableMeter() {
-		return addedIndexCable.values().stream().reduce(0.0, Double::sum);
-	}
-
-	private int calculateAmountOfAddedSwitches() {
-		return (int)this.switchList.stream().filter(sw -> sw.getName().contains("AddedSwitch")).count();
-	}
-	
-	protected abstract double evaluateState(Model model, int amountOfAddedSwitch, double addedCableMeter, boolean moreInfromation);
-
-	
-	private void run() {
-		cancel = false;
-		control.guiSetEnabled(false);
-		runPrinter.openStream();
-		runPrinter.println("");
-		runPrinter.println("Start:" + stringStatFromActualState());
-		runPrinter.closeStream();
-		if(this.useStepping) {
-			initParameterStepping();
-			do {
-					executeAlgoWithParameter();
-					if(cancel) break;
-					resetState();
-			}while(updateOneParameter());
-			resetParameterStepping();
-		}else {
-			executeAlgoWithParameter();
-			
-		}
-		TopologieObjectiveFunction.averageLog.clear();
-		updateVisual();
-		runProgressbar.finishedCancel();
-		control.guiSetEnabled(true);
-	}
-	@SuppressWarnings("rawtypes")
-	private void initParameterStepping() {
-		for(ParameterStepping param :this.parameterSteppingList) {
-			param.init();
-		}
-		
-	}
-	@SuppressWarnings("rawtypes")
-	private void resetParameterStepping() {
-		for(ParameterStepping param :this.parameterSteppingList) {
-			param.reset();
-		}
-		
-	}
-
-
-
-
-	@SuppressWarnings("rawtypes")
-	private boolean updateOneParameter() {
-		List<ParameterStepping> parameterInUseList = this.parameterSteppingList.stream().filter(param -> param.useThisParameter).collect(Collectors.toList());
-		Collections.reverse(parameterInUseList);
-		int lastParameter = parameterInUseList.size() - 1 ;
-		int actualParameter = 0;
-		for(ParameterStepping param : parameterInUseList) {
-			
-			if(param.canUpdate()) {
-				param.update();
-				return true;
-			}else {
-				if(actualParameter == lastParameter) break;
-				param.reset();
-			}
-			actualParameter++;
-		}
-		//No Param can be updated 
-		return false;
-	}
-
-
-
-
-
-
-	private void executeAlgoWithParameter(){
-		double startFitness = evaluatePosition(extractPositionAndAccess());
-		resetChain.removeLast();
-		runPrinter.openStream();
-		runPrinter.println("");
-		runPrinter.println(algoInformationToPrint());
-		runPrinter.closeStream();
-		console.println(algoInformationToPrint());
-		runProgressbar.start();
-		Individual runBest = new Individual();
-		runBest.fitness = Double.MAX_VALUE;
-		for(int r = 0; r < rounds; r++)
-		{	
-			
-			resetState();
-			startTimer();
-			Individual  roundBest = executeAlgo();
-			if(cancel)return;
-			long executionTime = printElapsedTime();
-			setState(roundBest.position);
-			runPrinter.openStream();
-			runPrinter.println(runList.stream().map(Object::toString).collect(Collectors.joining(", ")));
-			runPrinter.println(stringStatFromActualState());
-			runPrinter.println("Result: " + roundBest.fitness + " ExecutionTime:" + executionTime);
-			runPrinter.closeStream();
-			
-			if(roundBest.fitness < runBest.fitness) runBest = roundBest;
-		}
-		
-		setState(runBest.position);
-		openAllSwitchInSwitchList();
-		updateVisual();
-		evaluateNetworkAndPrint();
-		console.println("Start: " + startFitness);
-		console.println("AlgoResult: " + runBest.fitness);
-	}
-	
-	
-
-
-
-
-
-
-
-	protected abstract Individual executeAlgo();
-
-
-
-
-
-
-	private void reset() {
-		if(runThread.isAlive()) {
-			console.println("Run have to be cancelled First.");
-			return;
-		}
-		if(!resetChain.isEmpty()) {
-			console.println("Resetting..");
-			setState(resetChain.getFirst());
-			resetChain.clear();
-			control.resetSimulation();
-			control.getModel().setCurrentIteration(0);
-			updateVisual();
-		}else {
-			console.println("No run inistialized.");
-		}
-	}
-
-
-	/**
-	 * To let the User See the current state without touching the Canvas.
-	 */
-	private void updateVisual() {
-		control.calculateStateForCurrentIteration();
-	}
-	/**
-	 * Sets the Model back to its original State before the LAST run.
-	 */
-	private void resetState() {
-		if(!resetChain.isEmpty()) {
-			setState(resetChain.removeLast());			
-		}
-		resetAllList();
-	}
-
-
-	/**
-	 * Sets the State out of the given position for calculation or to show the user.
-	 * @param position
-	 */
-	private void setState(List<Integer> position) {
-		this.removeAllAddedObjects();
-		for(int i = 0; i < this.amountOfNewCables; i++) {
-			generateCable(position.get(2 * i), position.get(2 * i + 1), position.get(2 * amountOfNewCables + i) == 1);
-		}
-		//Switches new Cable
-		//Switches existing cable
-		int count = 0;
-		for(int i = 3 * amountOfNewCables; i < 3 * this.amountOfNewCables + this.amountOfExistingCables; i++) {
-			generateEdgeFromIndexCable(cableList.get(count++), position.get(i) == 1);
-		}
-		//WildCards
-		count = 0;
-		for(int i = 3 * amountOfNewCables + amountOfExistingCables; i < position.size(); i++) {
-			accessWildcards.get(count++).setState(position.get(i));
-		}
-		openAllSwitchInSwitchList();
-		control.calculateStateForCurrentIteration();
-}
-
-
-	/**
-	 * Method to get the current Position alias a ListOf Booleans for aktive settings on the Objects on the Canvas.
-	 * Also initialize the Access Hashmap to swap faster positions.
-	 */
-	protected List<Integer> extractPositionAndAccess() {
-		Model model = control.getModel();
-		
-		resetAllList();
-		Optional<Category> category = control.findCategoryWithName("Wildcards");
-		category.ifPresentOrElse(cat -> {
-			int count = 1;
-			for(AbstractCanvasObject obj : cat.getObjects()) {
-				accessIntegerToWildcard.put(count, obj);
-				count++;
-			}
-		}, () -> {
-			console.println("No 'Wildcards' Category");
-		});
-
-		
-		List<Integer> initialState = new ArrayList<Integer>();
-		generateAccess(model.getCanvas().getObjectsInThisLayer(), null);			
-		addCables(model.getEdgesOnCanvas());
-		model.getEdgesOnCanvas().clear();
-		//New Cables
-		for(int i = 0; i < this.amountOfNewCables; i++) {
-			initialState.add(0);
-			initialState.add(0);
-		}
-		//switch in new Cables
-		for(int i = 0; i < this.amountOfNewCables; i++) {
-			initialState.add(0);
-		}
-		//Switch in initial Cable
-		cableSet.stream().forEach(indexCale -> initialState.add(0));
-		amountOfExistingCables = cableSet.size();
-		//wildcards
-		for(int i = 0; i < accessWildcards.size(); i++) {
-			initialState.add(0);
-		}
-		resetChain.add(initialState);
-		//console.println(accessIntToObject.values().stream().map(hO -> hO.getName()).collect(Collectors.joining(", ")));
-		//console.println(cableSet.stream().map(Object::toString).collect(Collectors.f(", ")));
-		return initialState;
-	}
-
-
-
-
-
-
-	private void resetAllList() {
-		accessWildcards.clear();
-		this.countForAccessMap = 0;
-		amountOfExistingCables = 0;
-		accessIntToObject.clear();
-		accessObjectToInt.clear();
-		cableSet.clear();
-		cableList.clear();
-		accessGroupNode.clear();
-		accessIntegerToWildcard.clear();
-		addedIndexCable.clear();
-		switchList.clear();
-		accessSwitchGroupNode.clear();
-		edgeList.clear();
-	}
-	
-	
-	
-	
-	/**
-	 * Method to extract the Informations recursively out of the Model.
-	 * @param nodes
-	 */
-	private void generateAccess(Stream<AbstractCanvasObject> nodes, GroupNode groupnode) {
-		nodes.forEach(aCps -> {
-			if(aCps instanceof HolonObject hO) {
-				accessIntToObject.put(++countForAccessMap, hO);
-				accessObjectToInt.put(hO, countForAccessMap);
-				if(hO.getName().contains("Wildcard")) {
-					accessWildcards.add(new AccessWrapper(hO));
-				}
-				if(groupnode != null) {
-					accessGroupNode.put(hO, groupnode);
-				}
-			}
-			if(aCps instanceof HolonSwitch hSwitch) {
-				accessIntToObject.put(++countForAccessMap, hSwitch);
-				accessObjectToInt.put(hSwitch, countForAccessMap);
-				if(groupnode != null) {
-					accessGroupNode.put(hSwitch, groupnode);
+    double currentFitness = evaluateNetworkAndPrint();
+    console.println("Actual Fitnessvalue: " + currentFitness);
+  }
+
+
+  protected double evaluatePosition(List<Integer> positionToEvaluate) {
+    setState(positionToEvaluate); // execution time critical
+    return evaluateNetwork();
+  }
+
+  private double evaluateNetwork() {
+    runProgressbar.step();
+    return evaluateState(control.getModel(), calculateAmountOfAddedSwitches(), addedCableMeter(),
+        false);
+  }
+
+  private double evaluateNetworkAndPrint() {
+    runProgressbar.step();
+    openAllSwitchInSwitchList();
+    control.calculateStateForCurrentIteration();
+    return evaluateState(control.getModel(), calculateAmountOfAddedSwitches(), addedCableMeter(),
+        true);
+  }
+
+  private void openAllSwitchInSwitchList() {
+    for (HolonSwitch hSwitch : switchList) {
+      hSwitch.setMode(SwitchMode.Manual);
+      hSwitch.setManualState(SwitchState.Open);
+    }
+  }
+
+
+  private double addedCableMeter() {
+    return addedIndexCable.values().stream().reduce(0.0, Double::sum);
+  }
+
+  private int calculateAmountOfAddedSwitches() {
+    return (int) this.switchList.stream().filter(sw -> sw.getName().contains("AddedSwitch"))
+        .count();
+  }
+
+  protected abstract double evaluateState(Model model, int amountOfAddedSwitch,
+      double addedCableMeter, boolean moreInfromation);
+
+
+  private void run() {
+    cancel = false;
+    control.guiSetEnabled(false);
+    runPrinter.openStream();
+    runPrinter.println("");
+    runPrinter.println("Start:" + stringStatFromActualState());
+    runPrinter.closeStream();
+    if (this.useStepping) {
+      initParameterStepping();
+      do {
+        executeAlgoWithParameter();
+				if (cancel) {
+					break;
 				}
 				}
-			}
-			if(aCps instanceof Node node) {
-				accessIntToObject.put(++countForAccessMap, node);
-				accessObjectToInt.put(node, countForAccessMap);
-				if(groupnode != null) {
-					accessGroupNode.put(node, groupnode);
+        resetState();
+      } while (updateOneParameter());
+      resetParameterStepping();
+    } else {
+      executeAlgoWithParameter();
+
+    }
+    TopologieObjectiveFunction.averageLog.clear();
+    updateVisual();
+    runProgressbar.finishedCancel();
+    control.guiSetEnabled(true);
+  }
+
+  @SuppressWarnings("rawtypes")
+  private void initParameterStepping() {
+    for (ParameterStepping param : this.parameterSteppingList) {
+      param.init();
+    }
+
+  }
+
+  @SuppressWarnings("rawtypes")
+  private void resetParameterStepping() {
+    for (ParameterStepping param : this.parameterSteppingList) {
+      param.reset();
+    }
+
+  }
+
+
+  @SuppressWarnings("rawtypes")
+  private boolean updateOneParameter() {
+    List<ParameterStepping> parameterInUseList = this.parameterSteppingList.stream()
+        .filter(param -> param.useThisParameter).collect(Collectors.toList());
+    Collections.reverse(parameterInUseList);
+    int lastParameter = parameterInUseList.size() - 1;
+    int actualParameter = 0;
+    for (ParameterStepping param : parameterInUseList) {
+
+      if (param.canUpdate()) {
+        param.update();
+        return true;
+      } else {
+				if (actualParameter == lastParameter) {
+					break;
 				}
 				}
+        param.reset();
+      }
+      actualParameter++;
+    }
+    //No Param can be updated
+    return false;
+  }
+
+
+  private void executeAlgoWithParameter() {
+    double startFitness = evaluatePosition(extractPositionAndAccess());
+    resetChain.removeLast();
+    runPrinter.openStream();
+    runPrinter.println("");
+    runPrinter.println(algoInformationToPrint());
+    runPrinter.closeStream();
+    console.println(algoInformationToPrint());
+    runProgressbar.start();
+    Individual runBest = new Individual();
+    runBest.fitness = Double.MAX_VALUE;
+    for (int r = 0; r < rounds; r++) {
+
+      resetState();
+      startTimer();
+      Individual roundBest = executeAlgo();
+			if (cancel) {
+				return;
 			}
 			}
-			else if(aCps instanceof GroupNode groupNode) {
-				generateAccess(groupNode.getObjectsInThisLayer(), groupNode);
-			}
-		});
-	}
-	
-	
-	protected void resetWildcards() {
-		this.accessWildcards.forEach(AccessWrapper::resetState);
-	}
-	/**
-	 * All Nodes have to be in the access map !!
-	 */
-	private void addCables(Set<Edge> edges) {
-		
-		for (Edge edge : edges) {
-			edge.mode = Edge.EdgeMode.Unlimited;
-			edgeList.add(edge);
-			//console.println("Cable from " + edge.getA().getName() + " to " + edge.getB().getName());
-			if(!accessObjectToInt.containsKey(edge.getA())) {
-				console.println("Node A [" + edge.getA() + "] from Edge[" + edge + "] not exist");
-				continue;
-			} else if (!accessObjectToInt.containsKey(edge.getB())) {
-				console.println("Node B [" + edge.getB() + "]from Edge[" + edge + "] not exist");
-				continue;
-			}
-			IndexCable cable = new IndexCable(accessObjectToInt.get(edge.getA()), accessObjectToInt.get(edge.getB()));
-			boolean success = cableSet.add(cable);
-			if(success) {
-				cableList.add(cable);
-			}
-			
-		}
-	}
-	
-	
-	
-	private void generateCable(int index0, int index1, boolean switchBetween) {
-		//If cable isnt valid
-		if(index0 == 0 || index1 == 0 || index0 == index1) {
-			//console.println("Cable("+index1+","+index2+ ") isn't valid");
-			return;
-		}
-		IndexCable cable = new IndexCable(index0, index1);
-		//if cable is in existing cables
-		if(cableSet.contains(cable) || addedIndexCable.keySet().contains(cable)) {
-			return;
-		}
-		generateEdgeFromIndexCable(cable, switchBetween);
-		addedIndexCable.put(cable, cable.getLength());
-	}
-	
-	private void generateEdgeFromIndexCable(IndexCable cable, boolean switchBetween){
-		if(switchBetween) {
-			//generate Switch
-			AbstractCanvasObject fromObject =  accessIntToObject.get(cable.first);
-			AbstractCanvasObject toObject =  accessIntToObject.get(cable.second);
-			int middleX = (fromObject.getPosition().getX() +   toObject.getPosition().getX())/2;
-			int middleY = (fromObject.getPosition().getY() +   toObject.getPosition().getY())/2;
-			HolonSwitch newSwitch = new HolonSwitch("AddedSwitch");
-			newSwitch.setPosition(middleX, middleY);
-			//If fromObject is in Group
-			if(accessGroupNode.containsKey(fromObject)) {
-				GroupNode groupnode = accessGroupNode.get(fromObject);
-				groupnode.add(newSwitch);
-				accessSwitchGroupNode.put(newSwitch, groupnode);
-			} else if(accessGroupNode.containsKey(toObject)) {
-				GroupNode groupnode = accessGroupNode.get(toObject);
-				groupnode.add(newSwitch);
-				accessSwitchGroupNode.put(newSwitch, groupnode);
-			}else {
-				control.getModel().getCanvas().add(newSwitch);		
-			}
-			//else if toObject is in Group
-			this.switchList.add(newSwitch);
-			//Generate Cable From Object A To Switch
-			Edge edge1 = new Edge(fromObject, newSwitch, 0);
-			edge1.mode = Edge.EdgeMode.Unlimited;
-			control.getModel().getEdgesOnCanvas().add(edge1);
-			edgeList.add(edge1);
-			
-			//Generate Cable From Object B To Switch
-			Edge edge = new Edge(newSwitch, toObject, 0);
-			edge.mode = Edge.EdgeMode.Unlimited;
-			control.getModel().getEdgesOnCanvas().add(edge);
-			edgeList.add(edge);
-			}else {
-			Edge edge = new Edge(accessIntToObject.get(cable.first), accessIntToObject.get(cable.second), 0);
-			edge.mode = Edge.EdgeMode.Unlimited;
-			control.getModel().getEdgesOnCanvas().add(edge);
-			edgeList.add(edge);
-		}
-	}
-	private void removeAllAddedObjects() {
-		control.getModel().getEdgesOnCanvas().removeAll(edgeList);
-		addedIndexCable.clear();
-		//control.getModel().getObjectsOnCanvas().removeAll(switchList);
-		for(HolonSwitch hSwitch: switchList) {
-			if(this.accessSwitchGroupNode.containsKey(hSwitch)) {
-				accessSwitchGroupNode.get(hSwitch).remove(hSwitch);
-			}
-			else {
-				control.getModel().getCanvas().remove(hSwitch);
-			}
-		}
-		accessSwitchGroupNode.clear();
-		switchList.clear();
-		edgeList.clear();
-	}
-
-	private String stringStatFromActualState() {
-		AlgorithmFrameworkFlex.RunValues val = new AlgorithmFrameworkFlex.RunValues();
-		GroupNode canvas = control.getModel().getCanvas();
-		List<HolonObject> holonObjectList = canvas.getAllHolonObjectsRecursive().toList();
-		Map<HolonObject.HolonObjectState, Long> stateMap = holonObjectList.stream().collect(Collectors.groupingBy(HolonObject::getState, Collectors.counting()));
-		// UPDATE SUPPLY STATE
-		val.producer = Math.toIntExact(stateMap.getOrDefault(HolonObject.HolonObjectState.PRODUCER, 0L));
-		val.overSupplied = Math.toIntExact(stateMap.getOrDefault(HolonObject.HolonObjectState.OVER_SUPPLIED, 0L));
-		val.supplied = Math.toIntExact(stateMap.getOrDefault(HolonObject.HolonObjectState.SUPPLIED, 0L));
-		val.partiallySupplied = Math.toIntExact(stateMap.getOrDefault(HolonObject.HolonObjectState.PARTIALLY_SUPPLIED, 0L));
-		val.unsupplied = Math.toIntExact(stateMap.getOrDefault(HolonObject.HolonObjectState.NOT_SUPPLIED, 0L));
-		val.passiv = Math.toIntExact(stateMap.getOrDefault(HolonObject.HolonObjectState.NO_ENERGY, 0L));
-		val.consumer = val.overSupplied + val.supplied + val.partiallySupplied + val.unsupplied;
-		val.objects = val.consumer + val.producer + val.passiv;
-
-		List<HolonElement> holonElementList = canvas.getAllHolonElements().toList();
-		val.elements = holonElementList.size();
-		// UPDATE ActiveInActive
-		val.activeElements = holonElementList.stream().filter(HolonElement::isOn).count();
-		val.consumption = canvas.getTotalConsumption();
-		val.production = canvas.getTotalProduction();
-		val.difference= Math.abs(val.production - val.consumption);
-
-		List<Flexibility> activeFlex = holonElementList.stream().flatMap(ele -> ele.flexList.stream()).filter(flex -> flex.getState().equals(Flexibility.FlexState.IN_USE)).toList();
-		Map<HolonElement.Priority, Long> priorityCounts = activeFlex.stream().collect(Collectors.groupingBy(flex -> flex.getElement().priority, Collectors.counting()));
-		val.essentialFlex = priorityCounts.getOrDefault(HolonElement.Priority.Essential, 0L);
-		val.highFlex = priorityCounts.getOrDefault(HolonElement.Priority.High, 0L);
-		val.mediumFlex = priorityCounts.getOrDefault(HolonElement.Priority.Medium, 0L);
-		val.lowFlex = priorityCounts.getOrDefault(HolonElement.Priority.Low, 0L);
-
-		val.flexebilities = activeFlex.size();
-		val.holon = control.getModel().holons.size();
-		List<HolonSwitch> switchList = canvas.getAllSwitchObjectsRecursive().toList();
-		val.switches = switchList.size();
-		val.activeSwitches = (int)switchList.stream().filter(HolonSwitch::isClosed).count();
-
-		DoubleSummaryStatistics overStat = holonObjectList.stream().filter(con -> con.getState().equals(HolonObject.HolonObjectState.OVER_SUPPLIED))
-				.mapToDouble(HolonObject::getSupplyBarPercentage).summaryStatistics();
-
-		DoubleSummaryStatistics partiallyStat = holonObjectList.stream().filter(con -> con.getState().equals(HolonObject.HolonObjectState.PARTIALLY_SUPPLIED))
-				.mapToDouble(HolonObject::getSupplyBarPercentage).summaryStatistics();
-
-		val.partiallyMin = AlgorithmFrameworkFlex.RunValues.filterInf(partiallyStat.getMin());
-		val.partiallyMax = AlgorithmFrameworkFlex.RunValues.filterInf(partiallyStat.getMax());
-		val.partiallyAverage = AlgorithmFrameworkFlex.RunValues.filterInf(partiallyStat.getAverage());
-
-		val.overMin = AlgorithmFrameworkFlex.RunValues.filterInf(overStat.getMin());
-		val.overMax = AlgorithmFrameworkFlex.RunValues.filterInf(overStat.getMax());
-		val.overAverage = AlgorithmFrameworkFlex.RunValues.filterInf(overStat.getAverage());
-
-
-		int addedSwitches = calculateAmountOfAddedSwitches();
-		double addedCableMeters = addedCableMeter();
-		double wildcardCost = TopologieObjectiveFunction.calculateWildcardCost(control.getModel());
-		double cableCost = TopologieObjectiveFunction.calculateAddedCableCost(addedCableMeters);
-		double switchCost = TopologieObjectiveFunction.calculateAddedSwitchCost(addedSwitches);
-		double totalCost = wildcardCost + cableCost + switchCost;
-
-		return val.stringStatFromRunValues("")
-			+ " Topology["
-			+ " addedCableMeters:" + addedCableMeters
-			+ " addedSwitches: " + addedSwitches
-			+ " totalCost: " + totalCost + "("
-			+ " wildcardCost: " + wildcardCost
-			+ " cableCost: " + cableCost
-			+ " switchCost: " + switchCost
-			+  ")]";
-	}
-	
-
-	
-	@Override
-	public JPanel getPanel() {
-		return content;
-	}
-
-	@Override
-	public void setController(Control control) {
-		this.control = control;
-	}
-	
-	//                 | New Cable          | Switches   | Wildcards             |
-	//return index:    |  countForAccessMap | 1  		 | accessWildcards.size()|	
-	public int getMaximumIndexObjects(int index) {
-		int maximumIndex = -1;
-		//New Cables
-		if(index < 2 * amountOfNewCables) {
-			maximumIndex =  this.countForAccessMap;
-		}
-		//Switches in existing and in new Cables
-		else if (index < 3 * amountOfNewCables + this.amountOfExistingCables) {
-			maximumIndex =  1;
-		}
-		//wildcards
-		else {
-			maximumIndex =  this.accessIntegerToWildcard.size();
-		}
-		return maximumIndex;
-	}
-	
-	
-	private class RunProgressBar{
-		//progressbar
-		private JProgressBar progressBar = new JProgressBar();
-		private int count = 0;
-		private boolean isActive = false;
-		
-		public void step() {
-			if(isActive) progressBar.setValue(count++);
-		}
-		public void start() {
-			progressBar.setIndeterminate(false);
-			count = 0;
-			isActive = true;
-			progressBar.setValue(0);
-			progressBar.setMaximum(getProgressBarMaxCount());
-		}
-		public void cancel() {
-			isActive = false;
-			progressBar.setIndeterminate(true);
-		}
-		public void finishedCancel() {
-			progressBar.setIndeterminate(false);
-			progressBar.setValue(0);
-		}
-		public JProgressBar getJProgressBar(){
-			return progressBar;
-		}
-	}
-	
-	protected abstract int getProgressBarMaxCount();
-	
-	protected abstract String algoInformationToPrint();
-	protected abstract String plottFileName();
-	
-	
-	
-	public class Printer{
-		private JFileChooser fileChooser = new JFileChooser();
-		private BufferedWriter out;
-		public Printer(String filename){
-			fileChooser.setCurrentDirectory(new File(System.getProperty("user.dir")));
-			fileChooser.setSelectedFile(new File(filename));
-		}
-		public void openStream() {
-			File file = fileChooser.getSelectedFile();
-			try {
-				file.createNewFile();
-				out = new BufferedWriter(new OutputStreamWriter(
-					    new FileOutputStream(file, true), "UTF-8"));
-			} catch (IOException e) {
-				System.out.println(e.getMessage());
-			}
-		}
-		
-		
-		public void println(String stringToPrint) {
-			try {
-				out.write(stringToPrint);
-				out.newLine();
-			} catch (IOException e) {
-				System.out.println(e.getMessage());
-			}
-		}
-		public void closeStream() {
-			try {
-				out.close();
-			} catch (IOException e) {
-				System.out.println(e.getMessage());
-			}
-		}
-	}
-		
-	
-	/**
-	 * A Wrapper Class to access wildcards
-	 */
-	private class AccessWrapper {
-		int state = 0;
-		HolonObject wildcard;
-		public AccessWrapper(HolonObject wildcard) {
-			this.wildcard = wildcard;
-		}
-		
-		public void setState(int state) {
-			if(this.state !=  state) {
-				this.state = state;
-				if(state > 0) {
-					wildcard.clearElements();
-					HolonObject hO = (HolonObject)accessIntegerToWildcard.get(state);
-					if(hO == null) {
-						console.println("null set state(" + state + ")");
-					}else {
-						if(hO.getName().contains(":")) {
-							wildcard.setName("Wildcard" + hO.getName().substring(hO.getName().lastIndexOf(":")));
-						}else {
-							wildcard.setName("Wildcard");
-						}
-						wildcard.add(hO.elementsStream().toList());
-						wildcard.setImagePath(hO.getImagePath());
-					}
-				}else {
-					resetState();
-				}
+      long executionTime = printElapsedTime();
+      setState(roundBest.position);
+      runPrinter.openStream();
+      runPrinter.println(runList.stream().map(Object::toString).collect(Collectors.joining(", ")));
+      runPrinter.println(stringStatFromActualState());
+      runPrinter.println("Result: " + roundBest.fitness + " ExecutionTime:" + executionTime);
+      runPrinter.closeStream();
+
+			if (roundBest.fitness < runBest.fitness) {
+				runBest = roundBest;
 			}
 			}
-		}
-		public void resetState() {
-			state = 0;
-			wildcard.setName("Wildcard");
-			wildcard.setImagePath(ImagePreference.Canvas.DefaultObject.House);
-			wildcard.clearElements();
-		}
-		
-		public String toString() {
-			return wildcard + "have state: " + state;
-		}
-	}
-	
-	
-	public class Individual {
-		public double fitness;
-		public  List<Integer> position;
-		
-		public Individual(){};
-		/**
-		 *  Copy Constructor
-		 */
-		public Individual(Individual c){
-			position = c.position.stream().collect(Collectors.toList());
-			fitness = c.fitness;
-		}
-	}
-	
-	protected class ParameterStepping<T>{
-		boolean useThisParameter = false;
-		String paramaterName;
-		private int count = 0;
-		int stepps;
-		T stepSize;
-		T startValue;
-		Consumer<T> setter;
-		Supplier<T> getter;
-		BiFunction<Integer,T,T> multyply;
-		BiFunction<T,T,T> add;
-		ParameterStepping(Consumer<T> setter, Supplier<T> getter, BiFunction<T,T,T> add, BiFunction<Integer,T,T> multyply, T stepSize, int stepps){
-			this.setter = setter;
-			this.getter = getter;
-			this.multyply = multyply;
-			this.add = add;
-			this.stepSize = stepSize;
-			this.stepps = stepps;
-		}
-		
-		void init() {
-			startValue = getter.get();
-		}
-		
-		boolean canUpdate() {
-			return count  < stepps;
-		}
-		
-		void update(){
-			if(canUpdate()) {
-				setter.accept(add.apply(startValue, multyply.apply(count + 1, stepSize)));
-				count ++;
+    }
+
+    setState(runBest.position);
+    openAllSwitchInSwitchList();
+    updateVisual();
+    evaluateNetworkAndPrint();
+    console.println("Start: " + startFitness);
+    console.println("AlgoResult: " + runBest.fitness);
+  }
+
+
+  protected abstract Individual executeAlgo();
+
+
+  private void reset() {
+    if (runThread.isAlive()) {
+      console.println("Run have to be cancelled First.");
+      return;
+    }
+    if (!resetChain.isEmpty()) {
+      console.println("Resetting..");
+      setState(resetChain.getFirst());
+      resetChain.clear();
+      control.resetSimulation();
+      control.getModel().setCurrentIteration(0);
+      updateVisual();
+    } else {
+      console.println("No run inistialized.");
+    }
+  }
+
+
+  /**
+   * To let the User See the current state without touching the Canvas.
+   */
+  private void updateVisual() {
+    control.updateStateForCurrentIteration();
+  }
+
+  /**
+   * Sets the Model back to its original State before the LAST run.
+   */
+  private void resetState() {
+    if (!resetChain.isEmpty()) {
+      setState(resetChain.removeLast());
+    }
+    resetAllList();
+  }
+
+
+  /**
+   * Sets the State out of the given position for calculation or to show the user.
+   *
+   * @param position
+   */
+  private void setState(List<Integer> position) {
+    this.removeAllAddedObjects();
+    for (int i = 0; i < this.amountOfNewCables; i++) {
+      generateCable(position.get(2 * i), position.get(2 * i + 1),
+          position.get(2 * amountOfNewCables + i) == 1);
+    }
+    //Switches new Cable
+    //Switches existing cable
+    int count = 0;
+    for (int i = 3 * amountOfNewCables;
+        i < 3 * this.amountOfNewCables + this.amountOfExistingCables; i++) {
+      generateEdgeFromIndexCable(cableList.get(count++), position.get(i) == 1);
+    }
+    //WildCards
+    count = 0;
+    for (int i = 3 * amountOfNewCables + amountOfExistingCables; i < position.size(); i++) {
+      accessWildcards.get(count++).setState(position.get(i));
+    }
+    openAllSwitchInSwitchList();
+    control.calculateStateForCurrentIteration();
+  }
+
+
+  /**
+   * Method to get the current Position alias a ListOf Booleans for aktive settings on the Objects
+   * on the Canvas. Also initialize the Access Hashmap to swap faster positions.
+   */
+  protected List<Integer> extractPositionAndAccess() {
+    Model model = control.getModel();
+
+    resetAllList();
+    Optional<Category> category = control.findCategoryWithName("Wildcards");
+    category.ifPresentOrElse(cat -> {
+      int count = 1;
+      for (AbstractCanvasObject obj : cat.getObjects()) {
+        accessIntegerToWildcard.put(count, obj);
+        count++;
+      }
+    }, () -> {
+      console.println("No 'Wildcards' Category");
+    });
+
+    List<Integer> initialState = new ArrayList<Integer>();
+    generateAccess(model.getCanvas().getObjectsInThisLayer(), null);
+    addCables(model.getEdgesOnCanvas());
+    model.getEdgesOnCanvas().clear();
+    //New Cables
+    for (int i = 0; i < this.amountOfNewCables; i++) {
+      initialState.add(0);
+      initialState.add(0);
+    }
+    //switch in new Cables
+    for (int i = 0; i < this.amountOfNewCables; i++) {
+      initialState.add(0);
+    }
+    //Switch in initial Cable
+    cableSet.stream().forEach(indexCale -> initialState.add(0));
+    amountOfExistingCables = cableSet.size();
+    //wildcards
+    for (int i = 0; i < accessWildcards.size(); i++) {
+      initialState.add(0);
+    }
+    resetChain.add(initialState);
+    //console.println(accessIntToObject.values().stream().map(hO -> hO.getName()).collect(Collectors.joining(", ")));
+    //console.println(cableSet.stream().map(Object::toString).collect(Collectors.f(", ")));
+    return initialState;
+  }
+
+
+  private void resetAllList() {
+    accessWildcards.clear();
+    this.countForAccessMap = 0;
+    amountOfExistingCables = 0;
+    accessIntToObject.clear();
+    accessObjectToInt.clear();
+    cableSet.clear();
+    cableList.clear();
+    accessGroupNode.clear();
+    accessIntegerToWildcard.clear();
+    addedIndexCable.clear();
+    switchList.clear();
+    accessSwitchGroupNode.clear();
+    edgeList.clear();
+  }
+
+
+  /**
+   * Method to extract the Informations recursively out of the Model.
+   *
+   * @param nodes
+   */
+  private void generateAccess(Stream<AbstractCanvasObject> nodes, GroupNode groupnode) {
+    nodes.forEach(aCps -> {
+      if (aCps instanceof HolonObject hO) {
+        accessIntToObject.put(++countForAccessMap, hO);
+        accessObjectToInt.put(hO, countForAccessMap);
+        if (hO.getName().contains("Wildcard")) {
+          accessWildcards.add(new AccessWrapper(hO));
+        }
+        if (groupnode != null) {
+          accessGroupNode.put(hO, groupnode);
+        }
+      }
+      if (aCps instanceof HolonSwitch hSwitch) {
+        accessIntToObject.put(++countForAccessMap, hSwitch);
+        accessObjectToInt.put(hSwitch, countForAccessMap);
+        if (groupnode != null) {
+          accessGroupNode.put(hSwitch, groupnode);
+        }
+      }
+      if (aCps instanceof Node node) {
+        accessIntToObject.put(++countForAccessMap, node);
+        accessObjectToInt.put(node, countForAccessMap);
+        if (groupnode != null) {
+          accessGroupNode.put(node, groupnode);
+        }
+      } else if (aCps instanceof GroupNode groupNode) {
+        generateAccess(groupNode.getObjectsInThisLayer(), groupNode);
+      }
+    });
+  }
+
+
+  protected void resetWildcards() {
+    this.accessWildcards.forEach(AccessWrapper::resetState);
+  }
+
+  /**
+   * All Nodes have to be in the access map !!
+   */
+  private void addCables(Set<Edge> edges) {
+
+    for (Edge edge : edges) {
+      edge.mode = Edge.EdgeMode.Unlimited;
+      edgeList.add(edge);
+      //console.println("Cable from " + edge.getA().getName() + " to " + edge.getB().getName());
+      if (!accessObjectToInt.containsKey(edge.getA())) {
+        console.println("Node A [" + edge.getA() + "] from Edge[" + edge + "] not exist");
+        continue;
+      } else if (!accessObjectToInt.containsKey(edge.getB())) {
+        console.println("Node B [" + edge.getB() + "]from Edge[" + edge + "] not exist");
+        continue;
+      }
+      IndexCable cable = new IndexCable(accessObjectToInt.get(edge.getA()),
+          accessObjectToInt.get(edge.getB()));
+      boolean success = cableSet.add(cable);
+      if (success) {
+        cableList.add(cable);
+      }
+
+    }
+  }
+
+
+  private void generateCable(int index0, int index1, boolean switchBetween) {
+    //If cable isnt valid
+    if (index0 == 0 || index1 == 0 || index0 == index1) {
+      //console.println("Cable("+index1+","+index2+ ") isn't valid");
+      return;
+    }
+    IndexCable cable = new IndexCable(index0, index1);
+    //if cable is in existing cables
+    if (cableSet.contains(cable) || addedIndexCable.keySet().contains(cable)) {
+      return;
+    }
+    generateEdgeFromIndexCable(cable, switchBetween);
+    addedIndexCable.put(cable, cable.getLength());
+  }
+
+  private void generateEdgeFromIndexCable(IndexCable cable, boolean switchBetween) {
+    if (switchBetween) {
+      //generate Switch
+      AbstractCanvasObject fromObject = accessIntToObject.get(cable.first);
+      AbstractCanvasObject toObject = accessIntToObject.get(cable.second);
+      int middleX = (fromObject.getPosition().getX() + toObject.getPosition().getX()) / 2;
+      int middleY = (fromObject.getPosition().getY() + toObject.getPosition().getY()) / 2;
+      HolonSwitch newSwitch = new HolonSwitch("AddedSwitch");
+      newSwitch.setPosition(middleX, middleY);
+      //If fromObject is in Group
+      if (accessGroupNode.containsKey(fromObject)) {
+        GroupNode groupnode = accessGroupNode.get(fromObject);
+        groupnode.add(newSwitch);
+        accessSwitchGroupNode.put(newSwitch, groupnode);
+      } else if (accessGroupNode.containsKey(toObject)) {
+        GroupNode groupnode = accessGroupNode.get(toObject);
+        groupnode.add(newSwitch);
+        accessSwitchGroupNode.put(newSwitch, groupnode);
+      } else {
+        control.getModel().getCanvas().add(newSwitch);
+      }
+      //else if toObject is in Group
+      this.switchList.add(newSwitch);
+      //Generate Cable From Object A To Switch
+      Edge edge1 = new Edge(fromObject, newSwitch, 0);
+      edge1.mode = Edge.EdgeMode.Unlimited;
+      control.getModel().getEdgesOnCanvas().add(edge1);
+      edgeList.add(edge1);
+
+      //Generate Cable From Object B To Switch
+      Edge edge = new Edge(newSwitch, toObject, 0);
+      edge.mode = Edge.EdgeMode.Unlimited;
+      control.getModel().getEdgesOnCanvas().add(edge);
+      edgeList.add(edge);
+    } else {
+      Edge edge = new Edge(accessIntToObject.get(cable.first), accessIntToObject.get(cable.second),
+          0);
+      edge.mode = Edge.EdgeMode.Unlimited;
+      control.getModel().getEdgesOnCanvas().add(edge);
+      edgeList.add(edge);
+    }
+  }
+
+  private void removeAllAddedObjects() {
+    control.getModel().getEdgesOnCanvas().removeAll(edgeList);
+    addedIndexCable.clear();
+    //control.getModel().getObjectsOnCanvas().removeAll(switchList);
+    for (HolonSwitch hSwitch : switchList) {
+      if (this.accessSwitchGroupNode.containsKey(hSwitch)) {
+        accessSwitchGroupNode.get(hSwitch).remove(hSwitch);
+      } else {
+        control.getModel().getCanvas().remove(hSwitch);
+      }
+    }
+    accessSwitchGroupNode.clear();
+    switchList.clear();
+    edgeList.clear();
+  }
+
+  private String stringStatFromActualState() {
+    AlgorithmFrameworkFlex.RunValues val = new AlgorithmFrameworkFlex.RunValues();
+    GroupNode canvas = control.getModel().getCanvas();
+    List<HolonObject> holonObjectList = canvas.getAllHolonObjectsRecursive().toList();
+    Map<HolonObject.HolonObjectState, Long> stateMap = holonObjectList.stream()
+        .collect(Collectors.groupingBy(HolonObject::getState, Collectors.counting()));
+    // UPDATE SUPPLY STATE
+    val.producer = Math.toIntExact(
+        stateMap.getOrDefault(HolonObject.HolonObjectState.PRODUCER, 0L));
+    val.overSupplied = Math.toIntExact(
+        stateMap.getOrDefault(HolonObject.HolonObjectState.OVER_SUPPLIED, 0L));
+    val.supplied = Math.toIntExact(
+        stateMap.getOrDefault(HolonObject.HolonObjectState.SUPPLIED, 0L));
+    val.partiallySupplied = Math.toIntExact(
+        stateMap.getOrDefault(HolonObject.HolonObjectState.PARTIALLY_SUPPLIED, 0L));
+    val.unsupplied = Math.toIntExact(
+        stateMap.getOrDefault(HolonObject.HolonObjectState.NOT_SUPPLIED, 0L));
+    val.passiv = Math.toIntExact(stateMap.getOrDefault(HolonObject.HolonObjectState.NO_ENERGY, 0L));
+    val.consumer = val.overSupplied + val.supplied + val.partiallySupplied + val.unsupplied;
+    val.objects = val.consumer + val.producer + val.passiv;
+
+    List<HolonElement> holonElementList = canvas.getAllHolonElements().toList();
+    val.elements = holonElementList.size();
+    // UPDATE ActiveInActive
+    val.activeElements = holonElementList.stream().filter(HolonElement::isOn).count();
+    val.consumption = canvas.getTotalConsumption();
+    val.production = canvas.getTotalProduction();
+    val.difference = Math.abs(val.production - val.consumption);
+
+    List<Flexibility> activeFlex = holonElementList.stream().flatMap(ele -> ele.flexList.stream())
+        .filter(flex -> flex.getState().equals(Flexibility.FlexState.IN_USE)).toList();
+    Map<HolonElement.Priority, Long> priorityCounts = activeFlex.stream()
+        .collect(Collectors.groupingBy(flex -> flex.getElement().priority, Collectors.counting()));
+    val.essentialFlex = priorityCounts.getOrDefault(HolonElement.Priority.Essential, 0L);
+    val.highFlex = priorityCounts.getOrDefault(HolonElement.Priority.High, 0L);
+    val.mediumFlex = priorityCounts.getOrDefault(HolonElement.Priority.Medium, 0L);
+    val.lowFlex = priorityCounts.getOrDefault(HolonElement.Priority.Low, 0L);
+
+    val.flexebilities = activeFlex.size();
+    val.holon = control.getModel().holons.size();
+    List<HolonSwitch> switchList = canvas.getAllSwitchObjectsRecursive().toList();
+    val.switches = switchList.size();
+    val.activeSwitches = (int) switchList.stream().filter(HolonSwitch::isClosed).count();
+
+    DoubleSummaryStatistics overStat = holonObjectList.stream()
+        .filter(con -> con.getState().equals(HolonObject.HolonObjectState.OVER_SUPPLIED))
+        .mapToDouble(HolonObject::getSupplyBarPercentage).summaryStatistics();
+
+    DoubleSummaryStatistics partiallyStat = holonObjectList.stream()
+        .filter(con -> con.getState().equals(HolonObject.HolonObjectState.PARTIALLY_SUPPLIED))
+        .mapToDouble(HolonObject::getSupplyBarPercentage).summaryStatistics();
+
+    val.partiallyMin = AlgorithmFrameworkFlex.RunValues.filterInf(partiallyStat.getMin());
+    val.partiallyMax = AlgorithmFrameworkFlex.RunValues.filterInf(partiallyStat.getMax());
+    val.partiallyAverage = AlgorithmFrameworkFlex.RunValues.filterInf(partiallyStat.getAverage());
+
+    val.overMin = AlgorithmFrameworkFlex.RunValues.filterInf(overStat.getMin());
+    val.overMax = AlgorithmFrameworkFlex.RunValues.filterInf(overStat.getMax());
+    val.overAverage = AlgorithmFrameworkFlex.RunValues.filterInf(overStat.getAverage());
+
+    int addedSwitches = calculateAmountOfAddedSwitches();
+    double addedCableMeters = addedCableMeter();
+    double wildcardCost = TopologieObjectiveFunction.calculateWildcardCost(control.getModel());
+    double cableCost = TopologieObjectiveFunction.calculateAddedCableCost(addedCableMeters);
+    double switchCost = TopologieObjectiveFunction.calculateAddedSwitchCost(addedSwitches);
+    double totalCost = wildcardCost + cableCost + switchCost;
+
+    return val.stringStatFromRunValues("")
+        + " Topology["
+        + " addedCableMeters:" + addedCableMeters
+        + " addedSwitches: " + addedSwitches
+        + " totalCost: " + totalCost + "("
+        + " wildcardCost: " + wildcardCost
+        + " cableCost: " + cableCost
+        + " switchCost: " + switchCost
+        + ")]";
+  }
+
+
+  @Override
+  public JPanel getPanel() {
+    return content;
+  }
+
+  @Override
+  public void setController(Control control) {
+    this.control = control;
+  }
+
+  //                 | New Cable          | Switches   | Wildcards             |
+  //return index:    |  countForAccessMap | 1  		 | accessWildcards.size()|
+  public int getMaximumIndexObjects(int index) {
+    int maximumIndex = -1;
+    //New Cables
+    if (index < 2 * amountOfNewCables) {
+      maximumIndex = this.countForAccessMap;
+    }
+    //Switches in existing and in new Cables
+    else if (index < 3 * amountOfNewCables + this.amountOfExistingCables) {
+      maximumIndex = 1;
+    }
+    //wildcards
+    else {
+      maximumIndex = this.accessIntegerToWildcard.size();
+    }
+    return maximumIndex;
+  }
+
+  protected abstract int getProgressBarMaxCount();
+
+  protected abstract String algoInformationToPrint();
+
+  protected abstract String plottFileName();
+
+  private class RunProgressBar {
+
+    //progressbar
+    private JProgressBar progressBar = new JProgressBar();
+    private int count = 0;
+    private boolean isActive = false;
+
+    public void step() {
+			if (isActive) {
+				progressBar.setValue(count++);
 			}
 			}
-		}
-		
-		void reset() {
-			setter.accept(startValue);
-			count = 0;
-		}
-	}
-	
-	
-	
-	
-	
-	public class IndexCable{
-	    public final Integer first;
-	    public final Integer second;
-
-	    public IndexCable(Integer first, Integer second) {
-	    	if(first.equals(second)) {
-	    		throw new IllegalArgumentException("(" + first + "==" + second + ")" 
-	    							+ "Two ends of the cable are at the same Object");
-	    	} else if(first.compareTo(second) < 0) {
-	    		this.first = first;
-	    		this.second = second;	    		
-	    	}else {
-	    		this.first = second;
-	    		this.second = first;
-	    	}
-	    }
-
-	    @Override
-	    public boolean equals(Object o) {
-	        if(o instanceof IndexCable cable) {
-	        	 return Objects.equals(cable.first, first) && Objects.equals(cable.second, second);
-	        }
-	        return false;
-	    }
-
-	    @Override
-	    public int hashCode() {
-	        return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
-	    }
-	    @Override
-	    public String toString() {
-			return "{" + first + "," + second + "}";
-	    }
-	    public double getLength() {
-	    	return accessIntToObject.get(first).getPosition().getDistance(accessIntToObject.get(second).getPosition());
-	    }
-	}
+    }
+
+    public void start() {
+      progressBar.setIndeterminate(false);
+      count = 0;
+      isActive = true;
+      progressBar.setValue(0);
+      progressBar.setMaximum(getProgressBarMaxCount());
+    }
+
+    public void cancel() {
+      isActive = false;
+      progressBar.setIndeterminate(true);
+    }
+
+    public void finishedCancel() {
+      progressBar.setIndeterminate(false);
+      progressBar.setValue(0);
+    }
+
+    public JProgressBar getJProgressBar() {
+      return progressBar;
+    }
+  }
+
+  public class Printer {
+
+    private JFileChooser fileChooser = new JFileChooser();
+    private BufferedWriter out;
+
+    public Printer(String filename) {
+      fileChooser.setCurrentDirectory(new File(System.getProperty("user.dir")));
+      fileChooser.setSelectedFile(new File(filename));
+    }
+
+    public void openStream() {
+      File file = fileChooser.getSelectedFile();
+      try {
+        file.createNewFile();
+        out = new BufferedWriter(new OutputStreamWriter(
+            new FileOutputStream(file, true), "UTF-8"));
+      } catch (IOException e) {
+        System.out.println(e.getMessage());
+      }
+    }
+
+
+    public void println(String stringToPrint) {
+      try {
+        out.write(stringToPrint);
+        out.newLine();
+      } catch (IOException e) {
+        System.out.println(e.getMessage());
+      }
+    }
+
+    public void closeStream() {
+      try {
+        out.close();
+      } catch (IOException e) {
+        System.out.println(e.getMessage());
+      }
+    }
+  }
+
+
+  /**
+   * A Wrapper Class to access wildcards
+   */
+  private class AccessWrapper {
+
+    int state = 0;
+    HolonObject wildcard;
+
+    public AccessWrapper(HolonObject wildcard) {
+      this.wildcard = wildcard;
+    }
+
+    public void setState(int state) {
+      if (this.state != state) {
+        this.state = state;
+        if (state > 0) {
+          wildcard.clearElements();
+          HolonObject hO = (HolonObject) accessIntegerToWildcard.get(state);
+          if (hO == null) {
+            console.println("null set state(" + state + ")");
+          } else {
+            if (hO.getName().contains(":")) {
+              wildcard.setName("Wildcard" + hO.getName().substring(hO.getName().lastIndexOf(":")));
+            } else {
+              wildcard.setName("Wildcard");
+            }
+            wildcard.add(hO.elementsStream().toList());
+            wildcard.setImagePath(hO.getImagePath());
+          }
+        } else {
+          resetState();
+        }
+      }
+    }
+
+    public void resetState() {
+      state = 0;
+      wildcard.setName("Wildcard");
+      wildcard.setImagePath(ImagePreference.Canvas.DefaultObject.House);
+      wildcard.clearElements();
+    }
+
+    public String toString() {
+      return wildcard + "have state: " + state;
+    }
+  }
+
+
+  public class Individual {
+
+    public double fitness;
+    public List<Integer> position;
+
+    public Individual() {
+    }
+
+    ;
+
+    /**
+     * Copy Constructor
+     */
+    public Individual(Individual c) {
+      position = c.position.stream().collect(Collectors.toList());
+      fitness = c.fitness;
+    }
+  }
+
+  protected class ParameterStepping<T> {
+
+    boolean useThisParameter = false;
+    String paramaterName;
+    int stepps;
+    T stepSize;
+    T startValue;
+    Consumer<T> setter;
+    Supplier<T> getter;
+    BiFunction<Integer, T, T> multyply;
+    BiFunction<T, T, T> add;
+    private int count = 0;
+
+    ParameterStepping(Consumer<T> setter, Supplier<T> getter, BiFunction<T, T, T> add,
+        BiFunction<Integer, T, T> multyply, T stepSize, int stepps) {
+      this.setter = setter;
+      this.getter = getter;
+      this.multyply = multyply;
+      this.add = add;
+      this.stepSize = stepSize;
+      this.stepps = stepps;
+    }
+
+    void init() {
+      startValue = getter.get();
+    }
+
+    boolean canUpdate() {
+      return count < stepps;
+    }
+
+    void update() {
+      if (canUpdate()) {
+        setter.accept(add.apply(startValue, multyply.apply(count + 1, stepSize)));
+        count++;
+      }
+    }
+
+    void reset() {
+      setter.accept(startValue);
+      count = 0;
+    }
+  }
+
+
+  public class IndexCable {
+
+    public final Integer first;
+    public final Integer second;
+
+    public IndexCable(Integer first, Integer second) {
+      if (first.equals(second)) {
+        throw new IllegalArgumentException("(" + first + "==" + second + ")"
+            + "Two ends of the cable are at the same Object");
+      } else if (first.compareTo(second) < 0) {
+        this.first = first;
+        this.second = second;
+      } else {
+        this.first = second;
+        this.second = first;
+      }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (o instanceof IndexCable cable) {
+        return Objects.equals(cable.first, first) && Objects.equals(cable.second, second);
+      }
+      return false;
+    }
+
+    @Override
+    public int hashCode() {
+      return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
+    }
+
+    @Override
+    public String toString() {
+      return "{" + first + "," + second + "}";
+    }
+
+    public double getLength() {
+      return accessIntToObject.get(first).getPosition()
+          .getDistance(accessIntToObject.get(second).getPosition());
+    }
+  }
 }
 }

+ 33 - 31
src/holeg/interfaces/GraphEditable.java

@@ -1,43 +1,45 @@
 package holeg.interfaces;
 package holeg.interfaces;
 
 
-import java.util.LinkedList;
-
 import holeg.utility.math.vector.Vec2f;
 import holeg.utility.math.vector.Vec2f;
+import java.util.LinkedList;
 
 
 /**
 /**
  * Interface for all Elements that have a Graph to edit it state over time.
  * Interface for all Elements that have a Graph to edit it state over time.
- * @author Tom Troppmann
  *
  *
+ * @author Tom Troppmann
  */
  */
 
 
 
 
-
 public interface GraphEditable {
 public interface GraphEditable {
-	/**
-	 * all types of graphs
-	 */
-	enum GraphType {
-		boolGraph, doubleGraph
-	}
-	/**
-	 * Determine what type the Graph have.
-	 * @return the type of the Graph
-	 */
-	GraphType getGraphType();
-	/**
-	 * Getter for the graph.
-	 * @return The list of all graph points.
-	 */
-	LinkedList<Vec2f> getStateGraph();
-	
-	/**
-	 * Sample the Graph on the object.
-	 */
-	void sampleGraph();
-	
-	/**
-	 * Resets the Graph two the initial start
-	 * e.g. the Point Left and Right at 100%
-	 */
-	void reset();
+
+  /**
+   * Determine what type the Graph have.
+   *
+   * @return the type of the Graph
+   */
+  GraphType getGraphType();
+
+  /**
+   * Getter for the graph.
+   *
+   * @return The list of all graph points.
+   */
+  LinkedList<Vec2f> getStateGraph();
+
+  /**
+   * Sample the Graph on the object.
+   */
+  void sampleGraph();
+
+  /**
+   * Resets the Graph two the initial start e.g. the Point Left and Right at 100%
+   */
+  void reset();
+
+  /**
+   * all types of graphs
+   */
+  enum GraphType {
+    boolGraph, doubleGraph
+  }
 }
 }

+ 63 - 59
src/holeg/interfaces/LocalMode.java

@@ -1,63 +1,67 @@
 package holeg.interfaces;
 package holeg.interfaces;
 
 
 public interface LocalMode {
 public interface LocalMode {
-	
-	int STANDARD_GRAPH_ACCURACY=100;
-	class Period {
-		public Period(Period other) {
-			this.type = other.type;
-			this.interval = other.interval;
-		}
-
-		public enum PeriodType{
-			Local, Global
-		}
-		private final PeriodType type;
-		private int interval;
-		public Period(int interval){
-			this.interval = interval;
-			type = PeriodType.Local;
-		}
-		public Period(){
-			type = PeriodType.Global;
-		};
-		/**
-		 * Sets the local period of the element.
-		 * If the simulation has 100 steps and the local period is 50,
-		 * then there will be two full cycles during the simulation.
-		 * @param interval The local period for this element.
-		 */
-		public void setInterval(int interval){
-			this.interval = interval;
-		}
-
-		/**
-		 * Used to query the local period of an element.
-		 * @return The local period of this element.
-		 * This should return the set local period,
-		 * which may be anything, even if the component is set to be "stretching",
-		 * that is,
-		 * acting as if the local period was the same
-		 * as the number of total iterations for this simulation.
-		 */
-		public int getInterval(){
-			if (type == PeriodType.Local) {
-				return interval;
-			}
-			return STANDARD_GRAPH_ACCURACY;
-		}
-
-		public Period.PeriodType getType() {
-			return type;
-		}
-	}
-
-
-
-	Period getPeriod();
-	/**
-	 *  Determine if it should use his own LocalPeriod or use the global Period over the entire simulation.
-	 * 	Local Period is opposed to repeated once the period is over.
-	 */
-	void setPeriod(Period period);
+
+  int STANDARD_GRAPH_ACCURACY = 100;
+
+  Period getPeriod();
+
+  /**
+   * Determine if it should use his own LocalPeriod or use the global Period over the entire
+   * simulation. Local Period is opposed to repeated once the period is over.
+   */
+  void setPeriod(Period period);
+
+  class Period {
+
+    private final PeriodType type;
+    private int interval;
+
+    public Period(Period other) {
+      this.type = other.type;
+      this.interval = other.interval;
+    }
+    public Period(int interval) {
+      this.interval = interval;
+      type = PeriodType.Local;
+    }
+
+    public Period() {
+      type = PeriodType.Global;
+    }
+
+    /**
+     * Used to query the local period of an element.
+     *
+     * @return The local period of this element. This should return the set local period, which may
+     * be anything, even if the component is set to be "stretching", that is, acting as if the local
+     * period was the same as the number of total iterations for this simulation.
+     */
+    public int getInterval() {
+      if (type == PeriodType.Local) {
+        return interval;
+      }
+      return STANDARD_GRAPH_ACCURACY;
+    }
+
+    ;
+
+    /**
+     * Sets the local period of the element. If the simulation has 100 steps and the local period is
+     * 50, then there will be two full cycles during the simulation.
+     *
+     * @param interval The local period for this element.
+     */
+    public void setInterval(int interval) {
+      this.interval = interval;
+    }
+
+    public Period.PeriodType getType() {
+      return type;
+    }
+
+    public enum PeriodType {
+      Local, Global
+    }
+  }
 }
 }

+ 3 - 1
src/holeg/interfaces/TimelineDependent.java

@@ -1,3 +1,5 @@
 package holeg.interfaces;
 package holeg.interfaces;
 
 
-public interface TimelineDependent extends GraphEditable, LocalMode {}
+public interface TimelineDependent extends GraphEditable, LocalMode {
+
+}

+ 116 - 118
src/holeg/model/AbstractCanvasObject.java

@@ -2,129 +2,127 @@ package holeg.model;
 
 
 import holeg.ui.model.IdCounter;
 import holeg.ui.model.IdCounter;
 import holeg.utility.math.vector.Vec2i;
 import holeg.utility.math.vector.Vec2i;
-
 import java.util.Optional;
 import java.util.Optional;
 
 
 /**
 /**
- * The abstract class "CpsObject" represents any possible object in the system
- * (except Edges). The representation of any object contains following
- * variables: see description of variables
+ * The abstract class "CpsObject" represents any possible object in the system (except Edges). The
+ * representation of any object contains following variables: see description of variables
  *
  *
  * @author Gruppe14
  * @author Gruppe14
  */
  */
 public abstract class AbstractCanvasObject {
 public abstract class AbstractCanvasObject {
-    /* Name given by the user. */
-    String name = "";
-    /* Path of the image for the Obj. */
-    String imagePath = "";
-    /* Position with a X and Y value */
-    Vec2i position = new Vec2i(0, 0);
-    /* ID of the Obj. */
-    private final int id;
-    private transient GroupNode groupNode;
-
-    /**
-     * Constructor for a CpsObejct with an unique ID.
-     *
-     * @param objName of the Object
-     */
-    public AbstractCanvasObject(String objName) {
-        setName(objName);
-        this.id = IdCounter.next();
-    }
-
-    /**
-     * Constructor for a new CpsObject with an unique ID (This constructor
-     * correspond to the interaction between the Categories and Canvas)-->
-     * actually the "new" Object is a copy.
-     *
-     * @param other Object to be copied
-     */
-    public AbstractCanvasObject(AbstractCanvasObject other) {
-        setName(other.getName());
-        setImagePath(other.getImagePath());
-        this.position = new Vec2i(other.position);
-        this.id = IdCounter.next();
-
-    }
-
-    public Optional<GroupNode> getGroupNode() {
-        return Optional.ofNullable(groupNode);
-    }
-
-    public void setGroupNode(GroupNode groupNode) {
-        this.groupNode = groupNode;
-    }
-
-
-    public abstract AbstractCanvasObject copy();
-
-    /**
-     * Getter for the user-defined name (no unique).
-     *
-     * @return String
-     */
-    public String getName() {
-        return name;
-    }
-
-    /**
-     * Set the name.
-     *
-     * @param name String
-     */
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    /**
-     * Get the path of the image for the selected Object.
-     *
-     * @return String
-     */
-    public String getImagePath() {
-        return imagePath;
-    }
-
-    /**
-     * Set the path of the image.
-     *
-     * @param imagePath the Image to set
-     */
-    public void setImagePath(String imagePath) {
-        this.imagePath = imagePath;
-    }
-
-    public int getId() {
-        return id;
-    }
-
-
-    /**
-     * Set the position of the Object in the canvas.
-     *
-     * @param x X-Coord
-     * @param y Y-Coord
-     */
-    public void setPosition(int x, int y) {
-        setPosition(new Vec2i(x, y));
-    }
-
-    /**
-     * Get the actual position of the Object.
-     *
-     * @return Position Position of this Object
-     */
-    public Vec2i getPosition() {
-        return position;
-    }
-
-    /**
-     * Set the position of the Object in the canvas.
-     *
-     * @param pos Coordinates
-     */
-    public void setPosition(Vec2i pos) {
-        this.position = pos;
-    }
+
+  /* ID of the Obj. */
+  private final int id;
+  /* Name given by the user. */
+  String name = "";
+  /* Path of the image for the Obj. */
+  String imagePath = "";
+  /* Position with a X and Y value */
+  Vec2i position = new Vec2i(0, 0);
+  private transient GroupNode groupNode;
+
+  /**
+   * Constructor for a CpsObejct with an unique ID.
+   *
+   * @param objName of the Object
+   */
+  public AbstractCanvasObject(String objName) {
+    setName(objName);
+    this.id = IdCounter.next();
+  }
+
+  /**
+   * Constructor for a new CpsObject with an unique ID (This constructor correspond to the
+   * interaction between the Categories and Canvas)--> actually the "new" Object is a copy.
+   *
+   * @param other Object to be copied
+   */
+  public AbstractCanvasObject(AbstractCanvasObject other) {
+    setName(other.getName());
+    setImagePath(other.getImagePath());
+    this.position = new Vec2i(other.position);
+    this.id = IdCounter.next();
+
+  }
+
+  public Optional<GroupNode> getGroupNode() {
+    return Optional.ofNullable(groupNode);
+  }
+
+  public void setGroupNode(GroupNode groupNode) {
+    this.groupNode = groupNode;
+  }
+
+
+  public abstract AbstractCanvasObject copy();
+
+  /**
+   * Getter for the user-defined name (no unique).
+   *
+   * @return String
+   */
+  public String getName() {
+    return name;
+  }
+
+  /**
+   * Set the name.
+   *
+   * @param name String
+   */
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  /**
+   * Get the path of the image for the selected Object.
+   *
+   * @return String
+   */
+  public String getImagePath() {
+    return imagePath;
+  }
+
+  /**
+   * Set the path of the image.
+   *
+   * @param imagePath the Image to set
+   */
+  public void setImagePath(String imagePath) {
+    this.imagePath = imagePath;
+  }
+
+  public int getId() {
+    return id;
+  }
+
+
+  /**
+   * Set the position of the Object in the canvas.
+   *
+   * @param x X-Coord
+   * @param y Y-Coord
+   */
+  public void setPosition(int x, int y) {
+    setPosition(new Vec2i(x, y));
+  }
+
+  /**
+   * Get the actual position of the Object.
+   *
+   * @return Position Position of this Object
+   */
+  public Vec2i getPosition() {
+    return position;
+  }
+
+  /**
+   * Set the position of the Object in the canvas.
+   *
+   * @param pos Coordinates
+   */
+  public void setPosition(Vec2i pos) {
+    this.position = pos;
+  }
 }
 }

+ 34 - 30
src/holeg/model/Constrain.java

@@ -2,36 +2,40 @@ package holeg.model;
 
 
 import java.util.function.Predicate;
 import java.util.function.Predicate;
 
 
-import com.google.gson.annotations.Expose;
-
 public class Constrain {
 public class Constrain {
-	private final Predicate<Flexibility> constrainFunction;
-	private final String name;
-	
-	public Constrain(Predicate<Flexibility> constrainFunction,String name) {
-		this.constrainFunction = constrainFunction;
-		this.name = name;
-	}
-	
-	public Predicate<Flexibility> getConstrainFunction() {
-		return constrainFunction;
-	}
-	public String getName() {
-		return name;
-	}
-	
-	
-	//Example Constrains:
-	/** Flexibility should be offered when Element is active.*/
-	public static Predicate<Flexibility> onConstrain = f 	-> 	f.getElement().active;
-	/** Flexibility should be offered when Element is inactive.*/
-	public static Predicate<Flexibility> offConstrain = f	-> 	!f.getElement().active;
-	
-	public static Constrain createOnConstrain() {
-		return new Constrain( onConstrain, "onConstrain");
-	}
-	public static Constrain createOffConstrain() {
-		return new Constrain( offConstrain, "offConstrain");
-	}
+
+  /**
+   * Flexibility should be offered when Element is active.
+   */
+  public static Predicate<Flexibility> onConstrain = f -> f.getElement().active;
+  /**
+   * Flexibility should be offered when Element is inactive.
+   */
+  public static Predicate<Flexibility> offConstrain = f -> !f.getElement().active;
+  private final Predicate<Flexibility> constrainFunction;
+  private final String name;
+
+  public Constrain(Predicate<Flexibility> constrainFunction, String name) {
+    this.constrainFunction = constrainFunction;
+    this.name = name;
+  }
+
+  //Example Constrains:
+
+  public static Constrain createOnConstrain() {
+    return new Constrain(onConstrain, "onConstrain");
+  }
+
+  public static Constrain createOffConstrain() {
+    return new Constrain(offConstrain, "offConstrain");
+  }
+
+  public Predicate<Flexibility> getConstrainFunction() {
+    return constrainFunction;
+  }
+
+  public String getName() {
+    return name;
+  }
 
 
 }
 }

+ 145 - 145
src/holeg/model/Edge.java

@@ -3,149 +3,149 @@ package holeg.model;
 
 
 public class Edge {
 public class Edge {
 
 
-    // Max. capacity of the Edge, if flow is greater than the status --> is
-    // Working would be false
-    public float maxCapacity;
-    // Source
-    AbstractCanvasObject a;
-    // Destination
-    AbstractCanvasObject b;
-    public EdgeMode mode = EdgeMode.Normal;
-    private transient EdgeState state = initState();
-    private transient float flowEnergy = 0;
-
-    /**
-     * Constructor with a user-defined max. capacity
-     *
-     * @param a      Source
-     * @param b      Destination
-     * @param maxCap Maximum Capacity
-     */
-    public Edge(AbstractCanvasObject a, AbstractCanvasObject b, float maxCap) {
-        setA(a);
-        setB(b);
-        this.maxCapacity = maxCap;
-    }
-
-
-    /**
-     * Clone Constructor
-     */
-    public Edge(Edge other) {
-        setA(other.a);
-        setB(other.b);
-        this.maxCapacity = other.maxCapacity;
-        this.state = other.state;
-        this.mode = other.mode;
-        this.flowEnergy = other.flowEnergy;
-    }
-
-    /**
-     * Getter for the length of the Cable.
-     */
-    public float getLength() {
-        return a.getPosition().getDistance(b.getPosition());
-    }
-
-    /**
-     * Getter for the Source.
-     *
-     * @return the a
-     */
-    public AbstractCanvasObject getA() {
-        return a;
-    }
-
-    /**
-     * Set the Source to a new one.
-     *
-     * @param a the a to set
-     */
-    public void setA(AbstractCanvasObject a) {
-        this.a = a;
-    }
-
-    /**
-     * Getter for the destination.
-     *
-     * @return the b
-     */
-    public AbstractCanvasObject getB() {
-        return b;
-    }
-
-    /**
-     * Set the Destination to a new one.
-     *
-     * @param b the b to set
-     */
-    public void setB(AbstractCanvasObject b) {
-        this.b = b;
-    }
-
-    /**
-     * Check if a CpsEdge is Connected to the AbstractCpsObject.
-     *
-     * @param holonObject the AbstractCpsObject to check.
-     * @return true if either a or b is the AbstractCpsObject to check.
-     */
-    public boolean isConnectedTo(AbstractCanvasObject holonObject) {
-        return (holonObject.equals(a) || holonObject.equals(b));
-    }
-
-    @Override
-    public String toString() {
-        String A = (a == null) ? "null" : a.getName() + " [" + a.getId() + "]";
-        String B = (b == null) ? "null" : b.getName() + " [" + b.getId() + "]";
-        return "Edge: " + A + " to " + B;
-    }
-
-    public EdgeState getState() {
-        return state;
-    }
-
-    public void setState(EdgeState state) {
-        this.state = state;
-    }
-
-    void reset() {
-        state = initState();
-    }
-
-    private EdgeState initState() {
-        if (mode == EdgeMode.Disconnected) {
-            return EdgeState.Burned;
-        }
-        return EdgeState.Working;
-    }
-
-    public float getActualFlow() {
-        return flowEnergy;
-    }
-
-    public void setActualFlow(float energyToSupplyInTheNetwork) {
-        flowEnergy = energyToSupplyInTheNetwork;
-    }
-
-    public float getEnergyFromConneted() {
-        float energy = 0.0f;
-        if (getA() instanceof HolonObject hO && hO.getActualEnergy() > 0) {
-            energy += hO.getActualEnergy();
-        }
-        if (getB() instanceof HolonObject hO && hO.getActualEnergy() > 0) {
-            energy += hO.getActualEnergy();
-        }
-        return energy;
-    }
-
-    public enum EdgeMode {
-        Normal, Unlimited, Disconnected
-    }
-
-    /*
-     * STATE
-     */
-    public enum EdgeState {
-        Working, Burned
-    }
+  // Max. capacity of the Edge, if flow is greater than the status --> is
+  // Working would be false
+  public float maxCapacity;
+  public EdgeMode mode = EdgeMode.Normal;
+  // Source
+  AbstractCanvasObject a;
+  // Destination
+  AbstractCanvasObject b;
+  private transient EdgeState state = initState();
+  private transient float flowEnergy = 0;
+
+  /**
+   * Constructor with a user-defined max. capacity
+   *
+   * @param a      Source
+   * @param b      Destination
+   * @param maxCap Maximum Capacity
+   */
+  public Edge(AbstractCanvasObject a, AbstractCanvasObject b, float maxCap) {
+    setA(a);
+    setB(b);
+    this.maxCapacity = maxCap;
+  }
+
+
+  /**
+   * Clone Constructor
+   */
+  public Edge(Edge other) {
+    setA(other.a);
+    setB(other.b);
+    this.maxCapacity = other.maxCapacity;
+    this.state = other.state;
+    this.mode = other.mode;
+    this.flowEnergy = other.flowEnergy;
+  }
+
+  /**
+   * Getter for the length of the Cable.
+   */
+  public float getLength() {
+    return a.getPosition().getDistance(b.getPosition());
+  }
+
+  /**
+   * Getter for the Source.
+   *
+   * @return the a
+   */
+  public AbstractCanvasObject getA() {
+    return a;
+  }
+
+  /**
+   * Set the Source to a new one.
+   *
+   * @param a the a to set
+   */
+  public void setA(AbstractCanvasObject a) {
+    this.a = a;
+  }
+
+  /**
+   * Getter for the destination.
+   *
+   * @return the b
+   */
+  public AbstractCanvasObject getB() {
+    return b;
+  }
+
+  /**
+   * Set the Destination to a new one.
+   *
+   * @param b the b to set
+   */
+  public void setB(AbstractCanvasObject b) {
+    this.b = b;
+  }
+
+  /**
+   * Check if a CpsEdge is Connected to the AbstractCpsObject.
+   *
+   * @param holonObject the AbstractCpsObject to check.
+   * @return true if either a or b is the AbstractCpsObject to check.
+   */
+  public boolean isConnectedTo(AbstractCanvasObject holonObject) {
+    return (holonObject.equals(a) || holonObject.equals(b));
+  }
+
+  @Override
+  public String toString() {
+    String A = (a == null) ? "null" : a.getName() + " [" + a.getId() + "]";
+    String B = (b == null) ? "null" : b.getName() + " [" + b.getId() + "]";
+    return "Edge: " + A + " to " + B;
+  }
+
+  public EdgeState getState() {
+    return state;
+  }
+
+  public void setState(EdgeState state) {
+    this.state = state;
+  }
+
+  void reset() {
+    state = initState();
+  }
+
+  private EdgeState initState() {
+    if (mode == EdgeMode.Disconnected) {
+      return EdgeState.Burned;
+    }
+    return EdgeState.Working;
+  }
+
+  public float getActualFlow() {
+    return flowEnergy;
+  }
+
+  public void setActualFlow(float energyToSupplyInTheNetwork) {
+    flowEnergy = energyToSupplyInTheNetwork;
+  }
+
+  public float getEnergyFromConneted() {
+    float energy = 0.0f;
+    if (getA() instanceof HolonObject hO && hO.getActualEnergy() > 0) {
+      energy += hO.getActualEnergy();
+    }
+    if (getB() instanceof HolonObject hO && hO.getActualEnergy() > 0) {
+      energy += hO.getActualEnergy();
+    }
+    return energy;
+  }
+
+  public enum EdgeMode {
+    Normal, Unlimited, Disconnected
+  }
+
+  /*
+   * STATE
+   */
+  public enum EdgeState {
+    Working, Burned
+  }
 }
 }

+ 202 - 197
src/holeg/model/Flexibility.java

@@ -8,203 +8,208 @@ import java.util.function.Predicate;
  * Representative of a flexibility for a HolonElement.
  * Representative of a flexibility for a HolonElement.
  */
  */
 public class Flexibility {
 public class Flexibility {
-    /*
-     *  MODEL
-     */
-    /**
-     * The Name of a Flexibility.
-     */
-    public String name;
-    /**
-     * How fast in TimeSteps the Flexibility can be activated.
-     */
-    public int speed;
-    /**
-     * How high the cost for a activation are.
-     */
-    public float cost;
-    /**
-     * SHould this Flexibility be Offered when is constrainList is fulfilled the flexibility can be activated.
-     */
-    public boolean offered;
-    /**
-     * The List of Constrains the Flexibility
-     */
-    public List<Constrain> constrainList;
-    /**
-     * The owner of the Flexibility.
-     */
-    private transient HolonElement element;
-    /**
-     * The Duration in TimeSteps how long the Flexibility is activated.
-     */
-    private int duration;
-    /** The Element this flexibility is assigned.*/
-    /**
-     * The Duration after a successful activation between the next possible activation.
-     */
-    private int cooldown;
-    /*
-     *  STATE
-     */
-    private transient FlexState state = FlexState.OFFERED;
-    private transient int timeStep;
-    private transient int activationTime = -1;
-    private transient int durationEndTime = -1;
-    private transient int coolDownEndTime = -1;
-
-    public Flexibility(HolonElement element) {
-        this(0, 0.f, 1, 0, false, element);
-    }
-
-    public Flexibility(int speed, float cost, int duration, int cooldown, boolean offered, HolonElement element) {
-        this.speed = speed;
-        this.cost = cost;
-        setDuration(duration);
-        setCooldown(cooldown);
-        this.offered = offered;
-        this.element = element;
-        constrainList = new ArrayList<Constrain>();
-    }
-
-    public HolonElement getElement() {
-        return element;
-    }
-
-    public void setElement(HolonElement element) {
-        this.element = element;
-    }
-
-    public int getDuration() {
-        return duration;
-    }
-
-    /**
-     * Minimum duration is 1 TimeStep.
-     */
-    public void setDuration(int duration) {
-        this.duration = Math.max(1, duration);
-    }
-
-    public int getCooldown() {
-        return cooldown;
-    }
-
-    /**
-     * No negative cooldown TimeSteps.
-     */
-    public void setCooldown(int cooldown) {
-        this.cooldown = Math.max(0, cooldown);
-    }
-
-    /**
-     * returns the total energy Amount accumulated over the TimeSteps.
-     */
-    public float magnitude() {
-        return ((float) duration) * element.getEnergy();
-    }
-
-    public float energyReleased() {
-        return (constrainList.stream().map(Constrain::getName).anyMatch(name -> name.equals("onConstrain")) ? -1.0f : 1.0f) * element.getEnergy();
-    }
-
-    public boolean isPositive() {
-        return energyReleased() >= 0;
-    }
-
-    public boolean isNegative() {
-        return energyReleased() < 0;
-    }
-
-    public int getSpeed() {
-        return speed;
-    }
-
-    public void setSpeed(int speed) {
-        this.speed = speed;
-    }
-
-    @Override
-    public String toString() {
-        return "Flexibility: " + name + " from [HolonElement: " + element.getName() + "]";
-    }
-
-    void calculateState(int timestep) {
-        this.timeStep = timestep;
-        state = revalidateState();
-    }
-    public boolean order() {
-        if (canOrder()) {
-            state = FlexState.IN_USE;
-            durationEndTime = timeStep + this.getDuration();
-            coolDownEndTime = durationEndTime + this.getCooldown();
-            activationTime = timeStep;
-            return true;
-        }
-        return false;
-    }
-
-    public boolean cancel() {
-        if (activationTime == timeStep) {
-            reset();
-            return true;
-        }
-        return false;
-    }
-
-    void reset() {
-        durationEndTime = -1;
-        coolDownEndTime = -1;
-        state = revalidateState();
-    }
-
-    public boolean canActivate() {
-        return remainingTimeTillActivation() == 0;
-    }
-
-    public boolean canOrder() {
-        boolean flexIsOffered = state.equals(FlexState.OFFERED);
-        return flexIsOffered && !element.isFlexActive();
-    }
-
-    public FlexState getState() {
-        return state;
-    }
-
-    public int remainingTimeTillActivation() {
-        return Math.max(0, coolDownEndTime - timeStep);
-    }
-
-    public int remainingDuration() {
-        return Math.max(0, durationEndTime - timeStep);
-    }
-
-    /**
-     * Checks if all assigned constrains are fulfilled. When no constrains assigned returns true.
-     */
-    private boolean fulfillsConstrains() {
-        return constrainList.stream().map(Constrain::getConstrainFunction).reduce(Predicate::and).orElse(f -> true).test(this);
-    }
-
-    private FlexState revalidateState() {
-        if (canActivate()) {
-            if (!this.fulfillsConstrains() || element.isFlexActive()) {
-                return FlexState.UNAVAILABLE;
-            } else if (this.offered) {
-                return FlexState.OFFERED;
-            }
-            return FlexState.NOT_OFFERED;
-        } else if (remainingDuration() == 0) {
-            return FlexState.ON_COOLDOWN;
-        } else {
-            return FlexState.IN_USE;
-        }
-    }
-
-    public enum FlexState {
-        IN_USE, ON_COOLDOWN, OFFERED, NOT_OFFERED, UNAVAILABLE
-    }
-
+  /*
+   *  MODEL
+   */
+  /**
+   * The Name of a Flexibility.
+   */
+  public String name;
+  /**
+   * How fast in TimeSteps the Flexibility can be activated.
+   */
+  public int speed;
+  /**
+   * How high the cost for a activation are.
+   */
+  public float cost;
+  /**
+   * SHould this Flexibility be Offered when is constrainList is fulfilled the flexibility can be
+   * activated.
+   */
+  public boolean offered;
+  /**
+   * The List of Constrains the Flexibility
+   */
+  public List<Constrain> constrainList;
+  /**
+   * The owner of the Flexibility.
+   */
+  private transient HolonElement element;
+  /**
+   * The Duration in TimeSteps how long the Flexibility is activated.
+   */
+  private int duration;
+  /** The Element this flexibility is assigned.*/
+  /**
+   * The Duration after a successful activation between the next possible activation.
+   */
+  private int cooldown;
+  /*
+   *  STATE
+   */
+  private transient FlexState state = FlexState.OFFERED;
+  private transient int timeStep;
+  private transient int activationTime = -1;
+  private transient int durationEndTime = -1;
+  private transient int coolDownEndTime = -1;
+
+  public Flexibility(HolonElement element) {
+    this(0, 0.f, 1, 0, false, element);
+  }
+
+  public Flexibility(int speed, float cost, int duration, int cooldown, boolean offered,
+      HolonElement element) {
+    this.speed = speed;
+    this.cost = cost;
+    setDuration(duration);
+    setCooldown(cooldown);
+    this.offered = offered;
+    this.element = element;
+    constrainList = new ArrayList<Constrain>();
+  }
+
+  public HolonElement getElement() {
+    return element;
+  }
+
+  public void setElement(HolonElement element) {
+    this.element = element;
+  }
+
+  public int getDuration() {
+    return duration;
+  }
+
+  /**
+   * Minimum duration is 1 TimeStep.
+   */
+  public void setDuration(int duration) {
+    this.duration = Math.max(1, duration);
+  }
+
+  public int getCooldown() {
+    return cooldown;
+  }
+
+  /**
+   * No negative cooldown TimeSteps.
+   */
+  public void setCooldown(int cooldown) {
+    this.cooldown = Math.max(0, cooldown);
+  }
+
+  /**
+   * returns the total energy Amount accumulated over the TimeSteps.
+   */
+  public float magnitude() {
+    return ((float) duration) * element.getEnergy();
+  }
+
+  public float energyReleased() {
+    return
+        (constrainList.stream().map(Constrain::getName).anyMatch(name -> name.equals("onConstrain"))
+            ? -1.0f : 1.0f) * element.getEnergy();
+  }
+
+  public boolean isPositive() {
+    return energyReleased() >= 0;
+  }
+
+  public boolean isNegative() {
+    return energyReleased() < 0;
+  }
+
+  public int getSpeed() {
+    return speed;
+  }
+
+  public void setSpeed(int speed) {
+    this.speed = speed;
+  }
+
+  @Override
+  public String toString() {
+    return "Flexibility: " + name + " from [HolonElement: " + element.getName() + "]";
+  }
+
+  void calculateState(int timestep) {
+    this.timeStep = timestep;
+    state = revalidateState();
+  }
+
+  public boolean order() {
+    if (canOrder()) {
+      state = FlexState.IN_USE;
+      durationEndTime = timeStep + this.getDuration();
+      coolDownEndTime = durationEndTime + this.getCooldown();
+      activationTime = timeStep;
+      return true;
+    }
+    return false;
+  }
+
+  public boolean cancel() {
+    if (activationTime == timeStep) {
+      reset();
+      return true;
+    }
+    return false;
+  }
+
+  void reset() {
+    durationEndTime = -1;
+    coolDownEndTime = -1;
+    state = revalidateState();
+  }
+
+  public boolean canActivate() {
+    return remainingTimeTillActivation() == 0;
+  }
+
+  public boolean canOrder() {
+    boolean flexIsOffered = state.equals(FlexState.OFFERED);
+    return flexIsOffered && !element.isFlexActive();
+  }
+
+  public FlexState getState() {
+    return state;
+  }
+
+  public int remainingTimeTillActivation() {
+    return Math.max(0, coolDownEndTime - timeStep);
+  }
+
+  public int remainingDuration() {
+    return Math.max(0, durationEndTime - timeStep);
+  }
+
+  /**
+   * Checks if all assigned constrains are fulfilled. When no constrains assigned returns true.
+   */
+  private boolean fulfillsConstrains() {
+    return constrainList.stream().map(Constrain::getConstrainFunction).reduce(Predicate::and)
+        .orElse(f -> true).test(this);
+  }
+
+  private FlexState revalidateState() {
+    if (canActivate()) {
+      if (!this.fulfillsConstrains() || element.isFlexActive()) {
+        return FlexState.UNAVAILABLE;
+      } else if (this.offered) {
+        return FlexState.OFFERED;
+      }
+      return FlexState.NOT_OFFERED;
+    } else if (remainingDuration() == 0) {
+      return FlexState.ON_COOLDOWN;
+    } else {
+      return FlexState.IN_USE;
+    }
+  }
+
+  public enum FlexState {
+    IN_USE, ON_COOLDOWN, OFFERED, NOT_OFFERED, UNAVAILABLE
+  }
 
 
 
 
 }
 }

+ 195 - 193
src/holeg/model/GroupNode.java

@@ -1,203 +1,205 @@
 package holeg.model;
 package holeg.model;
 
 
+import holeg.preferences.ImagePreference;
+import holeg.serialize.PostDeserialize;
+import holeg.utility.math.vector.Vec2i;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collection;
 import java.util.List;
 import java.util.List;
-import java.util.Set;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
-import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import java.util.stream.Stream;
 
 
-import holeg.preferences.ImagePreference;
-import holeg.serialize.PostDeserialize;
-import holeg.ui.model.GuiSettings;
-import holeg.utility.math.vector.Vec2i;
-
 public class GroupNode extends AbstractCanvasObject implements PostDeserialize {
 public class GroupNode extends AbstractCanvasObject implements PostDeserialize {
-	private static final Logger log = Logger.getLogger(AbstractCanvasObject.class.getName());
-
-	protected final List<HolonObject> objectList = new ArrayList<>();
-	protected final List<HolonSwitch> switchList = new ArrayList<>();
-	protected final List<Node> nodeList = new ArrayList<>();
-	protected final List<GroupNode> groupNodeList = new ArrayList<>();
-
-	public GroupNode(String nodeName) {
-		super(nodeName);
-	}
-
-	public GroupNode(GroupNode other){
-		super(other.name);
-		for (HolonObject obj : other.objectList) {
-			this.add(new HolonObject(obj));
-		}
-		for (HolonSwitch sw : other.switchList) {
-			this.add(new HolonSwitch(sw));
-		}
-		for (Node node : other.nodeList) {
-			this.add(new Node(node));
-		}
-		for (GroupNode groupNode : other.groupNodeList) {
-			this.add(new GroupNode(groupNode));
-		}
-	}
-
-	@Override
-	public AbstractCanvasObject copy() {
-		return new GroupNode(this);
-	}
-
-
-
-
-	@Override
-	public String getImagePath() {
-		return ImagePreference.Canvas.GroupNode;
-	}
-	public void addAll(Stream<AbstractCanvasObject> stream) {
-		stream.forEach(this::add);
-	}
-	public void addAll(Collection<AbstractCanvasObject> collection) {
-		collection.forEach(this::add);
-	}
-	
-	public void add(AbstractCanvasObject object) {
-		if (object instanceof HolonObject hObject) {
-			objectList.add(hObject);
-		}else if(object instanceof HolonSwitch hSwitch) {
-			switchList.add(hSwitch);
-		}else if(object instanceof Node node) {
-			nodeList.add(node);
-		}else if(object instanceof GroupNode groupNode) {
-			groupNodeList.add(groupNode);
-		}
-		object.setGroupNode(this);
-	}
-	
-	public void remove(AbstractCanvasObject object) {
-		if (object instanceof HolonObject hObject) {
-			objectList.remove(hObject);
-		}else if(object instanceof HolonSwitch hSwitch) {
-			switchList.remove(hSwitch);
-		}else if(object instanceof Node node) {
-			nodeList.remove(node);
-		}else if(object instanceof GroupNode groupNode) {
-			groupNodeList.remove(groupNode);
-		}
-		object.setGroupNode(null);
-	}
-	public void removeAll(Stream<AbstractCanvasObject> stream){
-		stream.forEach(this::remove);
-	}
-	public void removeAll(Collection<AbstractCanvasObject> collection){
-		collection.forEach(this::remove);
-	}
-
-
-
-	public Stream<AbstractCanvasObject> getObjectsInThisLayer() {
-		return Stream.of(objectList.stream(), switchList.stream(), nodeList.stream(), groupNodeList.stream())
-				.flatMap(s -> s);
-	}
-
-	public Stream<AbstractCanvasObject> getAllObjectsRecursive() {
-		Stream<AbstractCanvasObject> objects = Stream.of(objectList.stream(), switchList.stream(), nodeList.stream())
-				.flatMap(s -> s);
-		return Stream.concat(objects,
-				groupNodeList.stream().flatMap(GroupNode::getObjectsInThisLayer));
-
-	}
-
-	public Stream<HolonObject> getAllHolonObjectsRecursive() {
-		return Stream.concat(objectList.stream(),
-				groupNodeList.stream().flatMap(GroupNode::getAllHolonObjectsRecursive));
-	}
-	public Stream<HolonSwitch> getAllSwitchObjectsRecursive() {
-		return Stream.concat(switchList.stream(),
-				groupNodeList.stream().flatMap(GroupNode::getAllSwitchObjectsRecursive));
-	}
-	public Stream<Node> getAllNodeObjectsRecursive() {
-		return Stream.concat(nodeList.stream(),
-				groupNodeList.stream().flatMap(GroupNode::getAllNodeObjectsRecursive));
-	}
-	public Stream<GroupNode> getAllGroupNodeObjectsRecursive() {
-		return Stream.concat(groupNodeList.stream(),
-				groupNodeList.stream().flatMap(GroupNode::getAllGroupNodeObjectsRecursive));
-	}
-	
-	public Stream<HolonObject> getHolonObjects() {
-		return objectList.stream();
-	}
-	
-	public Stream<HolonSwitch> getSwitches() {
-		return switchList.stream();
-	}
-	public Stream<Node> getNodes() {
-		return nodeList.stream();
-	}
-	
-	public Stream<GroupNode> getGroupNodes() {
-		return groupNodeList.stream();
-	}
-
-	public Stream<HolonElement> getHolonElements(){
-		return objectList.stream().flatMap(HolonObject::elementsStream);
-	}
-	public Stream<HolonElement> getAllHolonElements(){
-		return Stream.concat(getHolonElements(),
-				groupNodeList.stream().flatMap(GroupNode::getAllHolonElements));
-	}
-
-	public Stream<Flexibility> getAllFlexibilities() {
-		return getAllHolonObjectsRecursive().flatMap(hO -> hO.elementsStream().flatMap(ele -> ele.flexList.stream()));
-	}
-
-
-	public void ungroup(){
-		getObjectsInThisLayer().forEach(obj -> {
-			obj.setGroupNode(null);
-		});
-		getGroupNode().ifPresent(parent -> {
-			parent.addAll(getObjectsInThisLayer());
-			parent.remove(this);
-		});
-
-		clear();
-	}
-
-	public static Vec2i calculateMiddlePosition(Collection<AbstractCanvasObject> objects){
-		Vec2i middle = new Vec2i();
-		if(!objects.isEmpty()){
-			objects.forEach(obj -> middle.addAssign(obj.getPosition()));
-			middle.divideAssign(objects.size());
-		}
-		return middle;
-	}
-
-	public float getTotalConsumption() {
-		return getAllHolonObjectsRecursive().map(HolonObject::getConsumption).reduce(0.f, Float::sum);
-	}
-
-	public float getTotalProduction() {
-		return getAllHolonObjectsRecursive().map(HolonObject::getProduction).reduce(0.f, Float::sum);
-	}
-
-
-
-	public void clear() {
-		objectList.clear();
-		switchList.clear();
-		nodeList.clear();
-		groupNodeList.clear();
-	}
-
-	@Override
-	public void postDeserialize() {
-		getObjectsInThisLayer().forEach(obj -> obj.setGroupNode(this));
-	}
-
-
-	@Override
-	public String toString(){
-		return "" +  objectList + switchList + nodeList +groupNodeList ;
-	}
+
+  private static final Logger log = Logger.getLogger(AbstractCanvasObject.class.getName());
+
+  protected final List<HolonObject> objectList = new ArrayList<>();
+  protected final List<HolonSwitch> switchList = new ArrayList<>();
+  protected final List<Node> nodeList = new ArrayList<>();
+  protected final List<GroupNode> groupNodeList = new ArrayList<>();
+
+  public GroupNode(String nodeName) {
+    super(nodeName);
+  }
+
+  public GroupNode(GroupNode other) {
+    super(other.name);
+    for (HolonObject obj : other.objectList) {
+      this.add(new HolonObject(obj));
+    }
+    for (HolonSwitch sw : other.switchList) {
+      this.add(new HolonSwitch(sw));
+    }
+    for (Node node : other.nodeList) {
+      this.add(new Node(node));
+    }
+    for (GroupNode groupNode : other.groupNodeList) {
+      this.add(new GroupNode(groupNode));
+    }
+  }
+
+  public static Vec2i calculateMiddlePosition(Collection<AbstractCanvasObject> objects) {
+    Vec2i middle = new Vec2i();
+    if (!objects.isEmpty()) {
+      objects.forEach(obj -> middle.addAssign(obj.getPosition()));
+      middle.divideAssign(objects.size());
+    }
+    return middle;
+  }
+
+  @Override
+  public AbstractCanvasObject copy() {
+    return new GroupNode(this);
+  }
+
+  @Override
+  public String getImagePath() {
+    return ImagePreference.Canvas.GroupNode;
+  }
+
+  public void addAll(Stream<AbstractCanvasObject> stream) {
+    stream.forEach(this::add);
+  }
+
+  public void addAll(Collection<AbstractCanvasObject> collection) {
+    collection.forEach(this::add);
+  }
+
+  public void add(AbstractCanvasObject object) {
+    if (object instanceof HolonObject hObject) {
+      objectList.add(hObject);
+    } else if (object instanceof HolonSwitch hSwitch) {
+      switchList.add(hSwitch);
+    } else if (object instanceof Node node) {
+      nodeList.add(node);
+    } else if (object instanceof GroupNode groupNode) {
+      groupNodeList.add(groupNode);
+    }
+    object.setGroupNode(this);
+  }
+
+  public void remove(AbstractCanvasObject object) {
+    if (object instanceof HolonObject hObject) {
+      objectList.remove(hObject);
+    } else if (object instanceof HolonSwitch hSwitch) {
+      switchList.remove(hSwitch);
+    } else if (object instanceof Node node) {
+      nodeList.remove(node);
+    } else if (object instanceof GroupNode groupNode) {
+      groupNodeList.remove(groupNode);
+    }
+    object.setGroupNode(null);
+  }
+
+  public void removeAll(Stream<AbstractCanvasObject> stream) {
+    stream.forEach(this::remove);
+  }
+
+  public void removeAll(Collection<AbstractCanvasObject> collection) {
+    collection.forEach(this::remove);
+  }
+
+  public Stream<AbstractCanvasObject> getObjectsInThisLayer() {
+    return Stream.of(objectList.stream(), switchList.stream(), nodeList.stream(),
+            groupNodeList.stream())
+        .flatMap(s -> s);
+  }
+
+  public Stream<AbstractCanvasObject> getAllObjectsRecursive() {
+    Stream<AbstractCanvasObject> objects = Stream.of(objectList.stream(), switchList.stream(),
+            nodeList.stream())
+        .flatMap(s -> s);
+    return Stream.concat(objects,
+        groupNodeList.stream().flatMap(GroupNode::getObjectsInThisLayer));
+
+  }
+
+  public Stream<HolonObject> getAllHolonObjectsRecursive() {
+    return Stream.concat(objectList.stream(),
+        groupNodeList.stream().flatMap(GroupNode::getAllHolonObjectsRecursive));
+  }
+
+  public Stream<HolonSwitch> getAllSwitchObjectsRecursive() {
+    return Stream.concat(switchList.stream(),
+        groupNodeList.stream().flatMap(GroupNode::getAllSwitchObjectsRecursive));
+  }
+
+  public Stream<Node> getAllNodeObjectsRecursive() {
+    return Stream.concat(nodeList.stream(),
+        groupNodeList.stream().flatMap(GroupNode::getAllNodeObjectsRecursive));
+  }
+
+  public Stream<GroupNode> getAllGroupNodeObjectsRecursive() {
+    return Stream.concat(groupNodeList.stream(),
+        groupNodeList.stream().flatMap(GroupNode::getAllGroupNodeObjectsRecursive));
+  }
+
+  public Stream<HolonObject> getHolonObjects() {
+    return objectList.stream();
+  }
+
+  public Stream<HolonSwitch> getSwitches() {
+    return switchList.stream();
+  }
+
+  public Stream<Node> getNodes() {
+    return nodeList.stream();
+  }
+
+  public Stream<GroupNode> getGroupNodes() {
+    return groupNodeList.stream();
+  }
+
+  public Stream<HolonElement> getHolonElements() {
+    return objectList.stream().flatMap(HolonObject::elementsStream);
+  }
+
+  public Stream<HolonElement> getAllHolonElements() {
+    return Stream.concat(getHolonElements(),
+        groupNodeList.stream().flatMap(GroupNode::getAllHolonElements));
+  }
+
+  public Stream<Flexibility> getAllFlexibilities() {
+    return getAllHolonObjectsRecursive().flatMap(
+        hO -> hO.elementsStream().flatMap(ele -> ele.flexList.stream()));
+  }
+
+  public void ungroup() {
+    getObjectsInThisLayer().forEach(obj -> {
+      obj.setGroupNode(null);
+    });
+    getGroupNode().ifPresent(parent -> {
+      parent.addAll(getObjectsInThisLayer());
+      parent.remove(this);
+    });
+
+    clear();
+  }
+
+  public float getTotalConsumption() {
+    return getAllHolonObjectsRecursive().map(HolonObject::getConsumption).reduce(0.f, Float::sum);
+  }
+
+  public float getTotalProduction() {
+    return getAllHolonObjectsRecursive().map(HolonObject::getProduction).reduce(0.f, Float::sum);
+  }
+
+
+  public void clear() {
+    objectList.clear();
+    switchList.clear();
+    nodeList.clear();
+    groupNodeList.clear();
+  }
+
+  @Override
+  public void postDeserialize() {
+    getObjectsInThisLayer().forEach(obj -> obj.setGroupNode(this));
+  }
+
+
+  @Override
+  public String toString() {
+    return "" + objectList + switchList + nodeList + groupNodeList;
+  }
 }
 }

+ 262 - 252
src/holeg/model/Holon.java

@@ -9,267 +9,277 @@ import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import java.util.stream.Stream;
 
 
 public class Holon {
 public class Holon {
-    private static final Logger log = Logger.getLogger(Holon.class.getName());
-    public Set<HolonObject> holonObjects = new HashSet<>();
-    public Set<AbstractCanvasObject> objects = new HashSet<>();
-    public Set<Edge> edges = new HashSet<>();
-
-    public Holon(HolonObject holonObject) {
-        holonObjects.add(holonObject);
-        objects.add(holonObject);
-    }
-
-    public Holon(Edge edge) {
-        add(edge);
-    }
 
 
-    public void add(Edge edge) {
-        add(edge.getA());
-        add(edge.getB());
-        edges.add(edge);
+  private static final Logger log = Logger.getLogger(Holon.class.getName());
+  public Set<HolonObject> holonObjects = new HashSet<>();
+  public Set<AbstractCanvasObject> objects = new HashSet<>();
+  public Set<Edge> edges = new HashSet<>();
+
+  public Holon(HolonObject holonObject) {
+    holonObjects.add(holonObject);
+    objects.add(holonObject);
+  }
+
+  public Holon(Edge edge) {
+    add(edge);
+  }
+
+  public void add(Edge edge) {
+    add(edge.getA());
+    add(edge.getB());
+    edges.add(edge);
+  }
+
+  public void add(AbstractCanvasObject obj) {
+    if (obj instanceof HolonObject holonObject) {
+      holonObjects.add(holonObject);
     }
     }
-
-    public void add(AbstractCanvasObject obj) {
-        if (obj instanceof HolonObject holonObject) {
-            holonObjects.add(holonObject);
+    objects.add(obj);
+  }
+
+
+  public void clear() {
+    holonObjects.clear();
+    edges.clear();
+    objects.clear();
+  }
+
+  @Override
+  public String toString() {
+    return "[" + objects.stream().map(AbstractCanvasObject::getName)
+        .collect(Collectors.joining(", ")) + "]";
+  }
+
+
+  public void calculate() {
+    Map<Boolean, List<HolonObject>> partition = holonObjects.stream()
+        .collect(Collectors.partitioningBy(hO -> hO.getActualEnergy() > 0));
+    List<HolonObject> supplierList = partition.get(true);
+    List<HolonObject> consumerList = partition.get(false);
+    supplierList.sort((a, b) -> -Float.compare(a.getActualEnergy(), b.getActualEnergy()));
+
+    float energyToSupplyInTheNetwork = supplierList.stream()
+        .map(HolonObject::getActualEnergy)
+        .reduce(0f, Float::sum);
+
+    // STEP 1:
+    // Supply consuming element first
+
+    // Sort ConsumerList according to the MinimumConsumingElementEnergy minimum first.
+    consumerList.sort((a, b) -> Float.compare(a.getMinimumConsumingElementEnergy(),
+        b.getMinimumConsumingElementEnergy()));
+    outerLoop:
+    for (HolonObject con : consumerList) {
+      for (HolonObject sup : supplierList) {
+        float energyRdyToSupply = sup.getActualEnergy() - sup.getEnergyToHolon();
+        if (energyRdyToSupply <= 0.0f) {
+          continue;
         }
         }
-        objects.add(obj);
-    }
-
-
-    public void clear() {
-        holonObjects.clear();
-        edges.clear();
-        objects.clear();
-    }
-
-    @Override
-    public String toString() {
-        return "[" + objects.stream().map(AbstractCanvasObject::getName).collect(Collectors.joining(", ")) + "]";
+        float energyNeededForMinimumConsumingElement = con.getMinimumConsumingElementEnergy()
+            - con.getEnergyFromHolon();
+        if (energyNeededForMinimumConsumingElement > energyToSupplyInTheNetwork) {
+          // Dont supply a minimumElement when you cant supply it fully
+          break outerLoop;
+        }
+        if (energyRdyToSupply >= energyNeededForMinimumConsumingElement) {
+          energyToSupplyInTheNetwork -= energyNeededForMinimumConsumingElement;
+          supply(con, sup, energyNeededForMinimumConsumingElement);
+          continue outerLoop;
+        } else {
+          energyToSupplyInTheNetwork -= energyRdyToSupply;
+          supply(con, sup, energyRdyToSupply);
+        }
+      }
+      // No more Energy in the network
+      break;
     }
     }
 
 
-
-    public void calculate() {
-        Map<Boolean, List<HolonObject>> partition = holonObjects.stream().collect(Collectors.partitioningBy(hO -> hO.getActualEnergy() > 0));
-        List<HolonObject> supplierList = partition.get(true);
-        List<HolonObject> consumerList = partition.get(false);
-        supplierList.sort((a, b) -> -Float.compare(a.getActualEnergy(), b.getActualEnergy()));
-
-        float energyToSupplyInTheNetwork = supplierList.stream()
-                .map(HolonObject::getActualEnergy)
-                .reduce(0f, Float::sum);
-
-
-        // STEP 1:
-        // Supply consuming element first
-
-        // Sort ConsumerList according to the MinimumConsumingElementEnergy minimum first.
-        consumerList.sort((a, b) -> Float.compare(a.getMinimumConsumingElementEnergy(), b.getMinimumConsumingElementEnergy()));
-        outerLoop:
-        for (HolonObject con : consumerList) {
-            for (HolonObject sup : supplierList) {
-                float energyRdyToSupply = sup.getActualEnergy() - sup.getEnergyToHolon();
-                if (energyRdyToSupply <= 0.0f) {
-                    continue;
-                }
-                float energyNeededForMinimumConsumingElement = con.getMinimumConsumingElementEnergy()
-                        - con.getEnergyFromHolon();
-                if (energyNeededForMinimumConsumingElement > energyToSupplyInTheNetwork) {
-                    // Dont supply a minimumElement when you cant supply it fully
-                    break outerLoop;
-                }
-                if (energyRdyToSupply >= energyNeededForMinimumConsumingElement) {
-                    energyToSupplyInTheNetwork -= energyNeededForMinimumConsumingElement;
-                    supply(con, sup, energyNeededForMinimumConsumingElement);
-                    continue outerLoop;
-                } else {
-                    energyToSupplyInTheNetwork -= energyRdyToSupply;
-                    supply(con, sup, energyRdyToSupply);
-                }
-            }
-            // No more Energy in the network
-            break;
+    // STEP 2:
+    // Supply consumer fully
+
+    // Sort ConsumerList according to the EnergyNeeded to supply fully after minimum
+    // Demand First.
+    consumerList.sort((l, r) -> Float.compare(
+        l.getEnergyNeededFromHolon() - l.getEnergyFromHolon(),
+        r.getEnergyNeededFromHolon() - r.getEnergyFromHolon()));
+    outerLoop:
+    for (HolonObject con : consumerList) {
+      for (HolonObject sup : supplierList) {
+        float energyRdyToSupply = sup.getActualEnergy() - sup.getEnergyToHolon();
+        if (energyRdyToSupply <= 0.0f) {
+          continue;
         }
         }
-
-
-        // STEP 2:
-        // Supply consumer fully
-
-        // Sort ConsumerList according to the EnergyNeeded to supply fully after minimum
-        // Demand First.
-        consumerList.sort((l, r) -> Float.compare(
-                l.getEnergyNeededFromHolon() - l.getEnergyFromHolon(),
-                r.getEnergyNeededFromHolon() - r.getEnergyFromHolon()));
-        outerLoop:
-        for (HolonObject con : consumerList) {
-            for (HolonObject sup : supplierList) {
-                float energyRdyToSupply = sup.getActualEnergy() - sup.getEnergyToHolon();
-                if (energyRdyToSupply <= 0.0f)
-                    continue;
-                float energyNeededForFullySupply = con.getEnergyNeededFromHolon() - con.getEnergyFromHolon();
-                if (energyNeededForFullySupply <= 0.0f)
-                    continue outerLoop;
-                if (energyRdyToSupply >= energyNeededForFullySupply) {
-                    energyToSupplyInTheNetwork -= energyNeededForFullySupply;
-                    supply(con, sup, energyNeededForFullySupply);
-                    continue outerLoop;
-                } else {
-                    energyToSupplyInTheNetwork -= energyRdyToSupply;
-                    supply(con, sup, energyRdyToSupply);
-                }
-            }
-            // No more Energy in the network
-            break;
+        float energyNeededForFullySupply =
+            con.getEnergyNeededFromHolon() - con.getEnergyFromHolon();
+        if (energyNeededForFullySupply <= 0.0f) {
+          continue outerLoop;
         }
         }
-
-        // STEP 3:
-        // If energy is still left, oversupply
-
-        if (energyToSupplyInTheNetwork > 0.0f && (consumerList.size() != 0)) {
-            float equalAmountOfEnergyToSupply = energyToSupplyInTheNetwork
-                    / ((float) (consumerList.size()));
-            outerLoop:
-            for (HolonObject con : consumerList) {
-                for (HolonObject sup : supplierList) {
-                    float energyRdyToSupply = sup.getActualEnergy() - sup.getEnergyToHolon();
-                    if (energyRdyToSupply <= 0.0f)
-                        continue;
-                    float energyNeededToSupplyConsumerTheEqualAmount = equalAmountOfEnergyToSupply
-                            + con.getEnergyNeededFromHolon() - con.getEnergyFromHolon();
-                    if (energyRdyToSupply >= energyNeededToSupplyConsumerTheEqualAmount) {
-                        supply(con, sup, energyNeededToSupplyConsumerTheEqualAmount);
-                        continue outerLoop;
-                    } else {
-                        supply(con, sup, energyRdyToSupply);
-                    }
-                }
-                // No more Energy in the network
-                break;
-            }
+        if (energyRdyToSupply >= energyNeededForFullySupply) {
+          energyToSupplyInTheNetwork -= energyNeededForFullySupply;
+          supply(con, sup, energyNeededForFullySupply);
+          continue outerLoop;
+        } else {
+          energyToSupplyInTheNetwork -= energyRdyToSupply;
+          supply(con, sup, energyRdyToSupply);
         }
         }
-        holonObjects.forEach(HolonObject::calculateState);
-    }
-
-
-    private void supply(HolonObject consumer, HolonObject supplier, float energy) {
-        consumer.setEnergyFromHolon(consumer.getEnergyFromHolon() + energy);
-        supplier.setEnergyToHolon(supplier.getEnergyToHolon() + energy);
-    }
-
-
-    public Stream<Float> getListOfEnergyThatIsOfferedByFlexibilitiesInThisNetwork() {
-
-        return holonObjects.stream().flatMap(HolonObject::elementsStream)
-                .filter(ele -> (ele.flexList.stream().anyMatch(flex -> flex.offered)))
-                .map(ele -> -ele.getActualEnergy());
-    }
-
-    public Stream<Float> getListOfEnergyInProductionThatIsOfferedByFlexibilitiesInThisNetwork() {
-        return getListOfEnergyThatIsOfferedByFlexibilitiesInThisNetwork().filter(value -> (value > 0.f));
-    }
-
-    public Stream<Float> getListOfEnergyInConsumptionThatIsOfferedByFlexibilitiesInThisNetwork() {
-        return getListOfEnergyThatIsOfferedByFlexibilitiesInThisNetwork().filter(value -> (value < 0.f))
-                .map(value -> -value);
-    }
-
-    public float getFlexibilityProductionCapacity() {
-        return getListOfEnergyInProductionThatIsOfferedByFlexibilitiesInThisNetwork().reduce(0.f, Float::sum);
-    }
-
-    public float getFlexibilityConsumptionCapacity() {
-        return getListOfEnergyInConsumptionThatIsOfferedByFlexibilitiesInThisNetwork().reduce(0.f, Float::sum);
-    }
-
-    public int getAmountOfProductionFlexibilities() {
-        return (int)getListOfEnergyInProductionThatIsOfferedByFlexibilitiesInThisNetwork().count();
-    }
-
-    public int getAmountOfConsumptionFlexibilities() {
-        return (int)getListOfEnergyInConsumptionThatIsOfferedByFlexibilitiesInThisNetwork().count();
-    }
-
-    public float getAverageFlexibilityProduction() {
-        int amount = getAmountOfProductionFlexibilities();
-        return (amount > 0) ? getFlexibilityProductionCapacity() / (float) amount : 0.f;
-    }
-
-    public float getAverageFlexibilityConsumption() {
-        int amount = getAmountOfConsumptionFlexibilities();
-        return (amount > 0) ? getFlexibilityConsumptionCapacity() / (float) amount : 0.f;
-    }
-
-    public float getVarianceInFlexibilitiesConsumption() {
-        float average = getAverageFlexibilityConsumption();
-        float sum = getListOfEnergyInConsumptionThatIsOfferedByFlexibilitiesInThisNetwork()
-                .map(energy -> squared(energy - average)).reduce(0.f, Float::sum);
-        int amountOfFlexibilities = getAmountOfConsumptionFlexibilities();
-        return (amountOfFlexibilities > 0) ? sum / (float) amountOfFlexibilities : 0.f;
-    }
-
-    public float getVarianceInFlexibilityProduction() {
-        float average = getAverageFlexibilityProduction();
-        float sum = getListOfEnergyInProductionThatIsOfferedByFlexibilitiesInThisNetwork()
-                .map(energy -> squared(energy - average)).reduce(0.f, Float::sum);
-        int amountOfFlexibilities = getAmountOfProductionFlexibilities();
-        return (amountOfFlexibilities > 0) ? sum / (float) amountOfFlexibilities : 0.f;
-    }
-
-    public float getDeviationInFlexibilityConsumption() {
-        return (float) Math.sqrt(getVarianceInFlexibilitiesConsumption());
-    }
-
-    public float getDeviationInFlexibilityProduction() {
-        return (float) Math.sqrt(getVarianceInFlexibilityProduction());
-    }
-
-    public float getTotalConsumption() {
-        return holonObjects.stream().map(HolonObject::getConsumption).reduce(0.f, Float::sum);
-    }
-
-    public float getAverageConsumptionInNetworkForHolonObject() {
-        return getTotalConsumption() / (float) holonObjects.size();
+      }
+      // No more Energy in the network
+      break;
     }
     }
 
 
-    public float getTotalProduction() {
-        return holonObjects.stream().map(HolonObject::getProduction).reduce(0.f, Float::sum);
-    }
-
-    public float getAverageProductionInNetworkForHolonObject() {
-        return getTotalProduction() / (float) holonObjects.size();
-    }
-
-    /**
-     * returns the Varianz in Poduction
-     *
-     */
-    public float getVarianceInProductionInNetworkForHolonObjects() {
-        float average = getAverageProductionInNetworkForHolonObject();
-        float sum = holonObjects.stream().map(hO -> squared(hO.getProduction() - average)).reduce(0.f, Float::sum);
-        return sum / (float) holonObjects.size();
-    }
-
-    public float getDeviationInProductionInNetworkForHolonObjects() {
-        return (float) Math.sqrt(getVarianceInProductionInNetworkForHolonObjects());
-    }
-
-    public float getVarianceInConsumptionInNetworkForHolonObjects() {
-        float average = getAverageConsumptionInNetworkForHolonObject();
-        float sum = holonObjects.stream().map(hO -> squared(hO.getConsumption() - average)).reduce(0.f, Float::sum);
-        return sum / (float) holonObjects.size();
-    }
-
-    public float getDeviationInConsumptionInNetworkForHolonObjects() {
-        return (float) Math.sqrt(getVarianceInConsumptionInNetworkForHolonObjects());
-    }
-
-
-    // Help Function
-    private float squared(float input) {
-        return input * input;
-    }
-
-    public int getAmountOfElements() {
-        return (int) holonObjects.stream().flatMap(HolonObject::elementsStream).count();
+    // STEP 3:
+    // If energy is still left, oversupply
+
+    if (energyToSupplyInTheNetwork > 0.0f && (consumerList.size() != 0)) {
+      float equalAmountOfEnergyToSupply = energyToSupplyInTheNetwork
+          / ((float) (consumerList.size()));
+      outerLoop:
+      for (HolonObject con : consumerList) {
+        for (HolonObject sup : supplierList) {
+          float energyRdyToSupply = sup.getActualEnergy() - sup.getEnergyToHolon();
+          if (energyRdyToSupply <= 0.0f) {
+            continue;
+          }
+          float energyNeededToSupplyConsumerTheEqualAmount = equalAmountOfEnergyToSupply
+              + con.getEnergyNeededFromHolon() - con.getEnergyFromHolon();
+          if (energyRdyToSupply >= energyNeededToSupplyConsumerTheEqualAmount) {
+            supply(con, sup, energyNeededToSupplyConsumerTheEqualAmount);
+            continue outerLoop;
+          } else {
+            supply(con, sup, energyRdyToSupply);
+          }
+        }
+        // No more Energy in the network
+        break;
+      }
     }
     }
+    holonObjects.forEach(HolonObject::calculateState);
+  }
+
+
+  private void supply(HolonObject consumer, HolonObject supplier, float energy) {
+    consumer.setEnergyFromHolon(consumer.getEnergyFromHolon() + energy);
+    supplier.setEnergyToHolon(supplier.getEnergyToHolon() + energy);
+  }
+
+
+  public Stream<Float> getListOfEnergyThatIsOfferedByFlexibilitiesInThisNetwork() {
+
+    return holonObjects.stream().flatMap(HolonObject::elementsStream)
+        .filter(ele -> (ele.flexList.stream().anyMatch(flex -> flex.offered)))
+        .map(ele -> -ele.getActualEnergy());
+  }
+
+  public Stream<Float> getListOfEnergyInProductionThatIsOfferedByFlexibilitiesInThisNetwork() {
+    return getListOfEnergyThatIsOfferedByFlexibilitiesInThisNetwork().filter(
+        value -> (value > 0.f));
+  }
+
+  public Stream<Float> getListOfEnergyInConsumptionThatIsOfferedByFlexibilitiesInThisNetwork() {
+    return getListOfEnergyThatIsOfferedByFlexibilitiesInThisNetwork().filter(value -> (value < 0.f))
+        .map(value -> -value);
+  }
+
+  public float getFlexibilityProductionCapacity() {
+    return getListOfEnergyInProductionThatIsOfferedByFlexibilitiesInThisNetwork().reduce(0.f,
+        Float::sum);
+  }
+
+  public float getFlexibilityConsumptionCapacity() {
+    return getListOfEnergyInConsumptionThatIsOfferedByFlexibilitiesInThisNetwork().reduce(0.f,
+        Float::sum);
+  }
+
+  public int getAmountOfProductionFlexibilities() {
+    return (int) getListOfEnergyInProductionThatIsOfferedByFlexibilitiesInThisNetwork().count();
+  }
+
+  public int getAmountOfConsumptionFlexibilities() {
+    return (int) getListOfEnergyInConsumptionThatIsOfferedByFlexibilitiesInThisNetwork().count();
+  }
+
+  public float getAverageFlexibilityProduction() {
+    int amount = getAmountOfProductionFlexibilities();
+    return (amount > 0) ? getFlexibilityProductionCapacity() / (float) amount : 0.f;
+  }
+
+  public float getAverageFlexibilityConsumption() {
+    int amount = getAmountOfConsumptionFlexibilities();
+    return (amount > 0) ? getFlexibilityConsumptionCapacity() / (float) amount : 0.f;
+  }
+
+  public float getVarianceInFlexibilitiesConsumption() {
+    float average = getAverageFlexibilityConsumption();
+    float sum = getListOfEnergyInConsumptionThatIsOfferedByFlexibilitiesInThisNetwork()
+        .map(energy -> squared(energy - average)).reduce(0.f, Float::sum);
+    int amountOfFlexibilities = getAmountOfConsumptionFlexibilities();
+    return (amountOfFlexibilities > 0) ? sum / (float) amountOfFlexibilities : 0.f;
+  }
+
+  public float getVarianceInFlexibilityProduction() {
+    float average = getAverageFlexibilityProduction();
+    float sum = getListOfEnergyInProductionThatIsOfferedByFlexibilitiesInThisNetwork()
+        .map(energy -> squared(energy - average)).reduce(0.f, Float::sum);
+    int amountOfFlexibilities = getAmountOfProductionFlexibilities();
+    return (amountOfFlexibilities > 0) ? sum / (float) amountOfFlexibilities : 0.f;
+  }
+
+  public float getDeviationInFlexibilityConsumption() {
+    return (float) Math.sqrt(getVarianceInFlexibilitiesConsumption());
+  }
+
+  public float getDeviationInFlexibilityProduction() {
+    return (float) Math.sqrt(getVarianceInFlexibilityProduction());
+  }
+
+  public float getTotalConsumption() {
+    return holonObjects.stream().map(HolonObject::getConsumption).reduce(0.f, Float::sum);
+  }
+
+  public float getAverageConsumptionInNetworkForHolonObject() {
+    return getTotalConsumption() / (float) holonObjects.size();
+  }
+
+  public float getTotalProduction() {
+    return holonObjects.stream().map(HolonObject::getProduction).reduce(0.f, Float::sum);
+  }
+
+  public float getAverageProductionInNetworkForHolonObject() {
+    return getTotalProduction() / (float) holonObjects.size();
+  }
+
+  /**
+   * returns the Varianz in Poduction
+   */
+  public float getVarianceInProductionInNetworkForHolonObjects() {
+    float average = getAverageProductionInNetworkForHolonObject();
+    float sum = holonObjects.stream().map(hO -> squared(hO.getProduction() - average))
+        .reduce(0.f, Float::sum);
+    return sum / (float) holonObjects.size();
+  }
+
+  public float getDeviationInProductionInNetworkForHolonObjects() {
+    return (float) Math.sqrt(getVarianceInProductionInNetworkForHolonObjects());
+  }
+
+  public float getVarianceInConsumptionInNetworkForHolonObjects() {
+    float average = getAverageConsumptionInNetworkForHolonObject();
+    float sum = holonObjects.stream().map(hO -> squared(hO.getConsumption() - average))
+        .reduce(0.f, Float::sum);
+    return sum / (float) holonObjects.size();
+  }
+
+  public float getDeviationInConsumptionInNetworkForHolonObjects() {
+    return (float) Math.sqrt(getVarianceInConsumptionInNetworkForHolonObjects());
+  }
+
+
+  // Help Function
+  private float squared(float input) {
+    return input * input;
+  }
+
+  public int getAmountOfElements() {
+    return (int) holonObjects.stream().flatMap(HolonObject::elementsStream).count();
+  }
 }
 }

+ 337 - 335
src/holeg/model/HolonElement.java

@@ -5,7 +5,6 @@ import holeg.model.Flexibility.FlexState;
 import holeg.serialize.PostDeserialize;
 import holeg.serialize.PostDeserialize;
 import holeg.ui.controller.IndexTranslator;
 import holeg.ui.controller.IndexTranslator;
 import holeg.utility.math.vector.Vec2f;
 import holeg.utility.math.vector.Vec2f;
-
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.List;
@@ -13,348 +12,351 @@ import java.util.ListIterator;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
 
 
 /**
 /**
- * The class "HolonElement" represents any possible element that can be added to
- * a HolonObject.
+ * The class "HolonElement" represents any possible element that can be added to a HolonObject.
  *
  *
  * @author Gruppe14
  * @author Gruppe14
  */
  */
 public class HolonElement implements TimelineDependent, PostDeserialize {
 public class HolonElement implements TimelineDependent, PostDeserialize {
-    private static final Logger log = Logger.getLogger(HolonElement.class.getName());
-    /**
-     * Owner of the Element
-     */
-    public transient HolonObject parentObject;
-    /**
-     * Whether the gadget is active or not (currently uses/produces the energy in energyPerElement)
-     */
-    public boolean active = true;
-    public Priority priority = Priority.Low;
-    public List<Flexibility> flexList = new ArrayList<>();
-    /**
-     * Points of new TestGraph
-     * Represent the Graph
-     * the X component from a Point is period from 0..1
-     * the Y component from a Point is the percentage from 0..1
-     */
-    private LinkedList<Vec2f> graphPoints = new LinkedList<>();
-    /**
-     * Name of the gadget, e.g. TV
-     */
-    private String name;
-    /**
-     * Amount of same elements
-     */
-    private float energy;
-    private Period period = new Period();
-    /*
-     * Energy at each point of the graph with 100 predefined points. At the
-     * beginning, it starts with all values at energyPerElement.
-     * If switched to flexible, this represents the maximum of usable energy
-     */
-    private transient float[] curveSample;
-    private transient float actualEnergy = 0;
 
 
-
-    /**
-     * Create a new HolonElement with a user-defined name, amount of the same
-     * element, energyPerElement and corresponding model.
-     *
-     * @param eleName String
-     * @param energy  float
-     */
-
-    /**
-     * same as standard constructor, but with already given id (so the counter is not increased twice)
-     */
-    public HolonElement(HolonObject parentObject, String name, float energy) {
-        this.parentObject = parentObject;
-        setName(name);
-        setEnergy(energy);
-        initGraphPoints();
-        sampleGraph();
+  private static final Logger log = Logger.getLogger(HolonElement.class.getName());
+  /**
+   * Owner of the Element
+   */
+  public transient HolonObject parentObject;
+  /**
+   * Whether the gadget is active or not (currently uses/produces the energy in energyPerElement)
+   */
+  public boolean active = true;
+  public Priority priority = Priority.Low;
+  public List<Flexibility> flexList = new ArrayList<>();
+  /**
+   * Points of new TestGraph Represent the Graph the X component from a Point is period from 0..1
+   * the Y component from a Point is the percentage from 0..1
+   */
+  private LinkedList<Vec2f> graphPoints = new LinkedList<>();
+  /**
+   * Name of the gadget, e.g. TV
+   */
+  private String name;
+  /**
+   * Amount of same elements
+   */
+  private float energy;
+  private Period period = new Period();
+  /*
+   * Energy at each point of the graph with 100 predefined points. At the
+   * beginning, it starts with all values at energyPerElement.
+   * If switched to flexible, this represents the maximum of usable energy
+   */
+  private transient float[] curveSample;
+  private transient float actualEnergy = 0;
+
+  /**
+   * Create a new HolonElement with a user-defined name, amount of the same
+   * element, energyPerElement and corresponding model.
+   *
+   * @param eleName String
+   * @param energy  float
+   */
+
+  /**
+   * same as standard constructor, but with already given id (so the counter is not increased
+   * twice)
+   */
+  public HolonElement(HolonObject parentObject, String name, float energy) {
+    this.parentObject = parentObject;
+    setName(name);
+    setEnergy(energy);
+    initGraphPoints();
+    sampleGraph();
+  }
+
+
+  /**
+   * Create a copy of the HolonElement given each one a new ID.
+   *
+   * @param other element to copy
+   */
+  public HolonElement(HolonElement other) {
+    this.parentObject = other.parentObject;
+    this.priority = other.getPriority();
+    this.period = other.period;
+    this.flexList = new ArrayList<>(other.flexList);
+    setName(other.getName());
+    setEnergy(other.getEnergy());
+    this.active = other.active;
+    setGraphPoints(new LinkedList<>());
+    for (Vec2f p : other.getGraphPoints()) {
+      this.graphPoints.add(new Vec2f(p));
     }
     }
-
-
-
-
-
-    /**
-     * Create a copy of the HolonElement given each one a new ID.
-     *
-     * @param other element to copy
-     */
-    public HolonElement(HolonElement other) {
-        this.parentObject = other.parentObject;
-        this.priority = other.getPriority();
-        this.period = other.period;
-        this.flexList = new ArrayList<>(other.flexList);
-        setName(other.getName());
-        setEnergy(other.getEnergy());
-        this.active = other.active;
-        setGraphPoints(new LinkedList<>());
-        for (Vec2f p : other.getGraphPoints()) {
-            this.graphPoints.add(new Vec2f(p));
-        }
-        this.actualEnergy = other.actualEnergy;
-        sampleGraph();
-    }
-
-    @Override
-    public Period getPeriod() {
-        return period;
+    this.actualEnergy = other.actualEnergy;
+    sampleGraph();
+  }
+
+  @Override
+  public Period getPeriod() {
+    return period;
+  }
+
+  @Override
+  public void setPeriod(Period period) {
+    this.period = period;
+  }
+
+
+  /**
+   * Get the user-defined Name.
+   *
+   * @return the name String
+   */
+  public String getName() {
+    return name;
+  }
+
+  /**
+   * Set the name to any new name.
+   *
+   * @param name the name to set
+   */
+  public void setName(String name) {
+    this.name = name;
+  }
+
+
+  /**
+   * Get the energyPerElement value of the selected Element.
+   *
+   * @return the energyPerElement
+   */
+  public float getEnergy() {
+    return energy;
+  }
+
+  /**
+   * Set the energyPerElement value of the selected Element.
+   *
+   * @param energyPerElement the energyPerElement to set
+   */
+  public void setEnergy(float energyPerElement) {
+    log.finest(this.energy + " -> " + energyPerElement);
+    this.energy = energyPerElement;
+  }
+
+
+  /**
+   * Check the HolonElemnet is a Producer
+   *
+   * @return true when the energy used be each element is higher then 0
+   */
+  public boolean isProducer() {
+    return (energy > 0);
+  }
+
+  /**
+   * Check the HolonElemnet is a Consumer
+   *
+   * @return true when the energy used be each element is lower then 0
+   */
+  public boolean isConsumer() {
+    return (energy < 0);
+  }
+
+
+  public Priority getPriority() {
+    return priority;
+  }
+
+
+  public void setPriority(Priority priority) {
+    this.priority = priority;
+  }
+
+  public String toString() {
+    return "[HolonElement: " +
+        ", eleName=" + name +
+        ", parentName=" + parentObject.getName() +
+        ", active=" + active +
+        ", energyPerElement used=" + energy +
+        "]";
+  }
+
+  /**
+   * Initialize the {@link HolonElement#graphPoints} List with the normal 2 Points at 100%.
+   */
+  private void initGraphPoints() {
+    graphPoints.clear();
+    graphPoints.add(new Vec2f(0f, 1.0f));
+    graphPoints.add(new Vec2f(1f, 1.0f));
+  }
+
+  /**
+   * Getter for the graphPoint List.
+   *
+   * @return {@link HolonElement#graphPoints}
+   */
+  public LinkedList<Vec2f> getGraphPoints() {
+    return graphPoints;
+  }
+
+  /**
+   * Setter for the graphPoint List.
+   */
+  public void setGraphPoints(LinkedList<Vec2f> graphPoints) {
+    this.graphPoints = graphPoints;
+  }
+
+
+  //interfaces.GraphEditable
+  @Override
+  public GraphType getGraphType() {
+    return GraphType.doubleGraph;
+  }
+
+
+  @Override
+  public LinkedList<Vec2f> getStateGraph() {
+    return getGraphPoints();
+  }
+
+
+  @Override
+  public void sampleGraph() {
+    curveSample = sampleGraph(100);
+  }
+
+  @Override
+  public void reset() {
+    initGraphPoints();
+    sampleGraph();
+  }
+
+  /**
+   * Generate out of the Graph Points a array of floats that represent the Curve at each sample
+   * position. The Values are in the Range [0,1]. e.g. 0.0 represent: "0%" , 0.34 represent: 34%
+   * 1.0 represent: "100%"
+   *
+   * @param sampleLength amount of samplePositions. The positions are equidistant on the
+   *                     Range[0,1].
+   * @return the float array of samplepoints.
+   */
+  private float[] sampleGraph(int sampleLength) {
+    ListIterator<Vec2f> iter = this.graphPoints.listIterator();
+    Vec2f before = iter.next();
+    Vec2f after = iter.next();
+    float[] sampleCurve = new float[sampleLength];
+    for (int i = 0; i < sampleLength; i++) {
+      double graphX = (double) i / (double) (sampleLength - 1); //from 0.0 to 1.0
+      if (graphX > after.x) {
+        before = after;
+        after = iter.next();
+      }
+      //t to determine how many percentage the graphX is to the next Point needed to calc Bezier
+      //inverseLerp(valueBetween, min, max) (valueBetween - min) / (max - min)
+      // e.g. old.x = 0.4, actual.x = 0.8 and graphX = 0.6 then t is 0.5
+      double t = (after.x - before.x > 0) ? (graphX - before.x) / (after.x - before.x) : 0.0;
+      sampleCurve[i] = (float) getYBetweenTwoPoints(t, before, after);
     }
     }
-
-    @Override
-    public void setPeriod(Period period) {
-        this.period = period;
-    }
-
-
-
-    /**
-     * Get the user-defined Name.
-     *
-     * @return the name String
-     */
-    public String getName() {
-        return name;
-    }
-
-    /**
-     * Set the name to any new name.
-     *
-     * @param name the name to set
-     */
-    public void setName(String name) {
-        this.name = name;
-    }
-
-
-    /**
-     * Get the energyPerElement value of the selected Element.
-     *
-     * @return the energyPerElement
-     */
-    public float getEnergy() {
-        return energy;
-    }
-
-    /**
-     * Set the energyPerElement value of the selected Element.
-     *
-     * @param energyPerElement the energyPerElement to set
-     */
-    public void setEnergy(float energyPerElement) {
-        log.finest(this.energy + " -> " + energyPerElement);
-        this.energy = energyPerElement;
-    }
-
-
-    /**
-     * Check the HolonElemnet is a Producer
-     *
-     * @return true when the energy used be each element is higher then 0
-     */
-    public boolean isProducer() {
-        return (energy > 0);
-    }
-
-    /**
-     * Check the HolonElemnet is a Consumer
-     *
-     * @return true when the energy used be each element is lower then 0
-     */
-    public boolean isConsumer() {
-        return (energy < 0);
-    }
-
-
-    public Priority getPriority() {
-        return priority;
-    }
-
-
-    public void setPriority(Priority priority) {
-        this.priority = priority;
-    }
-
-    public String toString() {
-        return "[HolonElement: " +
-                ", eleName=" + name +
-                ", parentName=" + parentObject.getName() +
-                ", active=" + active +
-                ", energyPerElement used=" + energy +
-                "]";
-    }
-
-    /**
-     * Initialize the {@link HolonElement#graphPoints} List with the normal 2 Points at 100%.
-     */
-    private void initGraphPoints() {
-        graphPoints.clear();
-        graphPoints.add(new Vec2f(0f, 1.0f));
-        graphPoints.add(new Vec2f(1f, 1.0f));
-    }
-
-    /**
-     * Getter for the graphPoint List.
-     *
-     * @return {@link HolonElement#graphPoints}
-     */
-    public LinkedList<Vec2f> getGraphPoints() {
-        return graphPoints;
-    }
-
-    /**
-     * Setter for the graphPoint List.
-     */
-    public void setGraphPoints(LinkedList<Vec2f> graphPoints) {
-        this.graphPoints = graphPoints;
-    }
-
-
-    //interfaces.GraphEditable
-    @Override
-    public GraphType getGraphType() {
-        return GraphType.doubleGraph;
-    }
-
-
-    @Override
-    public LinkedList<Vec2f> getStateGraph() {
-        return getGraphPoints();
-    }
-
-
-    @Override
-    public void sampleGraph() {
-        curveSample = sampleGraph(100);
-    }
-
-    @Override
-    public void reset() {
-        initGraphPoints();
-        sampleGraph();
-    }
-
-    /**
-     * Generate out of the Graph Points a array of floats that represent the Curve at each sample position. The Values are in the Range [0,1].
-     * e.g. 0.0 represent: "0%" , 0.34 represent: 34%  1.0 represent: "100%"
-     *
-     * @param sampleLength amount of samplePositions. The positions are equidistant on the Range[0,1].
-     * @return the float array of samplepoints.
-     */
-    private float[] sampleGraph(int sampleLength) {
-        ListIterator<Vec2f> iter = this.graphPoints.listIterator();
-        Vec2f before = iter.next();
-        Vec2f after = iter.next();
-        float[] sampleCurve = new float[sampleLength];
-        for (int i = 0; i < sampleLength; i++) {
-            double graphX = (double) i / (double) (sampleLength - 1); //from 0.0 to 1.0
-            if (graphX > after.x) {
-                before = after;
-                after = iter.next();
-            }
-            //t to determine how many percentage the graphX is to the next Point needed to calc Bezier
-            //inverseLerp(valueBetween, min, max) (valueBetween - min) / (max - min)
-            // e.g. old.x = 0.4, actual.x = 0.8 and graphX = 0.6 then t is 0.5
-            double t = (after.x - before.x > 0) ? (graphX - before.x) / (after.x - before.x) : 0.0;
-            sampleCurve[i] = (float) getYBetweenTwoPoints(t, before, after);
-        }
-        return sampleCurve;
-    }
-
-    /**
-     * Helper method for {@link HolonElement#sampleGraph(int)}.
-     * <p>
-     * Its get the start and Endposition and calculate the Points in between for the Bezi�r Curve.
-     * Then its get the Y Value a.k.a. the percentage from the curve at the X value t.
-     *
-     * @param t     is in Range [0,1] and represent how much the X value is traverse along the Curve between the two Points.
-     * @param start is the start Point of the Curve.
-     * @param end   is the end Point of the Curve.
-     * @return the percentage from the Curve at the X Value based on t.
-     */
-    private double getYBetweenTwoPoints(double t, Vec2f start, Vec2f end) {
-
-        float mitte = (start.x + end.x) * 0.5f;
-        Vec2f bezier = getBezierPoint(t, start, new Vec2f(mitte, start.y), new Vec2f(mitte, end.y), end);
-        return bezier.y;
-    }
-
-    /**
-     * Helper method for {@link HolonElement#getYBetweenTwoPoints(double, Vec2f, Vec2f)}.
-     * <p>
-     * A Method for a normal Cubic Bezier Curve. A Cubic Bezier curve has four control points.
-     *
-     * @param t  is in Range [0,1] how much it traverse along the curve.
-     * @param p0 StartPoint
-     * @param p1 ControlPoint
-     * @param p2 ControlPoint
-     * @param p3 EndPoint
-     * @return the BezierPosition at t.
-     */
-    private Vec2f getBezierPoint(double t, Vec2f p0, Vec2f p1, Vec2f p2, Vec2f p3) {
-        /*
-         * Calculate Bezi�r:
-         * B(t) = (1-t)^3 * P0 + 3*(1-t)^2 * t * P1 + 3*(1-t)*t^2 * P2 + t^3 * P3 , 0 < t < 1
-         *
-         * Source: //http://www.theappguruz.com/blog/bezier-curve-in-games
-         */
-        Vec2f bezier = new Vec2f();
-        double OneSubT = 1 - t;
-        double OneSubT2 = Math.pow(OneSubT, 2);
-        double OneSubT3 = Math.pow(OneSubT, 3);
-        double t2 = Math.pow(t, 2);
-        double t3 = Math.pow(t, 3);
-
-        bezier.x = (float) (OneSubT3 * p0.x + 3 * OneSubT2 * t * p1.x + 3 * OneSubT * t2 * p2.x + t3 * p3.x);
-        bezier.y = (float) (OneSubT3 * p0.y + 3 * OneSubT2 * t * p1.y + 3 * OneSubT * t2 * p2.y + t3 * p3.y);
-        return bezier;
-
-    }
-
-
+    return sampleCurve;
+  }
+
+  /**
+   * Helper method for {@link HolonElement#sampleGraph(int)}.
+   * <p>
+   * Its get the start and Endposition and calculate the Points in between for the Bezi�r Curve.
+   * Then its get the Y Value a.k.a. the percentage from the curve at the X value t.
+   *
+   * @param t     is in Range [0,1] and represent how much the X value is traverse along the Curve
+   *              between the two Points.
+   * @param start is the start Point of the Curve.
+   * @param end   is the end Point of the Curve.
+   * @return the percentage from the Curve at the X Value based on t.
+   */
+  private double getYBetweenTwoPoints(double t, Vec2f start, Vec2f end) {
+
+    float mitte = (start.x + end.x) * 0.5f;
+    Vec2f bezier = getBezierPoint(t, start, new Vec2f(mitte, start.y), new Vec2f(mitte, end.y),
+        end);
+    return bezier.y;
+  }
+
+  /**
+   * Helper method for {@link HolonElement#getYBetweenTwoPoints(double, Vec2f, Vec2f)}.
+   * <p>
+   * A Method for a normal Cubic Bezier Curve. A Cubic Bezier curve has four control points.
+   *
+   * @param t  is in Range [0,1] how much it traverse along the curve.
+   * @param p0 StartPoint
+   * @param p1 ControlPoint
+   * @param p2 ControlPoint
+   * @param p3 EndPoint
+   * @return the BezierPosition at t.
+   */
+  private Vec2f getBezierPoint(double t, Vec2f p0, Vec2f p1, Vec2f p2, Vec2f p3) {
     /*
     /*
-     * STATE
-     */
-
-    public void calculateState(int iteration) {
-        flexList.forEach(flex -> flex.calculateState(iteration));
-        float energyWhenActive = energy * this.curveSample[IndexTranslator.getEffectiveIndex(this, iteration)];
-        actualEnergy = isOn() ? energyWhenActive : 0;
-    }
-
-    /**
-     * Get the energyPerElement currently(at given time step) available
+     * Calculate Bezi�r:
+     * B(t) = (1-t)^3 * P0 + 3*(1-t)^2 * t * P1 + 3*(1-t)*t^2 * P2 + t^3 * P3 , 0 < t < 1
+     *
+     * Source: //http://www.theappguruz.com/blog/bezier-curve-in-games
      */
      */
-    public float calculateExpectedEnergyAtTimeStep(int iteration) {
-        float energyWhenActive = energy * this.curveSample[IndexTranslator.getEffectiveIndex(this, iteration)];
-        return active ? energyWhenActive : 0;
-    }
-
-    public float getActualEnergy() {
-        return actualEnergy;
-    }
-
-    public boolean isOn() {
-        //return isFlexActive()?!active:active;
-        //Bool logic XOR
-        return isFlexActive() ^ active;
-    }
-
-    public boolean isFlexActive() {
-        return flexList.stream().anyMatch(flex -> flex.getState() == FlexState.IN_USE || flex.getState() == FlexState.ON_COOLDOWN);
-    }
-
-    @Override
-    public void postDeserialize() {
-        flexList.forEach(flex -> flex.setElement(this));
-        sampleGraph();
-    }
-
-    public enum Priority {
-        Low, Medium, High, Essential
-    }
+    Vec2f bezier = new Vec2f();
+    double OneSubT = 1 - t;
+    double OneSubT2 = Math.pow(OneSubT, 2);
+    double OneSubT3 = Math.pow(OneSubT, 3);
+    double t2 = Math.pow(t, 2);
+    double t3 = Math.pow(t, 3);
+
+    bezier.x = (float) (OneSubT3 * p0.x + 3 * OneSubT2 * t * p1.x + 3 * OneSubT * t2 * p2.x
+        + t3 * p3.x);
+    bezier.y = (float) (OneSubT3 * p0.y + 3 * OneSubT2 * t * p1.y + 3 * OneSubT * t2 * p2.y
+        + t3 * p3.y);
+    return bezier;
+
+  }
+
+
+  /*
+   * STATE
+   */
+
+  public void calculateState(int iteration) {
+    flexList.forEach(flex -> flex.calculateState(iteration));
+    float energyWhenActive =
+        energy * this.curveSample[IndexTranslator.getEffectiveIndex(this, iteration)];
+    actualEnergy = isOn() ? energyWhenActive : 0;
+  }
+
+  /**
+   * Get the energyPerElement currently(at given time step) available
+   */
+  public float calculateExpectedEnergyAtTimeStep(int iteration) {
+    float energyWhenActive =
+        energy * this.curveSample[IndexTranslator.getEffectiveIndex(this, iteration)];
+    return active ? energyWhenActive : 0;
+  }
+
+  public float getActualEnergy() {
+    return actualEnergy;
+  }
+
+  public boolean isOn() {
+    //return isFlexActive()?!active:active;
+    //Bool logic XOR
+    return isFlexActive() ^ active;
+  }
+
+  public boolean isFlexActive() {
+    return flexList.stream().anyMatch(
+        flex -> flex.getState() == FlexState.IN_USE || flex.getState() == FlexState.ON_COOLDOWN);
+  }
+
+  @Override
+  public void postDeserialize() {
+    flexList.forEach(flex -> flex.setElement(this));
+    sampleGraph();
+  }
+
+  public enum Priority {
+    Low, Medium, High, Essential
+  }
 
 
 }
 }

+ 277 - 270
src/holeg/model/HolonObject.java

@@ -1,284 +1,291 @@
 package holeg.model;
 package holeg.model;
 
 
 import holeg.serialize.PostDeserialize;
 import holeg.serialize.PostDeserialize;
-
-import java.util.*;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import java.util.stream.Stream;
 
 
 /**
 /**
- * The class HolonObject represents any Object on the system which capability of
- * injecting or consuming energy on the network, for instance a house or a power
- * plant.
+ * The class HolonObject represents any Object on the system which capability of injecting or
+ * consuming energy on the network, for instance a house or a power plant.
  *
  *
  * @author Gruppe14
  * @author Gruppe14
  */
  */
 public class HolonObject extends AbstractCanvasObject implements PostDeserialize {
 public class HolonObject extends AbstractCanvasObject implements PostDeserialize {
-    /* Array of all consumers */
-    private final Set<HolonElement> elements = new HashSet<>();
-
-    //Calculated values
-    private transient HolonObjectState state;
-    private transient float actualEnergy;
-    private transient float energyFromHolon;
-    private transient float energyToHolon;
-    private transient float minimumConsumingElementEnergy;
-    private transient float energyNeededFromHolon;
-    private transient float consumption;
-    private transient float production;
-
-    /**
-     * Constructor Set by default the name of the object equals to the category
-     * name, until the user changes it.
-     *
-     * @param objName name of the Object
-     */
-    public HolonObject(String objName) {
-        super(objName);
-    }
-
-
-
-
-
-    /**
-     * Contructor of a copy of an Object.
-     *
-     * @param obj object to be copied
-     */
-    public HolonObject(HolonObject obj) {
-        super(obj);
-        for (HolonElement ele : obj.elements) {
-            this.add(new HolonElement(ele));
-        }
-    }
-
-    @Override
-    public AbstractCanvasObject copy(){
-        return new HolonObject(this);
-    }
-
-    /**
-     * Getter for all Elements in the HolonObject.
-     *
-     * @return the elements ArrayList
-     */
-    public Stream<HolonElement> elementsStream() {
-        return elements.stream();
-    }
-
-
-
-
-    public void clearElements() {
-        elements.clear();
-    }
-
-    /**
-     * adds an Element to the Object.
-     *
-     * @param element the Element to add
-     */
-    public void add(HolonElement element) {
-        elements.add(element);
-        element.parentObject = this;
-    }
-
-    public void add(Collection<HolonElement> elements) {
-        for (HolonElement hE : elements) {
-            hE.parentObject = this;
-        }
-        this.elements.addAll(elements);
-    }
-
-    /**
-     * remove an Element to the Object.
-     *
-     * @param element the Element to add
-     */
-    public void remove(HolonElement element) {
-        elements.remove(element);
-        element.parentObject = null;
-    }
-
-
-    /**
-     * This Method returns the smallest consuming HolonElement that is ACTIVE. If
-     * the HolonObject has no Consumer its return null.
-     *
-     * @return The smallest consuming HolonElement or null.
-     */
-    public Optional<HolonElement> getMinimumConsumingElement() {
-        return elements.stream().filter(element -> element.getActualEnergy() < 0).max((lhs, rhs) -> Float.compare(lhs.getActualEnergy(), rhs.getActualEnergy()));
-    }
-
-    /**
-     * This Method returns the smallest consuming HolonElement'Energy that is
-     * ACTIVE. If the HolonObject has no Consumer its return 0.
-     *
-     * @return The smallest consuming HolonElement or 0.
-     */
-    public float getMinimumConsumingElementEnergy() {
-        return minimumConsumingElementEnergy;
-    }
-
-    /**
-     * This Method returns the biggest consuming HolonElement'Energy that is ACTIVE.
-     * If the HolonObject has no Consumer its return 0.
-     *
-     * @return The biggest consuming HolonElement or 0.
-     */
-    public float getMaximumConsumingElementEnergy() {
-        return elements.stream().filter(element -> element.getActualEnergy() < 0).map(element -> -element.getActualEnergy()).max(Float::compare).orElse(0.0f);
-    }
-
-    public float getMaximumProductionPossible() {
-        return elements.stream().map(HolonElement::getEnergy).filter(energy -> energy > 0).reduce(0.0f, Float::sum);
-    }
-
-    public float getMaximumConsumptionPossible() {
-        return elements.stream().filter(element -> element.getEnergy() < 0).map(element -> -element.getEnergy()).reduce(0.0f, Float::sum);
-    }
-
-    /**
-     * This Method returns the Energy of all HolonElements from the HolonObject that
-     * are consuming. Its sums all Energies from the HolonElements of the
-     * HolonObject that are ACTIVE and are Consumer. If the HolonObject have no
-     * HolonElement its return 0;
-     *
-     * @return The Energy of the consuming HolonElements.
-     */
-    public float getEnergyNeededFromConsumingElements() {
-        return consumption;
-    }
-
-    /**
-     * This Method calculate the amount of HolonElements that are consuming Energy
-     * and are ACTIVE.
-     *
-     * @return The amount of HolonElements that are consuming Energy.
-     */
-    public int countConsumingElements() {
-        return (int) elements.stream().filter(element -> element.getActualEnergy() < 0).count();
-    }
-
-    /**
-     * This Method calculate the amount of HolonElements that are producing Energy
-     * and are ACTIVE.
-     *
-     * @return The amount of HolonElements that are producing Energy.
-     */
-    public int countProducingElements() {
-        return (int) elements.stream().filter(element -> element.getActualEnergy() > 0).count();
-    }
-
-    public int getNumberOfActiveElements() {
-        return (int) elements.stream().filter(ele -> ele.active).count();
-    }
-
-    public int getNumberOfInActiveElements() {
-        return (int) elements.stream().filter(ele -> !ele.active).count();
-    }
-
-    public int getNumberOfElements() {
-        return elements.size();
-    }
-
-    /**
-     * This Method returns the Energy of a HolonObject. Its sums all Energies from
-     * the HolonElements of the HolonObject that are ACTIVE. If the HolonObject have
-     * no HolonElement its return 0; Is the returned Energy negative then the
-     * HolonObject need Energy because its consuming HolonElements need more Energy
-     * then the producing HolonElements. Is the returned Energy positive its
-     * reversed.
-     *
-     * @param timeStep is the TimeStep to compare the HolonElements.
-     */
-    public void calculateEnergy(int timeStep) {
-        elements.forEach(ele -> ele.calculateState(timeStep));
-        actualEnergy = elements.stream().map(HolonElement::getActualEnergy).reduce(0f, Float::sum);
-        minimumConsumingElementEnergy = elements.stream().filter(element -> element.getActualEnergy() < 0).map(element -> -element.getActualEnergy()).min(Float::compare).orElse(0.0f);
-        energyNeededFromHolon = (actualEnergy >= 0) ? 0 : -actualEnergy;
-        consumption = elements.stream().filter(element -> element.getActualEnergy() < 0).map(element -> -element.getActualEnergy()).reduce(0.0f, Float::sum);
-        production = elements.stream().map(HolonElement::getActualEnergy).filter(energy -> energy > 0).reduce(0.0f, Float::sum);
-        energyToHolon = energyFromHolon = 0;
-    }
-
-    public float getActualEnergy() {
-        return actualEnergy;
-    }
-
-    public HolonObjectState getState() {
-        return state;
-    }
-
-    public boolean isProducer(){
-        return getProduction() >= getConsumption();
-    }
-    public boolean isConsumer(){
-        return getConsumption() >= getProduction();
-    }
-
-    public float getEnergyFromHolon() {
-        return energyFromHolon;
-    }
-
-    void setEnergyFromHolon(float energyFromHolon) {
-        this.energyFromHolon = energyFromHolon;
-    }
 
 
-    public float getEnergyNeededFromHolon() {
-        return energyNeededFromHolon;
-    }
-
-    public float getConsumption() { return consumption;}
-    public float getProduction() {
-        return production;
-    }
-
-    public float getCurrentEnergy() {
-        return energyFromHolon - energyNeededFromHolon;
-    }
-
-    public float getSupplyBarPercentage() {
-        return (consumption > 0.001) ? (energyFromHolon + production) / consumption : 1.0f;
-    }
-
-    public String toString() {
-        return "[HolonObject: " + "id=" + getId() + ", name=" + name + ", state=" + state + ", pos=" + position+ ", elements=[" + elementsStream().map(HolonElement::getName).collect(Collectors.joining(", ")) + "]]";
-    }
-
-    public float getEnergyToHolon() {
-        return energyToHolon;
-    }
-
-    void setEnergyToHolon(float energyToHolon) {
-        this.energyToHolon = energyToHolon;
-    }
-
-    public void calculateState() {
-        if(actualEnergy > 0){
-            state = HolonObjectState.PRODUCER;
-        }else if(elements.isEmpty() || consumption == 0 && production == 0){
-            state = HolonObjectState.NO_ENERGY;
-        }else if(production + energyFromHolon > consumption) {
-            state = (HolonObjectState.OVER_SUPPLIED);
-        }else if(production + energyFromHolon == consumption) {
-            state = (HolonObjectState.SUPPLIED);
-        }else if(production + energyFromHolon >= minimumConsumingElementEnergy) {
-            state = (HolonObjectState.PARTIALLY_SUPPLIED);
-        }else {
-            state = (HolonObjectState.NOT_SUPPLIED);
-        }
-    }
-
-    @Override
-    public void postDeserialize() {
-        elements.forEach(ele -> ele.parentObject = this);
-    }
-
-    public enum HolonObjectState {
-        NO_ENERGY, NOT_SUPPLIED, SUPPLIED, PRODUCER, PARTIALLY_SUPPLIED, OVER_SUPPLIED
-    }
+  /* Array of all consumers */
+  private final Set<HolonElement> elements = new HashSet<>();
+
+  //Calculated values
+  private transient HolonObjectState state;
+  private transient float actualEnergy;
+  private transient float energyFromHolon;
+  private transient float energyToHolon;
+  private transient float minimumConsumingElementEnergy;
+  private transient float energyNeededFromHolon;
+  private transient float consumption;
+  private transient float production;
+
+  /**
+   * Constructor Set by default the name of the object equals to the category name, until the user
+   * changes it.
+   *
+   * @param objName name of the Object
+   */
+  public HolonObject(String objName) {
+    super(objName);
+  }
+
+
+  /**
+   * Contructor of a copy of an Object.
+   *
+   * @param obj object to be copied
+   */
+  public HolonObject(HolonObject obj) {
+    super(obj);
+    for (HolonElement ele : obj.elements) {
+      this.add(new HolonElement(ele));
+    }
+  }
+
+  @Override
+  public AbstractCanvasObject copy() {
+    return new HolonObject(this);
+  }
+
+  /**
+   * Getter for all Elements in the HolonObject.
+   *
+   * @return the elements ArrayList
+   */
+  public Stream<HolonElement> elementsStream() {
+    return elements.stream();
+  }
+
+
+  public void clearElements() {
+    elements.clear();
+  }
+
+  /**
+   * adds an Element to the Object.
+   *
+   * @param element the Element to add
+   */
+  public void add(HolonElement element) {
+    elements.add(element);
+    element.parentObject = this;
+  }
+
+  public void add(Collection<HolonElement> elements) {
+    for (HolonElement hE : elements) {
+      hE.parentObject = this;
+    }
+    this.elements.addAll(elements);
+  }
+
+  /**
+   * remove an Element to the Object.
+   *
+   * @param element the Element to add
+   */
+  public void remove(HolonElement element) {
+    elements.remove(element);
+    element.parentObject = null;
+  }
+
+
+  /**
+   * This Method returns the smallest consuming HolonElement that is ACTIVE. If the HolonObject has
+   * no Consumer its return null.
+   *
+   * @return The smallest consuming HolonElement or null.
+   */
+  public Optional<HolonElement> getMinimumConsumingElement() {
+    return elements.stream().filter(element -> element.getActualEnergy() < 0)
+        .max((lhs, rhs) -> Float.compare(lhs.getActualEnergy(), rhs.getActualEnergy()));
+  }
+
+  /**
+   * This Method returns the smallest consuming HolonElement'Energy that is ACTIVE. If the
+   * HolonObject has no Consumer its return 0.
+   *
+   * @return The smallest consuming HolonElement or 0.
+   */
+  public float getMinimumConsumingElementEnergy() {
+    return minimumConsumingElementEnergy;
+  }
+
+  /**
+   * This Method returns the biggest consuming HolonElement'Energy that is ACTIVE. If the
+   * HolonObject has no Consumer its return 0.
+   *
+   * @return The biggest consuming HolonElement or 0.
+   */
+  public float getMaximumConsumingElementEnergy() {
+    return elements.stream().filter(element -> element.getActualEnergy() < 0)
+        .map(element -> -element.getActualEnergy()).max(Float::compare).orElse(0.0f);
+  }
+
+  public float getMaximumProductionPossible() {
+    return elements.stream().map(HolonElement::getEnergy).filter(energy -> energy > 0)
+        .reduce(0.0f, Float::sum);
+  }
+
+  public float getMaximumConsumptionPossible() {
+    return elements.stream().filter(element -> element.getEnergy() < 0)
+        .map(element -> -element.getEnergy()).reduce(0.0f, Float::sum);
+  }
+
+  /**
+   * This Method returns the Energy of all HolonElements from the HolonObject that are consuming.
+   * Its sums all Energies from the HolonElements of the HolonObject that are ACTIVE and are
+   * Consumer. If the HolonObject have no HolonElement its return 0;
+   *
+   * @return The Energy of the consuming HolonElements.
+   */
+  public float getEnergyNeededFromConsumingElements() {
+    return consumption;
+  }
+
+  /**
+   * This Method calculate the amount of HolonElements that are consuming Energy and are ACTIVE.
+   *
+   * @return The amount of HolonElements that are consuming Energy.
+   */
+  public int countConsumingElements() {
+    return (int) elements.stream().filter(element -> element.getActualEnergy() < 0).count();
+  }
+
+  /**
+   * This Method calculate the amount of HolonElements that are producing Energy and are ACTIVE.
+   *
+   * @return The amount of HolonElements that are producing Energy.
+   */
+  public int countProducingElements() {
+    return (int) elements.stream().filter(element -> element.getActualEnergy() > 0).count();
+  }
+
+  public int getNumberOfActiveElements() {
+    return (int) elements.stream().filter(ele -> ele.active).count();
+  }
+
+  public int getNumberOfInActiveElements() {
+    return (int) elements.stream().filter(ele -> !ele.active).count();
+  }
+
+  public int getNumberOfElements() {
+    return elements.size();
+  }
+
+  /**
+   * This Method returns the Energy of a HolonObject. Its sums all Energies from the HolonElements
+   * of the HolonObject that are ACTIVE. If the HolonObject have no HolonElement its return 0; Is
+   * the returned Energy negative then the HolonObject need Energy because its consuming
+   * HolonElements need more Energy then the producing HolonElements. Is the returned Energy
+   * positive its reversed.
+   *
+   * @param timeStep is the TimeStep to compare the HolonElements.
+   */
+  public void calculateEnergy(int timeStep) {
+    elements.forEach(ele -> ele.calculateState(timeStep));
+    actualEnergy = elements.stream().map(HolonElement::getActualEnergy).reduce(0f, Float::sum);
+    minimumConsumingElementEnergy = elements.stream()
+        .filter(element -> element.getActualEnergy() < 0).map(element -> -element.getActualEnergy())
+        .min(Float::compare).orElse(0.0f);
+    energyNeededFromHolon = (actualEnergy >= 0) ? 0 : -actualEnergy;
+    consumption = elements.stream().filter(element -> element.getActualEnergy() < 0)
+        .map(element -> -element.getActualEnergy()).reduce(0.0f, Float::sum);
+    production = elements.stream().map(HolonElement::getActualEnergy).filter(energy -> energy > 0)
+        .reduce(0.0f, Float::sum);
+    energyToHolon = energyFromHolon = 0;
+  }
+
+  public float getActualEnergy() {
+    return actualEnergy;
+  }
+
+  public HolonObjectState getState() {
+    return state;
+  }
+
+  public boolean isProducer() {
+    return getProduction() >= getConsumption();
+  }
+
+  public boolean isConsumer() {
+    return getConsumption() >= getProduction();
+  }
+
+  public float getEnergyFromHolon() {
+    return energyFromHolon;
+  }
+
+  void setEnergyFromHolon(float energyFromHolon) {
+    this.energyFromHolon = energyFromHolon;
+  }
+
+  public float getEnergyNeededFromHolon() {
+    return energyNeededFromHolon;
+  }
+
+  public float getConsumption() {
+    return consumption;
+  }
+
+  public float getProduction() {
+    return production;
+  }
+
+  public float getCurrentEnergy() {
+    return energyFromHolon - energyNeededFromHolon;
+  }
+
+  public float getSupplyBarPercentage() {
+    return (consumption > 0.001) ? (energyFromHolon + production) / consumption : 1.0f;
+  }
+
+  public String toString() {
+    return "[HolonObject: " + "id=" + getId() + ", name=" + name + ", state=" + state + ", pos="
+        + position + ", elements=[" + elementsStream().map(HolonElement::getName)
+        .collect(Collectors.joining(", ")) + "]]";
+  }
+
+  public float getEnergyToHolon() {
+    return energyToHolon;
+  }
+
+  void setEnergyToHolon(float energyToHolon) {
+    this.energyToHolon = energyToHolon;
+  }
+
+  public void calculateState() {
+    if (actualEnergy > 0) {
+      state = HolonObjectState.PRODUCER;
+    } else if (elements.isEmpty() || consumption == 0 && production == 0) {
+      state = HolonObjectState.NO_ENERGY;
+    } else if (production + energyFromHolon > consumption) {
+      state = (HolonObjectState.OVER_SUPPLIED);
+    } else if (production + energyFromHolon == consumption) {
+      state = (HolonObjectState.SUPPLIED);
+    } else if (production + energyFromHolon >= minimumConsumingElementEnergy) {
+      state = (HolonObjectState.PARTIALLY_SUPPLIED);
+    } else {
+      state = (HolonObjectState.NOT_SUPPLIED);
+    }
+  }
+
+  @Override
+  public void postDeserialize() {
+    elements.forEach(ele -> ele.parentObject = this);
+  }
+
+  public enum HolonObjectState {
+    NO_ENERGY, NOT_SUPPLIED, SUPPLIED, PRODUCER, PARTIALLY_SUPPLIED, OVER_SUPPLIED
+  }
 
 
 }
 }

+ 223 - 222
src/holeg/model/HolonSwitch.java

@@ -6,242 +6,243 @@ import holeg.preferences.ImagePreference;
 import holeg.serialize.PostDeserialize;
 import holeg.serialize.PostDeserialize;
 import holeg.ui.controller.IndexTranslator;
 import holeg.ui.controller.IndexTranslator;
 import holeg.utility.math.vector.Vec2f;
 import holeg.utility.math.vector.Vec2f;
-
 import java.util.LinkedList;
 import java.util.LinkedList;
 import java.util.ListIterator;
 import java.util.ListIterator;
 
 
 /**
 /**
- * The class HolonSwitch represents an Object in the system, that has the
- * capacity of manipulate the electricity flow. The switch can be manage
- * automatically through a graph or direct manually.
+ * The class HolonSwitch represents an Object in the system, that has the capacity of manipulate the
+ * electricity flow. The switch can be manage automatically through a graph or direct manually.
  *
  *
  * @author Gruppe14
  * @author Gruppe14
  */
  */
-public class HolonSwitch extends AbstractCanvasObject implements TimelineDependent, PostDeserialize {
-    /**
-     * Energy at each point of the graph with 50 predefined points. At the
-     * beginning, it starts with all values at energy
-     */
-    boolean[] activeAt = new boolean[LocalMode.STANDARD_GRAPH_ACCURACY];
-    /**
-     * Points on the UnitGraph
-     */
-    LinkedList<Vec2f> graphPoints = new LinkedList<>();
-    private SwitchMode mode = SwitchMode.Auto;
-    private SwitchState manualState = SwitchState.Closed;
-    private SwitchState state = SwitchState.Closed;
-    private Period period = new Period();
-
-    /**
-     * Create a new HolonSwitch with a custom name, a default value of automatic
-     * handle and active status.
-     *
-     * @param name String
-     */
-    public HolonSwitch(String name) {
-        super(name);
-        initGraphPoints();
-        sampleGraph();
-    }
-
-
-    /**
-     * Create a copy of an existing HolonSwitch.
-     *
-     * @param other the Object to copy
-     */
-    public HolonSwitch(HolonSwitch other) {
-        super(other);
-        mode = other.mode;
-        manualState = other.manualState;
-        state = other.state;
-        setPeriod(other.getPeriod());
-        activeAt = new boolean[LocalMode.STANDARD_GRAPH_ACCURACY];
-        setName(other.getName());
-        for (Vec2f p : other.getGraphPoints()) {
-            this.graphPoints.add(new Vec2f(p.getX(), p.getY()));
-        }
-        sampleGraph();
-    }
-
-    @Override
-    public AbstractCanvasObject copy(){
-        return new HolonSwitch(this);
-    }
-
-
-    @Override
-    public String getImagePath() {
-        return switch (state) {
-            case Open -> ImagePreference.Canvas.Switch.Open;
-            case Closed -> ImagePreference.Canvas.Switch.Closed;
-        };
-    }
-
-    /**
-     * Calculates the state of the Switch.
-     */
-    public void flipManualState() {
-        manualState = SwitchState.opposite(manualState);
-    }
-
-    public void calculateState(int timestep) {
-        switch (mode) {
-            case Auto:
-                state = activeAt[IndexTranslator.getEffectiveIndex(this, timestep)] ? SwitchState.Open : SwitchState.Closed;
-            case Manual:
-            default:
-                state = manualState;
-        }
-    }
-
-    /*
-     * STATE
-     */
-
-    public SwitchState getState() {
-        return state;
-    }
-
-    /**
-     * For automatic use only (through the graph).
-     *
-     * @return the Graph Points
-     */
-    public LinkedList<Vec2f> getGraphPoints() {
-        return graphPoints;
-    }
-
-    /**
-     * Set the values of the switch in the graph (auto. mode only).
-     *
-     * @param linkedList the Graph points
-     */
-    public void setGraphPoints(LinkedList<Vec2f> linkedList) {
-        this.graphPoints = linkedList;
-    }
-
-    /**
-     * Initialize the Graph as a closed Switch.
-     */
-    private void initGraphPoints() {
-        graphPoints.clear();
-        graphPoints.add(new Vec2f(0, 1));
-        graphPoints.add(new Vec2f(1, 1));
-    }
-
-    public SwitchMode getMode() {
-        return mode;
-    }
-
-    public void setMode(SwitchMode mode) {
-        this.mode = mode;
-    }
-
-    public SwitchState getManualState() {
-        return manualState;
-    }
-
-    public void setManualState(SwitchState manuelState) {
-        this.manualState = manuelState;
-    }
-
-    // interfaces.GraphEditable
-    @Override
-    public GraphType getGraphType() {
-        return GraphType.boolGraph;
-    }
-
-    @Override
-    public LinkedList<Vec2f> getStateGraph() {
-        return graphPoints;
-    }
-
-    @Override
-    public void reset() {
-        initGraphPoints();
-        sampleGraph();
-    }
-
-    @Override
-    public void sampleGraph() {
-        activeAt = sampleGraph(100);
-    }
-
-    /**
-     * Generate out of the Graph Points a array of boolean that represent the
-     * Curve("on or off"-Graph) at each sample position. The Values are in the Range
-     * [0,1].
-     *
-     * @param sampleLength amount of samplePositions. The positions are equidistant
-     *                     on the Range[0,1].
-     * @return the boolean array of samplepoints.
-     */
-    private boolean[] sampleGraph(int sampleLength) {
-        ListIterator<Vec2f> iter = this.graphPoints.listIterator();
-        Vec2f before = iter.next();
-        Vec2f after = iter.next();
-        boolean[] activeTriggerPos = new boolean[sampleLength];
-        for (int i = 0; i < sampleLength; i++) {
-            double graphX = (double) i / (double) (sampleLength - 1); // from 0.0 to 1.0
-            if (graphX > after.x) {
-                before = after;
-                after = iter.next();
-            }
-            activeTriggerPos[i] = (before.getY() >= 0.5);
-        }
-        return activeTriggerPos;
-    }
-
-    @Override
-    public Period getPeriod() {
-
-        return period;
-    }
-    @Override
-    public void setPeriod(Period period) {
-        this.period = period;
-    }
-
-    public String toString() {
-        return name + "[ID:" + getId() + "]";
-
-    }
-
-    @Override
-    public void postDeserialize() {
-        sampleGraph();
-    }
-
-    public enum SwitchState {
-        Open, Closed;
-
-        public static SwitchState opposite(SwitchState state) {
-            return switch (state) {
-                case Closed -> Open;
-                case Open -> Closed;
-            };
-        }
-
-        public boolean isOpen() {
-            return this == Open;
-        }
-
-        public boolean isClosed() {
-            return this == Closed;
-        }
+public class HolonSwitch extends AbstractCanvasObject implements TimelineDependent,
+    PostDeserialize {
+
+  /**
+   * Energy at each point of the graph with 50 predefined points. At the beginning, it starts with
+   * all values at energy
+   */
+  boolean[] activeAt = new boolean[LocalMode.STANDARD_GRAPH_ACCURACY];
+  /**
+   * Points on the UnitGraph
+   */
+  LinkedList<Vec2f> graphPoints = new LinkedList<>();
+  private SwitchMode mode = SwitchMode.Auto;
+  private SwitchState manualState = SwitchState.Closed;
+  private SwitchState state = SwitchState.Closed;
+  private Period period = new Period();
+
+  /**
+   * Create a new HolonSwitch with a custom name, a default value of automatic handle and active
+   * status.
+   *
+   * @param name String
+   */
+  public HolonSwitch(String name) {
+    super(name);
+    initGraphPoints();
+    sampleGraph();
+  }
+
+
+  /**
+   * Create a copy of an existing HolonSwitch.
+   *
+   * @param other the Object to copy
+   */
+  public HolonSwitch(HolonSwitch other) {
+    super(other);
+    mode = other.mode;
+    manualState = other.manualState;
+    state = other.state;
+    setPeriod(other.getPeriod());
+    activeAt = new boolean[LocalMode.STANDARD_GRAPH_ACCURACY];
+    setName(other.getName());
+    for (Vec2f p : other.getGraphPoints()) {
+      this.graphPoints.add(new Vec2f(p.getX(), p.getY()));
+    }
+    sampleGraph();
+  }
+
+  @Override
+  public AbstractCanvasObject copy() {
+    return new HolonSwitch(this);
+  }
+
+
+  @Override
+  public String getImagePath() {
+    return switch (state) {
+      case Open -> ImagePreference.Canvas.Switch.Open;
+      case Closed -> ImagePreference.Canvas.Switch.Closed;
+    };
+  }
+
+  /**
+   * Calculates the state of the Switch.
+   */
+  public void flipManualState() {
+    manualState = SwitchState.opposite(manualState);
+  }
+
+  public void calculateState(int timestep) {
+    switch (mode) {
+      case Auto:
+        state = activeAt[IndexTranslator.getEffectiveIndex(this, timestep)] ? SwitchState.Open
+            : SwitchState.Closed;
+      case Manual:
+      default:
+        state = manualState;
+    }
+  }
+
+  /*
+   * STATE
+   */
+
+  public SwitchState getState() {
+    return state;
+  }
+
+  /**
+   * For automatic use only (through the graph).
+   *
+   * @return the Graph Points
+   */
+  public LinkedList<Vec2f> getGraphPoints() {
+    return graphPoints;
+  }
+
+  /**
+   * Set the values of the switch in the graph (auto. mode only).
+   *
+   * @param linkedList the Graph points
+   */
+  public void setGraphPoints(LinkedList<Vec2f> linkedList) {
+    this.graphPoints = linkedList;
+  }
+
+  /**
+   * Initialize the Graph as a closed Switch.
+   */
+  private void initGraphPoints() {
+    graphPoints.clear();
+    graphPoints.add(new Vec2f(0, 1));
+    graphPoints.add(new Vec2f(1, 1));
+  }
+
+  public SwitchMode getMode() {
+    return mode;
+  }
+
+  public void setMode(SwitchMode mode) {
+    this.mode = mode;
+  }
+
+  public SwitchState getManualState() {
+    return manualState;
+  }
+
+  public void setManualState(SwitchState manuelState) {
+    this.manualState = manuelState;
+  }
+
+  // interfaces.GraphEditable
+  @Override
+  public GraphType getGraphType() {
+    return GraphType.boolGraph;
+  }
+
+  @Override
+  public LinkedList<Vec2f> getStateGraph() {
+    return graphPoints;
+  }
+
+  @Override
+  public void reset() {
+    initGraphPoints();
+    sampleGraph();
+  }
+
+  @Override
+  public void sampleGraph() {
+    activeAt = sampleGraph(100);
+  }
+
+  /**
+   * Generate out of the Graph Points a array of boolean that represent the Curve("on or off"-Graph)
+   * at each sample position. The Values are in the Range [0,1].
+   *
+   * @param sampleLength amount of samplePositions. The positions are equidistant on the
+   *                     Range[0,1].
+   * @return the boolean array of samplepoints.
+   */
+  private boolean[] sampleGraph(int sampleLength) {
+    ListIterator<Vec2f> iter = this.graphPoints.listIterator();
+    Vec2f before = iter.next();
+    Vec2f after = iter.next();
+    boolean[] activeTriggerPos = new boolean[sampleLength];
+    for (int i = 0; i < sampleLength; i++) {
+      double graphX = (double) i / (double) (sampleLength - 1); // from 0.0 to 1.0
+      if (graphX > after.x) {
+        before = after;
+        after = iter.next();
+      }
+      activeTriggerPos[i] = (before.getY() >= 0.5);
+    }
+    return activeTriggerPos;
+  }
+
+  @Override
+  public Period getPeriod() {
+
+    return period;
+  }
+
+  @Override
+  public void setPeriod(Period period) {
+    this.period = period;
+  }
+
+  public String toString() {
+    return name + "[ID:" + getId() + "]";
+
+  }
+
+  @Override
+  public void postDeserialize() {
+    sampleGraph();
+  }
+
+  public boolean isOpen() {
+    return getState().isOpen();
+  }
+
+  public boolean isClosed() {
+    return getState().isClosed();
+  }
+
+  public enum SwitchState {
+    Open, Closed;
+
+    public static SwitchState opposite(SwitchState state) {
+      return switch (state) {
+        case Closed -> Open;
+        case Open -> Closed;
+      };
     }
     }
 
 
     public boolean isOpen() {
     public boolean isOpen() {
-        return getState().isOpen();
+      return this == Open;
     }
     }
 
 
     public boolean isClosed() {
     public boolean isClosed() {
-        return getState().isClosed();
+      return this == Closed;
     }
     }
+  }
 
 
 
 
-    public enum SwitchMode {
-        Manual, Auto
-    }
+  public enum SwitchMode {
+    Manual, Auto
+  }
 }
 }

+ 85 - 82
src/holeg/model/Model.java

@@ -8,93 +8,96 @@ import java.util.stream.Collectors;
 
 
 
 
 /**
 /**
- * The Class Model is the class where everything is saved. All changes made to
- * the Data is managed via a controller.
+ * The Class Model is the class where everything is saved. All changes made to the Data is managed
+ * via a controller.
  *
  *
  * @author Gruppe14
  * @author Gruppe14
  */
  */
 public class Model {
 public class Model {
 
 
-    private static final Logger log = Logger.getLogger(Model.class.getName());
-    private GroupNode canvas = new GroupNode("Canvas");
-    public transient Set<Holon> holons = new HashSet<>();
-
-    /** the amount of iterations */
-    private int currentIteration = 0;
-    private int maxIterations = 100;
-
-    private Set<Edge> edgesOnCanvas = new HashSet<>();
-
-    public Model() {
-        log.fine("Init Model");
-    }
-
-    public GroupNode getCanvas() {
-        return canvas;
-    }
-
-    public Set<Edge> getEdgesOnCanvas() {
-        return edgesOnCanvas;
-    }
-
-    public void addEdgeOnCanvas(Edge edge) {
-        this.edgesOnCanvas.add(edge);
-    }
-
-    public void removeEdgesOnCanvas(Edge edge) {
-        this.edgesOnCanvas.remove(edge);
-    }
-
-    public int getMaxIterations() {
-        return maxIterations;
-    }
-
-    public int getCurrentIteration() {
-        return currentIteration;
-    }
-
-    public void setCurrentIteration(int value) {
-        this.currentIteration = value;
-    }
-
-    public List<HolonElement> getAllHolonElements() {
-        return canvas.getAllHolonObjectsRecursive().flatMap(HolonObject::elementsStream).collect(Collectors.toList());
-    }
-
-    public List<Flexibility> getAllFlexibilities() {
-        return canvas.getAllHolonObjectsRecursive().flatMap(hO -> hO.elementsStream().flatMap(ele -> ele.flexList.stream())).collect(Collectors.toList());
-    }
-
-    public void reset() {
-        resetFlexibilities();
-        resetEdges();
-    }
-
-    private void resetFlexibilities() {
-        getAllFlexibilities().forEach(Flexibility::reset);
-    }
-
-    private void resetEdges() {
-        this.getEdgesOnCanvas().forEach(Edge::reset);
-    }
-
-    public void setIterations(int iterations) {
-        this.maxIterations = iterations;
-    }
-
-    public void clear() {
-        this.edgesOnCanvas.clear();
-        canvas.clear();
-    }
-
-    public void setCanvas(GroupNode canvas) {
-        this.canvas = canvas;
-    }
-
-    public void setEdgesOnCanvas(Set<Edge> edgesOnCanvas) {
-        this.edgesOnCanvas = edgesOnCanvas;
-    }
-
+  private static final Logger log = Logger.getLogger(Model.class.getName());
+  public transient Set<Holon> holons = new HashSet<>();
+  private GroupNode canvas = new GroupNode("Canvas");
+  /**
+   * the amount of iterations
+   */
+  private int currentIteration = 0;
+  private int maxIterations = 100;
+
+  private Set<Edge> edgesOnCanvas = new HashSet<>();
+
+  public Model() {
+    log.fine("Init Model");
+  }
+
+  public GroupNode getCanvas() {
+    return canvas;
+  }
+
+  public void setCanvas(GroupNode canvas) {
+    this.canvas = canvas;
+  }
+
+  public Set<Edge> getEdgesOnCanvas() {
+    return edgesOnCanvas;
+  }
+
+  public void setEdgesOnCanvas(Set<Edge> edgesOnCanvas) {
+    this.edgesOnCanvas = edgesOnCanvas;
+  }
+
+  public void addEdgeOnCanvas(Edge edge) {
+    this.edgesOnCanvas.add(edge);
+  }
+
+  public void removeEdgesOnCanvas(Edge edge) {
+    this.edgesOnCanvas.remove(edge);
+  }
+
+  public int getMaxIterations() {
+    return maxIterations;
+  }
+
+  public int getCurrentIteration() {
+    return currentIteration;
+  }
+
+  public void setCurrentIteration(int value) {
+    this.currentIteration = value;
+  }
+
+  public List<HolonElement> getAllHolonElements() {
+    return canvas.getAllHolonObjectsRecursive().flatMap(HolonObject::elementsStream)
+        .collect(Collectors.toList());
+  }
+
+  public List<Flexibility> getAllFlexibilities() {
+    return canvas.getAllHolonObjectsRecursive()
+        .flatMap(hO -> hO.elementsStream().flatMap(ele -> ele.flexList.stream()))
+        .collect(Collectors.toList());
+  }
+
+  public void reset() {
+    resetFlexibilities();
+    resetEdges();
+  }
+
+  private void resetFlexibilities() {
+    getAllFlexibilities().forEach(Flexibility::reset);
+  }
+
+  private void resetEdges() {
+    this.getEdgesOnCanvas().forEach(Edge::reset);
+  }
+
+  public void setIterations(int iterations) {
+    this.maxIterations = iterations;
+  }
+
+  public void clear() {
+    this.edgesOnCanvas.clear();
+    canvas.clear();
+  }
 
 
 
 
 }
 }

+ 17 - 19
src/holeg/model/Node.java

@@ -1,29 +1,27 @@
 package holeg.model;
 package holeg.model;
 
 
 /**
 /**
- * The class "CpsNode" represents empty Objects in the system. They are just
- * nodes between Objects
- * 
- * @author Gruppe14
+ * The class "CpsNode" represents empty Objects in the system. They are just nodes between Objects
  *
  *
+ * @author Gruppe14
  */
  */
 public class Node extends AbstractCanvasObject {
 public class Node extends AbstractCanvasObject {
 
 
-	public Node(String objName) {
-		super(objName);
-	}
-	
-	public Node(Node node){
-		super(node);
-	}
+  public Node(String objName) {
+    super(objName);
+  }
+
+  public Node(Node node) {
+    super(node);
+  }
+
+  @Override
+  public AbstractCanvasObject copy() {
+    return new Node(this);
+  }
 
 
-	@Override
-	public AbstractCanvasObject copy(){
-		return new Node(this);
-	}
-	
-	public String toString(){
-		return "Node ID:" + getId();
-	}
+  public String toString() {
+    return "Node ID:" + getId();
+  }
 
 
 }
 }

+ 105 - 91
src/holeg/preferences/ColorPreference.java

@@ -2,8 +2,7 @@ package holeg.preferences;
 
 
 import holeg.model.Flexibility.FlexState;
 import holeg.model.Flexibility.FlexState;
 import holeg.model.HolonObject.HolonObjectState;
 import holeg.model.HolonObject.HolonObjectState;
-
-import java.awt.*;
+import java.awt.Color;
 
 
 /**
 /**
  * A Class to save all colors in Holeg.
  * A Class to save all colors in Holeg.
@@ -13,110 +12,125 @@ import java.awt.*;
 public class ColorPreference {
 public class ColorPreference {
 
 
 
 
-    public static class Element {
-        public static final Color Active = new Color(255, 203, 35);
-        public static final Color Inactive = new Color(128, 154, 163);
+  public static class Element {
 
 
-        public static class Priority {
-            public static final Color Essential = new Color(201, 44, 74);
-            public static final Color High = new Color(255, 92, 26);
-            public static final Color Medium = new Color(255, 216, 57);
-            public static final Color Low = new Color(255, 255, 175);
-        }
-    }
+    public static final Color Active = new Color(255, 203, 35);
+    public static final Color Inactive = new Color(128, 154, 163);
 
 
-    public static class HolonObject {
-        public static final Color Producer = new Color(149, 152, 159, 211);
-        public static final Color OverSupplied = new Color(166, 78, 229);
-        public static final Color Supplied = new Color(13, 175, 28);
-        public static final Color PartiallySupplied = new Color(255, 233, 1);
-        public static final Color NotSupplied = new Color(230, 120, 100);
-        public static final Color NoEnergy = new Color(239, 239, 239);
-
-        public static Color getStateColor(HolonObjectState state) {
-            return switch (state) {
-                case NOT_SUPPLIED -> NotSupplied;
-                case OVER_SUPPLIED -> OverSupplied;
-                case PARTIALLY_SUPPLIED -> PartiallySupplied;
-                case PRODUCER -> Producer;
-                case SUPPLIED -> Supplied;
-                case NO_ENERGY -> NoEnergy;
-            };
-        }
-    }
+    public static class Priority {
 
 
-    public static class Edge {
-        public static final Color Working = new Color(13, 175, 28);
-        public static final Color Burned = Color.red;
+      public static final Color Essential = new Color(201, 44, 74);
+      public static final Color High = new Color(255, 92, 26);
+      public static final Color Medium = new Color(255, 216, 57);
+      public static final Color Low = new Color(255, 255, 175);
+    }
+  }
+
+  public static class HolonObject {
+
+    public static final Color Producer = new Color(149, 152, 159, 211);
+    public static final Color OverSupplied = new Color(166, 78, 229);
+    public static final Color Supplied = new Color(13, 175, 28);
+    public static final Color PartiallySupplied = new Color(255, 233, 1);
+    public static final Color NotSupplied = new Color(230, 120, 100);
+    public static final Color NoEnergy = new Color(239, 239, 239);
+
+    public static Color getStateColor(HolonObjectState state) {
+      return switch (state) {
+        case NOT_SUPPLIED -> NotSupplied;
+        case OVER_SUPPLIED -> OverSupplied;
+        case PARTIALLY_SUPPLIED -> PartiallySupplied;
+        case PRODUCER -> Producer;
+        case SUPPLIED -> Supplied;
+        case NO_ENERGY -> NoEnergy;
+      };
     }
     }
+  }
 
 
+  public static class Edge {
 
 
-    public static class Energy {
-        public static final Color Production = new Color(61, 133, 243);
-        public static final Color Consumption = new Color(255, 67, 60);
-    }
+    public static final Color Working = new Color(13, 175, 28);
+    public static final Color Burned = Color.red;
+  }
 
 
-    public static class Flexibility {
-        public static final Color InUse = new Color(182, 238, 166);
-        public static final Color OnCooldown = new Color(239, 215, 128);
-        public static final Color Offered = new Color(75, 170, 72);
-        public static final Color NotOffered = new Color(237, 106, 90);
-        public static final Color Unavailable = new Color(193, 193, 193);
-        public static final Color NoFlexibility = new Color(101, 101, 101);
-
-        public static Color getStateColor(FlexState state) {
-            return switch (state) {
-                case IN_USE -> InUse;
-                case NOT_OFFERED -> NotOffered;
-                case OFFERED -> Offered;
-                case ON_COOLDOWN -> OnCooldown;
-                case UNAVAILABLE -> Unavailable;
-            };
-        }
-    }
 
 
-    public static class Panel {
-        public static final Color Transparent = new Color(0, 0, 0, 0);
-        public static final Color Background = new Color(250, 250, 250);
-        public static final Color Title = new Color(54, 73, 78);
-    }
+  public static class Energy {
 
 
-    public static class Canvas {
-        public static final Color MouseSelectionBorder = new Color(0, 120, 215);
-        public static final Color MouseSelectionFill = new Color(128, 174, 247, 40);
-        public static final Color ObjectSelectionBorder = new Color(153, 209, 255);
-        public static final Color ObjectSelectionFill = new Color(205, 233, 255);
-        public static final Color HolonObjectEnergy = new Color(26, 26, 26);
+    public static final Color Production = new Color(61, 133, 243);
+    public static final Color Consumption = new Color(255, 67, 60);
+  }
 
 
-    }
+  public static class Flexibility {
 
 
-    public static class InformationPanel{
-        public static final Color NoData = new Color(243, 243, 243, 255);
-    }
+    public static final Color InUse = new Color(182, 238, 166);
+    public static final Color OnCooldown = new Color(239, 215, 128);
+    public static final Color Offered = new Color(75, 170, 72);
+    public static final Color NotOffered = new Color(237, 106, 90);
+    public static final Color Unavailable = new Color(193, 193, 193);
+    public static final Color NoFlexibility = new Color(101, 101, 101);
 
 
-    public static class Dialog {
-        public static final Color BackgroundColor = new Color(255, 50, 50);
+    public static Color getStateColor(FlexState state) {
+      return switch (state) {
+        case IN_USE -> InUse;
+        case NOT_OFFERED -> NotOffered;
+        case OFFERED -> Offered;
+        case ON_COOLDOWN -> OnCooldown;
+        case UNAVAILABLE -> Unavailable;
+      };
     }
     }
+  }
 
 
-    public static class Category {
-        public final static Color Focus = new Color(219, 245, 255);
-    }
+  public static class Panel {
 
 
-    public static class Inspector {
-        public final static Color Selected = new Color(126, 186, 255);
-        public final static Color Border = new Color(171, 173, 179);
-    }
+    public static final Color Transparent = new Color(0, 0, 0, 0);
+    public static final Color Background = new Color(250, 250, 250);
+    public static final Color Title = new Color(54, 73, 78);
+  }
 
 
-    public static class TimePanel {
-        public static final Color Invalid = new Color(255, 192, 192);
-    }
+  public static class Canvas {
 
 
-    public static class UnitGraph{
-        public static final Color DotColor = Color.blue;
-        public static final Color EditDotColor = new Color(255, 119, 0);
-        public static final Color[] SeriesColorArray = { Color.blue, Color.cyan, Color.black, Color.green, Color.gray,
-                Color.magenta, Color.yellow, Color.PINK, Color.red };
-        public static final Color GlobalCurveColor = new Color(255, 30, 30);
-        public static final Color ZeroLineColor = new Color(255, 153, 153);
-    }
+    public static final Color MouseSelectionBorder = new Color(0, 120, 215);
+    public static final Color MouseSelectionFill = new Color(128, 174, 247, 40);
+    public static final Color ObjectSelectionBorder = new Color(153, 209, 255);
+    public static final Color ObjectSelectionFill = new Color(205, 233, 255);
+    public static final Color HolonObjectEnergy = new Color(26, 26, 26);
+
+  }
+
+  public static class InformationPanel {
+
+    public static final Color NoData = new Color(243, 243, 243, 255);
+  }
+
+  public static class Dialog {
+
+    public static final Color BackgroundColor = new Color(255, 50, 50);
+  }
+
+  public static class Category {
+
+    public final static Color Focus = new Color(219, 245, 255);
+  }
+
+  public static class Inspector {
+
+    public final static Color Selected = new Color(126, 186, 255);
+    public final static Color Border = new Color(171, 173, 179);
+  }
+
+  public static class TimePanel {
+
+    public static final Color Invalid = new Color(255, 192, 192);
+  }
+
+  public static class UnitGraph {
+
+    public static final Color DotColor = Color.blue;
+    public static final Color EditDotColor = new Color(255, 119, 0);
+    public static final Color[] SeriesColorArray = {Color.blue, Color.cyan, Color.black,
+        Color.green, Color.gray,
+        Color.magenta, Color.yellow, Color.PINK, Color.red};
+    public static final Color GlobalCurveColor = new Color(255, 30, 30);
+    public static final Color ZeroLineColor = new Color(34, 255, 0);
+  }
 }
 }

+ 91 - 67
src/holeg/preferences/ImagePreference.java

@@ -2,71 +2,95 @@ package holeg.preferences;
 
 
 public class ImagePreference {
 public class ImagePreference {
 
 
-	public static class Canvas {
-		public static class Switch {
-			public static final String Open = "/images/canvas/switch_open.png";
-			public static final String Closed = "/images/canvas/switch_closed.png";
-		}
-		public static final String GroupNode = "/images/canvas/group_node.png";
-		public static class Node {
-			public static final String Selected = "/images/canvas/node_selected.png";
-			public static final String Unselected = "/images/canvas/node_unselected.png";
-		}
-		
-		public static class DefaultObject {
-			public static final String House = "/images/canvas/house.png";
-			public static final String PowerPlant = "/images/canvas/power_plant.png";
-		}		
-		public static final String ImageNotFound = "/images/canvas/image_not_found.png";
-		public static final String ReplaceSymbol = "/images/canvas/replace.png";
-		public static final String ExternSymbol = "/images/canvas/extern.png";
-
-	}
-	
-	public static class Button {
-		public static final String Settings = "/images/buttons/settings.png";
-		public static class Console {
-			public static final String Clear = "/images/buttons/clear.png";
-			public static final String Top = "/images/buttons/top.png";
-			public static final String Bottom = "/images/buttons/bottom.png";	
-		}
-		public static class Inspector {
-			public static final String Reset = "/images/buttons/reset_circle.png";				
-			public static final String Graph = "/images/buttons/graph.png";
-			public static final String Add = "images/buttons/plus.png";
-			public static final String Remove = "images/buttons/minus.png";
-			public static final String Duplicate = "images/buttons/duplicate.png";
-
-		}
-		public static class Menu {
-			public static final String Algo = "/images/buttons/algo.png";						
-			public static final String Outliner = "/images/buttons/outliner.png";						
-		}
-		public static class TimePanel {
-			public static final String Play = "/images/buttons/play.png";						
-			public static final String Pause = "/images/buttons/pause.png";						
-			public static final String Reset = "/images/buttons/reset.png";						
-			public static final String Forward = "/images/buttons/forward.png";						
-			public static final String Backward = "/images/buttons/backward.png";						
-		}
-		public static class Outliner {
-			public static final String Open = "/images/buttons/opened.png";
-			public static final String Closed = "/images/buttons/closed.png";						
-			public static final String Leaf = "/images/buttons/leaf.png";						
-		}
-		public static class GroupNode{
-			public static final String Close = "/images/buttons/close_button.png";
-		}
-	}
-	public static class Category {
-		public static final String Folder = "/images/buttons/folder.png";
-		public static final String Add = "/images/buttons/plus.png";
-		public static final String Delete = "/images/buttons/minus.png";
-	}
-	public static class HolonInformationPanel{
-		public static final String Filter = "/images/buttons/down.png";
-		public static final String FilterHovered = "/images/buttons/down_hovered.png";
-		public static final String FilterPressed = "/images/buttons/down_pressed.png";
-	}
-	public static final String Logo = "/images/logo/holeg.png";
+  public static final String Logo = "/images/logo/holeg.png";
+
+  public static class Canvas {
+
+    public static final String GroupNode = "/images/canvas/group_node.png";
+    public static final String ImageNotFound = "/images/canvas/image_not_found.png";
+    public static final String ReplaceSymbol = "/images/canvas/replace.png";
+    public static final String ExternSymbol = "/images/canvas/extern.png";
+
+    public static class Switch {
+
+      public static final String Open = "/images/canvas/switch_open.png";
+      public static final String Closed = "/images/canvas/switch_closed.png";
+    }
+
+    public static class Node {
+
+      public static final String Selected = "/images/canvas/node_selected.png";
+      public static final String Unselected = "/images/canvas/node_unselected.png";
+    }
+
+    public static class DefaultObject {
+
+      public static final String House = "/images/canvas/house.png";
+      public static final String PowerPlant = "/images/canvas/power_plant.png";
+    }
+
+  }
+
+  public static class Button {
+
+    public static final String Settings = "/images/buttons/settings.png";
+
+    public static class Console {
+
+      public static final String Clear = "/images/buttons/clear.png";
+      public static final String Top = "/images/buttons/top.png";
+      public static final String Bottom = "/images/buttons/bottom.png";
+    }
+
+    public static class Inspector {
+
+      public static final String Reset = "/images/buttons/reset_circle.png";
+      public static final String Graph = "/images/buttons/graph.png";
+      public static final String Add = "images/buttons/plus.png";
+      public static final String Remove = "images/buttons/minus.png";
+      public static final String Duplicate = "images/buttons/duplicate.png";
+
+    }
+
+    public static class Menu {
+
+      public static final String Algo = "/images/buttons/algo.png";
+      public static final String Outliner = "/images/buttons/outliner.png";
+    }
+
+    public static class TimePanel {
+
+      public static final String Play = "/images/buttons/play.png";
+      public static final String Pause = "/images/buttons/pause.png";
+      public static final String Reset = "/images/buttons/reset.png";
+      public static final String Forward = "/images/buttons/forward.png";
+      public static final String Backward = "/images/buttons/backward.png";
+    }
+
+    public static class Outliner {
+
+      public static final String Open = "/images/buttons/opened.png";
+      public static final String Closed = "/images/buttons/closed.png";
+      public static final String Leaf = "/images/buttons/leaf.png";
+    }
+
+    public static class GroupNode {
+
+      public static final String Close = "/images/buttons/close_button.png";
+    }
+  }
+
+  public static class Category {
+
+    public static final String Folder = "/images/buttons/folder.png";
+    public static final String Add = "/images/buttons/plus.png";
+    public static final String Delete = "/images/buttons/minus.png";
+  }
+
+  public static class HolonInformationPanel {
+
+    public static final String Filter = "/images/buttons/down.png";
+    public static final String FilterHovered = "/images/buttons/down_hovered.png";
+    public static final String FilterPressed = "/images/buttons/down_pressed.png";
+  }
 }
 }

+ 31 - 23
src/holeg/preferences/PreferenceKeys.java

@@ -1,27 +1,35 @@
 package holeg.preferences;
 package holeg.preferences;
 
 
 public class PreferenceKeys {
 public class PreferenceKeys {
-    public static class Gui{
-        public static final String DefaultFolder = "DefaultFolder";
-        public static final String XPos = "XPos";
-        public static final String YPos = "YPos";
-        public static final String Width = "Width";
-        public static final String Height = "Height";
-    }
-    public static class Appearance {
-        public static final String SupplyBarVisible = "SupplyBarVisible";
-        public static final String EdgeCapacityVisible = "EdgeCapacityVisible";
-        public static final String CanvasObjectEnergyVisible = "CanvasObjectEnergyVisible";
-    }
-    public static class EmailNotification{
-        public static final String Hostname = "Hostname";
-        public static final String Port = "Port";
-        public static final String Username = "Username";
-        public static final String Password = "Password";
-        public static final String FromEmail = "FromEmail";
-        public static final String ToEmail = "ToEmail";
-    }
-    public static class Category{
-        public static final String DefaultCategory = "DefaultCategory";
-    }
+
+  public static class Gui {
+
+    public static final String DefaultFolder = "DefaultFolder";
+    public static final String XPos = "XPos";
+    public static final String YPos = "YPos";
+    public static final String Width = "Width";
+    public static final String Height = "Height";
+  }
+
+  public static class Appearance {
+
+    public static final String SupplyBarVisible = "SupplyBarVisible";
+    public static final String EdgeCapacityVisible = "EdgeCapacityVisible";
+    public static final String CanvasObjectEnergyVisible = "CanvasObjectEnergyVisible";
+  }
+
+  public static class EmailNotification {
+
+    public static final String Hostname = "Hostname";
+    public static final String Port = "Port";
+    public static final String Username = "Username";
+    public static final String Password = "Password";
+    public static final String FromEmail = "FromEmail";
+    public static final String ToEmail = "ToEmail";
+  }
+
+  public static class Category {
+
+    public static final String DefaultCategory = "DefaultCategory";
+  }
 }
 }

+ 52 - 45
src/holeg/serialize/CategoryAdapter.java

@@ -1,63 +1,70 @@
 package holeg.serialize;
 package holeg.serialize;
 
 
-import com.google.gson.*;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
 import com.google.gson.reflect.TypeToken;
 import com.google.gson.reflect.TypeToken;
-import com.google.gson.stream.JsonReader;
-import com.google.gson.stream.JsonToken;
-import com.google.gson.stream.JsonWriter;
 import holeg.model.AbstractCanvasObject;
 import holeg.model.AbstractCanvasObject;
-import holeg.model.Edge;
 import holeg.model.HolonObject;
 import holeg.model.HolonObject;
 import holeg.model.HolonSwitch;
 import holeg.model.HolonSwitch;
 import holeg.ui.view.category.Category;
 import holeg.ui.view.category.Category;
-
-import java.io.IOException;
 import java.lang.reflect.Type;
 import java.lang.reflect.Type;
-import java.util.Collection;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
 import java.util.Set;
 import java.util.Set;
-import java.util.logging.Logger;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
 public class CategoryAdapter implements JsonSerializer<Category>, JsonDeserializer<Category> {
 public class CategoryAdapter implements JsonSerializer<Category>, JsonDeserializer<Category> {
-    public static final Gson Gson = initGson();
-    public static final Type CategorySet = new TypeToken<Set<Category>>(){}.getType();
-    private static final Type HolonObjectList = new TypeToken<List<HolonObject>>(){}.getType();
-    private static final Type HolonSwitchList = new TypeToken<List<HolonSwitch>>(){}.getType();
-
-
-    private static Gson initGson() {
-        GsonBuilder gson = new GsonBuilder();
-        gson.registerTypeAdapter(Category.class, new CategoryAdapter());
-        gson.registerTypeAdapterFactory(new PostDeserializeEnabler());
-        gson.serializeNulls();
-        return gson.create();
-    }
 
 
-    @Override
-    public JsonElement serialize(Category src, Type typeOfSrc, JsonSerializationContext context) {
-        JsonObject object = new JsonObject();
-        object.addProperty("name", src.getName());
-
-        Map<Class<?>, List<AbstractCanvasObject>> map =
-                src.getObjects().stream()
-                        .collect(Collectors.groupingBy(Object::getClass));
-        object.add("objects", context.serialize(map.get(HolonObject.class), HolonObjectList));
-        object.add("switches", context.serialize(map.get(HolonSwitch.class), HolonSwitchList));
-        return object;
-    }
+  public static final Gson Gson = initGson();
+  public static final Type CategorySet = new TypeToken<Set<Category>>() {
+  }.getType();
+  private static final Type HolonObjectList = new TypeToken<List<HolonObject>>() {
+  }.getType();
+  private static final Type HolonSwitchList = new TypeToken<List<HolonSwitch>>() {
+  }.getType();
+
 
 
-    @Override
-    public Category deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
-        JsonObject object = json.getAsJsonObject();
-        Category cat = new Category(object.get("name").getAsString());
-        if(object.has("objects") && !object.get("objects").isJsonNull()){
-            cat.getObjects().addAll(context.deserialize(object.getAsJsonArray("objects"), HolonObjectList));
-        }
-        if(object.has("switches") && !object.get("switches").isJsonNull()){
-            cat.getObjects().addAll(context.deserialize(object.getAsJsonArray("switches"), HolonSwitchList));
-        }
-        return cat;
+  private static Gson initGson() {
+    GsonBuilder gson = new GsonBuilder();
+    gson.registerTypeAdapter(Category.class, new CategoryAdapter());
+    gson.registerTypeAdapterFactory(new PostDeserializeEnabler());
+    gson.serializeNulls();
+    return gson.create();
+  }
+
+  @Override
+  public JsonElement serialize(Category src, Type typeOfSrc, JsonSerializationContext context) {
+    JsonObject object = new JsonObject();
+    object.addProperty("name", src.getName());
+
+    Map<Class<?>, List<AbstractCanvasObject>> map =
+        src.getObjects().stream()
+            .collect(Collectors.groupingBy(Object::getClass));
+    object.add("objects", context.serialize(map.get(HolonObject.class), HolonObjectList));
+    object.add("switches", context.serialize(map.get(HolonSwitch.class), HolonSwitchList));
+    return object;
+  }
+
+  @Override
+  public Category deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
+      throws JsonParseException {
+    JsonObject object = json.getAsJsonObject();
+    Category cat = new Category(object.get("name").getAsString());
+    if (object.has("objects") && !object.get("objects").isJsonNull()) {
+      cat.getObjects()
+          .addAll(context.deserialize(object.getAsJsonArray("objects"), HolonObjectList));
+    }
+    if (object.has("switches") && !object.get("switches").isJsonNull()) {
+      cat.getObjects()
+          .addAll(context.deserialize(object.getAsJsonArray("switches"), HolonSwitchList));
     }
     }
+    return cat;
+  }
 }
 }

+ 22 - 18
src/holeg/serialize/EdgeDeserializer.java

@@ -1,33 +1,37 @@
 package holeg.serialize;
 package holeg.serialize;
 
 
-import com.google.gson.*;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
 import holeg.model.AbstractCanvasObject;
 import holeg.model.AbstractCanvasObject;
 import holeg.model.Edge;
 import holeg.model.Edge;
-
 import java.lang.reflect.Type;
 import java.lang.reflect.Type;
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map;
 
 
 public class EdgeDeserializer implements JsonDeserializer<Edge> {
 public class EdgeDeserializer implements JsonDeserializer<Edge> {
-    public Map<Integer, AbstractCanvasObject> idMap= new HashMap<>();
 
 
+  public Map<Integer, AbstractCanvasObject> idMap = new HashMap<>();
 
 
 
 
-    @Override
-    public Edge deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
-        JsonObject jsonObj = json.getAsJsonObject();
-        Edge edge = new Edge(idToCanvasObject(jsonObj.get("idA").getAsInt()),
-                idToCanvasObject(jsonObj.get("idB").getAsInt()),
-                jsonObj.get("maxCapacity").getAsFloat());
-        edge.mode = Edge.EdgeMode.valueOf(jsonObj.get("mode").getAsString());
-        return edge;
-    }
+  @Override
+  public Edge deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
+      throws JsonParseException {
+    JsonObject jsonObj = json.getAsJsonObject();
+    Edge edge = new Edge(idToCanvasObject(jsonObj.get("idA").getAsInt()),
+        idToCanvasObject(jsonObj.get("idB").getAsInt()),
+        jsonObj.get("maxCapacity").getAsFloat());
+    edge.mode = Edge.EdgeMode.valueOf(jsonObj.get("mode").getAsString());
+    return edge;
+  }
 
 
-    private AbstractCanvasObject idToCanvasObject(int id) throws JsonParseException{
-        AbstractCanvasObject object = idMap.get(id);
-        if(object == null){
-            throw new JsonParseException("Cannot find AbstractCanvasObject with id: " + id);
-        }
-        return object;
+  private AbstractCanvasObject idToCanvasObject(int id) throws JsonParseException {
+    AbstractCanvasObject object = idMap.get(id);
+    if (object == null) {
+      throw new JsonParseException("Cannot find AbstractCanvasObject with id: " + id);
     }
     }
+    return object;
+  }
 }
 }

+ 9 - 10
src/holeg/serialize/EdgeSerializer.java

@@ -5,18 +5,17 @@ import com.google.gson.JsonObject;
 import com.google.gson.JsonSerializationContext;
 import com.google.gson.JsonSerializationContext;
 import com.google.gson.JsonSerializer;
 import com.google.gson.JsonSerializer;
 import holeg.model.Edge;
 import holeg.model.Edge;
-
 import java.lang.reflect.Type;
 import java.lang.reflect.Type;
 
 
 public class EdgeSerializer implements JsonSerializer<Edge> {
 public class EdgeSerializer implements JsonSerializer<Edge> {
 
 
-    @Override
-    public JsonElement serialize(Edge edge, Type typeOfSrc, JsonSerializationContext context) {
-        JsonObject jsonObj = new JsonObject();
-        jsonObj.addProperty("idA", edge.getA().getId());
-        jsonObj.addProperty("idB", edge.getB().getId());
-        jsonObj.addProperty("maxCapacity", edge.maxCapacity);
-        jsonObj.addProperty("mode", edge.mode.toString());
-        return jsonObj;
-    }
+  @Override
+  public JsonElement serialize(Edge edge, Type typeOfSrc, JsonSerializationContext context) {
+    JsonObject jsonObj = new JsonObject();
+    jsonObj.addProperty("idA", edge.getA().getId());
+    jsonObj.addProperty("idB", edge.getB().getId());
+    jsonObj.addProperty("maxCapacity", edge.maxCapacity);
+    jsonObj.addProperty("mode", edge.mode.toString());
+    return jsonObj;
+  }
 }
 }

+ 52 - 39
src/holeg/serialize/ModelDeserializer.java

@@ -1,50 +1,63 @@
 package holeg.serialize;
 package holeg.serialize;
 
 
-import com.google.gson.*;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
 import com.google.gson.reflect.TypeToken;
 import com.google.gson.reflect.TypeToken;
-import holeg.model.*;
+import holeg.model.AbstractCanvasObject;
+import holeg.model.Edge;
+import holeg.model.GroupNode;
+import holeg.model.Model;
 import holeg.ui.model.IdCounter;
 import holeg.ui.model.IdCounter;
-
 import java.lang.reflect.Type;
 import java.lang.reflect.Type;
 import java.util.HashSet;
 import java.util.HashSet;
 import java.util.function.Function;
 import java.util.function.Function;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
-public class ModelDeserializer implements JsonDeserializer<Model>{
-    public static final Gson gson = initGson();
-    private static final Logger log = Logger.getLogger(ModelDeserializer.class.getName());
-    private final static Type edgeSetType = TypeToken.getParameterized(HashSet.class, Edge.class).getType();
-    private final EdgeDeserializer edgeDeserializer = new EdgeDeserializer();
-    private final Gson edgeGson = new GsonBuilder().registerTypeAdapter(Edge.class, edgeDeserializer).create();
-    private static Gson initGson() {
-        GsonBuilder builder = new GsonBuilder();
-        builder.registerTypeAdapter(Edge.class, new EdgeSerializer());
-        builder.registerTypeAdapter(Model.class, new ModelDeserializer());
-        builder.registerTypeAdapterFactory(new PostDeserializeEnabler());
-
-        builder.serializeNulls();
-        builder.setPrettyPrinting();
-        return builder.create();
-    }
-
-    @Override
-    public Model deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
-        JsonObject jsonObj = json.getAsJsonObject();
-
-        Model model = new Model();
-        GroupNode canvas = context.deserialize(jsonObj.getAsJsonObject("canvas"), GroupNode.class);
-        model.setCanvas(canvas);
-        edgeDeserializer.idMap = canvas.getAllObjectsRecursive()
-                .collect(Collectors.toMap(AbstractCanvasObject::getId, Function.identity()));
-        model.setEdgesOnCanvas(edgeGson.fromJson(jsonObj.getAsJsonArray("edgesOnCanvas"), edgeSetType));
-
-        updateIdCounter(model.getCanvas());
-        return model;
-    }
-
-    private void updateIdCounter(GroupNode canvas){
-        canvas.getAllObjectsRecursive().mapToInt(AbstractCanvasObject::getId).max()
-                .ifPresent(maxId -> IdCounter.set(maxId + 1));
-    }
+public class ModelDeserializer implements JsonDeserializer<Model> {
+
+  public static final Gson gson = initGson();
+  private static final Logger log = Logger.getLogger(ModelDeserializer.class.getName());
+  private final static Type edgeSetType = TypeToken.getParameterized(HashSet.class, Edge.class)
+      .getType();
+  private final EdgeDeserializer edgeDeserializer = new EdgeDeserializer();
+  private final Gson edgeGson = new GsonBuilder().registerTypeAdapter(Edge.class, edgeDeserializer)
+      .create();
+
+  private static Gson initGson() {
+    GsonBuilder builder = new GsonBuilder();
+    builder.registerTypeAdapter(Edge.class, new EdgeSerializer());
+    builder.registerTypeAdapter(Model.class, new ModelDeserializer());
+    builder.registerTypeAdapterFactory(new PostDeserializeEnabler());
+
+    builder.serializeNulls();
+    builder.setPrettyPrinting();
+    return builder.create();
+  }
+
+  @Override
+  public Model deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
+      throws JsonParseException {
+    JsonObject jsonObj = json.getAsJsonObject();
+
+    Model model = new Model();
+    GroupNode canvas = context.deserialize(jsonObj.getAsJsonObject("canvas"), GroupNode.class);
+    model.setCanvas(canvas);
+    edgeDeserializer.idMap = canvas.getAllObjectsRecursive()
+        .collect(Collectors.toMap(AbstractCanvasObject::getId, Function.identity()));
+    model.setEdgesOnCanvas(edgeGson.fromJson(jsonObj.getAsJsonArray("edgesOnCanvas"), edgeSetType));
+
+    updateIdCounter(model.getCanvas());
+    return model;
+  }
+
+  private void updateIdCounter(GroupNode canvas) {
+    canvas.getAllObjectsRecursive().mapToInt(AbstractCanvasObject::getId).max()
+        .ifPresent(maxId -> IdCounter.set(maxId + 1));
+  }
 }
 }

+ 2 - 1
src/holeg/serialize/PostDeserialize.java

@@ -1,5 +1,6 @@
 package holeg.serialize;
 package holeg.serialize;
 
 
 public interface PostDeserialize {
 public interface PostDeserialize {
-    void postDeserialize();
+
+  void postDeserialize();
 }
 }

+ 17 - 17
src/holeg/serialize/PostDeserializeEnabler.java

@@ -6,26 +6,26 @@ import com.google.gson.TypeAdapterFactory;
 import com.google.gson.reflect.TypeToken;
 import com.google.gson.reflect.TypeToken;
 import com.google.gson.stream.JsonReader;
 import com.google.gson.stream.JsonReader;
 import com.google.gson.stream.JsonWriter;
 import com.google.gson.stream.JsonWriter;
-
 import java.io.IOException;
 import java.io.IOException;
 
 
 public class PostDeserializeEnabler implements TypeAdapterFactory {
 public class PostDeserializeEnabler implements TypeAdapterFactory {
-    @Override
-    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
-        final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
 
 
-        return new TypeAdapter<T>() {
-            public void write(JsonWriter out, T value) throws IOException {
-                delegate.write(out, value);
-            }
+  @Override
+  public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
+    final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
+
+    return new TypeAdapter<T>() {
+      public void write(JsonWriter out, T value) throws IOException {
+        delegate.write(out, value);
+      }
 
 
-            public T read(JsonReader in) throws IOException {
-                T obj = delegate.read(in);
-                if (obj instanceof PostDeserialize post) {
-                    post.postDeserialize();
-                }
-                return obj;
-            }
-        };
-    }
+      public T read(JsonReader in) throws IOException {
+        T obj = delegate.read(in);
+        if (obj instanceof PostDeserialize post) {
+          post.postDeserialize();
+        }
+        return obj;
+      }
+    };
+  }
 }
 }

+ 128 - 126
src/holeg/ui/controller/CanvasController.java

@@ -1,13 +1,11 @@
 package holeg.ui.controller;
 package holeg.ui.controller;
 
 
-import holeg.model.*;
+import holeg.model.AbstractCanvasObject;
+import holeg.model.Edge;
+import holeg.model.GroupNode;
 import holeg.ui.model.GuiSettings;
 import holeg.ui.model.GuiSettings;
-import holeg.model.Model;
-import holeg.utility.math.vector.Vec2f;
 import holeg.utility.math.vector.Vec2i;
 import holeg.utility.math.vector.Vec2i;
-
 import java.util.Collection;
 import java.util.Collection;
-import java.util.HashSet;
 import java.util.Set;
 import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
@@ -18,131 +16,135 @@ import java.util.stream.Collectors;
  */
  */
 public class CanvasController {
 public class CanvasController {
 
 
-    private final Control control;
-
-    /**
-     * Constructor.
-     *
-     * @param control the Controller
-     *
-     */
-    public CanvasController(Control control) {
-        this.control = control;
-    }
-
-    /**
-     * Add an CpsObject to the model and notify the ObjectListener for update.
-     *
-     * @param object CpsObject to be added.
-     */
-    public void addObject(GroupNode groupNode, AbstractCanvasObject object) {
-        groupNode.add(object);
+  private final Control control;
+
+  /**
+   * Constructor.
+   *
+   * @param control the Controller
+   */
+  public CanvasController(Control control) {
+    this.control = control;
+  }
+
+  /**
+   * Add an CpsObject to the model and notify the ObjectListener for update.
+   *
+   * @param object CpsObject to be added.
+   */
+  public void addObject(GroupNode groupNode, AbstractCanvasObject object) {
+    groupNode.add(object);
+  }
+
+
+  /**
+   * Deletes an CpsObject on the Canvas and its connections.
+   *
+   * @param obj AbstractCpsObject
+   */
+  public void deleteObject(AbstractCanvasObject obj) {
+    if (obj instanceof GroupNode groupNode) {
+      deleteAllObjectsInGroupNode(groupNode);
+      control.OnRemoveGroupNode.broadcast(groupNode);
+    } else {
+      removeAllConnectionsFromObject(obj);
     }
     }
-
-
-    /**
-     * Deletes an CpsObject on the Canvas and its connections.
-     *
-     * @param obj AbstractCpsObject
-     */
-    public void deleteObject(AbstractCanvasObject obj) {
-        if(obj instanceof GroupNode groupNode) {
-            deleteAllObjectsInGroupNode(groupNode);
-            control.OnRemoveGroupNode.broadcast(groupNode);
-        }else{
-            removeAllConnectionsFromObject(obj);
+    obj.getGroupNode().ifPresent(groupNode -> groupNode.remove(obj));
+  }
+
+  public void deleteObjects(Collection<AbstractCanvasObject> objects) {
+    objects.forEach(this::deleteObject);
+  }
+
+  /**
+   * Replaces {@code toBeReplaced} by {@code by} on the canvas
+   *
+   * @param toBeReplaced the object that will be replaced
+   * @param by           the object that will replace it
+   */
+  public void replaceObject(AbstractCanvasObject toBeReplaced, AbstractCanvasObject by) {
+    //Replace edges
+    for (Edge edge : control.getModel().getEdgesOnCanvas()) {
+      if (edge.getA() == toBeReplaced && edge.getB() != by) {
+        if (control.doesEdgeExist(new Edge(by, edge.getB(), 0))) {
+          continue;
         }
         }
-        obj.getGroupNode().ifPresent(groupNode -> groupNode.remove(obj));
-    }
-
-    public void deleteObjects(Collection<AbstractCanvasObject> objects) {
-		objects.forEach(this::deleteObject);
-	}
-
-    /**
-     * Replaces {@code toBeReplaced} by {@code by} on the canvas
-     *
-     * @param toBeReplaced the object that will be replaced
-     * @param by           the object that will replace it
-     */
-    public void replaceObject(AbstractCanvasObject toBeReplaced, AbstractCanvasObject by) {
-        //Replace edges
-        for (Edge edge : control.getModel().getEdgesOnCanvas()) {
-            if (edge.getA() == toBeReplaced && edge.getB() != by) {
-                if(control.doesEdgeExist(new Edge(by, edge.getB(), 0))){
-                    continue;
-                }
-                edge.setA(by);
-            } else if (edge.getB() == toBeReplaced && edge.getA() != by) {
-                if(control.doesEdgeExist(new Edge(edge.getA(), by, 0))){
-                    continue;
-                }
-                edge.setB(by);
-            }
+        edge.setA(by);
+      } else if (edge.getB() == toBeReplaced && edge.getA() != by) {
+        if (control.doesEdgeExist(new Edge(edge.getA(), by, 0))) {
+          continue;
         }
         }
-        // set Position of by to exactly toBeReplaced
-        by.setPosition(toBeReplaced.getPosition());
-        deleteObject(toBeReplaced);
-    }
-
-    /**
-     * Add an edge to the Canvas.
-     *
-     * @param edge the edge
-     */
-    public void addEdgeOnCanvas(Edge edge) {
-        control.getModel().getEdgesOnCanvas().add(edge);
-    }
-
-    /**
-     * Removes an Edge from the Canvas.
-     *
-     * @param edge the edge to remove
-     */
-    public void removeEdgesOnCanvas(Edge edge) {
-        control.getModel().getEdgesOnCanvas().remove(edge);
+        edge.setB(by);
+      }
     }
     }
-
-
-
-    /**
-     * Some cleaning Algorithm which traverses the UpperNode through BFS Can be
-     * extended with other cleaning stuff No need for coloring since there tree
-     * is only directed in one direction
-     */
-    public void deleteAllObjectsInGroupNode(GroupNode node) {
-        Set<AbstractCanvasObject> objectsInGroupNode = node.getAllObjectsRecursive().collect(Collectors.toSet());
-        control.getModel().getEdgesOnCanvas().removeIf(edge -> objectsInGroupNode.contains(edge.getA()) || objectsInGroupNode.contains(edge.getB()));
-    }
-
-    public void removeAllConnectionsFromObject(AbstractCanvasObject obj) {
-        control.getModel().getEdgesOnCanvas().removeIf(edge -> edge.getA() == obj || edge.getB() == obj);
-    }
-
-    public void group(Set<AbstractCanvasObject> objects) {
-        if(objects.isEmpty()){
-            return;
-        }
-        final GroupNode groupNode = new GroupNode("GroupNode");
-        groupNode.setPosition(GroupNode.calculateMiddlePosition(objects));
-        objects.stream().findFirst().flatMap(AbstractCanvasObject::getGroupNode)
-                .ifPresent(parentGroupNode -> parentGroupNode.add(groupNode));
-        objects.forEach(object -> object.getGroupNode().ifPresent(old -> old.remove(object)));
-        groupNode.addAll(objects);
-
+    // set Position of by to exactly toBeReplaced
+    by.setPosition(toBeReplaced.getPosition());
+    deleteObject(toBeReplaced);
+  }
+
+  /**
+   * Add an edge to the Canvas.
+   *
+   * @param edge the edge
+   */
+  public void addEdgeOnCanvas(Edge edge) {
+    control.getModel().getEdgesOnCanvas().add(edge);
+  }
+
+  /**
+   * Removes an Edge from the Canvas.
+   *
+   * @param edge the edge to remove
+   */
+  public void removeEdgesOnCanvas(Edge edge) {
+    control.getModel().getEdgesOnCanvas().remove(edge);
+  }
+
+
+  /**
+   * Some cleaning Algorithm which traverses the UpperNode through BFS Can be extended with other
+   * cleaning stuff No need for coloring since there tree is only directed in one direction
+   */
+  public void deleteAllObjectsInGroupNode(GroupNode node) {
+    Set<AbstractCanvasObject> objectsInGroupNode = node.getAllObjectsRecursive()
+        .collect(Collectors.toSet());
+    control.getModel().getEdgesOnCanvas().removeIf(
+        edge -> objectsInGroupNode.contains(edge.getA()) || objectsInGroupNode.contains(
+            edge.getB()));
+  }
+
+  public void removeAllConnectionsFromObject(AbstractCanvasObject obj) {
+    control.getModel().getEdgesOnCanvas()
+        .removeIf(edge -> edge.getA() == obj || edge.getB() == obj);
+  }
+
+  public void group(Set<AbstractCanvasObject> objects) {
+    if (objects.isEmpty()) {
+      return;
     }
     }
-
-
-    public void ungroup(Set<AbstractCanvasObject> objects) {
-        for(AbstractCanvasObject obj : objects){
-            if(obj instanceof GroupNode groupNode){
-                Vec2i middle = GroupNode.calculateMiddlePosition(groupNode.getObjectsInThisLayer().collect(Collectors.toList()));
-                groupNode.getObjectsInThisLayer().forEach(child -> {child.setPosition(groupNode.getPosition().subtract(middle).add(child.getPosition()));
-                    child.getPosition().clampX(0, GuiSettings.canvasSize.getX());
-                    child.getPosition().clampY(0, GuiSettings.canvasSize.getY());});
-                groupNode.ungroup();
-                control.OnRemoveGroupNode.broadcast(groupNode);
-            }
-        }
+    final GroupNode groupNode = new GroupNode("GroupNode");
+    groupNode.setPosition(GroupNode.calculateMiddlePosition(objects));
+    objects.stream().findFirst().flatMap(AbstractCanvasObject::getGroupNode)
+        .ifPresent(parentGroupNode -> parentGroupNode.add(groupNode));
+    objects.forEach(object -> object.getGroupNode().ifPresent(old -> old.remove(object)));
+    groupNode.addAll(objects);
+
+  }
+
+
+  public void ungroup(Set<AbstractCanvasObject> objects) {
+    for (AbstractCanvasObject obj : objects) {
+      if (obj instanceof GroupNode groupNode) {
+        Vec2i middle = GroupNode.calculateMiddlePosition(
+            groupNode.getObjectsInThisLayer().collect(Collectors.toList()));
+        groupNode.getObjectsInThisLayer().forEach(child -> {
+          child.setPosition(groupNode.getPosition().subtract(middle).add(child.getPosition()));
+          child.getPosition().clampX(0, GuiSettings.canvasSize.getX());
+          child.getPosition().clampY(0, GuiSettings.canvasSize.getY());
+        });
+        groupNode.ungroup();
+        control.OnRemoveGroupNode.broadcast(groupNode);
+      }
     }
     }
+  }
 }
 }

+ 473 - 452
src/holeg/ui/controller/Control.java

@@ -1,6 +1,14 @@
 package holeg.ui.controller;
 package holeg.ui.controller;
 
 
-import holeg.model.*;
+import static holeg.serialize.ModelDeserializer.gson;
+
+import holeg.model.AbstractCanvasObject;
+import holeg.model.Edge;
+import holeg.model.GroupNode;
+import holeg.model.HolonElement;
+import holeg.model.HolonObject;
+import holeg.model.HolonSwitch;
+import holeg.model.Model;
 import holeg.preferences.ImagePreference;
 import holeg.preferences.ImagePreference;
 import holeg.preferences.PreferenceKeys;
 import holeg.preferences.PreferenceKeys;
 import holeg.serialize.CategoryAdapter;
 import holeg.serialize.CategoryAdapter;
@@ -11,474 +19,487 @@ import holeg.ui.view.category.Category;
 import holeg.utility.events.Action;
 import holeg.utility.events.Action;
 import holeg.utility.events.Event;
 import holeg.utility.events.Event;
 import holeg.utility.math.vector.Vec2i;
 import holeg.utility.math.vector.Vec2i;
-
 import java.io.File;
 import java.io.File;
 import java.io.FileReader;
 import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.IOException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
 import java.util.prefs.Preferences;
 import java.util.prefs.Preferences;
 
 
-import static holeg.serialize.ModelDeserializer.gson;
-
 
 
 /**
 /**
  * The Class represents the controller.
  * The Class represents the controller.
  */
  */
 public class Control {
 public class Control {
-    private static final Logger log = Logger.getLogger(Control.class.getName());
-    private static final Preferences prefs = Preferences.userNodeForPackage(Control.class);
-    private final CanvasController canvasController;
-    private final SimulationManager simulationManager;
-    public Event OnCategoryChanged = new Event();
-    public Event OnSelectionChanged = new Event();
-    public Event OnCanvasUpdate = new Event();
-    public Action<Boolean> OnGuiSetEnabled = new Action<>();
-    public Action<GroupNode> OnShowGroupNode = new Action<>();
-    public Action<GroupNode> OnRemoveGroupNode = new Action<>();
-    public Event OnModelChanged = new Event();
-    private Model model;
-
-    public Control(Model model) {
-        this.model = model;
-        this.canvasController = new CanvasController(this);
-        this.simulationManager = new SimulationManager(this);
-        OnCanvasUpdate.addListener(() -> UndoHistory.addSave(saveModelToJsonString()));
-        UndoHistory.addSave(saveModelToJsonString());
-    }
-
-
-
-
-
-
-    /* Operations for Categories and Objects */
-
-    /**
-     * init default category and objects.
-     */
-    public void resetCategories() {
-        GuiSettings.getCategories().clear();
-        initCategories();
-        saveCategories();
-    }
-
-    /**
-     * Add new Holon Object to a Category.
-     */
-    public void addObject(Category cat, String obj, List<HolonElement> list, String img) {
-        addNewHolonObject(cat, obj, list, img);
-        OnCategoryChanged.broadcast();
-        saveCategories();
-    }
-
-
-    public void deleteCategory(Category category) {
-        GuiSettings.getCategories().remove(category);
-        OnCategoryChanged.broadcast();
-        saveCategories();
-    }
-
-    /**
-     * removes a selectedObject from selection.
-     */
-    public void removeObjectsFromSelection(Collection<AbstractCanvasObject> objects) {
-        if (GuiSettings.getSelectedObjects().removeAll(objects)) {
-            OnSelectionChanged.broadcast();
-        }
-    }
-
-    /**
-     * removes a selectedObject from selection.
-     *
-     * @param obj
-     */
-    public void removeObjectFromSelection(AbstractCanvasObject obj) {
-        if (GuiSettings.getSelectedObjects().remove(obj)) {
-            OnSelectionChanged.broadcast();
-        }
-    }
-
-    public void addObjectToSelection(AbstractCanvasObject obj) {
-        if (GuiSettings.getSelectedObjects().add(obj)) {
-            OnSelectionChanged.broadcast();
-        }
-    }
-
-    public void addObjectsToSelection(Collection<AbstractCanvasObject> objects) {
-        if (GuiSettings.getSelectedObjects().addAll(objects)) {
-            OnSelectionChanged.broadcast();
-        }
-
-    }
-
-
-    public void setSelection(Collection<AbstractCanvasObject> objects) {
-        GuiSettings.getSelectedObjects().clear();
-        addObjectsToSelection(objects);
-    }
-
-    public void clearSelection() {
-        if (!GuiSettings.getSelectedObjects().isEmpty()) {
-            GuiSettings.getSelectedObjects().clear();
-            OnSelectionChanged.broadcast();
-        }
-    }
-
-    public void addObjectOnCanvas(GroupNode node, AbstractCanvasObject object) {
-        canvasController.addObject(node, object);
-        updateStateForIteration(model.getCurrentIteration());
-    }
-
-
-    /**
-     * Deletes an CpsObject on the Canvas and its connections.
-     *
-     * @param obj AbstractCpsObject
-     */
-    public void deleteObject(AbstractCanvasObject obj) {
-        canvasController.deleteObject(obj);
-        if (obj instanceof GroupNode groupnode) {
-            canvasController.deleteAllObjectsInGroupNode(groupnode);
-        }
-        calculateStateForCurrentIteration();
-        OnCanvasUpdate.broadcast();
-    }
-
-    public void deleteCanvasObjects(Collection<AbstractCanvasObject> objects) {
-        canvasController.deleteObjects(objects);
-        calculateStateForCurrentIteration();
-        OnCanvasUpdate.broadcast();
-    }
-
-    /**
-     * Replaces {@code toBeReplaced} by {@code by} on the canvas
-     *
-     * @param toBeReplaced the object that will be replaced
-     * @param by           the object that will replace it
-     */
-    public void replaceCanvasObject(AbstractCanvasObject toBeReplaced, AbstractCanvasObject by) {
-        canvasController.replaceObject(toBeReplaced, by);
-        OnCanvasUpdate.broadcast();
-    }
-
-    /**
-     * Add an edge to the Canvas.
-     *
-     * @param edge the edge
-     */
-    public boolean addEdgeOnCanvas(Edge edge) {
-        if (doesEdgeExist(edge)) {
-            return false;
-        }
-        canvasController.addEdgeOnCanvas(edge);
-        OnCanvasUpdate.broadcast();
-        return true;
-    }
-
-    public boolean doesEdgeExist(Edge edge){
-        boolean connectsToSelf = edge.getA() == edge.getB();
-        return !connectsToSelf && model.getEdgesOnCanvas().stream().anyMatch(e -> (e.getA() == edge.getA() && e.getB() == edge.getB())
-                || (e.getB() == edge.getA() && e.getA() == edge.getB()));
-    }
-
-
-    /**
-     * Add an edge to the Canvas.
-     *
-     * @param edge the edge
-     */
-    public void addEdgeOnCanvasOrRemoveExisting(Edge edge) {
-        boolean connectsToSelf = edge.getA() == edge.getB();
-        if(connectsToSelf){
-            return;
-        }
-        Optional<Edge> edgeToRemove = model.getEdgesOnCanvas().stream().filter(e -> (e.getA() == edge.getA() && e.getB() == edge.getB())
-                || (e.getB() == edge.getA() && e.getA() == edge.getB())).findAny();
-        edgeToRemove.ifPresentOrElse(canvasController::removeEdgesOnCanvas, () -> canvasController.addEdgeOnCanvas(edge));
-        updateStateForCurrentIteration();
-    }
-
-
-
-    public void calculateStateForCurrentIteration() {
-        simulationManager.calculateStateForIteration(model.getCurrentIteration());
-    }
-    public void updateStateForCurrentIteration() {
-        simulationManager.calculateStateForIteration(model.getCurrentIteration());
-        OnCanvasUpdate.broadcast();
-    }
-
-    /**
-     * calculates the flow of the edges and the supply for objects.
-     *
-     * @param x current Iteration
-     */
-    public void updateStateForIteration(int x) {
-        simulationManager.calculateStateForIteration(x);
-        OnCanvasUpdate.broadcast();
-    }
-
-    /**
-     * resets the whole State of the simulation including a reset of all Edges to
-     * the default "is working" state
-     */
-    public void resetSimulation() {
-        model.reset();
-    }
-
+
+  private static final Logger log = Logger.getLogger(Control.class.getName());
+  private static final Preferences prefs = Preferences.userNodeForPackage(Control.class);
+  private final CanvasController canvasController;
+  private final SimulationManager simulationManager;
+  public Event OnCategoryChanged = new Event();
+  public Event OnSelectionChanged = new Event();
+  public Event OnCanvasUpdate = new Event();
+  public Action<Boolean> OnGuiSetEnabled = new Action<>();
+  public Action<GroupNode> OnShowGroupNode = new Action<>();
+  public Action<GroupNode> OnRemoveGroupNode = new Action<>();
+  public Event OnModelChanged = new Event();
+  private Model model;
+
+  public Control(Model model) {
+    this.model = model;
+    this.canvasController = new CanvasController(this);
+    this.simulationManager = new SimulationManager(this);
+    OnCanvasUpdate.addListener(() -> UndoHistory.addSave(saveModelToJsonString()));
+    UndoHistory.addSave(saveModelToJsonString());
+  }
 
 
 
 
-    /**
-     * Getter for Model.
-     *
-     * @return the Model
-     */
-    public Model getModel() {
-        return model;
-    }
 
 
 
 
-    /**
-     * Copy all Selected Objects.
-     */
-    public void copy() {
-        GuiSettings.getClipboardObjects().clear();
-        GuiSettings.getClipboardObjects().addAll(GuiSettings.getSelectedObjects());
-        GuiSettings.getClipboardEdges().clear();
-        GuiSettings.getClipboardEdges().addAll(getEdgesBetweenObjects(GuiSettings.getSelectedObjects()));
-    }
 
 
-    private List<Edge> getEdgesBetweenObjects(Collection<AbstractCanvasObject> selectedObjects) {
-        return model.getEdgesOnCanvas().stream()
-                .filter(edge -> selectedObjects.containsAll(Arrays.asList(edge.getA(), edge.getB()))).toList();
-    }
 
 
-    public void paste(GroupNode groupNode, Vec2i offset) {
-        if (GuiSettings.getClipboardObjects().isEmpty()) {
-            return;
-        }
-        HashMap<AbstractCanvasObject, AbstractCanvasObject> oldToNew = new HashMap<>();
-        Collection<AbstractCanvasObject> copies = GuiSettings.getClipboardObjects().stream().map(obj -> {
-            AbstractCanvasObject copy = obj.copy();
-            oldToNew.put(obj, copy);
-            return copy;
+  /* Operations for Categories and Objects */
+
+  /**
+   * init default category and objects.
+   */
+  public void resetCategories() {
+    GuiSettings.getCategories().clear();
+    initCategories();
+    saveCategories();
+  }
+
+  /**
+   * Add new Holon Object to a Category.
+   */
+  public void addObject(Category cat, String obj, List<HolonElement> list, String img) {
+    addNewHolonObject(cat, obj, list, img);
+    OnCategoryChanged.broadcast();
+    saveCategories();
+  }
+
+
+  public void deleteCategory(Category category) {
+    GuiSettings.getCategories().remove(category);
+    OnCategoryChanged.broadcast();
+    saveCategories();
+  }
+
+  /**
+   * removes a selectedObject from selection.
+   */
+  public void removeObjectsFromSelection(Collection<AbstractCanvasObject> objects) {
+    if (GuiSettings.getSelectedObjects().removeAll(objects)) {
+      OnSelectionChanged.broadcast();
+    }
+  }
+
+  /**
+   * removes a selectedObject from selection.
+   *
+   * @param obj
+   */
+  public void removeObjectFromSelection(AbstractCanvasObject obj) {
+    if (GuiSettings.getSelectedObjects().remove(obj)) {
+      OnSelectionChanged.broadcast();
+    }
+  }
+
+  public void addObjectToSelection(AbstractCanvasObject obj) {
+    if (GuiSettings.getSelectedObjects().add(obj)) {
+      OnSelectionChanged.broadcast();
+    }
+  }
+
+  public void addObjectsToSelection(Collection<AbstractCanvasObject> objects) {
+    if (GuiSettings.getSelectedObjects().addAll(objects)) {
+      OnSelectionChanged.broadcast();
+    }
+
+  }
+
+
+  public void setSelection(Collection<AbstractCanvasObject> objects) {
+    GuiSettings.getSelectedObjects().clear();
+    addObjectsToSelection(objects);
+  }
+
+  public void clearSelection() {
+    if (!GuiSettings.getSelectedObjects().isEmpty()) {
+      GuiSettings.getSelectedObjects().clear();
+      OnSelectionChanged.broadcast();
+    }
+  }
+
+  public void addObjectOnCanvas(GroupNode node, AbstractCanvasObject object) {
+    canvasController.addObject(node, object);
+    updateStateForIteration(model.getCurrentIteration());
+  }
+
+
+  /**
+   * Deletes an CpsObject on the Canvas and its connections.
+   *
+   * @param obj AbstractCpsObject
+   */
+  public void deleteObject(AbstractCanvasObject obj) {
+    canvasController.deleteObject(obj);
+    if (obj instanceof GroupNode groupnode) {
+      canvasController.deleteAllObjectsInGroupNode(groupnode);
+    }
+    calculateStateForCurrentIteration();
+    OnCanvasUpdate.broadcast();
+  }
+
+  public void deleteCanvasObjects(Collection<AbstractCanvasObject> objects) {
+    canvasController.deleteObjects(objects);
+    calculateStateForCurrentIteration();
+    OnCanvasUpdate.broadcast();
+  }
+
+  /**
+   * Replaces {@code toBeReplaced} by {@code by} on the canvas
+   *
+   * @param toBeReplaced the object that will be replaced
+   * @param by           the object that will replace it
+   */
+  public void replaceCanvasObject(AbstractCanvasObject toBeReplaced, AbstractCanvasObject by) {
+    canvasController.replaceObject(toBeReplaced, by);
+    OnCanvasUpdate.broadcast();
+  }
+
+  /**
+   * Add an edge to the Canvas.
+   *
+   * @param edge the edge
+   */
+  public boolean addEdgeOnCanvas(Edge edge) {
+    if (doesEdgeExist(edge)) {
+      return false;
+    }
+    canvasController.addEdgeOnCanvas(edge);
+    OnCanvasUpdate.broadcast();
+    return true;
+  }
+
+  public boolean doesEdgeExist(Edge edge) {
+    boolean connectsToSelf = edge.getA() == edge.getB();
+    return !connectsToSelf && model.getEdgesOnCanvas().stream()
+        .anyMatch(e -> (e.getA() == edge.getA() && e.getB() == edge.getB())
+            || (e.getB() == edge.getA() && e.getA() == edge.getB()));
+  }
+
+
+  /**
+   * Add an edge to the Canvas.
+   *
+   * @param edge the edge
+   */
+  public void addEdgeOnCanvasOrRemoveExisting(Edge edge) {
+    boolean connectsToSelf = edge.getA() == edge.getB();
+    if (connectsToSelf) {
+      return;
+    }
+    Optional<Edge> edgeToRemove = model.getEdgesOnCanvas().stream()
+        .filter(e -> (e.getA() == edge.getA() && e.getB() == edge.getB())
+            || (e.getB() == edge.getA() && e.getA() == edge.getB())).findAny();
+    edgeToRemove.ifPresentOrElse(canvasController::removeEdgesOnCanvas,
+        () -> canvasController.addEdgeOnCanvas(edge));
+    updateStateForCurrentIteration();
+  }
+
+
+  public void calculateStateForCurrentIteration() {
+    simulationManager.calculateStateForIteration(model.getCurrentIteration());
+  }
+
+  public void updateStateForCurrentIteration() {
+    simulationManager.calculateStateForIteration(model.getCurrentIteration());
+    OnCanvasUpdate.broadcast();
+  }
+
+  /**
+   * calculates the flow of the edges and the supply for objects.
+   *
+   * @param x current Iteration
+   */
+  public void updateStateForIteration(int x) {
+    simulationManager.calculateStateForIteration(x);
+    OnCanvasUpdate.broadcast();
+  }
+
+  /**
+   * resets the whole State of the simulation including a reset of all Edges to the default "is
+   * working" state
+   */
+  public void resetSimulation() {
+    model.reset();
+  }
+
+
+  /**
+   * Getter for Model.
+   *
+   * @return the Model
+   */
+  public Model getModel() {
+    return model;
+  }
+
+
+  /**
+   * Copy all Selected Objects.
+   */
+  public void copy() {
+    GuiSettings.getClipboardObjects().clear();
+    GuiSettings.getClipboardObjects().addAll(GuiSettings.getSelectedObjects());
+    GuiSettings.getClipboardEdges().clear();
+    GuiSettings.getClipboardEdges()
+        .addAll(getEdgesBetweenObjects(GuiSettings.getSelectedObjects()));
+  }
+
+  private List<Edge> getEdgesBetweenObjects(Collection<AbstractCanvasObject> selectedObjects) {
+    return model.getEdgesOnCanvas().stream()
+        .filter(edge -> selectedObjects.containsAll(Arrays.asList(edge.getA(), edge.getB())))
+        .toList();
+  }
+
+  public void paste(GroupNode groupNode, Vec2i offset) {
+    if (GuiSettings.getClipboardObjects().isEmpty()) {
+      return;
+    }
+    HashMap<AbstractCanvasObject, AbstractCanvasObject> oldToNew = new HashMap<>();
+    Collection<AbstractCanvasObject> copies = GuiSettings.getClipboardObjects().stream()
+        .map(obj -> {
+          AbstractCanvasObject copy = obj.copy();
+          oldToNew.put(obj, copy);
+          return copy;
         }).toList();
         }).toList();
-        copies.forEach(obj -> {
-            obj.getPosition().addAssign(offset);
-            obj.getPosition().clampX(0, GuiSettings.canvasSize.getX());
-            obj.getPosition().clampY(0, GuiSettings.canvasSize.getY());
-        });
-        groupNode.addAll(copies);
-        Collection<Edge> copyEdges =  GuiSettings.getClipboardEdges().stream().map(
-                edge -> new Edge(oldToNew.get(edge.getA()), oldToNew.get(edge.getB()), edge.maxCapacity)).toList();
-        model.getEdgesOnCanvas().addAll(copyEdges);
-        updateStateForCurrentIteration();
-        OnSelectionChanged.broadcast();
-    }
-
-    public void cut() {
-        copy();
-        deleteCanvasObjects(GuiSettings.getSelectedObjects());
-        clearSelection();
-    }
-
-
-    public void guiSetEnabled(boolean state) {
-        OnGuiSetEnabled.broadcast(state);
-    }
-
-
-    /**
-     * init default category and objects.
-     */
-    private void initCategories() {
-        Category energy = createCategoryWithName("Energy");
-        Category building = createCategoryWithName("Building");
-        Category component = createCategoryWithName("Component");
-        HolonObject powerPlant = addNewHolonObject(energy, "Power Plant", new ArrayList<>(),
-                ImagePreference.Canvas.DefaultObject.PowerPlant);
-        HolonObject house = addNewHolonObject(building, "House", new ArrayList<>(), ImagePreference.Canvas.DefaultObject.House);
-        HolonSwitch sw = new HolonSwitch("Switch");
-        component.getObjects().add(sw);
-        powerPlant.add(new HolonElement(null, "Power", 10000));
-        energy.getObjects().add(powerPlant);
-
-        house.add(new HolonElement(null, "TV", -250));
-        house.add(new HolonElement(null, "TV", -250));
-        house.add(new HolonElement(null, "Fridge", -500));
-        house.add(new HolonElement(null, "Radio", -100));
-        house.add(new HolonElement(null, "PC", -250));
-        house.add(new HolonElement(null, "PC", -250));
-        house.add(new HolonElement(null, "PC", -250));
-        house.add(new HolonElement(null, "Light", -50));
-        house.add(new HolonElement(null, "Light", -50));
-        house.add(new HolonElement(null, "Light", -50));
-        house.add(new HolonElement(null, "Light", -50));
-        house.add(new HolonElement(null, "Light", -50));
-        house.add(new HolonElement(null, "Solar Panel", 300));
-        building.getObjects().add(house);
-        OnCategoryChanged.broadcast();
-    }
-
-
-    public Category createCategoryWithName(String categoryName) {
-        Optional<Category> category = findCategoryWithName(categoryName);
-        if (category.isEmpty()) {
-            Category cat = new Category(categoryName);
-            GuiSettings.getCategories().add(cat);
-            OnCategoryChanged.broadcast();
-            return cat;
-        } else {
-            return category.get();
-        }
-
-    }
-
-
-
-    /**
-     * Add Object into a Category.
-     *
-     * @param category Category
-     * @param object   Object
-     */
-    public void addObject(Category category, AbstractCanvasObject object) {
-        int i = 0;
-        while (category.findObjectWithName(object.getName()).isPresent()) {
-            if (object.getName().contains("_"))
-                object.setName(object.getName().substring(0, object.getName().indexOf('_')));
-            object.setName(object.getName() + "_" + i);
-            i++;
-        }
-        category.getObjects().add(object);
-    }
-
-    /**
-     * Add new Holon Object to a Category.
-     *
-     * @param category Category
-     * @param object   New Object Name
-     * @param list     Array of Elements
-     * @param image    the image Path
-     */
-    public HolonObject addNewHolonObject(Category category, String object, List<HolonElement> list, String image) {
-        HolonObject obj = new HolonObject(object);
-        obj.setImagePath(image);
-        obj.clearElements();
-        obj.add(list);
-        addObject(category, obj);
-        return obj;
-    }
-
-
-    public Optional<Category> findCategoryWithName(String categoryName) {
-        return GuiSettings.getCategories().stream().filter(cat -> cat.getName().equals(categoryName)).findAny();
-    }
-
-    public void loadFile(File file) {
-        log.info("load" + file);
-        try {
-            FileReader reader = new FileReader(file);
-            Model model = gson.fromJson(reader, Model.class);
-            reader.close();
-            this.model = model;
-            calculateStateForCurrentIteration();
-            OnModelChanged.broadcast();
-        } catch (IOException e) {
-            log.warning(e.getLocalizedMessage());
-        }
-        clearSelection();
-        GuiSettings.setActualSaveFile(file);
-    }
-    public void loadModelFromJsonString(String json){
-        this.model = gson.fromJson(json, Model.class);
-        calculateStateForCurrentIteration();
-        OnModelChanged.broadcast();
-    }
-
-    public String saveModelToJsonString(){
-        return gson.toJson(model);
-    }
-
-
-
-    public void toggleSelectedObjects(Collection<AbstractCanvasObject> objects) {
-        Set<AbstractCanvasObject> intersection = new HashSet<>(objects);
-        intersection.retainAll(GuiSettings.getSelectedObjects());
-        GuiSettings.getSelectedObjects().addAll(objects);
-        GuiSettings.getSelectedObjects().removeAll(intersection);
-        OnSelectionChanged.broadcast();
-    }
-
-
-    public void saveFile(File file) {
-        log.info("save" + file);
-        try {
-            FileWriter writer = new FileWriter(file);
-            gson.toJson(model, writer);
-            writer.close();
-        } catch (IOException e) {
-            log.warning(e.getLocalizedMessage());
-        }
-        GuiSettings.setActualSaveFile(file);
-    }
-
-    public void group() {
-        canvasController.group(GuiSettings.getSelectedObjects());
-        clearSelection();
-        OnCanvasUpdate.broadcast();
-    }
-
-    public void ungroup() {
-        canvasController.ungroup(GuiSettings.getSelectedObjects());
-        clearSelection();
-        OnCanvasUpdate.broadcast();
-    }
-
-
-    public void undo(){
-        UndoHistory.undo().ifPresent(this::loadModelFromJsonString);
-    }
-    public void redo(){
-        UndoHistory.redo().ifPresent(this::loadModelFromJsonString);
-    }
-
-
-
-
-
-
-    public void clearModel() {
-        model.clear();
-        clearSelection();
-        model.setCurrentIteration(0);
-        IdCounter.reset();
-        calculateStateForCurrentIteration();
-        OnModelChanged.broadcast();
-        GuiSettings.setActualSaveFile(null);
-    }
-
-    public void showGroupNode(GroupNode groupNode) {
-        OnShowGroupNode.broadcast(groupNode);
-        clearSelection();
-    }
-
-
-    public void loadCategory(){
-        String json = prefs.get(PreferenceKeys.Category.DefaultCategory, "Init");
-        if(json.equals("Init")){
-            initCategories();
-            return;
-        }
-        GuiSettings.getCategories().clear();
-        GuiSettings.getCategories().addAll(CategoryAdapter.Gson.fromJson(json, CategoryAdapter.CategorySet));
-        OnCategoryChanged.broadcast();
-
-    }
-    public void saveCategories(){
-        String json = CategoryAdapter.Gson.toJson(GuiSettings.getCategories());
-        prefs.put(PreferenceKeys.Category.DefaultCategory, json);
-    }
+    copies.forEach(obj -> {
+      obj.getPosition().addAssign(offset);
+      obj.getPosition().clampX(0, GuiSettings.canvasSize.getX());
+      obj.getPosition().clampY(0, GuiSettings.canvasSize.getY());
+    });
+    groupNode.addAll(copies);
+    Collection<Edge> copyEdges = GuiSettings.getClipboardEdges().stream().map(
+            edge -> new Edge(oldToNew.get(edge.getA()), oldToNew.get(edge.getB()), edge.maxCapacity))
+        .toList();
+    model.getEdgesOnCanvas().addAll(copyEdges);
+    updateStateForCurrentIteration();
+    OnSelectionChanged.broadcast();
+  }
+
+  public void cut() {
+    copy();
+    deleteCanvasObjects(GuiSettings.getSelectedObjects());
+    clearSelection();
+  }
+
+
+  public void guiSetEnabled(boolean state) {
+    OnGuiSetEnabled.broadcast(state);
+  }
+
+
+  /**
+   * init default category and objects.
+   */
+  private void initCategories() {
+    Category energy = createCategoryWithName("Energy");
+    Category building = createCategoryWithName("Building");
+    Category component = createCategoryWithName("Component");
+    HolonObject powerPlant = addNewHolonObject(energy, "Power Plant", new ArrayList<>(),
+        ImagePreference.Canvas.DefaultObject.PowerPlant);
+    HolonObject house = addNewHolonObject(building, "House", new ArrayList<>(),
+        ImagePreference.Canvas.DefaultObject.House);
+    HolonSwitch sw = new HolonSwitch("Switch");
+    component.getObjects().add(sw);
+    powerPlant.add(new HolonElement(null, "Power", 10000));
+    energy.getObjects().add(powerPlant);
+
+    house.add(new HolonElement(null, "TV", -250));
+    house.add(new HolonElement(null, "TV", -250));
+    house.add(new HolonElement(null, "Fridge", -500));
+    house.add(new HolonElement(null, "Radio", -100));
+    house.add(new HolonElement(null, "PC", -250));
+    house.add(new HolonElement(null, "PC", -250));
+    house.add(new HolonElement(null, "PC", -250));
+    house.add(new HolonElement(null, "Light", -50));
+    house.add(new HolonElement(null, "Light", -50));
+    house.add(new HolonElement(null, "Light", -50));
+    house.add(new HolonElement(null, "Light", -50));
+    house.add(new HolonElement(null, "Light", -50));
+    house.add(new HolonElement(null, "Solar Panel", 300));
+    building.getObjects().add(house);
+    OnCategoryChanged.broadcast();
+  }
+
+
+  public Category createCategoryWithName(String categoryName) {
+    Optional<Category> category = findCategoryWithName(categoryName);
+    if (category.isEmpty()) {
+      Category cat = new Category(categoryName);
+      GuiSettings.getCategories().add(cat);
+      OnCategoryChanged.broadcast();
+      return cat;
+    } else {
+      return category.get();
+    }
+
+  }
+
+
+  /**
+   * Add Object into a Category.
+   *
+   * @param category Category
+   * @param object   Object
+   */
+  public void addObject(Category category, AbstractCanvasObject object) {
+    int i = 0;
+    while (category.findObjectWithName(object.getName()).isPresent()) {
+      if (object.getName().contains("_")) {
+        object.setName(object.getName().substring(0, object.getName().indexOf('_')));
+      }
+      object.setName(object.getName() + "_" + i);
+      i++;
+    }
+    category.getObjects().add(object);
+  }
+
+  /**
+   * Add new Holon Object to a Category.
+   *
+   * @param category Category
+   * @param object   New Object Name
+   * @param list     Array of Elements
+   * @param image    the image Path
+   */
+  public HolonObject addNewHolonObject(Category category, String object, List<HolonElement> list,
+      String image) {
+    HolonObject obj = new HolonObject(object);
+    obj.setImagePath(image);
+    obj.clearElements();
+    obj.add(list);
+    addObject(category, obj);
+    return obj;
+  }
+
+
+  public Optional<Category> findCategoryWithName(String categoryName) {
+    return GuiSettings.getCategories().stream().filter(cat -> cat.getName().equals(categoryName))
+        .findAny();
+  }
+
+  public void loadFile(File file) {
+    log.info("load" + file);
+    try {
+      FileReader reader = new FileReader(file);
+      Model model = gson.fromJson(reader, Model.class);
+      reader.close();
+      this.model = model;
+      calculateStateForCurrentIteration();
+      OnModelChanged.broadcast();
+    } catch (IOException e) {
+      log.warning(e.getLocalizedMessage());
+    }
+    clearSelection();
+    GuiSettings.setActualSaveFile(file);
+  }
+
+  public void loadModelFromJsonString(String json) {
+    this.model = gson.fromJson(json, Model.class);
+    calculateStateForCurrentIteration();
+    OnModelChanged.broadcast();
+  }
+
+  public String saveModelToJsonString() {
+    return gson.toJson(model);
+  }
+
+
+  public void toggleSelectedObjects(Collection<AbstractCanvasObject> objects) {
+    Set<AbstractCanvasObject> intersection = new HashSet<>(objects);
+    intersection.retainAll(GuiSettings.getSelectedObjects());
+    GuiSettings.getSelectedObjects().addAll(objects);
+    GuiSettings.getSelectedObjects().removeAll(intersection);
+    OnSelectionChanged.broadcast();
+  }
+
+
+  public void saveFile(File file) {
+    log.info("save" + file);
+    try {
+      FileWriter writer = new FileWriter(file);
+      gson.toJson(model, writer);
+      writer.close();
+    } catch (IOException e) {
+      log.warning(e.getLocalizedMessage());
+    }
+    GuiSettings.setActualSaveFile(file);
+  }
+
+  public void group() {
+    canvasController.group(GuiSettings.getSelectedObjects());
+    clearSelection();
+    OnCanvasUpdate.broadcast();
+  }
+
+  public void ungroup() {
+    canvasController.ungroup(GuiSettings.getSelectedObjects());
+    clearSelection();
+    OnCanvasUpdate.broadcast();
+  }
+
+
+  public void undo() {
+    UndoHistory.undo().ifPresent(this::loadModelFromJsonString);
+  }
+
+  public void redo() {
+    UndoHistory.redo().ifPresent(this::loadModelFromJsonString);
+  }
+
+
+  public void clearModel() {
+    model.clear();
+    clearSelection();
+    model.setCurrentIteration(0);
+    IdCounter.reset();
+    calculateStateForCurrentIteration();
+    OnModelChanged.broadcast();
+    GuiSettings.setActualSaveFile(null);
+  }
+
+  public void showGroupNode(GroupNode groupNode) {
+    OnShowGroupNode.broadcast(groupNode);
+    clearSelection();
+  }
+
+
+  public void loadCategory() {
+    String json = prefs.get(PreferenceKeys.Category.DefaultCategory, "Init");
+    if (json.equals("Init")) {
+      initCategories();
+      return;
+    }
+    GuiSettings.getCategories().clear();
+    GuiSettings.getCategories()
+        .addAll(CategoryAdapter.Gson.fromJson(json, CategoryAdapter.CategorySet));
+    OnCategoryChanged.broadcast();
+
+  }
+
+  public void saveCategories() {
+    String json = CategoryAdapter.Gson.toJson(GuiSettings.getCategories());
+    prefs.put(PreferenceKeys.Category.DefaultCategory, json);
+  }
 }
 }

+ 14 - 13
src/holeg/ui/controller/IndexTranslator.java

@@ -4,17 +4,18 @@ import holeg.interfaces.LocalMode;
 
 
 
 
 public class IndexTranslator {
 public class IndexTranslator {
-	   /**
-     * Determines the index of the internal value array
-     * of an element that should be used, since elements only save 100 values,
-     * but iterations and local period can be anything between 1 and 100000.
-     *
-     * @param e the element for which the calculation should be made.
-     * @param timeStep the iteration for which the calculation should be made.
-     * @return effective Index
-     */
-    public static int getEffectiveIndex(LocalMode e, int timeStep){
-		int period = e.getPeriod().getInterval();
-		return timeStep % period * 100 / period;
-    }
+
+  /**
+   * Determines the index of the internal value array of an element that should be used, since
+   * elements only save 100 values, but iterations and local period can be anything between 1 and
+   * 100000.
+   *
+   * @param e        the element for which the calculation should be made.
+   * @param timeStep the iteration for which the calculation should be made.
+   * @return effective Index
+   */
+  public static int getEffectiveIndex(LocalMode e, int timeStep) {
+    int period = e.getPeriod().getInterval();
+    return timeStep % period * 100 / period;
+  }
 }
 }

+ 104 - 94
src/holeg/ui/controller/SimulationManager.java

@@ -3,120 +3,130 @@ package holeg.ui.controller;
 import holeg.model.AbstractCanvasObject;
 import holeg.model.AbstractCanvasObject;
 import holeg.model.Edge;
 import holeg.model.Edge;
 import holeg.model.Edge.EdgeState;
 import holeg.model.Edge.EdgeState;
+import holeg.model.Holon;
 import holeg.model.HolonObject;
 import holeg.model.HolonObject;
 import holeg.model.HolonSwitch;
 import holeg.model.HolonSwitch;
 import holeg.model.HolonSwitch.SwitchState;
 import holeg.model.HolonSwitch.SwitchState;
-import holeg.model.Holon;
 import holeg.model.Model;
 import holeg.model.Model;
-
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Optional;
+import java.util.Set;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
 public class SimulationManager {
 public class SimulationManager {
-    private static final Logger log = Logger.getLogger(SimulationManager.class.getName());
-    private final Control control;
 
 
-    public SimulationManager(Control control) {
-        log.fine("Construct SimulationManager");
-        this.control = control;
-    }
+  private static final Logger log = Logger.getLogger(SimulationManager.class.getName());
+  private final Control control;
 
 
-    public void calculateStateForIteration(int timeStep) {
-        Model model =  control.getModel();
-        model.getCanvas().getAllSwitchObjectsRecursive().forEach(sw -> sw.calculateState(timeStep));
-        List<HolonObject> holonObjectList = model.getCanvas().getAllHolonObjectsRecursive().collect(Collectors.toList());
-        List<Edge> edgeList = new ArrayList<>(model.getEdgesOnCanvas());
-        Set<Holon> holons = getHolons(holonObjectList, edgeList, timeStep);
-        holons.forEach(Holon::calculate);
-        model.holons = holons;
-    }
+  public SimulationManager(Control control) {
+    log.fine("Construct SimulationManager");
+    this.control = control;
+  }
 
 
+  public void calculateStateForIteration(int timeStep) {
+    Model model = control.getModel();
+    model.getCanvas().getAllSwitchObjectsRecursive().forEach(sw -> sw.calculateState(timeStep));
+    List<HolonObject> holonObjectList = model.getCanvas().getAllHolonObjectsRecursive()
+        .collect(Collectors.toList());
+    List<Edge> edgeList = new ArrayList<>(model.getEdgesOnCanvas());
+    Set<Holon> holons = getHolons(holonObjectList, edgeList, timeStep);
+    holons.forEach(Holon::calculate);
+    model.holons = holons;
+  }
 
 
-    private Set<Holon> getHolons(List<HolonObject> holonObjectList, List<Edge> edgeList, int timeStep) {
-        Set<Holon> holons = new HashSet<>();
-        for (Holon holon : calculateHolonStructure(holonObjectList, edgeList)) {
-            final float energyOnCables = holon.holonObjects.stream().map(hO -> {
-                        hO.calculateEnergy(timeStep);
-                        return hO.getActualEnergy();
-                    })
-                    .filter(energy -> energy > 0.0f).reduce(0.0f, (Float::sum));
-            // find the edge with the energy supplied from his two connected objects are
-            // the biggest, from all cables that the network give more energy than the
-            // edge capacity.
-            Optional<Edge> edge = holon.edges.stream()
-                    .filter(e -> energyOnCables > e.maxCapacity && e.mode == Edge.EdgeMode.Normal)
-                    .max((lhs, rhs) -> Float.compare(lhs.getEnergyFromConneted(), rhs.getEnergyFromConneted()));
-            edge.ifPresentOrElse(e -> {
-                //Burn Cable
-                e.setState(EdgeState.Burned);
-                e.setActualFlow(0.0f);
-                //Split Holon
-                holons.addAll(getHolons(new ArrayList<>(holon.holonObjects), new ArrayList<>(holon.edges), timeStep));
-            }, () -> {
-                holon.edges.forEach(e -> e.setActualFlow(energyOnCables));
-                holons.add(holon);
-            });
-        }
-        return holons;
+
+  private Set<Holon> getHolons(List<HolonObject> holonObjectList, List<Edge> edgeList,
+      int timeStep) {
+    Set<Holon> holons = new HashSet<>();
+    for (Holon holon : calculateHolonStructure(holonObjectList, edgeList)) {
+      final float energyOnCables = holon.holonObjects.stream().map(hO -> {
+            hO.calculateEnergy(timeStep);
+            return hO.getActualEnergy();
+          })
+          .filter(energy -> energy > 0.0f).reduce(0.0f, (Float::sum));
+      // find the edge with the energy supplied from his two connected objects are
+      // the biggest, from all cables that the network give more energy than the
+      // edge capacity.
+      Optional<Edge> edge = holon.edges.stream()
+          .filter(e -> energyOnCables > e.maxCapacity && e.mode == Edge.EdgeMode.Normal)
+          .max((lhs, rhs) -> Float.compare(lhs.getEnergyFromConneted(),
+              rhs.getEnergyFromConneted()));
+      edge.ifPresentOrElse(e -> {
+        //Burn Cable
+        e.setState(EdgeState.Burned);
+        e.setActualFlow(0.0f);
+        //Split Holon
+        holons.addAll(
+            getHolons(new ArrayList<>(holon.holonObjects), new ArrayList<>(holon.edges), timeStep));
+      }, () -> {
+        holon.edges.forEach(e -> e.setActualFlow(energyOnCables));
+        holons.add(holon);
+      });
     }
     }
+    return holons;
+  }
 
 
-    Set<Holon> calculateHolonStructure(List<HolonObject> holonObjectList, List<Edge> edgeList) {
-        Set<Holon> holons = new HashSet<>();
-        while (!holonObjectList.isEmpty()) {
-            // lookAt the first holonObject and find his neighbors
-            HolonObject lookAtObject = holonObjectList.get(0);
-            // delete out of list
-            holonObjectList.remove(0);
-            // create a new Network
-            Holon actualNetwork = new Holon(lookAtObject);
-            // create List of neighbors
-            LinkedList<AbstractCanvasObject> neighbors = new LinkedList<>();
-            populateListOfNeighbors(edgeList, lookAtObject, actualNetwork, neighbors);
-            while (!neighbors.isEmpty()) {
-                AbstractCanvasObject lookAtNeighbor = neighbors.getFirst();
-                if (lookAtNeighbor instanceof HolonObject) {
-                    holonObjectList.remove(lookAtNeighbor);
-                }
-                actualNetwork.add(lookAtNeighbor);
-                // When HolonSwitch Check if closed
-                if (!(lookAtNeighbor instanceof HolonSwitch sw) || sw.getState() == SwitchState.Closed) {
-                    populateListOfNeighbors(edgeList, lookAtNeighbor, actualNetwork, neighbors);
-                }
-                neighbors.removeFirst();
-            }
-            holons.add(actualNetwork);
+  Set<Holon> calculateHolonStructure(List<HolonObject> holonObjectList, List<Edge> edgeList) {
+    Set<Holon> holons = new HashSet<>();
+    while (!holonObjectList.isEmpty()) {
+      // lookAt the first holonObject and find his neighbors
+      HolonObject lookAtObject = holonObjectList.get(0);
+      // delete out of list
+      holonObjectList.remove(0);
+      // create a new Network
+      Holon actualNetwork = new Holon(lookAtObject);
+      // create List of neighbors
+      LinkedList<AbstractCanvasObject> neighbors = new LinkedList<>();
+      populateListOfNeighbors(edgeList, lookAtObject, actualNetwork, neighbors);
+      while (!neighbors.isEmpty()) {
+        AbstractCanvasObject lookAtNeighbor = neighbors.getFirst();
+        if (lookAtNeighbor instanceof HolonObject) {
+          holonObjectList.remove(lookAtNeighbor);
         }
         }
-        for (Edge e : edgeList) {
-            e.setActualFlow(0.0f);
+        actualNetwork.add(lookAtNeighbor);
+        // When HolonSwitch Check if closed
+        if (!(lookAtNeighbor instanceof HolonSwitch sw) || sw.getState() == SwitchState.Closed) {
+          populateListOfNeighbors(edgeList, lookAtNeighbor, actualNetwork, neighbors);
         }
         }
-        return holons;
+        neighbors.removeFirst();
+      }
+      holons.add(actualNetwork);
     }
     }
+    for (Edge e : edgeList) {
+      e.setActualFlow(0.0f);
+    }
+    return holons;
+  }
 
 
-    /**
-     * Adds  neighbors.
-     */
-    void populateListOfNeighbors(List<Edge> edgeList, AbstractCanvasObject lookAtObject,
-                                 Holon actualNetwork, LinkedList<AbstractCanvasObject> neighbors) {
-        ListIterator<Edge> iter = edgeList.listIterator();
-        while (iter.hasNext()) {
-            Edge lookAtEdge = iter.next();
-            if (lookAtEdge.getState() == EdgeState.Working && lookAtEdge.isConnectedTo(lookAtObject)) {
-                iter.remove();
-                actualNetwork.edges.add(lookAtEdge);
+  /**
+   * Adds  neighbors.
+   */
+  void populateListOfNeighbors(List<Edge> edgeList, AbstractCanvasObject lookAtObject,
+      Holon actualNetwork, LinkedList<AbstractCanvasObject> neighbors) {
+    ListIterator<Edge> iter = edgeList.listIterator();
+    while (iter.hasNext()) {
+      Edge lookAtEdge = iter.next();
+      if (lookAtEdge.getState() == EdgeState.Working && lookAtEdge.isConnectedTo(lookAtObject)) {
+        iter.remove();
+        actualNetwork.edges.add(lookAtEdge);
 
 
-                // Add neighbor
-                AbstractCanvasObject edgeNeighbor;
-                if (lookAtEdge.getA().equals(lookAtObject)) {
-                    edgeNeighbor = lookAtEdge.getB();
-                } else {
-                    edgeNeighbor = lookAtEdge.getA();
-                }
-                if (!neighbors.contains(edgeNeighbor)) {
-                    neighbors.add(edgeNeighbor);
-                }
-            }
+        // Add neighbor
+        AbstractCanvasObject edgeNeighbor;
+        if (lookAtEdge.getA().equals(lookAtObject)) {
+          edgeNeighbor = lookAtEdge.getB();
+        } else {
+          edgeNeighbor = lookAtEdge.getA();
+        }
+        if (!neighbors.contains(edgeNeighbor)) {
+          neighbors.add(edgeNeighbor);
         }
         }
+      }
     }
     }
+  }
 
 
 }
 }

+ 51 - 54
src/holeg/ui/model/GuiSettings.java

@@ -1,71 +1,68 @@
 package holeg.ui.model;
 package holeg.ui.model;
 
 
-import java.io.File;
-import java.util.*;
-
 import holeg.model.AbstractCanvasObject;
 import holeg.model.AbstractCanvasObject;
 import holeg.model.Edge;
 import holeg.model.Edge;
 import holeg.ui.view.category.Category;
 import holeg.ui.view.category.Category;
 import holeg.utility.math.vector.Vec2i;
 import holeg.utility.math.vector.Vec2i;
-
-import javax.swing.text.html.Option;
+import java.io.File;
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
 
 
 public class GuiSettings {
 public class GuiSettings {
 
 
-    private static int pictureScale = 50; // Picture Scale
-    private static int halfPictureScale = pictureScale / 2;
-    public static Vec2i canvasSize = new Vec2i(3000,3000);
-    
-    
-    public static int timerSpeed = 1000;
+  private static final Set<Edge> selectedEdges = new HashSet<>();
+  private static final Set<Category> categories = new HashSet<>();
+  private static final Set<AbstractCanvasObject> clipboardObjects = new HashSet<>();
+  private static final Set<Edge> clipboardEdges = new HashSet<>();
+  private static final Set<AbstractCanvasObject> selectedObjects = new HashSet<>();
+  public static Vec2i canvasSize = new Vec2i(3000, 3000);
+  public static int timerSpeed = 1000;
+  public static float maxCapacityForNewCreatedEdges = 10000;
+  public static float dragThresholdDistance = 5;
+  private static int pictureScale = 50; // Picture Scale
+  private static int halfPictureScale = pictureScale / 2;
+  private static File actualSaveFile = null;
+
+  public static Optional<File> getActualSaveFile() {
+    return Optional.ofNullable(actualSaveFile);
+  }
+
+  public static void setActualSaveFile(File file) {
+    actualSaveFile = file;
+  }
+
+
+  public static int getPictureScale() {
+    return pictureScale;
+  }
 
 
-    public static float maxCapacityForNewCreatedEdges = 10000;
-    
-    
-    private static final Set<Edge> selectedEdges = new HashSet<>();
-    private static final Set<Category> categories = new HashSet<>();
-    private static final Set<AbstractCanvasObject> clipboardObjects = new HashSet<>();
-    private static final Set<Edge> clipboardEdges = new HashSet<>();
-	private static final Set<AbstractCanvasObject> selectedObjects = new HashSet<>();
+  public static void setPictureScale(int value) {
+    pictureScale = value;
+    halfPictureScale = (value + 1) / 2;
+  }
 
 
+  public static int getPictureScaleDiv2() {
+    return halfPictureScale;
+  }
 
 
-    public static float dragThresholdDistance = 5;
-    private static File actualSaveFile = null;
+  public static Set<Edge> getSelectedEdges() {
+    return selectedEdges;
+  }
 
 
-	public static Optional<File> getActualSaveFile(){
-		return Optional.ofNullable(actualSaveFile);
-	}
-	public static void setActualSaveFile(File file){
-		actualSaveFile = file;
-	}
+  public static Set<Category> getCategories() {
+    return categories;
+  }
 
 
-    
-    public static int getPictureScale() {
-        return pictureScale;
-    }
+  public static Set<AbstractCanvasObject> getClipboardObjects() {
+    return clipboardObjects;
+  }
 
 
-    public static int getPictureScaleDiv2() {
-        return halfPictureScale;
-    }
-    public static void setPictureScale(int value) {
-    	pictureScale = value;
-    	halfPictureScale = (value + 1) / 2;
-    }
+  public static Set<Edge> getClipboardEdges() {
+    return clipboardEdges;
+  }
 
 
-    
-	public static Set<Edge> getSelectedEdges() {
-		return selectedEdges;
-	}
-	public static Set<Category> getCategories() {
-		return categories;
-	}
-	public static Set<AbstractCanvasObject> getClipboardObjects() {
-		return clipboardObjects;
-	}
-	public static Set<Edge> getClipboardEdges() {
-		return clipboardEdges;
-	}
-	public static Set<AbstractCanvasObject> getSelectedObjects() {
-		return selectedObjects;
-	}
+  public static Set<AbstractCanvasObject> getSelectedObjects() {
+    return selectedObjects;
+  }
 }
 }

+ 35 - 34
src/holeg/ui/model/IdCounter.java

@@ -1,44 +1,45 @@
 package holeg.ui.model;
 package holeg.ui.model;
 
 
 /**
 /**
- * Static counter
- * ID-Counter for all Cps Objects.
- * 
+ * Static counter ID-Counter for all Cps Objects.
+ *
  * @author Gruppe14
  * @author Gruppe14
  */
  */
 public class IdCounter {
 public class IdCounter {
-	private static int counter = 1;
-	/**
-	 * Return the next ID and increment the ID counter by 1.
-	 * @return the next ID
-	 */
-	public static synchronized int next() {
-			return counter++;
-	}
 
 
-	/**
-	 * Return the Counter.
-	 * 
-	 * @return the counter
-	 */
-	public static int get() {
-		return counter;
-	}
+  private static int counter = 1;
 
 
-	/**
-	 * Set the Counter.
-	 *
-	 * @param counter
-	 *            the counter to set
-	 */
-	public static void set(int counter) {
-		IdCounter.counter = counter;
-	}
+  /**
+   * Return the next ID and increment the ID counter by 1.
+   *
+   * @return the next ID
+   */
+  public static synchronized int next() {
+    return counter++;
+  }
 
 
-	/**
-	 * Reset the Counter.
-	 */
-	public static void reset() {
-				counter = 0;
-	}
+  /**
+   * Return the Counter.
+   *
+   * @return the counter
+   */
+  public static int get() {
+    return counter;
+  }
+
+  /**
+   * Set the Counter.
+   *
+   * @param counter the counter to set
+   */
+  public static void set(int counter) {
+    IdCounter.counter = counter;
+  }
+
+  /**
+   * Reset the Counter.
+   */
+  public static void reset() {
+    counter = 0;
+  }
 }
 }

+ 20 - 19
src/holeg/ui/model/LimitedSizeQueue.java

@@ -4,28 +4,29 @@ import java.util.ArrayList;
 
 
 public class LimitedSizeQueue<T> extends ArrayList<T> {
 public class LimitedSizeQueue<T> extends ArrayList<T> {
 
 
-    private final int maxSize;
+  private final int maxSize;
 
 
-    public LimitedSizeQueue(int size){
-        this.maxSize = size;
-    }
+  public LimitedSizeQueue(int size) {
+    this.maxSize = size;
+  }
 
 
-    public boolean add(T k){
-        boolean r = super.add(k);
-        if (size() > maxSize){
-            removeRange(0, size() - maxSize);
-        }
-        return r;
-    }
-    public void removeRange(int a, int b){
-        super.removeRange(a, b);
+  public boolean add(T k) {
+    boolean r = super.add(k);
+    if (size() > maxSize) {
+      removeRange(0, size() - maxSize);
     }
     }
+    return r;
+  }
 
 
-    public T getYoungest() {
-        return get(size() - 1);
-    }
+  public void removeRange(int a, int b) {
+    super.removeRange(a, b);
+  }
 
 
-    public T getOldest() {
-        return get(0);
-    }
+  public T getYoungest() {
+    return get(size() - 1);
+  }
+
+  public T getOldest() {
+    return get(0);
+  }
 }
 }

+ 28 - 26
src/holeg/ui/model/PriorityCount.java

@@ -4,32 +4,34 @@ import holeg.model.HolonElement;
 import jdk.jfr.Unsigned;
 import jdk.jfr.Unsigned;
 
 
 public class PriorityCount {
 public class PriorityCount {
-	@Unsigned
-	public int low, medium, high, essential;
 
 
-	public void add(PriorityCount other) {
-		low += other.low;
-		medium += other.medium;
-		high += other.high;
-		essential += other.essential;
-	}
-	public void count(HolonElement element) {
-		switch (element.getPriority()) {
-		case Essential:
-			essential++;
-			break;
-		case High:
-			high++;
-			break;
-		case Medium:
-			medium++;
-			break;
-		case Low:
-			low++;
-			break;
-		default:
-			break;
+  @Unsigned
+  public int low, medium, high, essential;
 
 
-		}
-	}
+  public void add(PriorityCount other) {
+    low += other.low;
+    medium += other.medium;
+    high += other.high;
+    essential += other.essential;
+  }
+
+  public void count(HolonElement element) {
+    switch (element.getPriority()) {
+      case Essential:
+        essential++;
+        break;
+      case High:
+        high++;
+        break;
+      case Medium:
+        medium++;
+        break;
+      case Low:
+        low++;
+        break;
+      default:
+        break;
+
+    }
+  }
 }
 }

+ 33 - 29
src/holeg/ui/model/UndoHistory.java

@@ -3,40 +3,44 @@ package holeg.ui.model;
 import java.util.Optional;
 import java.util.Optional;
 
 
 public class UndoHistory {
 public class UndoHistory {
-    public static final int NumberOfSaves = 35;
-    private static final LimitedSizeQueue<String> jsonSaves = new LimitedSizeQueue<>(NumberOfSaves);
-    private static int actualIndex = -1;
 
 
+  public static final int NumberOfSaves = 35;
+  private static final LimitedSizeQueue<String> jsonSaves = new LimitedSizeQueue<>(NumberOfSaves);
+  private static int actualIndex = -1;
 
 
-    public static boolean canUndo(){
-        return actualIndex > 0;
-    }
-    public static Optional<String> undo(){
-        if(canUndo()){
-            actualIndex -= 1;
-            return Optional.of(jsonSaves.get(actualIndex));
-        }
-        return Optional.empty();
-    }
-    public static boolean canRedo(){
-        return actualIndex < jsonSaves.size() -1;
+
+  public static boolean canUndo() {
+    return actualIndex > 0;
+  }
+
+  public static Optional<String> undo() {
+    if (canUndo()) {
+      actualIndex -= 1;
+      return Optional.of(jsonSaves.get(actualIndex));
     }
     }
-    public static Optional<String> redo(){
-        if(canRedo()){
-            actualIndex += 1;
-            return Optional.of(jsonSaves.get(actualIndex));
-        }
-        return Optional.empty();
+    return Optional.empty();
+  }
+
+  public static boolean canRedo() {
+    return actualIndex < jsonSaves.size() - 1;
+  }
+
+  public static Optional<String> redo() {
+    if (canRedo()) {
+      actualIndex += 1;
+      return Optional.of(jsonSaves.get(actualIndex));
     }
     }
+    return Optional.empty();
+  }
 
 
-    public static  void addSave(String save){
-        if(canRedo()){
-            jsonSaves.removeRange(actualIndex + 1, jsonSaves.size());
-        }
-        if(actualIndex < NumberOfSaves){
-            actualIndex += 1;
-        }
-        jsonSaves.add(save);
+  public static void addSave(String save) {
+    if (canRedo()) {
+      jsonSaves.removeRange(actualIndex + 1, jsonSaves.size());
+    }
+    if (actualIndex < NumberOfSaves) {
+      actualIndex += 1;
     }
     }
+    jsonSaves.add(save);
+  }
 
 
 }
 }

+ 43 - 43
src/holeg/ui/view/Main.java

@@ -1,18 +1,17 @@
 package holeg.ui.view;
 package holeg.ui.view;
 
 
-import javax.swing.*;
-
-import holeg.ui.controller.Control;
 import holeg.model.Model;
 import holeg.model.Model;
+import holeg.ui.controller.Control;
 import holeg.ui.view.main.Gui;
 import holeg.ui.view.main.Gui;
-
-import java.awt.*;
+import java.awt.EventQueue;
 import java.io.FileInputStream;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.IOException;
 import java.util.Locale;
 import java.util.Locale;
 import java.util.logging.Level;
 import java.util.logging.Level;
 import java.util.logging.LogManager;
 import java.util.logging.LogManager;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
+import javax.swing.UIManager;
+import javax.swing.UnsupportedLookAndFeelException;
 
 
 /**
 /**
  * The main Class in this Program. The GUI is created in this Class.
  * The main Class in this Program. The GUI is created in this Class.
@@ -20,49 +19,50 @@ import java.util.logging.Logger;
  * @author Gruppe14
  * @author Gruppe14
  */
  */
 public class Main {
 public class Main {
-    private static final LogManager logManager = LogManager.getLogManager();
-    private static final Logger log = Logger.getLogger(Main.class.getName());
 
 
-    static {
-        try {
-            logManager.readConfiguration(new FileInputStream("./config/log.properties"));
-        } catch (IOException exception) {
-            log.log(Level.SEVERE, "Error in loading configuration", exception);
-        }
-    }
+  private static final LogManager logManager = LogManager.getLogManager();
+  private static final Logger log = Logger.getLogger(Main.class.getName());
 
 
-    /**
-     * main method of this program.
-     *
-     * @param args standard
-     */
-    public static void main(String[] args) {
-        setLookAndFeel();
-        setLocale();
-        EventQueue.invokeLater(() -> {
-            Model model = new Model();
-            Control control = new Control(model);
-            Gui view = new Gui(control);
-            control.loadCategory();
-            view.setVisible(true);
-        });
+  static {
+    try {
+      logManager.readConfiguration(new FileInputStream("./config/log.properties"));
+    } catch (IOException exception) {
+      log.log(Level.SEVERE, "Error in loading configuration", exception);
     }
     }
+  }
 
 
-    private static void setLocale() {
-        Locale.setDefault(Locale.US);
-    }
+  /**
+   * main method of this program.
+   *
+   * @param args standard
+   */
+  public static void main(String[] args) {
+    setLookAndFeel();
+    setLocale();
+    EventQueue.invokeLater(() -> {
+      Model model = new Model();
+      Control control = new Control(model);
+      Gui view = new Gui(control);
+      control.loadCategory();
+      view.setVisible(true);
+    });
+  }
+
+  private static void setLocale() {
+    Locale.setDefault(Locale.US);
+  }
 
 
-    /**
-     * This method loads the System LookAndFeel. Except for Linux OS.
-     */
-    private static void setLookAndFeel() {
-        try {
-            if (!System.getProperty("os.name").startsWith("Linux")) {
-                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
-            }
-        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
-                | UnsupportedLookAndFeelException ignored) {
-        }
+  /**
+   * This method loads the System LookAndFeel. Except for Linux OS.
+   */
+  private static void setLookAndFeel() {
+    try {
+      if (!System.getProperty("os.name").startsWith("Linux")) {
+        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+      }
+    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
+        | UnsupportedLookAndFeelException ignored) {
     }
     }
+  }
 
 
 }
 }

+ 359 - 331
src/holeg/ui/view/canvas/Canvas.java

@@ -1,15 +1,21 @@
 package holeg.ui.view.canvas;
 package holeg.ui.view.canvas;
 
 
-import holeg.model.*;
+import holeg.model.AbstractCanvasObject;
+import holeg.model.Edge;
+import holeg.model.GroupNode;
+import holeg.model.HolonObject;
+import holeg.model.HolonSwitch;
+import holeg.model.Node;
 import holeg.ui.controller.Control;
 import holeg.ui.controller.Control;
 import holeg.ui.model.GuiSettings;
 import holeg.ui.model.GuiSettings;
 import holeg.ui.view.dialog.CreateTemplatePopUp;
 import holeg.ui.view.dialog.CreateTemplatePopUp;
 import holeg.utility.math.vector.Geometry;
 import holeg.utility.math.vector.Geometry;
 import holeg.utility.math.vector.Vec2f;
 import holeg.utility.math.vector.Vec2f;
 import holeg.utility.math.vector.Vec2i;
 import holeg.utility.math.vector.Vec2i;
-
-import javax.swing.*;
-import java.awt.*;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
 import java.awt.event.MouseMotionListener;
@@ -17,373 +23,395 @@ import java.util.HashSet;
 import java.util.Optional;
 import java.util.Optional;
 import java.util.Set;
 import java.util.Set;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
+import javax.swing.JFrame;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.SwingUtilities;
 
 
 public class Canvas extends JPanel {
 public class Canvas extends JPanel {
-    private static final Logger log = Logger.getLogger(Canvas.class.getName());
-    private final Control control;
-    private final CanvasMouseListener canvasMouseListener = new CanvasMouseListener();
-    private GroupNode groupNode;
-    private boolean enabled = true;
-    private final JPopupMenu componentPopupMenu = new JPopupMenu();
-    private final JMenuItem groupMenu = new JMenuItem("Group");
-    private final JMenuItem ungroupMenu = new JMenuItem("Ungroup");
-    private final JMenuItem deleteMenu = new JMenuItem("Delete");
-    private final JMenuItem templateMenu = new JMenuItem("Template");
-
-
-
-    public Canvas(Control control, GroupNode groupNode) {
-        this.control = control;
-        this.groupNode = groupNode;
-        control.OnGuiSetEnabled.addListener(this::setCanvasEnabled);
-        control.OnSelectionChanged.addListener(this::repaint);
-        control.OnCanvasUpdate.addListener(this::repaint);
-        this.setBackground(Color.WHITE);
-        this.setPreferredSize(new Dimension(GuiSettings.canvasSize.getX(), GuiSettings.canvasSize.getY()));
-        this.addMouseListener(canvasMouseListener);
-        this.addMouseMotionListener(canvasMouseListener);
-        initPopupMenu();
-    }
 
 
-
-    private void initPopupMenu() {
-        componentPopupMenu.add(deleteMenu);
-        componentPopupMenu.addSeparator();
-        componentPopupMenu.add(groupMenu);
-        componentPopupMenu.add(ungroupMenu);
-        componentPopupMenu.addSeparator();
-        componentPopupMenu.add(templateMenu);
-        deleteMenu.addActionListener(clicked -> {
-            control.deleteCanvasObjects(GuiSettings.getSelectedObjects());
-            control.clearSelection();
-        });
-        groupMenu.addActionListener(clicked -> control.group());
-        ungroupMenu.addActionListener(clicked -> control.ungroup());
-        templateMenu.addActionListener(clicked -> GuiSettings.getSelectedObjects().stream().findAny().ifPresent(obj -> {
-           HolonObject hObject = (HolonObject)obj;
-            new CreateTemplatePopUp(hObject, (JFrame) SwingUtilities.getWindowAncestor(this), control);
+  private static final Logger log = Logger.getLogger(Canvas.class.getName());
+  private final Control control;
+  private final CanvasMouseListener canvasMouseListener = new CanvasMouseListener();
+  private final JPopupMenu componentPopupMenu = new JPopupMenu();
+  private final JMenuItem groupMenu = new JMenuItem("Group");
+  private final JMenuItem ungroupMenu = new JMenuItem("Ungroup");
+  private final JMenuItem deleteMenu = new JMenuItem("Delete");
+  private final JMenuItem templateMenu = new JMenuItem("Template");
+  private GroupNode groupNode;
+  private boolean enabled = true;
+
+
+  public Canvas(Control control, GroupNode groupNode) {
+    this.control = control;
+    this.groupNode = groupNode;
+    control.OnGuiSetEnabled.addListener(this::setCanvasEnabled);
+    control.OnSelectionChanged.addListener(this::repaint);
+    control.OnCanvasUpdate.addListener(this::repaint);
+    this.setBackground(Color.WHITE);
+    this.setPreferredSize(
+        new Dimension(GuiSettings.canvasSize.getX(), GuiSettings.canvasSize.getY()));
+    this.addMouseListener(canvasMouseListener);
+    this.addMouseMotionListener(canvasMouseListener);
+    initPopupMenu();
+  }
+
+  public static Rectangle getBoundsOfObject(AbstractCanvasObject obj) {
+    int pictureScale = GuiSettings.getPictureScale();
+    int pictureScaleDiv2 = GuiSettings.getPictureScaleDiv2();
+    Vec2i pos = obj.getPosition();
+    return new Rectangle(pos.getX() - pictureScaleDiv2, pos.getY() - pictureScaleDiv2, pictureScale,
+        pictureScale);
+  }
+
+  public static Vec2i boundsToCanvas(Vec2i pos) {
+    Vec2i position = new Vec2i(pos);
+    position.clampX(GuiSettings.getPictureScaleDiv2(),
+        GuiSettings.canvasSize.getX() - GuiSettings.getPictureScaleDiv2());
+    position.clampY(GuiSettings.getPictureScaleDiv2(),
+        GuiSettings.canvasSize.getY() - GuiSettings.getPictureScaleDiv2());
+    return position;
+  }
+
+  private void initPopupMenu() {
+    componentPopupMenu.add(deleteMenu);
+    componentPopupMenu.addSeparator();
+    componentPopupMenu.add(groupMenu);
+    componentPopupMenu.add(ungroupMenu);
+    componentPopupMenu.addSeparator();
+    componentPopupMenu.add(templateMenu);
+    deleteMenu.addActionListener(clicked -> {
+      control.deleteCanvasObjects(GuiSettings.getSelectedObjects());
+      control.clearSelection();
+    });
+    groupMenu.addActionListener(clicked -> control.group());
+    ungroupMenu.addActionListener(clicked -> control.ungroup());
+    templateMenu.addActionListener(
+        clicked -> GuiSettings.getSelectedObjects().stream().findAny().ifPresent(obj -> {
+          HolonObject hObject = (HolonObject) obj;
+          new CreateTemplatePopUp(hObject, (JFrame) SwingUtilities.getWindowAncestor(this),
+              control);
         }));
         }));
 
 
+  }
+
+  private void setCanvasEnabled(boolean state) {
+    enabled = state;
+  }
+
+  public GroupNode getGroupNode() {
+    return this.groupNode;
+  }
+
+  public void setGroupNode(GroupNode groupNode) {
+    this.groupNode = groupNode;
+  }
+
+  @Override
+  public void paintComponent(java.awt.Graphics g) {
+    super.paintComponent(g);
+    Graphics2D g2d = Rendering.initGraphics2D(g);
+    g2d.setColor(Color.gray);
+    g2d.fillRect(0, 0, getWidth(), getHeight());
+    g2d.setColor(Color.white);
+    g2d.fillRect(0, 0, GuiSettings.canvasSize.getX(), GuiSettings.canvasSize.getY());
+    Rendering.drawSelection(g2d);
+    paintEdges(g2d);
+    groupNode.getHolonObjects().forEach(hO -> Rendering.drawHolonObject(g2d, hO));
+    groupNode.getSwitches().forEach(hS -> Rendering.drawSwitchObject(g2d, hS));
+    groupNode.getGroupNodes().forEach(groupNode -> Rendering.drawGroupNode(g2d, groupNode));
+    groupNode.getNodes().forEach(node -> Rendering.drawNode(g2d, node));
+    switch (canvasMouseListener.state) {
+      case BoxSelection -> Rendering.drawSelectionBox(g2d,
+          canvasMouseListener.getRectangleOfSelectionBox());
+      case EdgeCreation -> Rendering.drawNewEdgeLine(g2d,
+          canvasMouseListener.selectedOnPressed.getPosition(), canvasMouseListener.lastPosition);
     }
     }
-
-    public static Rectangle getBoundsOfObject(AbstractCanvasObject obj) {
-        int pictureScale = GuiSettings.getPictureScale();
-        int pictureScaleDiv2 = GuiSettings.getPictureScaleDiv2();
-        Vec2i pos = obj.getPosition();
-        return new Rectangle(pos.getX() - pictureScaleDiv2, pos.getY() - pictureScaleDiv2, pictureScale, pictureScale);
+    if (canvasMouseListener.canBeReplaced) {
+      Rendering.drawReplacementSymbol(g2d, canvasMouseListener.selectedOnPressed);
     }
     }
-
-    private void setCanvasEnabled(boolean state) {
-        enabled = state;
+  }
+
+  private void paintEdges(Graphics2D g2d) {
+    control.getModel().getEdgesOnCanvas().forEach(edge -> {
+      if (edge.getA().getGroupNode().isEmpty() || edge.getB().getGroupNode().isEmpty()) {
+        return;
+      }
+      boolean aInside = edge.getA().getGroupNode().get() == groupNode;
+      boolean bInside = edge.getB().getGroupNode().get() == groupNode;
+      //both
+      if (aInside && bInside) {
+        Rendering.drawEdge(g2d, edge, edge.getA(), edge.getB());
+      } else if (aInside) {
+        SearchObjectIfParentOfGroupNode(edge.getB()).ifPresentOrElse(
+            alternative -> Rendering.drawEdge(g2d, edge, edge.getA(), alternative),
+            () -> Rendering.drawExternConnection(g2d, edge.getA()));
+      } else if (bInside) {
+        SearchObjectIfParentOfGroupNode(edge.getA()).ifPresentOrElse(
+            alternative -> Rendering.drawEdge(g2d, edge, alternative, edge.getB()),
+            () -> Rendering.drawExternConnection(g2d, edge.getB()));
+      } else {
+        Optional<AbstractCanvasObject> alternativeA = SearchObjectIfParentOfGroupNode(edge.getA());
+        Optional<AbstractCanvasObject> alternativeB = SearchObjectIfParentOfGroupNode(edge.getB());
+        if (alternativeA.isPresent() && alternativeB.isPresent() && !alternativeA.equals(
+            alternativeB)) {
+          Rendering.drawEdge(g2d, edge, alternativeA.get(), alternativeB.get());
+        }
+      }
+      //none
+    });
+  }
+
+  private Optional<AbstractCanvasObject> SearchObjectIfParentOfGroupNode(
+      AbstractCanvasObject current) {
+    while (current.getGroupNode().isPresent()) {
+      if (current.getGroupNode().get() == this.groupNode) {
+        return Optional.of(current);
+      }
+      current = current.getGroupNode().get();
     }
     }
+    return Optional.empty();
+  }
 
 
-    public GroupNode getGroupNode() {
-        return this.groupNode;
-    }
+  private Optional<AbstractCanvasObject> getObjectAtPosition(Vec2i pos) {
+    return groupNode.getObjectsInThisLayer().filter(obj ->
+        getBoundsOfObject(obj).contains(pos.getX(), pos.getY())
+    ).findAny();
+  }
+
+  /**
+   * Microsoft Windows10 selection & dragging behavior
+   */
+  private class CanvasMouseListener implements MouseListener, MouseMotionListener {
+
+    private Vec2i lastPosition = new Vec2i();
+    private Vec2i pressedPosition = new Vec2i();
+    private Set<AbstractCanvasObject> selectionBeforeBoxSelection = new HashSet<>();
+    private State state = State.None;
+    private AbstractCanvasObject selectedOnPressed = null;
+    private boolean canBeReplaced = false;
 
 
-    public void setGroupNode(GroupNode groupNode) {
-        this.groupNode = groupNode;
-    }
 
 
     @Override
     @Override
-    public void paintComponent(java.awt.Graphics g) {
-        super.paintComponent(g);
-        Graphics2D g2d = Rendering.initGraphics2D(g);
-        g2d.setColor(Color.gray);
-        g2d.fillRect(0,0,getWidth(), getHeight());
-        g2d.setColor(Color.white);
-        g2d.fillRect(0,0,GuiSettings.canvasSize.getX(), GuiSettings.canvasSize.getY());
-        Rendering.drawSelection(g2d);
-        paintEdges(g2d);
-        groupNode.getHolonObjects().forEach(hO -> Rendering.drawHolonObject(g2d, hO));
-        groupNode.getSwitches().forEach(hS -> Rendering.drawSwitchObject(g2d, hS));
-        groupNode.getGroupNodes().forEach(groupNode -> Rendering.drawGroupNode(g2d, groupNode));
-        groupNode.getNodes().forEach(node -> Rendering.drawNode(g2d, node));
-        switch (canvasMouseListener.state) {
-            case BoxSelection -> Rendering.drawSelectionBox(g2d, canvasMouseListener.getRectangleOfSelectionBox());
-            case EdgeCreation -> Rendering.drawNewEdgeLine(g2d, canvasMouseListener.selectedOnPressed.getPosition(), canvasMouseListener.lastPosition);
+    public void mousePressed(MouseEvent e) {
+      if (!enabled) {
+        return;
+      }
+      log.finest(state.toString());
+
+      Vec2i pos = new Vec2i(e.getPoint());
+      getObjectAtPosition(pos).ifPresentOrElse(obj -> {
+        if (!e.isControlDown() && !GuiSettings.getSelectedObjects().contains(obj)) {
+          GuiSettings.getSelectedObjects().clear();
         }
         }
-        if(canvasMouseListener.canBeReplaced){
-            Rendering.drawReplacementSymbol(g2d, canvasMouseListener.selectedOnPressed);
+        state = State.Selection;
+        GuiSettings.getSelectedObjects().add(obj);
+        selectedOnPressed = obj;
+      }, () -> {
+        if (!e.isControlDown()) {
+          GuiSettings.getSelectedObjects().clear();
         }
         }
+        state = State.BoxSelection;
+        selectionBeforeBoxSelection = Set.copyOf(GuiSettings.getSelectedObjects());
+      });
+      control.OnSelectionChanged.broadcast();
+      lastPosition = pressedPosition = pos;
     }
     }
 
 
-
-    private void paintEdges(Graphics2D g2d) {
-        control.getModel().getEdgesOnCanvas().forEach(edge -> {
-            if (edge.getA().getGroupNode().isEmpty() || edge.getB().getGroupNode().isEmpty()) {
-                return;
-            }
-            boolean aInside = edge.getA().getGroupNode().get() == groupNode;
-            boolean bInside = edge.getB().getGroupNode().get() == groupNode;
-            //both
-            if (aInside && bInside) {
-                Rendering.drawEdge(g2d, edge, edge.getA(), edge.getB());
-            } else if (aInside) {
-                SearchObjectIfParentOfGroupNode(edge.getB()).ifPresentOrElse(
-                        alternative -> Rendering.drawEdge(g2d, edge, edge.getA(), alternative),
-                        () -> Rendering.drawExternConnection(g2d, edge.getA()));
-            } else if (bInside) {
-                SearchObjectIfParentOfGroupNode(edge.getA()).ifPresentOrElse(
-                        alternative -> Rendering.drawEdge(g2d, edge, alternative, edge.getB()),
-                        () -> Rendering.drawExternConnection(g2d, edge.getB()));
+    @Override
+    public void mouseDragged(MouseEvent e) {
+      if (!enabled) {
+        return;
+      }
+      log.finest(state.toString());
+      Vec2i actualPos = new Vec2i(e.getPoint());
+      switch (state) {
+        case Selection -> {
+          // Not handle to small mouse dragging
+          if (!(pressedPosition.getSquaredDistance(actualPos)
+              > GuiSettings.dragThresholdDistance)) {
+            return;
+          }
+          if (SwingUtilities.isLeftMouseButton(e)) {
+            state = State.ObjectDragging;
+          } else if (SwingUtilities.isRightMouseButton(e)
+              && !(selectedOnPressed instanceof GroupNode)) {
+            state = State.EdgeCreation;
+          }
+        }
+        case BoxSelection -> {
+          Rectangle selectionBox = getRectangleOfSelectionBox();
+          groupNode.getObjectsInThisLayer().forEach(obj -> {
+            Rectangle bounds = getBoundsOfObject(obj);
+            if (selectionBox.intersects(bounds) ^ selectionBeforeBoxSelection.contains(obj)) {
+              GuiSettings.getSelectedObjects().add(obj);
             } else {
             } else {
-                Optional<AbstractCanvasObject> alternativeA = SearchObjectIfParentOfGroupNode(edge.getA());
-                Optional<AbstractCanvasObject> alternativeB = SearchObjectIfParentOfGroupNode(edge.getB());
-                if (alternativeA.isPresent() && alternativeB.isPresent() && !alternativeA.equals(alternativeB)) {
-                    Rendering.drawEdge(g2d, edge, alternativeA.get(), alternativeB.get());
-                }
+              GuiSettings.getSelectedObjects().remove(obj);
             }
             }
-            //none
-        });
-    }
-
-    private Optional<AbstractCanvasObject> SearchObjectIfParentOfGroupNode(AbstractCanvasObject current) {
-        while (current.getGroupNode().isPresent()) {
-            if (current.getGroupNode().get() == this.groupNode) {
-                return Optional.of(current);
-            }
-            current = current.getGroupNode().get();
+          });
+          repaint();
         }
         }
-        return Optional.empty();
-    }
-
-    private Optional<AbstractCanvasObject> getObjectAtPosition(Vec2i pos) {
-        return groupNode.getObjectsInThisLayer().filter(obj ->
-                getBoundsOfObject(obj).contains(pos.getX(), pos.getY())
-        ).findAny();
+        case ObjectDragging -> {
+          Vec2i delta = actualPos.subtract(lastPosition);
+          GuiSettings.getSelectedObjects()
+              .forEach(obj -> obj.setPosition(boundsToCanvas(obj.getPosition().add(delta))));
+          canBeReplaced = checkForReplacement(actualPos).isPresent();
+          repaint();
+        }
+        case EdgeCreation -> repaint();
+      }
+      lastPosition = actualPos;
     }
     }
 
 
-    public static Vec2i boundsToCanvas(Vec2i pos){
-        Vec2i position = new Vec2i(pos);
-        position.clampX(GuiSettings.getPictureScaleDiv2(), GuiSettings.canvasSize.getX() - GuiSettings.getPictureScaleDiv2());
-        position.clampY(GuiSettings.getPictureScaleDiv2(), GuiSettings.canvasSize.getY() - GuiSettings.getPictureScaleDiv2());
-        return position;
+    private Optional<AbstractCanvasObject> checkForReplacement(Vec2i pos) {
+      return groupNode.getObjectsInThisLayer().filter(obj -> obj != selectedOnPressed &&
+          getBoundsOfObject(obj).contains(pos.getX(), pos.getY())
+      ).findAny();
     }
     }
 
 
-
-    /**
-     * Microsoft Windows10 selection & dragging behavior
-     */
-    private class CanvasMouseListener implements MouseListener, MouseMotionListener {
-        private Vec2i lastPosition = new Vec2i();
-        private Vec2i pressedPosition = new Vec2i();
-        private Set<AbstractCanvasObject> selectionBeforeBoxSelection = new HashSet<>();
-        private State state = State.None;
-        private AbstractCanvasObject selectedOnPressed = null;
-        private boolean canBeReplaced = false;
-
-
-
-
-        @Override
-        public void mousePressed(MouseEvent e) {
-            if (!enabled) {
-                return;
+    @Override
+    public void mouseReleased(MouseEvent e) {
+      if (!enabled) {
+        return;
+      }
+      log.info(state.toString());
+      switch (state) {
+        case None -> {
+          if (SwingUtilities.isRightMouseButton(e)) {
+            preparePopupMenu();
+            componentPopupMenu.show(Canvas.this, e.getX(), e.getY());
+          } else {
+            if (GuiSettings.getSelectedObjects().contains(selectedOnPressed)) {
+              control.removeObjectFromSelection(selectedOnPressed);
+            } else {
+              control.addObjectToSelection(selectedOnPressed);
             }
             }
-            log.finest(state.toString());
-
-            Vec2i pos = new Vec2i(e.getPoint());
-            getObjectAtPosition(pos).ifPresentOrElse(obj -> {
-                if (!e.isControlDown() && !GuiSettings.getSelectedObjects().contains(obj)) {
-                    GuiSettings.getSelectedObjects().clear();
-                }
-                state = State.Selection;
-                GuiSettings.getSelectedObjects().add(obj);
-                selectedOnPressed = obj;
-            }, () -> {
-                if (!e.isControlDown()) {
-                    GuiSettings.getSelectedObjects().clear();
-                }
-                state = State.BoxSelection;
-                selectionBeforeBoxSelection = Set.copyOf(GuiSettings.getSelectedObjects());
-            });
-            control.OnSelectionChanged.broadcast();
-            lastPosition = pressedPosition = pos;
+          }
         }
         }
-
-        @Override
-        public void mouseDragged(MouseEvent e) {
-            if (!enabled) {
-                return;
+        case Selection, BoxSelection -> {
+          control.OnSelectionChanged.broadcast();
+          if (SwingUtilities.isRightMouseButton(e)) {
+            preparePopupMenu();
+            componentPopupMenu.show(Canvas.this, e.getX(), e.getY());
+          }
+        }
+        case EdgeCreation -> getObjectAtPosition(lastPosition).ifPresentOrElse(obj -> {
+          boolean isGroupNode = obj instanceof GroupNode;
+          if (!isGroupNode) {
+            control.addEdgeOnCanvasOrRemoveExisting(
+                new Edge(selectedOnPressed, obj, GuiSettings.maxCapacityForNewCreatedEdges));
+          }
+        }, () -> {
+
+          Node node = new Node("Node");
+          groupNode.add(node);
+          final float splitDetectionDistance = 15f;
+          Geometry.Circle detectionCircle = new Geometry.Circle(new Vec2f(lastPosition),
+              splitDetectionDistance);
+          node.setPosition(new Vec2i(boundsToCanvas(lastPosition)));
+          for (Edge edge : control.getModel().getEdgesOnCanvas()) {
+            if (edge.getA().getGroupNode().isEmpty() || edge.getB().getGroupNode().isEmpty() ||
+                edge.getA().getGroupNode().get() != groupNode
+                || edge.getB().getGroupNode().get() != groupNode) {
+              continue;
             }
             }
-            log.finest(state.toString());
-            Vec2i actualPos = new Vec2i(e.getPoint());
-            switch (state) {
-                case Selection -> {
-                    // Not handle to small mouse dragging
-                    if (!(pressedPosition.getSquaredDistance(actualPos) > GuiSettings.dragThresholdDistance)) {
-                        return;
-                    }
-                    if (SwingUtilities.isLeftMouseButton(e)) {
-                        state = State.ObjectDragging;
-                    } else if (SwingUtilities.isRightMouseButton(e) && !(selectedOnPressed instanceof GroupNode)) {
-                        state = State.EdgeCreation;
-                    }
-                }
-                case BoxSelection -> {
-                    Rectangle selectionBox = getRectangleOfSelectionBox();
-                    groupNode.getObjectsInThisLayer().forEach(obj -> {
-                        Rectangle bounds = getBoundsOfObject(obj);
-                        if (selectionBox.intersects(bounds) ^ selectionBeforeBoxSelection.contains(obj)) {
-                            GuiSettings.getSelectedObjects().add(obj);
-                        } else {
-                            GuiSettings.getSelectedObjects().remove(obj);
-                        }
-                    });
-                    repaint();
-                }
-                case ObjectDragging -> {
-                    Vec2i delta = actualPos.subtract(lastPosition);
-                    GuiSettings.getSelectedObjects().forEach(obj -> obj.setPosition(boundsToCanvas(obj.getPosition().add(delta))));
-                    canBeReplaced = checkForReplacement(actualPos).isPresent();
-                    repaint();
-                }
-                case EdgeCreation -> repaint();
+            Optional<Vec2f> pos = Geometry.getProjectionOnSegmentIfInRange(
+                new Geometry.Line(new Vec2f(edge.getA().getPosition())
+                    , new Vec2f(edge.getB().getPosition())), detectionCircle);
+            if (pos.isPresent()) {
+              Vec2f position = pos.get();
+              node.setPosition(new Vec2i((int) position.getX(), (int) position.getY()));
+              splitEdge(edge, node);
+              break;
             }
             }
-            lastPosition = actualPos;
-        }
+          }
+          control.addEdgeOnCanvas(
+              new Edge(selectedOnPressed, node, GuiSettings.maxCapacityForNewCreatedEdges));
+          control.calculateStateForCurrentIteration();
+        });
+        case ObjectDragging -> checkForReplacement(new Vec2i(e.getPoint())).ifPresent(
+            obj -> control.replaceCanvasObject(obj, selectedOnPressed));
+      }
+      canBeReplaced = false;
+      state = State.None;
+      repaint();
+    }
 
 
-        private Optional<AbstractCanvasObject> checkForReplacement(Vec2i pos){
-            return groupNode.getObjectsInThisLayer().filter(obj -> obj != selectedOnPressed &&
-                    getBoundsOfObject(obj).contains(pos.getX(), pos.getY())
-            ).findAny();
+    private void preparePopupMenu() {
+      int count = GuiSettings.getSelectedObjects().size();
+      boolean isAGroupNodeSelected = GuiSettings.getSelectedObjects().stream()
+          .anyMatch(obj -> obj instanceof GroupNode);
+      switch (count) {
+        case 0 -> {
+          groupMenu.setEnabled(false);
+          ungroupMenu.setEnabled(false);
+          deleteMenu.setEnabled(false);
+          templateMenu.setEnabled(false);
         }
         }
-
-        @Override
-        public void mouseReleased(MouseEvent e) {
-            if (!enabled) {
-                return;
-            }
-            log.info(state.toString());
-            switch (state) {
-                case None -> {
-                    if(SwingUtilities.isRightMouseButton(e)){
-                        preparePopupMenu();
-                        componentPopupMenu.show(Canvas.this, e.getX(), e.getY());
-                    }else {
-                        if (GuiSettings.getSelectedObjects().contains(selectedOnPressed)) {
-                            control.removeObjectFromSelection(selectedOnPressed);
-                        } else {
-                            control.addObjectToSelection(selectedOnPressed);
-                        }
-                    }
-                }
-                case Selection, BoxSelection -> {
-                    control.OnSelectionChanged.broadcast();
-                    if(SwingUtilities.isRightMouseButton(e)){
-                        preparePopupMenu();
-                        componentPopupMenu.show(Canvas.this, e.getX(), e.getY());
-                    }
-                }
-                case EdgeCreation -> getObjectAtPosition(lastPosition).ifPresentOrElse(obj -> {
-                    boolean isGroupNode = obj instanceof GroupNode;
-                    if (!isGroupNode) {
-                        control.addEdgeOnCanvasOrRemoveExisting(new Edge(selectedOnPressed, obj, GuiSettings.maxCapacityForNewCreatedEdges));
-                    }
-                }, () -> {
-
-                    Node node = new Node("Node");
-                    groupNode.add(node);
-                    final float splitDetectionDistance = 15f;
-                    Geometry.Circle detectionCircle = new Geometry.Circle(new Vec2f(lastPosition), splitDetectionDistance);
-                    node.setPosition(new Vec2i(boundsToCanvas(lastPosition)));
-                    for(Edge edge : control.getModel().getEdgesOnCanvas()) {
-                        if(edge.getA().getGroupNode().isEmpty() || edge.getB().getGroupNode().isEmpty() ||
-                                edge.getA().getGroupNode().get() != groupNode || edge.getB().getGroupNode().get() != groupNode){
-                            continue;
-                        }
-                        Optional<Vec2f> pos = Geometry.getProjectionOnSegmentIfInRange(new Geometry.Line(new Vec2f(edge.getA().getPosition())
-                                , new Vec2f(edge.getB().getPosition())), detectionCircle);
-                        if(pos.isPresent()){
-                            Vec2f position = pos.get();
-                            node.setPosition(new Vec2i((int)position.getX(), (int)position.getY()));
-                            splitEdge(edge, node);
-                            break;
-                        }
-                    }
-                    control.addEdgeOnCanvas(new Edge(selectedOnPressed, node, GuiSettings.maxCapacityForNewCreatedEdges));
-                    control.calculateStateForCurrentIteration();
-                });
-                case ObjectDragging -> checkForReplacement(new Vec2i(e.getPoint())).ifPresent(obj -> control.replaceCanvasObject(obj, selectedOnPressed));
-            }
-            canBeReplaced = false;
-            state = State.None;
-            repaint();
+        case 1 -> {
+          deleteMenu.setEnabled(true);
+          boolean isSelectedObjectAHolonObject = GuiSettings.getSelectedObjects().stream()
+              .anyMatch(obj -> obj instanceof HolonObject);
+          templateMenu.setEnabled(isSelectedObjectAHolonObject);
+          groupMenu.setEnabled(true);
+          ungroupMenu.setEnabled(isAGroupNodeSelected);
         }
         }
-
-        private void preparePopupMenu(){
-            int count = GuiSettings.getSelectedObjects().size();
-            boolean isAGroupNodeSelected = GuiSettings.getSelectedObjects().stream().anyMatch(obj -> obj instanceof GroupNode);
-            switch (count){
-                case 0 -> {
-                    groupMenu.setEnabled(false);
-                    ungroupMenu.setEnabled(false);
-                    deleteMenu.setEnabled(false);
-                    templateMenu.setEnabled(false);
-                }
-                case 1 -> {
-                    deleteMenu.setEnabled(true);
-                    boolean isSelectedObjectAHolonObject = GuiSettings.getSelectedObjects().stream().anyMatch(obj -> obj instanceof HolonObject);
-                    templateMenu.setEnabled(isSelectedObjectAHolonObject);
-                    groupMenu.setEnabled(true);
-                    ungroupMenu.setEnabled(isAGroupNodeSelected);
-                }
-                default -> {
-                    deleteMenu.setEnabled(true);
-                    templateMenu.setEnabled(false);
-                    groupMenu.setEnabled(true);
-                    ungroupMenu.setEnabled(isAGroupNodeSelected);
-                }
-            }
+        default -> {
+          deleteMenu.setEnabled(true);
+          templateMenu.setEnabled(false);
+          groupMenu.setEnabled(true);
+          ungroupMenu.setEnabled(isAGroupNodeSelected);
         }
         }
+      }
+    }
 
 
 
 
-        @Override
-        public void mouseClicked(MouseEvent e) {
-            boolean doubleLeftClick = e.getClickCount() % 2 == 0 && SwingUtilities.isLeftMouseButton(e);
-            if (doubleLeftClick) {
-                log.finest(state.toString());
-                getObjectAtPosition(new Vec2i(e.getPoint())).ifPresent(obj -> {
-                    if (obj instanceof HolonSwitch sw) {
-                        sw.setMode(HolonSwitch.SwitchMode.Manual);
-                        sw.flipManualState();
-                        control.calculateStateForCurrentIteration();
-                    } else if (obj instanceof GroupNode gNode) {
-                        control.showGroupNode(gNode);
-                    }
-                });
-            }
-        }
-
+    @Override
+    public void mouseClicked(MouseEvent e) {
+      boolean doubleLeftClick = e.getClickCount() % 2 == 0 && SwingUtilities.isLeftMouseButton(e);
+      if (doubleLeftClick) {
+        log.finest(state.toString());
+        getObjectAtPosition(new Vec2i(e.getPoint())).ifPresent(obj -> {
+          if (obj instanceof HolonSwitch sw) {
+            sw.setMode(HolonSwitch.SwitchMode.Manual);
+            sw.flipManualState();
+            control.calculateStateForCurrentIteration();
+          } else if (obj instanceof GroupNode gNode) {
+            control.showGroupNode(gNode);
+          }
+        });
+      }
+    }
 
 
-        Rectangle getRectangleOfSelectionBox() {
-            return Geometry.createRectangleFromCorners(lastPosition, pressedPosition);
-        }
 
 
+    Rectangle getRectangleOfSelectionBox() {
+      return Geometry.createRectangleFromCorners(lastPosition, pressedPosition);
+    }
 
 
-        public void splitEdge(Edge edge, Node node){
-            AbstractCanvasObject end = edge.getB();
-            edge.setB(node);
-            Edge additional = new Edge(node, end, edge.maxCapacity);
-            control.getModel().addEdgeOnCanvas(additional);
-        }
 
 
-        @Override
-        public void mouseEntered(MouseEvent e) {
-        }
+    public void splitEdge(Edge edge, Node node) {
+      AbstractCanvasObject end = edge.getB();
+      edge.setB(node);
+      Edge additional = new Edge(node, end, edge.maxCapacity);
+      control.getModel().addEdgeOnCanvas(additional);
+    }
 
 
-        @Override
-        public void mouseExited(MouseEvent e) {
-        }
+    @Override
+    public void mouseEntered(MouseEvent e) {
+    }
 
 
-        @Override
-        public void mouseMoved(MouseEvent e) {
-        }
+    @Override
+    public void mouseExited(MouseEvent e) {
+    }
 
 
-        private enum State {
-            None, BoxSelection, EdgeCreation, ObjectDragging, Selection
-        }
+    @Override
+    public void mouseMoved(MouseEvent e) {
+    }
 
 
+    private enum State {
+      None, BoxSelection, EdgeCreation, ObjectDragging, Selection
     }
     }
+
+  }
 }
 }

+ 91 - 81
src/holeg/ui/view/canvas/CanvasCollectionPanel.java

@@ -5,104 +5,114 @@ import holeg.preferences.ImagePreference;
 import holeg.ui.controller.Control;
 import holeg.ui.controller.Control;
 import holeg.ui.model.GuiSettings;
 import holeg.ui.model.GuiSettings;
 import holeg.ui.view.image.Import;
 import holeg.ui.view.image.Import;
-
-import javax.swing.*;
-import javax.swing.event.ChangeEvent;
-import java.awt.*;
+import java.awt.Component;
+import java.awt.Dimension;
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Optional;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTabbedPane;
+import javax.swing.event.ChangeEvent;
 
 
 public class CanvasCollectionPanel extends JTabbedPane {
 public class CanvasCollectionPanel extends JTabbedPane {
-    private final Control control;
-    private final Map<Component, Canvas> componentCanvasMap = new HashMap<>();
-    private final Map<GroupNode, Component> groupNodeComponentMap = new HashMap<>();
-    private Canvas main;
-    private Canvas actual;
 
 
-    public CanvasCollectionPanel(Control control) {
-        this.control = control;
-        control.OnShowGroupNode.addListener(this::showGroupNode);
-        control.OnRemoveGroupNode.addListener(this::removeGroupNode);
-        control.OnModelChanged.addListener(this::reset);
-        createMainCanvas();
-        this.addChangeListener(this::tabChangeEvent);
-    }
+  private final Control control;
+  private final Map<Component, Canvas> componentCanvasMap = new HashMap<>();
+  private final Map<GroupNode, Component> groupNodeComponentMap = new HashMap<>();
+  private Canvas main;
+  private Canvas actual;
 
 
-    private void reset() {
-        removeAll();
-        componentCanvasMap.clear();
-        groupNodeComponentMap.clear();
-        createMainCanvas();
-    }
+  public CanvasCollectionPanel(Control control) {
+    this.control = control;
+    control.OnShowGroupNode.addListener(this::showGroupNode);
+    control.OnRemoveGroupNode.addListener(this::removeGroupNode);
+    control.OnModelChanged.addListener(this::reset);
+    createMainCanvas();
+    this.addChangeListener(this::tabChangeEvent);
+  }
+
+  private void reset() {
+    removeAll();
+    componentCanvasMap.clear();
+    groupNodeComponentMap.clear();
+    createMainCanvas();
+  }
 
 
 
 
-    public void resetCanvasSizes(){
-        Dimension dimension = new Dimension(GuiSettings.canvasSize.getX(), GuiSettings.canvasSize.getY());
-        for (Map.Entry<Component, Canvas> entry : componentCanvasMap.entrySet()) {
-            entry.getValue().setPreferredSize(dimension);
-            entry.getKey().revalidate();
-        }
+  public void resetCanvasSizes() {
+    Dimension dimension = new Dimension(GuiSettings.canvasSize.getX(),
+        GuiSettings.canvasSize.getY());
+    for (Map.Entry<Component, Canvas> entry : componentCanvasMap.entrySet()) {
+      entry.getValue().setPreferredSize(dimension);
+      entry.getKey().revalidate();
     }
     }
+  }
 
 
-    private void tabChangeEvent(ChangeEvent changeEvent) {
-        Optional.ofNullable(componentCanvasMap.get(this.getSelectedComponent())).ifPresentOrElse(canvas -> {
-            actual = canvas;
+  private void tabChangeEvent(ChangeEvent changeEvent) {
+    Optional.ofNullable(componentCanvasMap.get(this.getSelectedComponent()))
+        .ifPresentOrElse(canvas -> {
+          actual = canvas;
         }, () -> actual = main);
         }, () -> actual = main);
-        control.clearSelection();
-    }
+    control.clearSelection();
+  }
 
 
-    private void createMainCanvas() {
-        GroupNode mainGroupNode = control.getModel().getCanvas();
-        Canvas canvas = new Canvas(control, mainGroupNode);
-        actual = main = canvas;
-        final JScrollPane scrollPane = new JScrollPane(canvas);
-        groupNodeComponentMap.put(mainGroupNode, scrollPane);
-        componentCanvasMap.put(scrollPane, canvas);
-        this.addTab("Main", scrollPane);
-    }
+  private void createMainCanvas() {
+    GroupNode mainGroupNode = control.getModel().getCanvas();
+    Canvas canvas = new Canvas(control, mainGroupNode);
+    actual = main = canvas;
+    final JScrollPane scrollPane = new JScrollPane(canvas);
+    groupNodeComponentMap.put(mainGroupNode, scrollPane);
+    componentCanvasMap.put(scrollPane, canvas);
+    this.addTab("Main", scrollPane);
+  }
 
 
-    private void showGroupNode(GroupNode groupNode) {
-        Optional.ofNullable(groupNodeComponentMap.get(groupNode))
-                .ifPresentOrElse(this::setSelectedComponent,
-                        () -> createNewCanvas(groupNode));
-    }
+  private void showGroupNode(GroupNode groupNode) {
+    Optional.ofNullable(groupNodeComponentMap.get(groupNode))
+        .ifPresentOrElse(this::setSelectedComponent,
+            () -> createNewCanvas(groupNode));
+  }
 
 
-    private void createNewCanvas(GroupNode groupNode) {
-        Canvas canvas = new Canvas(control, groupNode);
-        final JScrollPane scrollPane = new JScrollPane(canvas);
-        groupNodeComponentMap.put(groupNode, scrollPane);
-        componentCanvasMap.put(scrollPane, canvas);
-        addTab(groupNode.getName(), scrollPane);
-        setSelectedComponent(scrollPane);
-        setTabComponentAt(this.indexOfComponent(scrollPane), new GroupNodeHeader(groupNode));
-    }
+  private void createNewCanvas(GroupNode groupNode) {
+    Canvas canvas = new Canvas(control, groupNode);
+    final JScrollPane scrollPane = new JScrollPane(canvas);
+    groupNodeComponentMap.put(groupNode, scrollPane);
+    componentCanvasMap.put(scrollPane, canvas);
+    addTab(groupNode.getName(), scrollPane);
+    setSelectedComponent(scrollPane);
+    setTabComponentAt(this.indexOfComponent(scrollPane), new GroupNodeHeader(groupNode));
+  }
 
 
-    private void removeGroupNode(GroupNode groupNode){
-        Optional.ofNullable(groupNodeComponentMap.get(groupNode))
-                .ifPresent(scrollPane -> {
-                    remove(scrollPane);
-                    groupNodeComponentMap.remove(groupNode);
-                });
-    }
+  private void removeGroupNode(GroupNode groupNode) {
+    Optional.ofNullable(groupNodeComponentMap.get(groupNode))
+        .ifPresent(scrollPane -> {
+          remove(scrollPane);
+          groupNodeComponentMap.remove(groupNode);
+        });
+  }
 
 
-    public Canvas getActualCanvas() {
-        return actual;
-    }
+  public Canvas getActualCanvas() {
+    return actual;
+  }
+
+  private class GroupNodeHeader extends JPanel {
 
 
-    private class GroupNodeHeader extends JPanel {
-        public GroupNodeHeader(GroupNode groupNode) {
-            JLabel label = new JLabel(groupNode.getName());
-            add(label);
-            label.setBorder(null);
-            label.setPreferredSize(new Dimension(label.getPreferredSize().width,8));
-            this.setBorder(null);
-            this.setOpaque(false);
-            JButton button = new JButton(new ImageIcon(Import.loadImage(ImagePreference.Button.GroupNode.Close, 8,8)));
-            button.setPreferredSize(new Dimension(8, 8));
-            button.setBorder(null);
-            add(button);
-            button.addActionListener(clicked -> removeGroupNode(groupNode));
-        }
+    public GroupNodeHeader(GroupNode groupNode) {
+      JLabel label = new JLabel(groupNode.getName());
+      add(label);
+      label.setBorder(null);
+      label.setPreferredSize(new Dimension(label.getPreferredSize().width, 8));
+      this.setBorder(null);
+      this.setOpaque(false);
+      JButton button = new JButton(
+          new ImageIcon(Import.loadImage(ImagePreference.Button.GroupNode.Close, 8, 8)));
+      button.setPreferredSize(new Dimension(8, 8));
+      button.setBorder(null);
+      add(button);
+      button.addActionListener(clicked -> removeGroupNode(groupNode));
     }
     }
+  }
 }
 }

+ 227 - 192
src/holeg/ui/view/canvas/Rendering.java

@@ -1,6 +1,11 @@
 package holeg.ui.view.canvas;
 package holeg.ui.view.canvas;
 
 
-import holeg.model.*;
+import holeg.model.AbstractCanvasObject;
+import holeg.model.Edge;
+import holeg.model.GroupNode;
+import holeg.model.HolonObject;
+import holeg.model.HolonSwitch;
+import holeg.model.Node;
 import holeg.preferences.ColorPreference;
 import holeg.preferences.ColorPreference;
 import holeg.preferences.ImagePreference;
 import holeg.preferences.ImagePreference;
 import holeg.ui.model.GuiSettings;
 import holeg.ui.model.GuiSettings;
@@ -8,226 +13,256 @@ import holeg.ui.view.image.Import;
 import holeg.ui.view.main.Appearance;
 import holeg.ui.view.main.Appearance;
 import holeg.utility.math.decimal.Format;
 import holeg.utility.math.decimal.Format;
 import holeg.utility.math.vector.Vec2i;
 import holeg.utility.math.vector.Vec2i;
-
-import java.awt.*;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
 
 
 
 
 class Rendering {
 class Rendering {
-    private static final RenderingHints RenderingHint = new RenderingHints(RenderingHints.KEY_ANTIALIASING,
-            RenderingHints.VALUE_ANTIALIAS_ON);
-    private static final Font CanvasFont = new Font("TimesNewRoman", Font.PLAIN,
-            Math.max((int) (GuiSettings.getPictureScale() / 3.5f), 10));
-    private static final BasicStroke OnePixelStroke = new BasicStroke(1);
-    private static final BasicStroke TwoPixelStroke = new BasicStroke(2);
-    private static final Dimension SupplyBarDimensions = new Dimension(GuiSettings.getPictureScale(), GuiSettings.getPictureScale() / 5);
-    private static final Font SupplyBarFont = new Font("TimesNewRoman", Font.PLAIN, (int) (GuiSettings.getPictureScale() * 0.3) - 2);
-
-    private static final Color[] GroupNodeBarColors = {ColorPreference.HolonObject.Producer, ColorPreference.HolonObject.NotSupplied,
-            ColorPreference.HolonObject.PartiallySupplied, ColorPreference.HolonObject.Supplied,
-            ColorPreference.HolonObject.OverSupplied, ColorPreference.HolonObject.NoEnergy};
-
-    static Graphics2D initGraphics2D(Graphics g) {
-        Graphics2D g2d = (Graphics2D) g;
-        g2d.setRenderingHints(RenderingHint);
-        g2d.setFont(CanvasFont);
-        return g2d;
-    }
 
 
-    static void drawSwitchObject(Graphics2D g, HolonSwitch hS) {
-        drawCanvasObject(g, hS);
-    }
+  private static final RenderingHints RenderingHint = new RenderingHints(
+      RenderingHints.KEY_ANTIALIASING,
+      RenderingHints.VALUE_ANTIALIAS_ON);
+  private static final Font CanvasFont = new Font("TimesNewRoman", Font.PLAIN,
+      Math.max((int) (GuiSettings.getPictureScale() / 3.5f), 10));
+  private static final BasicStroke OnePixelStroke = new BasicStroke(1);
+  private static final BasicStroke TwoPixelStroke = new BasicStroke(2);
+  private static final Dimension SupplyBarDimensions = new Dimension(GuiSettings.getPictureScale(),
+      GuiSettings.getPictureScale() / 5);
+  private static final Font SupplyBarFont = new Font("TimesNewRoman", Font.PLAIN,
+      (int) (GuiSettings.getPictureScale() * 0.3) - 2);
 
 
-    static void drawHolonObject(Graphics2D g, HolonObject hO) {
-        Vec2i pos = hO.getPosition();
-        Color stateColor = ColorPreference.HolonObject.getStateColor(hO.getState());
-        g.setColor(ColorPreference.Canvas.HolonObjectEnergy);
-        if(Appearance.canvasObjectEnergyVisible){
-            final int gapBetweenRectAndEnergyString = 1;
-            g.drawString(Format.doubleTwoPlaces(hO.getActualEnergy()),pos.getX() - GuiSettings.getPictureScaleDiv2(),
-                    pos.getY() - GuiSettings.getPictureScaleDiv2() - gapBetweenRectAndEnergyString);
-        }
-        g.setColor(stateColor);
-        g.fillRect(pos.getX() - GuiSettings.getPictureScaleDiv2(), pos.getY() - GuiSettings.getPictureScaleDiv2(),
-                GuiSettings.getPictureScale(), GuiSettings.getPictureScale());
-        drawCanvasObject(g, hO.getImagePath(), pos);
-        if (Appearance.supplyBarVisible && (hO.isConsumer() && !hO.getState().equals(HolonObject.HolonObjectState.NO_ENERGY) )) {
-            drawSupplyBar(g, hO.getSupplyBarPercentage(), stateColor, pos);
-        }
-    }
+  private static final Color[] GroupNodeBarColors = {ColorPreference.HolonObject.Producer,
+      ColorPreference.HolonObject.NotSupplied,
+      ColorPreference.HolonObject.PartiallySupplied, ColorPreference.HolonObject.Supplied,
+      ColorPreference.HolonObject.OverSupplied, ColorPreference.HolonObject.NoEnergy};
 
 
-    static void drawCanvasObject(Graphics2D g, AbstractCanvasObject obj) {
-        drawCanvasObject(g, obj.getImagePath(), obj.getPosition());
-    }
-
-    static void drawCanvasObject(Graphics2D g, String imageName, Vec2i pos) {
-        int pictureScale = GuiSettings.getPictureScale();
-        int pictureScaleDiv2 = GuiSettings.getPictureScaleDiv2();
-        Image image = Import.loadImage(imageName, pictureScale, pictureScale);
-        g.drawImage(image, pos.getX() - pictureScaleDiv2, pos.getY() - pictureScaleDiv2, pictureScale, pictureScale,
-                null);
-    }
+  static Graphics2D initGraphics2D(Graphics g) {
+    Graphics2D g2d = (Graphics2D) g;
+    g2d.setRenderingHints(RenderingHint);
+    g2d.setFont(CanvasFont);
+    return g2d;
+  }
 
 
+  static void drawSwitchObject(Graphics2D g, HolonSwitch hS) {
+    drawCanvasObject(g, hS);
+  }
 
 
-    static void drawNode(Graphics2D g, Node node) {
-        Vec2i pos = node.getPosition();
-        drawCanvasObject(g, ImagePreference.Canvas.Node.Unselected, pos);
+  static void drawHolonObject(Graphics2D g, HolonObject hO) {
+    Vec2i pos = hO.getPosition();
+    Color stateColor = ColorPreference.HolonObject.getStateColor(hO.getState());
+    g.setColor(ColorPreference.Canvas.HolonObjectEnergy);
+    if (Appearance.canvasObjectEnergyVisible) {
+      final int gapBetweenRectAndEnergyString = 1;
+      g.drawString(Format.doubleTwoPlaces(hO.getActualEnergy()),
+          pos.getX() - GuiSettings.getPictureScaleDiv2(),
+          pos.getY() - GuiSettings.getPictureScaleDiv2() - gapBetweenRectAndEnergyString);
     }
     }
-
-    static void drawEdge(Graphics2D g, Edge edge, AbstractCanvasObject a, AbstractCanvasObject b) {
-        Vec2i start = a.getPosition();
-        Vec2i end = b.getPosition();
-        float currentEnergy = edge.getActualFlow();
-        float capacity = edge.maxCapacity;
-        boolean unlimited = edge.mode == Edge.EdgeMode.Unlimited;
-        switch (edge.getState()) {
-            case Burned -> {
-                g.setColor(ColorPreference.Edge.Burned);
-                g.setStroke(TwoPixelStroke);
-            }
-            case Working -> {
-                g.setColor(ColorPreference.Edge.Working);
-                g.setStroke(new BasicStroke(unlimited ? 2f : (currentEnergy / capacity * 2f) + 1));
-            }
-        }
-        g.drawLine(start.getX(), start.getY(), end.getX(), end.getY());
-        Vec2i middle = new Vec2i((start.getX() + end.getX()) / 2, (start.getY() + end.getY()) / 2);
-        if(Appearance.edgeCapacityVisible){
-            g.drawString(currentEnergy + "/" + (unlimited ? "\u221E" : capacity), middle.getX(), middle.getY());
-        }
+    g.setColor(stateColor);
+    g.fillRect(pos.getX() - GuiSettings.getPictureScaleDiv2(),
+        pos.getY() - GuiSettings.getPictureScaleDiv2(),
+        GuiSettings.getPictureScale(), GuiSettings.getPictureScale());
+    drawCanvasObject(g, hO.getImagePath(), pos);
+    if (Appearance.supplyBarVisible && (hO.isConsumer() && !hO.getState()
+        .equals(HolonObject.HolonObjectState.NO_ENERGY))) {
+      drawSupplyBar(g, hO.getSupplyBarPercentage(), stateColor, pos);
     }
     }
+  }
 
 
-    static void drawExternConnection(Graphics2D g, AbstractCanvasObject object) {
-        Vec2i pos = object.getPosition();
-        Dimension size = new Dimension(16, 16);
-        Image image = Import.loadImage(ImagePreference.Canvas.ExternSymbol, size.width, size.height);
-        g.drawImage(image, pos.getX() + GuiSettings.getPictureScaleDiv2(), pos.getY() - GuiSettings.getPictureScaleDiv2() - size.height,
-                size.width, size.height, null);
-    }
+  static void drawCanvasObject(Graphics2D g, AbstractCanvasObject obj) {
+    drawCanvasObject(g, obj.getImagePath(), obj.getPosition());
+  }
+
+  static void drawCanvasObject(Graphics2D g, String imageName, Vec2i pos) {
+    int pictureScale = GuiSettings.getPictureScale();
+    int pictureScaleDiv2 = GuiSettings.getPictureScaleDiv2();
+    Image image = Import.loadImage(imageName, pictureScale, pictureScale);
+    g.drawImage(image, pos.getX() - pictureScaleDiv2, pos.getY() - pictureScaleDiv2, pictureScale,
+        pictureScale,
+        null);
+  }
 
 
 
 
-    static void drawNewEdgeLine(Graphics2D g, Vec2i start, Vec2i end) {
+  static void drawNode(Graphics2D g, Node node) {
+    Vec2i pos = node.getPosition();
+    drawCanvasObject(g, ImagePreference.Canvas.Node.Unselected, pos);
+  }
+
+  static void drawEdge(Graphics2D g, Edge edge, AbstractCanvasObject a, AbstractCanvasObject b) {
+    Vec2i start = a.getPosition();
+    Vec2i end = b.getPosition();
+    float currentEnergy = edge.getActualFlow();
+    float capacity = edge.maxCapacity;
+    boolean unlimited = edge.mode == Edge.EdgeMode.Unlimited;
+    switch (edge.getState()) {
+      case Burned -> {
+        g.setColor(ColorPreference.Edge.Burned);
         g.setStroke(TwoPixelStroke);
         g.setStroke(TwoPixelStroke);
+      }
+      case Working -> {
         g.setColor(ColorPreference.Edge.Working);
         g.setColor(ColorPreference.Edge.Working);
-        g.drawLine(start.getX(), start.getY(), end.getX(), end.getY());
+        g.setStroke(new BasicStroke(unlimited ? 2f : (currentEnergy / capacity * 2f) + 1));
+      }
+    }
+    g.drawLine(start.getX(), start.getY(), end.getX(), end.getY());
+    Vec2i middle = new Vec2i((start.getX() + end.getX()) / 2, (start.getY() + end.getY()) / 2);
+    if (Appearance.edgeCapacityVisible) {
+      g.drawString(currentEnergy + "/" + (unlimited ? "\u221E" : capacity), middle.getX(),
+          middle.getY());
     }
     }
+  }
 
 
+  static void drawExternConnection(Graphics2D g, AbstractCanvasObject object) {
+    Vec2i pos = object.getPosition();
+    Dimension size = new Dimension(16, 16);
+    Image image = Import.loadImage(ImagePreference.Canvas.ExternSymbol, size.width, size.height);
+    g.drawImage(image, pos.getX() + GuiSettings.getPictureScaleDiv2(),
+        pos.getY() - GuiSettings.getPictureScaleDiv2() - size.height,
+        size.width, size.height, null);
+  }
 
 
-    static void drawGroupNode(Graphics2D g, GroupNode groupNode) {
-        Vec2i pos = groupNode.getPosition();
-        g.setColor(Color.gray);
-        g.fillRect(pos.getX() - GuiSettings.getPictureScaleDiv2(), pos.getY() - GuiSettings.getPictureScaleDiv2(),
-                GuiSettings.getPictureScale(), GuiSettings.getPictureScale());
-        drawCanvasObject(g, groupNode.getImagePath(), pos);
-        drawGroupNodeBar(g, groupNode, pos);
-    }
 
 
-    static void drawSelection(Graphics2D g) {
-        g.setStroke(OnePixelStroke);
-        for (AbstractCanvasObject aCps : GuiSettings.getSelectedObjects()) {
-            Vec2i pos = aCps.getPosition();
-            if (aCps instanceof Node) {
-                g.setColor(ColorPreference.Canvas.ObjectSelectionFill);
-                g.fillOval(pos.getX() - (GuiSettings.getPictureScaleDiv2()),
-                        pos.getY() - (GuiSettings.getPictureScaleDiv2()), GuiSettings.getPictureScale(), GuiSettings.getPictureScale());
-                g.setColor(ColorPreference.Canvas.ObjectSelectionBorder);
-                g.drawOval(pos.getX() - (GuiSettings.getPictureScaleDiv2()),
-                        pos.getY() - (GuiSettings.getPictureScaleDiv2()), GuiSettings.getPictureScale(), GuiSettings.getPictureScale());
-            } else {
-                g.setColor(ColorPreference.Canvas.ObjectSelectionFill);
-                g.fillRect(pos.getX() - (int) (GuiSettings.getPictureScaleDiv2() * 1.5f),
-                        pos.getY() - (int) (GuiSettings.getPictureScaleDiv2() * 1.5f), (int) (GuiSettings.getPictureScale() * 1.5f),
-                        (int) (GuiSettings.getPictureScale() * 1.5f));
-                g.setColor(ColorPreference.Canvas.ObjectSelectionBorder);
-                g.drawRect(pos.getX() - (int) (GuiSettings.getPictureScaleDiv2() * 1.5f),
-                        pos.getY() - (int) (GuiSettings.getPictureScaleDiv2() * 1.5f), (int) (GuiSettings.getPictureScale() * 1.5f),
-                        (int) (GuiSettings.getPictureScale() * 1.5f));
-            }
-        }
-    }
+  static void drawNewEdgeLine(Graphics2D g, Vec2i start, Vec2i end) {
+    g.setStroke(TwoPixelStroke);
+    g.setColor(ColorPreference.Edge.Working);
+    g.drawLine(start.getX(), start.getY(), end.getX(), end.getY());
+  }
+
 
 
-    static void drawSelectionBox(Graphics2D g, Rectangle selectionBox) {
-        g.setStroke(OnePixelStroke);
-        g.setColor(ColorPreference.Canvas.MouseSelectionBorder);
-        g.draw(selectionBox);
-        g.setColor(ColorPreference.Canvas.MouseSelectionFill);
-        g.fill(selectionBox);
+  static void drawGroupNode(Graphics2D g, GroupNode groupNode) {
+    Vec2i pos = groupNode.getPosition();
+    g.setColor(Color.gray);
+    g.fillRect(pos.getX() - GuiSettings.getPictureScaleDiv2(),
+        pos.getY() - GuiSettings.getPictureScaleDiv2(),
+        GuiSettings.getPictureScale(), GuiSettings.getPictureScale());
+    drawCanvasObject(g, groupNode.getImagePath(), pos);
+    drawGroupNodeBar(g, groupNode, pos);
+  }
 
 
+  static void drawSelection(Graphics2D g) {
+    g.setStroke(OnePixelStroke);
+    for (AbstractCanvasObject aCps : GuiSettings.getSelectedObjects()) {
+      Vec2i pos = aCps.getPosition();
+      if (aCps instanceof Node) {
+        g.setColor(ColorPreference.Canvas.ObjectSelectionFill);
+        g.fillOval(pos.getX() - (GuiSettings.getPictureScaleDiv2()),
+            pos.getY() - (GuiSettings.getPictureScaleDiv2()), GuiSettings.getPictureScale(),
+            GuiSettings.getPictureScale());
+        g.setColor(ColorPreference.Canvas.ObjectSelectionBorder);
+        g.drawOval(pos.getX() - (GuiSettings.getPictureScaleDiv2()),
+            pos.getY() - (GuiSettings.getPictureScaleDiv2()), GuiSettings.getPictureScale(),
+            GuiSettings.getPictureScale());
+      } else {
+        g.setColor(ColorPreference.Canvas.ObjectSelectionFill);
+        g.fillRect(pos.getX() - (int) (GuiSettings.getPictureScaleDiv2() * 1.5f),
+            pos.getY() - (int) (GuiSettings.getPictureScaleDiv2() * 1.5f),
+            (int) (GuiSettings.getPictureScale() * 1.5f),
+            (int) (GuiSettings.getPictureScale() * 1.5f));
+        g.setColor(ColorPreference.Canvas.ObjectSelectionBorder);
+        g.drawRect(pos.getX() - (int) (GuiSettings.getPictureScaleDiv2() * 1.5f),
+            pos.getY() - (int) (GuiSettings.getPictureScaleDiv2() * 1.5f),
+            (int) (GuiSettings.getPictureScale() * 1.5f),
+            (int) (GuiSettings.getPictureScale() * 1.5f));
+      }
     }
     }
+  }
+
+  static void drawSelectionBox(Graphics2D g, Rectangle selectionBox) {
+    g.setStroke(OnePixelStroke);
+    g.setColor(ColorPreference.Canvas.MouseSelectionBorder);
+    g.draw(selectionBox);
+    g.setColor(ColorPreference.Canvas.MouseSelectionFill);
+    g.fill(selectionBox);
+
+  }
 
 
-    private static void drawSupplyBar(Graphics2D g, float percentage, Color color, Vec2i pos) {
-        // +1, -2, -1 little Adjustment for pixel perfect alignment
-        g.setColor(Color.WHITE);
-        g.fillRect(pos.getX() - GuiSettings.getPictureScaleDiv2(), pos.getY() + GuiSettings.getPictureScaleDiv2() - 1, SupplyBarDimensions.width,
-                SupplyBarDimensions.height);
-        g.setColor(color);
-        g.fillRect(pos.getX() - GuiSettings.getPictureScaleDiv2(), pos.getY() + GuiSettings.getPictureScaleDiv2() - 1,
-                (int) (SupplyBarDimensions.width * (percentage < 1 ? percentage : 1.0f) - 1), SupplyBarDimensions.height);
-        g.setColor(Color.BLACK);
-        g.setStroke(new BasicStroke(1));
-        g.drawRect(pos.getX() - GuiSettings.getPictureScaleDiv2(), pos.getY() + GuiSettings.getPictureScaleDiv2() - 1, SupplyBarDimensions.width - 1,
-                SupplyBarDimensions.height);
-        g.setFont(SupplyBarFont);
-        String percentageString = (Math.round((percentage * 100))) + "%";
-        int stringWidth = (int) g.getFontMetrics().getStringBounds(percentageString, g).getWidth();
-        if (percentage > 1.0f) {
-            g.setColor(Color.WHITE); // Just to see better on purple
-        }
-        g.drawString(percentageString, pos.getX() + 1 - stringWidth / 2,
-                pos.getY() + GuiSettings.getPictureScaleDiv2() - 1 + SupplyBarDimensions.height);
+  private static void drawSupplyBar(Graphics2D g, float percentage, Color color, Vec2i pos) {
+    // +1, -2, -1 little Adjustment for pixel perfect alignment
+    g.setColor(Color.WHITE);
+    g.fillRect(pos.getX() - GuiSettings.getPictureScaleDiv2(),
+        pos.getY() + GuiSettings.getPictureScaleDiv2() - 1, SupplyBarDimensions.width,
+        SupplyBarDimensions.height);
+    g.setColor(color);
+    g.fillRect(pos.getX() - GuiSettings.getPictureScaleDiv2(),
+        pos.getY() + GuiSettings.getPictureScaleDiv2() - 1,
+        (int) (SupplyBarDimensions.width * (percentage < 1 ? percentage : 1.0f) - 1),
+        SupplyBarDimensions.height);
+    g.setColor(Color.BLACK);
+    g.setStroke(new BasicStroke(1));
+    g.drawRect(pos.getX() - GuiSettings.getPictureScaleDiv2(),
+        pos.getY() + GuiSettings.getPictureScaleDiv2() - 1, SupplyBarDimensions.width - 1,
+        SupplyBarDimensions.height);
+    g.setFont(SupplyBarFont);
+    String percentageString = (Math.round((percentage * 100))) + "%";
+    int stringWidth = (int) g.getFontMetrics().getStringBounds(percentageString, g).getWidth();
+    if (percentage > 1.0f) {
+      g.setColor(Color.WHITE); // Just to see better on purple
     }
     }
+    g.drawString(percentageString, pos.getX() + 1 - stringWidth / 2,
+        pos.getY() + GuiSettings.getPictureScaleDiv2() - 1 + SupplyBarDimensions.height);
+  }
+
+  private static void drawGroupNodeBar(Graphics2D g, GroupNode groupNode, Vec2i pos) {
+    // +1, -2, -1 little Adjustment for pixel perfect alignment
+    g.setColor(Color.WHITE);
+    g.fillRect(pos.getX() - GuiSettings.getPictureScaleDiv2(),
+        pos.getY() + GuiSettings.getPictureScaleDiv2() - 1, (int) SupplyBarDimensions.width,
+        SupplyBarDimensions.height);
+    float[] percentages = getGroupNodeBarPercentages(groupNode);
 
 
-    private static void drawGroupNodeBar(Graphics2D g, GroupNode groupNode, Vec2i pos) {
-	// +1, -2, -1 little Adjustment for pixel perfect alignment
-	g.setColor(Color.WHITE);
-	g.fillRect(pos.getX() - GuiSettings.getPictureScaleDiv2(), pos.getY() + GuiSettings.getPictureScaleDiv2() - 1, (int) SupplyBarDimensions.width,
-			SupplyBarDimensions.height);
-	float[] percentages = getGroupNodeBarPercentages(groupNode);
-
-	for (int i = 5; i >= 0; i--) {
-		g.setColor(GroupNodeBarColors[i]);
-		g.fillRect(pos.getX() - GuiSettings.getPictureScaleDiv2(), pos.getY() + GuiSettings.getPictureScaleDiv2() - 1,
-				(int) (SupplyBarDimensions.width * percentages[i] - 1), SupplyBarDimensions.height);
-	}
+    for (int i = 5; i >= 0; i--) {
+      g.setColor(GroupNodeBarColors[i]);
+      g.fillRect(pos.getX() - GuiSettings.getPictureScaleDiv2(),
+          pos.getY() + GuiSettings.getPictureScaleDiv2() - 1,
+          (int) (SupplyBarDimensions.width * percentages[i] - 1), SupplyBarDimensions.height);
+    }
     g.setColor(Color.BLACK);
     g.setColor(Color.BLACK);
-	g.setStroke(new BasicStroke(1));
-	g.drawRect(pos.getX() - GuiSettings.getPictureScaleDiv2(), pos.getY() + GuiSettings.getPictureScaleDiv2() - 1, SupplyBarDimensions.width - 1,
-			SupplyBarDimensions.height);
-}
+    g.setStroke(new BasicStroke(1));
+    g.drawRect(pos.getX() - GuiSettings.getPictureScaleDiv2(),
+        pos.getY() + GuiSettings.getPictureScaleDiv2() - 1, SupplyBarDimensions.width - 1,
+        SupplyBarDimensions.height);
+  }
 
 
-/**
- * HardCoded Stuff
- */
-public static float[] getGroupNodeBarPercentages(GroupNode groupNode) {
-	int[] amountOfObjects = new int[6];
+  /**
+   * HardCoded Stuff
+   */
+  public static float[] getGroupNodeBarPercentages(GroupNode groupNode) {
+    int[] amountOfObjects = new int[6];
     groupNode.getAllHolonObjectsRecursive().forEach(hO -> {
     groupNode.getAllHolonObjectsRecursive().forEach(hO -> {
-        switch (hO.getState()){
-            case PRODUCER -> amountOfObjects[0]++;
-            case NOT_SUPPLIED -> amountOfObjects[1]++;
-            case PARTIALLY_SUPPLIED -> amountOfObjects[2]++;
-            case SUPPLIED -> amountOfObjects[3]++;
-            case OVER_SUPPLIED -> amountOfObjects[4]++;
-            case NO_ENERGY -> amountOfObjects[5]++;
-        }
+      switch (hO.getState()) {
+        case PRODUCER -> amountOfObjects[0]++;
+        case NOT_SUPPLIED -> amountOfObjects[1]++;
+        case PARTIALLY_SUPPLIED -> amountOfObjects[2]++;
+        case SUPPLIED -> amountOfObjects[3]++;
+        case OVER_SUPPLIED -> amountOfObjects[4]++;
+        case NO_ENERGY -> amountOfObjects[5]++;
+      }
     });
     });
-	int countHolonObjects = amountOfObjects[0] + amountOfObjects[1] + amountOfObjects[2] + amountOfObjects[3]
-			+ amountOfObjects[4] + amountOfObjects[5];
-	float[] percentages = new float[6];
-	int count = 0;
-	for (int i = 0; i < 6; i++) {
-		count += amountOfObjects[i];
-		percentages[i] = (float) count / (float) countHolonObjects;
-	}
-	return percentages;
-}
-
-
+    int countHolonObjects =
+        amountOfObjects[0] + amountOfObjects[1] + amountOfObjects[2] + amountOfObjects[3]
+            + amountOfObjects[4] + amountOfObjects[5];
+    float[] percentages = new float[6];
+    int count = 0;
+    for (int i = 0; i < 6; i++) {
+      count += amountOfObjects[i];
+      percentages[i] = (float) count / (float) countHolonObjects;
+    }
+    return percentages;
+  }
 
 
 
 
-    public static void drawReplacementSymbol(Graphics2D g, AbstractCanvasObject hoveredObject) {
-        Vec2i pos = hoveredObject.getPosition();
-        Dimension size = new Dimension(16, 16);
-        Image image = Import.loadImage(ImagePreference.Canvas.ReplaceSymbol, size.width, size.height);
-        g.drawImage(image, pos.getX() - GuiSettings.getPictureScaleDiv2() -size.width, pos.getY() - GuiSettings.getPictureScaleDiv2() - size.height,
-                size.width, size.height, null);
-    }
+  public static void drawReplacementSymbol(Graphics2D g, AbstractCanvasObject hoveredObject) {
+    Vec2i pos = hoveredObject.getPosition();
+    Dimension size = new Dimension(16, 16);
+    Image image = Import.loadImage(ImagePreference.Canvas.ReplaceSymbol, size.width, size.height);
+    g.drawImage(image, pos.getX() - GuiSettings.getPictureScaleDiv2() - size.width,
+        pos.getY() - GuiSettings.getPictureScaleDiv2() - size.height,
+        size.width, size.height, null);
+  }
 }
 }

+ 58 - 63
src/holeg/ui/view/category/Category.java

@@ -1,80 +1,75 @@
 package holeg.ui.view.category;
 package holeg.ui.view.category;
+
+import holeg.model.AbstractCanvasObject;
 import java.util.HashSet;
 import java.util.HashSet;
 import java.util.Optional;
 import java.util.Optional;
 import java.util.Set;
 import java.util.Set;
 
 
-import com.google.gson.annotations.Expose;
-
-import holeg.model.AbstractCanvasObject;
-
 /**
 /**
- * Class "Category" performs the functionality of listing elements into groups.
- * Each Category contains an ArrayList of CpsObjects, a name and a HashMap of
- * ObjIdx.
- * 
- * @author Gruppe14
+ * Class "Category" performs the functionality of listing elements into groups. Each Category
+ * contains an ArrayList of CpsObjects, a name and a HashMap of ObjIdx.
  *
  *
+ * @author Gruppe14
  */
  */
 
 
 public class Category {
 public class Category {
-	// objects: is a ArrayList of all Objects that belongs to the Category
-	private Set<AbstractCanvasObject> objects = new HashSet<AbstractCanvasObject>();
-	// name: is a String chosen by the User
-	private String name; 
 
 
-	/**
-	 * Category Constructor.
-	 * 
-	 * @param name name of the Category
-	 */
-	public Category(String name) {
-		setName(name);
-	}
+  // objects: is a ArrayList of all Objects that belongs to the Category
+  private Set<AbstractCanvasObject> objects = new HashSet<AbstractCanvasObject>();
+  // name: is a String chosen by the User
+  private String name;
+
+  /**
+   * Category Constructor.
+   *
+   * @param name name of the Category
+   */
+  public Category(String name) {
+    setName(name);
+  }
+
+  /**
+   * Getter for all CpsObjects.
+   *
+   * @return the objects
+   */
+  public Set<AbstractCanvasObject> getObjects() {
+    return objects;
+  }
+
+  /**
+   * Set a new ArrayList of CpsObjects.
+   *
+   * @param objects the objects to set
+   */
+  public void setObjects(Set<AbstractCanvasObject> objects) {
+    this.objects = objects;
+  }
 
 
-	/**
-	 * Getter for all CpsObjects.
-	 * 
-	 * @return the objects
-	 */
-	public Set<AbstractCanvasObject> getObjects() {
-		return objects;
-	}
+  /**
+   * Getter the name of the Category.
+   *
+   * @return the name
+   */
+  public String getName() {
+    return name;
+  }
 
 
-	/**
-	 * Set a new ArrayList of CpsObjects.
-	 * 
-	 * @param objects
-	 *            the objects to set
-	 */
-	public void setObjects(Set<AbstractCanvasObject> objects) {
-		this.objects = objects;
-	}
+  /**
+   * Set the name of the Category to a new one.
+   *
+   * @param name the name to set
+   */
+  public void setName(String name) {
+    this.name = name;
+  }
 
 
-	/**
-	 * Getter the name of the Category.
-	 * 
-	 * @return the name
-	 */
-	public String getName() {
-		return name;
-	}
 
 
-	/**
-	 * Set the name of the Category to a new one.
-	 * 
-	 * @param name
-	 *            the name to set
-	 */
-	public void setName(String name) {
-		this.name = name;
-	}
+  public Optional<AbstractCanvasObject> findObjectWithName(String name) {
+    return objects.stream().filter(obj -> obj.getName().equals(name)).findFirst();
+  }
 
 
-	
-	public Optional<AbstractCanvasObject> findObjectWithName(String name){
-		return objects.stream().filter(obj -> obj.getName().equals(name)).findFirst();
-	}
-	
-	public boolean removeObjectsWithName(String name){
-		return objects.removeIf(obj -> obj.getName().equals(name));
-	}
+  public boolean removeObjectsWithName(String name) {
+    return objects.removeIf(obj -> obj.getName().equals(name));
+  }
 }
 }

+ 230 - 206
src/holeg/ui/view/category/CategoryPanel.java

@@ -12,243 +12,267 @@ import holeg.ui.view.dialog.AddObjectPopUp;
 import holeg.ui.view.dialog.NewCategoryDialog;
 import holeg.ui.view.dialog.NewCategoryDialog;
 import holeg.ui.view.image.Import;
 import holeg.ui.view.image.Import;
 import holeg.ui.view.main.Gui;
 import holeg.ui.view.main.Gui;
-
-import javax.swing.*;
-import javax.swing.tree.DefaultMutableTreeNode;
-import javax.swing.tree.DefaultTreeModel;
-import javax.swing.tree.TreeCellRenderer;
-import java.awt.*;
+import java.awt.Component;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.Image;
+import java.awt.Point;
+import java.awt.Toolkit;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseEvent;
 import java.util.Optional;
 import java.util.Optional;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
+import javax.swing.BoxLayout;
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JScrollPane;
+import javax.swing.JTree;
+import javax.swing.SwingUtilities;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreeCellRenderer;
 
 
 public class CategoryPanel extends JScrollPane {
 public class CategoryPanel extends JScrollPane {
-    private static final Logger log = Logger.getLogger(CategoryPanel.class.getName());
-    private final static int NODE_SIZE = 25;
-    private final Control control;
-    private final Gui gui;
-    private final JPanel buttonPanel = new JPanel();
-    // Buttons
-    private final JMenuItem mItemCategory = new JMenuItem("Category");
-    private final JMenuItem mItemObject = new JMenuItem("Object");
-    private final JMenuItem mItemSwitch = new JMenuItem("Switch");
-
-    private final JPopupMenu contextMenu = new JPopupMenu();
-    private final JMenu newMenu = new JMenu("New");
-    private final JMenuItem editItem = new JMenuItem("Edit Object");
-    private final JMenuItem removeItem = new JMenuItem("Remove");
-
-
-    private final JTree categoryTree = new JTree();
-    private Category actualSelectedCategory = null;
-
-
-    public CategoryPanel(Control control, Gui gui) {
-        this.control = control;
-        this.gui = gui;
-        init();
-        updateCategories();
-        control.OnCategoryChanged.addListener(this::updateCategories);
-    }
-
-    private void init() {
-        this.setMinimumSize(new Dimension(200, 200));
-        initLayout();
-        initButtons();
-        initContextHandle();
-        categoryTree.setCellRenderer(new CategoryTreeRenderer());
-        categoryTree.setRowHeight(NODE_SIZE);
-        CategoryMouseListener mouseListener = new CategoryMouseListener();
-        categoryTree.addMouseListener(mouseListener);
-        categoryTree.addMouseMotionListener(mouseListener);
-        setColumnHeaderView(buttonPanel);
-        setViewportView(categoryTree);
-        categoryTree.setFocusable(false);
-        this.setFocusable(false);
-    }
 
 
-    private void initContextHandle() {
-        contextMenu.add(newMenu);
-        contextMenu.add(editItem);
-        contextMenu.add(removeItem);
-        newMenu.add(mItemCategory);
-        newMenu.add(mItemObject);
-        newMenu.add(mItemSwitch);
-        editItem.addActionListener(clicked -> getSelectedNode().ifPresent(node -> {
-            ObjectTreeNode objectNode = (ObjectTreeNode) node;
-            objectNode.openEdit();
-        }));
-        removeItem.addActionListener(clicked -> getSelectedNode().ifPresent(selectedNode -> {
-            if (selectedNode instanceof CategoryTreeNode node) {
-                control.deleteCategory(node.getCategory());
-            } else if (selectedNode instanceof ObjectTreeNode node) {
-                node.getCategory().getObjects().remove(node.getObject());
-            }
-            updateCategories();
-        }));
-        categoryTree.setComponentPopupMenu(contextMenu);
+  private static final Logger log = Logger.getLogger(CategoryPanel.class.getName());
+  private final static int NODE_SIZE = 25;
+  private final Control control;
+  private final Gui gui;
+  private final JPanel buttonPanel = new JPanel();
+  // Buttons
+  private final JMenuItem mItemCategory = new JMenuItem("Category");
+  private final JMenuItem mItemObject = new JMenuItem("Object");
+  private final JMenuItem mItemSwitch = new JMenuItem("Switch");
+
+  private final JPopupMenu contextMenu = new JPopupMenu();
+  private final JMenu newMenu = new JMenu("New");
+  private final JMenuItem editItem = new JMenuItem("Edit Object");
+  private final JMenuItem removeItem = new JMenuItem("Remove");
+
+
+  private final JTree categoryTree = new JTree();
+  private Category actualSelectedCategory = null;
+
+
+  public CategoryPanel(Control control, Gui gui) {
+    this.control = control;
+    this.gui = gui;
+    init();
+    updateCategories();
+    control.OnCategoryChanged.addListener(this::updateCategories);
+  }
+
+  private void init() {
+    this.setMinimumSize(new Dimension(200, 200));
+    initLayout();
+    initButtons();
+    initContextHandle();
+    categoryTree.setCellRenderer(new CategoryTreeRenderer());
+    categoryTree.setRowHeight(NODE_SIZE);
+    CategoryMouseListener mouseListener = new CategoryMouseListener();
+    categoryTree.addMouseListener(mouseListener);
+    categoryTree.addMouseMotionListener(mouseListener);
+    setColumnHeaderView(buttonPanel);
+    setViewportView(categoryTree);
+    categoryTree.setFocusable(false);
+    this.setFocusable(false);
+  }
+
+  private void initContextHandle() {
+    contextMenu.add(newMenu);
+    contextMenu.add(editItem);
+    contextMenu.add(removeItem);
+    newMenu.add(mItemCategory);
+    newMenu.add(mItemObject);
+    newMenu.add(mItemSwitch);
+    editItem.addActionListener(clicked -> getSelectedNode().ifPresent(node -> {
+      ObjectTreeNode objectNode = (ObjectTreeNode) node;
+      objectNode.openEdit();
+    }));
+    removeItem.addActionListener(clicked -> getSelectedNode().ifPresent(selectedNode -> {
+      if (selectedNode instanceof CategoryTreeNode node) {
+        control.deleteCategory(node.getCategory());
+      } else if (selectedNode instanceof ObjectTreeNode node) {
+        node.getCategory().getObjects().remove(node.getObject());
+      }
+      updateCategories();
+    }));
+    categoryTree.setComponentPopupMenu(contextMenu);
+  }
+
+  private void initLayout() {
+    buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.Y_AXIS));
+  }
+
+  private void initButtons() {
+    mItemCategory.addActionListener(clicked -> new NewCategoryDialog(control, gui));
+    mItemObject.addActionListener(
+        clicked -> new AddObjectPopUp(control, new HolonObject("Object"), actualSelectedCategory,
+            gui));
+    mItemSwitch.addActionListener(clicked -> {
+      actualSelectedCategory.getObjects().add(new HolonSwitch("HolonSwitch"));
+      control.OnCategoryChanged.broadcast();
+    });
+  }
+
+
+  private void updateCategories() {
+    categoryTree.setModel(generateCategoryModel());
+  }
+
+  private DefaultTreeModel generateCategoryModel() {
+    DefaultMutableTreeNode root = new DefaultMutableTreeNode("Categories");
+    GuiSettings.getCategories().stream().map(CategoryTreeNode::new).forEach(root::add);
+    return new DefaultTreeModel(root);
+  }
+
+
+  private Optional<DefaultMutableTreeNode> getSelectedNode() {
+    return Optional.ofNullable(
+        (DefaultMutableTreeNode) categoryTree.getLastSelectedPathComponent());
+  }
+
+
+  private static class CategoryTreeRenderer implements TreeCellRenderer {
+
+    @Override
+    public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected,
+        boolean expanded,
+        boolean leaf, int row, boolean hasFocus) {
+      JLabel label = new JLabel(value.toString());
+      if (value instanceof CategoryTreeNode) {
+        label.setIcon(new ImageIcon(Import.loadImage(ImagePreference.Category.Folder)));
+      } else if (value instanceof ObjectTreeNode node) {
+        Image image = Import.loadImage(node.getObject().getImagePath(), tree.getRowHeight(),
+            tree.getRowHeight());
+        label.setIcon(new ImageIcon(image));
+      }
+      if (hasFocus) {
+        label.setBackground(ColorPreference.Category.Focus);
+        label.setOpaque(true);
+      }
+      return label;
     }
     }
+  }
 
 
-    private void initLayout() {
-        buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.Y_AXIS));
-    }
-
-    private void initButtons() {
-        mItemCategory.addActionListener(clicked -> new NewCategoryDialog(control, gui));
-        mItemObject.addActionListener(clicked -> new AddObjectPopUp(control, new HolonObject("Object"), actualSelectedCategory, gui));
-        mItemSwitch.addActionListener(clicked -> {
-            actualSelectedCategory.getObjects().add(new HolonSwitch("HolonSwitch"));
-            control.OnCategoryChanged.broadcast();
-        });
-    }
+  private class CategoryTreeNode extends DefaultMutableTreeNode {
 
 
+    private final Category category;
 
 
-    private void updateCategories() {
-        categoryTree.setModel(generateCategoryModel());
+    public CategoryTreeNode(Category category) {
+      super(category.getName());
+      this.category = category;
+      category.getObjects().stream().map(obj -> new ObjectTreeNode(category, obj))
+          .forEach(this::add);
     }
     }
 
 
-    private DefaultTreeModel generateCategoryModel(){
-        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Categories");
-        GuiSettings.getCategories().stream().map(CategoryTreeNode::new).forEach(root::add);
-        return new DefaultTreeModel(root);
+    public Category getCategory() {
+      return category;
     }
     }
+  }
 
 
+  private class ObjectTreeNode extends DefaultMutableTreeNode {
 
 
+    private final AbstractCanvasObject object;
+    private final Category category;
 
 
-    private Optional<DefaultMutableTreeNode> getSelectedNode() {
-        return Optional.ofNullable((DefaultMutableTreeNode) categoryTree.getLastSelectedPathComponent());
+    public ObjectTreeNode(Category category, AbstractCanvasObject object) {
+      super(object.getName());
+      this.category = category;
+      this.object = object;
     }
     }
 
 
-
-    private static class CategoryTreeRenderer implements TreeCellRenderer {
-
-        @Override
-        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded,
-                                                      boolean leaf, int row, boolean hasFocus) {
-            JLabel label = new JLabel(value.toString());
-            if (value instanceof CategoryTreeNode) {
-                label.setIcon(new ImageIcon(Import.loadImage(ImagePreference.Category.Folder)));
-            } else if (value instanceof ObjectTreeNode node) {
-                Image image = Import.loadImage(node.getObject().getImagePath(), tree.getRowHeight(), tree.getRowHeight());
-                label.setIcon(new ImageIcon(image));
-            }
-            if (hasFocus) {
-                label.setBackground(ColorPreference.Category.Focus);
-                label.setOpaque(true);
-            }
-            return label;
-        }
+    public AbstractCanvasObject getObject() {
+      return object;
     }
     }
 
 
-    private class CategoryTreeNode extends DefaultMutableTreeNode {
-        private final Category category;
-
-        public CategoryTreeNode(Category category) {
-            super(category.getName());
-            this.category = category;
-            category.getObjects().stream().map(obj -> new ObjectTreeNode(category, obj)).forEach(this::add);
-        }
+    public Category getCategory() {
+      return category;
+    }
 
 
-        public Category getCategory() {
-            return category;
-        }
+    public void openEdit() {
+      if (object instanceof HolonObject hO) {
+        new AddObjectPopUp(control, hO, category, gui);
+      }
     }
     }
+  }
 
 
-    private class ObjectTreeNode extends DefaultMutableTreeNode {
-        private final AbstractCanvasObject object;
-        private final Category category;
+  private class CategoryMouseListener extends MouseAdapter {
 
 
-        public ObjectTreeNode(Category category, AbstractCanvasObject object) {
-            super(object.getName());
-            this.category = category;
-            this.object = object;
-        }
+    AbstractCanvasObject selected = null;
 
 
-        public AbstractCanvasObject getObject() {
-            return object;
-        }
-        public Category getCategory() {
-            return category;
-        }
-
-        public void openEdit(){
-            if(object instanceof HolonObject hO){
-                new AddObjectPopUp(control, hO, category, gui);
-            }
+    @Override
+    public void mousePressed(MouseEvent e) {
+      if (SwingUtilities.isRightMouseButton(e)) {
+        preparePopUpMenu(e);
+        return;
+      }
+      getSelectedNode().ifPresent(node -> {
+        if (node.getLevel() != 2) {
+          return;
         }
         }
+        ObjectTreeNode objectNode = (ObjectTreeNode) node;
+        selected = objectNode.getObject();
+        Cursor cursor = Toolkit.getDefaultToolkit()
+            .createCustomCursor(Import.loadImage(selected.getImagePath(), 32, 32), new Point(),
+                "Image");
+        gui.setCursor(cursor);
+
+      });
     }
     }
 
 
-    private class CategoryMouseListener extends MouseAdapter {
-        AbstractCanvasObject selected = null;
-
-        @Override
-        public void mousePressed(MouseEvent e) {
-            if (SwingUtilities.isRightMouseButton(e)) {
-                preparePopUpMenu(e);
-                return;
-            }
-            getSelectedNode().ifPresent(node -> {
-                if (node.getLevel() != 2) {
-                    return;
-                }
-                ObjectTreeNode objectNode = (ObjectTreeNode) node;
-                selected = objectNode.getObject();
-                Cursor cursor = Toolkit.getDefaultToolkit().createCustomCursor(Import.loadImage(selected.getImagePath(), 32, 32), new Point(),
-                        "Image");
-                gui.setCursor(cursor);
-
-            });
-        }
-
-        private void preparePopUpMenu(MouseEvent e) {
-            categoryTree.setSelectionPath(categoryTree.getPathForLocation(e.getX(), e.getY()));
-            getSelectedNode().ifPresent(selectedNode -> {
-                if (selectedNode instanceof CategoryTreeNode node) {
-                    actualSelectedCategory = node.getCategory();
-                    mItemObject.setVisible(true);
-                    mItemSwitch.setVisible(true);
-                    editItem.setVisible(false);
-                    removeItem.setVisible(true);
-                } else if (selectedNode instanceof ObjectTreeNode node) {
-                    actualSelectedCategory = node.getCategory();
-                    mItemSwitch.setVisible(true);
-                    mItemObject.setVisible(true);
-                    editItem.setVisible(true);
-                    removeItem.setVisible(true);
-                }else{
-                    mItemObject.setVisible(false);
-                    mItemSwitch.setVisible(false);
-                    editItem.setVisible(false);
-                    removeItem.setVisible(false);
-                }
-            });
+    private void preparePopUpMenu(MouseEvent e) {
+      categoryTree.setSelectionPath(categoryTree.getPathForLocation(e.getX(), e.getY()));
+      getSelectedNode().ifPresent(selectedNode -> {
+        if (selectedNode instanceof CategoryTreeNode node) {
+          actualSelectedCategory = node.getCategory();
+          mItemObject.setVisible(true);
+          mItemSwitch.setVisible(true);
+          editItem.setVisible(false);
+          removeItem.setVisible(true);
+        } else if (selectedNode instanceof ObjectTreeNode node) {
+          actualSelectedCategory = node.getCategory();
+          mItemSwitch.setVisible(true);
+          mItemObject.setVisible(true);
+          editItem.setVisible(true);
+          removeItem.setVisible(true);
+        } else {
+          mItemObject.setVisible(false);
+          mItemSwitch.setVisible(false);
+          editItem.setVisible(false);
+          removeItem.setVisible(false);
         }
         }
+      });
+    }
 
 
-        @Override
-        public void mouseReleased(MouseEvent e) {
-            if (selected == null) {
-                return;
-            }
-            gui.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
-            Canvas groupNodeCanvas = gui.getActualCanvas();
-            Optional<Point> positionInCanvas = Optional.ofNullable(groupNodeCanvas.getMousePosition());
-            AbstractCanvasObject selectedObj = selected;
-            selected = null;
-            final int halfCursorSize = GuiSettings.getPictureScaleDiv2();
-            positionInCanvas.ifPresent(pos -> {
-                AbstractCanvasObject obj;
-                if (selectedObj instanceof HolonObject hO) {
-                    obj = new HolonObject(hO);
-                } else if (selectedObj instanceof HolonSwitch sw) {
-                    obj = new HolonSwitch(sw);
-                }else {
-                    return;
-                }
-                obj.setPosition(pos.x + halfCursorSize, pos.y + halfCursorSize);
-                control.addObjectOnCanvas(groupNodeCanvas.getGroupNode(), obj);
-                control.calculateStateForCurrentIteration();
-            });
+    @Override
+    public void mouseReleased(MouseEvent e) {
+      if (selected == null) {
+        return;
+      }
+      gui.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
+      Canvas groupNodeCanvas = gui.getActualCanvas();
+      Optional<Point> positionInCanvas = Optional.ofNullable(groupNodeCanvas.getMousePosition());
+      AbstractCanvasObject selectedObj = selected;
+      selected = null;
+      final int halfCursorSize = GuiSettings.getPictureScaleDiv2();
+      positionInCanvas.ifPresent(pos -> {
+        AbstractCanvasObject obj;
+        if (selectedObj instanceof HolonObject hO) {
+          obj = new HolonObject(hO);
+        } else if (selectedObj instanceof HolonSwitch sw) {
+          obj = new HolonSwitch(sw);
+        } else {
+          return;
         }
         }
+        obj.setPosition(pos.x + halfCursorSize, pos.y + halfCursorSize);
+        control.addObjectOnCanvas(groupNodeCanvas.getGroupNode(), obj);
+        control.calculateStateForCurrentIteration();
+      });
     }
     }
+  }
 }
 }

+ 118 - 133
src/holeg/ui/view/component/ButtonTabComponent.java

@@ -1,150 +1,135 @@
 package holeg.ui.view.component;
 package holeg.ui.view.component;
 
 
-/*
- * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *   - Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- *
- *   - Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- *
- *   - Neither the name of Oracle or the names of its
- *     contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-import javax.swing.*;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import javax.swing.AbstractButton;
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
 import javax.swing.plaf.basic.BasicButtonUI;
 import javax.swing.plaf.basic.BasicButtonUI;
-import java.awt.*;
-import java.awt.event.*;
 
 
 /**
 /**
- * Component to be used as tabComponent; Contains a JLabel to show the text and
- * a JButton to close the tab it belongs to
+ * Component to be used as tabComponent; Contains a JLabel to show the text and a JButton to close
+ * the tab it belongs to
  */
  */
 public class ButtonTabComponent extends JPanel {
 public class ButtonTabComponent extends JPanel {
-	private final JTabbedPane pane;
 
 
-	public ButtonTabComponent(final JTabbedPane pane) {
-		// unset default FlowLayout' gaps
-		super(new FlowLayout(FlowLayout.LEFT, 0, 0));
-		if (pane == null) {
-			throw new NullPointerException("TabbedPane is null");
-		}
-		this.pane = pane;
-		setOpaque(false);
+  private final static MouseListener buttonMouseListener = new MouseAdapter() {
+    public void mouseEntered(MouseEvent e) {
+      Component component = e.getComponent();
+      if (component instanceof AbstractButton button) {
+        button.setBorderPainted(true);
+      }
+    }
+
+    public void mouseExited(MouseEvent e) {
+      Component component = e.getComponent();
+      if (component instanceof AbstractButton button) {
+        button.setBorderPainted(false);
+      }
+    }
+  };
+  private final JTabbedPane pane;
+
+  public ButtonTabComponent(final JTabbedPane pane) {
+    // unset default FlowLayout' gaps
+    super(new FlowLayout(FlowLayout.LEFT, 0, 0));
+    if (pane == null) {
+      throw new NullPointerException("TabbedPane is null");
+    }
+    this.pane = pane;
+    setOpaque(false);
 
 
-		// make JLabel read titles from JTabbedPane
-		JLabel label = new JLabel() {
-			public String getText() {
-				int i = pane.indexOfTabComponent(ButtonTabComponent.this);
-				if (i != -1) {
-					return pane.getTitleAt(i);
-				}
-				return null;
-			}
-		};
+    // make JLabel read titles from JTabbedPane
+    JLabel label = new JLabel() {
+      public String getText() {
+        int i = pane.indexOfTabComponent(ButtonTabComponent.this);
+        if (i != -1) {
+          return pane.getTitleAt(i);
+        }
+        return null;
+      }
+    };
 
 
-		add(label);
-		// add more space between the label and the button
-		label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
-		// tab button
-		JButton button = new TabButton();
-		add(button);
-		// add more space to the top of the component
-		setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 0));
-	}
+    add(label);
+    // add more space between the label and the button
+    label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
+    // tab button
+    JButton button = new TabButton();
+    add(button);
+    // add more space to the top of the component
+    setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 0));
+  }
 
 
-	private class TabButton extends JButton implements ActionListener {
-		public TabButton() {
-			int size = 17;
-			setPreferredSize(new Dimension(size, size));
-			setToolTipText("close this tab");
-			// Make the button looks the same for all Laf's
-			setUI(new BasicButtonUI());
-			// Make it transparent
-			setContentAreaFilled(false);
-			// No need to be focusable
-			setFocusable(false);
-			setBorder(BorderFactory.createEtchedBorder());
-			setBorderPainted(false);
-			// Making nice rollover effect
-			// we use the same listener for all buttons
-			addMouseListener(buttonMouseListener);
-			setRolloverEnabled(true);
-			// Close the proper tab by clicking the button
-			addActionListener(this);
-		}
+  /**
+   * removes both Tabs
+   */
+  public void removeTabs() {
+    int i = pane.indexOfTabComponent(ButtonTabComponent.this);
+    if (i != -1) {
+      pane.remove(i);
+    }
+  }
 
 
-		public void actionPerformed(ActionEvent e) {
-			removeTabs();
-		}
+  private class TabButton extends JButton implements ActionListener {
 
 
-		// we don't want to update UI for this button
-		public void updateUI() {
-		}
+    public TabButton() {
+      int size = 17;
+      setPreferredSize(new Dimension(size, size));
+      setToolTipText("close this tab");
+      // Make the button looks the same for all Laf's
+      setUI(new BasicButtonUI());
+      // Make it transparent
+      setContentAreaFilled(false);
+      // No need to be focusable
+      setFocusable(false);
+      setBorder(BorderFactory.createEtchedBorder());
+      setBorderPainted(false);
+      // Making nice rollover effect
+      // we use the same listener for all buttons
+      addMouseListener(buttonMouseListener);
+      setRolloverEnabled(true);
+      // Close the proper tab by clicking the button
+      addActionListener(this);
+    }
 
 
-		// paint the cross
-		protected void paintComponent(Graphics g) {
-			super.paintComponent(g);
-			Graphics2D g2 = (Graphics2D) g.create();
-			// shift the image for pressed buttons
-			if (getModel().isPressed()) {
-				g2.translate(1, 1);
-			}
-			g2.setStroke(new BasicStroke(2));
-			g2.setColor(Color.BLACK);
-			if (getModel().isRollover()) {
-				g2.setColor(Color.MAGENTA);
-			}
-			int delta = 6;
-			g2.drawLine(delta, delta, getWidth() - delta - 1, getHeight() - delta - 1);
-			g2.drawLine(getWidth() - delta - 1, delta, delta, getHeight() - delta - 1);
-			g2.dispose();
-		}
-	}
+    public void actionPerformed(ActionEvent e) {
+      removeTabs();
+    }
 
 
-	private final static MouseListener buttonMouseListener = new MouseAdapter() {
-		public void mouseEntered(MouseEvent e) {
-			Component component = e.getComponent();
-			if (component instanceof AbstractButton button) {
-				button.setBorderPainted(true);
-			}
-		}
+    // we don't want to update UI for this button
+    public void updateUI() {
+    }
 
 
-		public void mouseExited(MouseEvent e) {
-			Component component = e.getComponent();
-			if (component instanceof AbstractButton button) {
-				button.setBorderPainted(false);
-			}
-		}
-	};
-	
-	/**
-	 * removes both Tabs 
-	 */
-	public void removeTabs() {
-		int i = pane.indexOfTabComponent(ButtonTabComponent.this);
-		if (i != -1) {
-			pane.remove(i);
-		}
-	}
+    // paint the cross
+    protected void paintComponent(Graphics g) {
+      super.paintComponent(g);
+      Graphics2D g2 = (Graphics2D) g.create();
+      // shift the image for pressed buttons
+      if (getModel().isPressed()) {
+        g2.translate(1, 1);
+      }
+      g2.setStroke(new BasicStroke(2));
+      g2.setColor(Color.BLACK);
+      if (getModel().isRollover()) {
+        g2.setColor(Color.MAGENTA);
+      }
+      int delta = 6;
+      g2.drawLine(delta, delta, getWidth() - delta - 1, getHeight() - delta - 1);
+      g2.drawLine(getWidth() - delta - 1, delta, delta, getHeight() - delta - 1);
+      g2.dispose();
+    }
+  }
 }
 }

+ 56 - 54
src/holeg/ui/view/component/Console.java

@@ -1,7 +1,8 @@
 package holeg.ui.view.component;
 package holeg.ui.view.component;
 
 
+import holeg.preferences.ImagePreference;
+import holeg.ui.view.image.Import;
 import java.awt.BorderLayout;
 import java.awt.BorderLayout;
-
 import javax.swing.Box;
 import javax.swing.Box;
 import javax.swing.ImageIcon;
 import javax.swing.ImageIcon;
 import javax.swing.JButton;
 import javax.swing.JButton;
@@ -11,62 +12,63 @@ import javax.swing.JTextArea;
 import javax.swing.JToolBar;
 import javax.swing.JToolBar;
 import javax.swing.text.DefaultCaret;
 import javax.swing.text.DefaultCaret;
 
 
-import holeg.preferences.ImagePreference;
-import holeg.ui.view.image.Import;
 /**
 /**
  * Little new swing object to print data to a console.
  * Little new swing object to print data to a console.
- * @author tom
  *
  *
+ * @author tom
  */
  */
 public class Console extends JPanel {
 public class Console extends JPanel {
-	private JTextArea textArea = new JTextArea();
-	private JScrollPane scrollPane;
-	
-	public Console() {
-		super();
-		this.setLayout(new BorderLayout());
-		textArea.setEditable(false);
-		DefaultCaret caret = (DefaultCaret)textArea.getCaret();
-		caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
-		scrollPane = new JScrollPane(textArea);
-		this.add(scrollPane, BorderLayout.CENTER);
-		JToolBar toolBar = new JToolBar();
-		toolBar.setFloatable(false);
-		JButton clearButton  = new JButton("", new ImageIcon(Import.loadImage(ImagePreference.Button.Console.Clear, 24, 24)));
-		clearButton.setToolTipText("Clear Console");
-		clearButton.addActionListener(actionEvent -> clear());
-		toolBar.add(clearButton);
-		toolBar.add(Box.createHorizontalGlue());
-		JButton topButton = new JButton("", new ImageIcon(Import.loadImage(ImagePreference.Button.Console.Top, 24, 24)));
-		topButton.setToolTipText("Scroll to top");
-		topButton.addActionListener(actionEvent -> scrollToTop());
-		toolBar.add(topButton);
-		JButton botButton = new JButton("", new ImageIcon(Import.loadImage(ImagePreference.Button.Console.Bottom, 24, 24)));
-		botButton.setToolTipText("Scroll to bottom");
-		botButton.addActionListener(actionEvent -> scrollToBottom());
-		toolBar.add(botButton);
-		scrollPane.setColumnHeaderView(toolBar);
-	}
-	private void scrollToTop() {
-		textArea.setCaretPosition(0);
-	}
-	private void scrollToBottom() {
-		textArea.setCaretPosition(textArea.getDocument().getLength());
-	}
-	
-	
-	
-	
-	
-	
-	public void clear() {
-		textArea.setText("");
-	}
-	public void print(String message) {
-		textArea.append(message);
-		
-	}
-	public void println(String message) {
-		textArea.append(message  + "\n");
-	}
+
+  private final JTextArea textArea = new JTextArea();
+
+  public Console() {
+    super();
+    this.setLayout(new BorderLayout());
+    textArea.setEditable(false);
+    DefaultCaret caret = (DefaultCaret) textArea.getCaret();
+    caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
+    JScrollPane scrollPane = new JScrollPane(textArea);
+    this.add(scrollPane, BorderLayout.CENTER);
+    JToolBar toolBar = new JToolBar();
+    toolBar.setFloatable(false);
+    JButton clearButton = new JButton("",
+        new ImageIcon(Import.loadImage(ImagePreference.Button.Console.Clear, 24, 24)));
+    clearButton.setToolTipText("Clear Console");
+    clearButton.addActionListener(actionEvent -> clear());
+    toolBar.add(clearButton);
+    toolBar.add(Box.createHorizontalGlue());
+    JButton topButton = new JButton("",
+        new ImageIcon(Import.loadImage(ImagePreference.Button.Console.Top, 24, 24)));
+    topButton.setToolTipText("Scroll to top");
+    topButton.addActionListener(actionEvent -> scrollToTop());
+    toolBar.add(topButton);
+    JButton botButton = new JButton("",
+        new ImageIcon(Import.loadImage(ImagePreference.Button.Console.Bottom, 24, 24)));
+    botButton.setToolTipText("Scroll to bottom");
+    botButton.addActionListener(actionEvent -> scrollToBottom());
+    toolBar.add(botButton);
+    scrollPane.setColumnHeaderView(toolBar);
+  }
+
+  private void scrollToTop() {
+    textArea.setCaretPosition(0);
+  }
+
+  private void scrollToBottom() {
+    textArea.setCaretPosition(textArea.getDocument().getLength());
+  }
+
+
+  public void clear() {
+    textArea.setText("");
+  }
+
+  public void print(String message) {
+    textArea.append(message);
+
+  }
+
+  public void println(String message) {
+    textArea.append(message + "\n");
+  }
 }
 }

+ 85 - 87
src/holeg/ui/view/component/TrippleCheckBox.java

@@ -5,97 +5,95 @@ import java.awt.Component;
 import java.awt.Graphics;
 import java.awt.Graphics;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.ActionListener;
-
 import javax.swing.Icon;
 import javax.swing.Icon;
 import javax.swing.JCheckBox;
 import javax.swing.JCheckBox;
 import javax.swing.UIManager;
 import javax.swing.UIManager;
 
 
 public class TrippleCheckBox extends JCheckBox implements Icon, ActionListener {
 public class TrippleCheckBox extends JCheckBox implements Icon, ActionListener {
 
 
-	public enum State {
-		unselected, mid_state_selection, selected
-	};
-
-	State state;
-	final static Icon icon = UIManager.getIcon("CheckBox.icon");
-
-	private static final Color borderColor = new Color(81, 81, 81);
-	private static final Color enabledBackgroundColor = new Color(51, 51, 51);
-	private static final Color disabledBackgroundColor = new Color(122, 138, 153);
-	
-	
-	
-	public TrippleCheckBox() {
-		this("", State.unselected);
-	}
-
-	public TrippleCheckBox(String text) {
-		this(text, State.unselected);
-	}
-
-	public TrippleCheckBox(String text, State selection) {
-		super(text, selection == State.selected);
-		setSelectionState(selection);
-		addActionListener(this);
-		setIcon(this);
-	}
-
-	@Override
-	public boolean isSelected() {
-		return (getSelectionState() == State.selected);
-	}
-
-	public State getSelectionState() {
-		return state;
-	}
-
-	public void setSelectionState(State selection) {
-		state = selection;
-		setSelected(state == State.selected);
-		repaint();
-	}
-
-
-	@Override
-	public void paintIcon(Component c, Graphics g, int x, int y) {
-		icon.paintIcon(c, g, x, y);
-		if (getSelectionState() != State.mid_state_selection)
-			return;
-
-		int w = getIconWidth();
-		int h = getIconHeight();
-		g.setColor(Color.white);
-		g.fillRect(x + 1, y + 1, w - 2, h - 2);
-		g.setColor(c.isEnabled() ? enabledBackgroundColor : disabledBackgroundColor);
-		g.fillRect(x + 4, y + 4, w - 8, h - 8);
-
-		if (!c.isEnabled())
-			return;
-		g.setColor(borderColor);
-		g.drawRect(x + 4, y + 4, w - 9, h - 9);
-	}
-
-	@Override
-	public int getIconWidth() {
-		return icon.getIconWidth();
-	}
-
-	@Override
-	public int getIconHeight() {
-		return icon.getIconHeight();
-	}
-
-	public void actionPerformed(ActionEvent e) {
-		switch (getSelectionState()) {
-		case unselected:
-			setSelectionState(State.selected);
-			break;
-		case mid_state_selection:
-			setSelectionState(State.unselected);
-			break;
-		case selected:
-			setSelectionState(State.unselected);
-			break;
-		}
-	}
+  final static Icon icon = UIManager.getIcon("CheckBox.icon");
+  private static final Color borderColor = new Color(81, 81, 81);
+  private static final Color enabledBackgroundColor = new Color(51, 51, 51);
+  private static final Color disabledBackgroundColor = new Color(122, 138, 153);
+  State state;
+
+  public TrippleCheckBox() {
+    this("", State.unselected);
+  }
+
+
+  public TrippleCheckBox(String text) {
+    this(text, State.unselected);
+  }
+
+  public TrippleCheckBox(String text, State selection) {
+    super(text, selection == State.selected);
+    setSelectionState(selection);
+    addActionListener(this);
+    setIcon(this);
+  }
+
+  @Override
+  public boolean isSelected() {
+    return (getSelectionState() == State.selected);
+  }
+
+  public State getSelectionState() {
+    return state;
+  }
+
+  public void setSelectionState(State selection) {
+    state = selection;
+    setSelected(state == State.selected);
+    repaint();
+  }
+
+  @Override
+  public void paintIcon(Component c, Graphics g, int x, int y) {
+    icon.paintIcon(c, g, x, y);
+    if (getSelectionState() != State.mid_state_selection) {
+      return;
+    }
+
+    int w = getIconWidth();
+    int h = getIconHeight();
+    g.setColor(Color.white);
+    g.fillRect(x + 1, y + 1, w - 2, h - 2);
+    g.setColor(c.isEnabled() ? enabledBackgroundColor : disabledBackgroundColor);
+    g.fillRect(x + 4, y + 4, w - 8, h - 8);
+
+    if (!c.isEnabled()) {
+      return;
+    }
+    g.setColor(borderColor);
+    g.drawRect(x + 4, y + 4, w - 9, h - 9);
+  }
+
+  @Override
+  public int getIconWidth() {
+    return icon.getIconWidth();
+  }
+
+  @Override
+  public int getIconHeight() {
+    return icon.getIconHeight();
+  }
+
+  public void actionPerformed(ActionEvent e) {
+    switch (getSelectionState()) {
+      case unselected:
+        setSelectionState(State.selected);
+        break;
+      case mid_state_selection:
+        setSelectionState(State.unselected);
+        break;
+      case selected:
+        setSelectionState(State.unselected);
+        break;
+    }
+  }
+
+  public enum State {
+    unselected, mid_state_selection, selected
+  }
 }
 }

+ 77 - 70
src/holeg/ui/view/dialog/AboutUsPopUp.java

@@ -1,11 +1,15 @@
 package holeg.ui.view.dialog;
 package holeg.ui.view.dialog;
 
 
-import javax.swing.*;
-
 import holeg.preferences.ImagePreference;
 import holeg.preferences.ImagePreference;
 import holeg.ui.view.image.Import;
 import holeg.ui.view.image.Import;
-
-import java.awt.*;
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.Font;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
 
 
 /**
 /**
  * AboutUs Pop Up Window.
  * AboutUs Pop Up Window.
@@ -14,76 +18,79 @@ import java.awt.*;
  */
  */
 public class AboutUsPopUp extends JFrame {
 public class AboutUsPopUp extends JFrame {
 
 
-    /**
-     * Constructor
-     */
-    public AboutUsPopUp(JFrame parentFrame) {
-        super("About Us");
+  /**
+   * Constructor
+   */
+  public AboutUsPopUp(JFrame parentFrame) {
+    super("About Us");
+
+    // Set fonts
+    Font fontTitle = new Font("Titel", Font.ITALIC, 35);
+    JLabel titel = new JLabel("HOLEG Simulator");
+    titel.setFont(fontTitle);
+    titel.setBounds(150, 30, 100, 20);
+    Font headerFont = new Font("Header", Font.ITALIC, 20);
+    JLabel h1 = new JLabel("Project Management & Architect");
+    h1.setFont(headerFont);
+    JLabel h2 = new JLabel("Software Developers");
+    h2.setFont(headerFont);
+    JLabel h3 = new JLabel("Documentation");
+    h3.setFont(headerFont);
+    JLabel h4 = new JLabel("Additional Collaborators");
+    h4.setFont(headerFont);
 
 
-        // Set fonts
-        Font fontTitle = new Font("Titel", Font.ITALIC, 35);
-        JLabel titel = new JLabel("HOLEG Simulator");
-        titel.setFont(fontTitle);
-        titel.setBounds(150, 30, 100, 20);
-        Font headerFont = new Font("Header", Font.ITALIC, 20);
-        JLabel h1 = new JLabel("Project Management & Architect");
-        h1.setFont(headerFont);
-        JLabel h2 = new JLabel("Software Developers");
-        h2.setFont(headerFont);
-        JLabel h3 = new JLabel("Documentation");
-        h3.setFont(headerFont);
-        JLabel h4 = new JLabel("Additional Collaborators");
-        h4.setFont(headerFont);
+    // Set labels
+    titel.setHorizontalAlignment(JLabel.CENTER);
 
 
-        // Set labels
-        titel.setHorizontalAlignment(JLabel.CENTER);
+    // Set layout
+    JPanel contentPanel = new JPanel();
+    contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.Y_AXIS));
+    JPanel contentPanel2 = new JPanel();
+    contentPanel2.setLayout(new BoxLayout(contentPanel2, BoxLayout.Y_AXIS));
+    JPanel contentPanel3 = new JPanel();
+    contentPanel3.setLayout(new BoxLayout(contentPanel3, BoxLayout.Y_AXIS));
 
 
-        // Set layout
-        JPanel contentPanel = new JPanel();
-        contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.Y_AXIS));
-        JPanel contentPanel2 = new JPanel();
-        contentPanel2.setLayout(new BoxLayout(contentPanel2, BoxLayout.Y_AXIS));
-        JPanel contentPanel3 = new JPanel();
-        contentPanel3.setLayout(new BoxLayout(contentPanel3, BoxLayout.Y_AXIS));
-        
-        this.setIconImage(Import.loadImage(ImagePreference.Logo,30,30));
-        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
-        setBounds(100, 100, 500, 800);
-        setLocationRelativeTo(parentFrame);
+    this.setIconImage(Import.loadImage(ImagePreference.Logo, 30, 30));
+    setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+    setBounds(100, 100, 500, 800);
+    setLocationRelativeTo(parentFrame);
 
 
-        contentPanel.add(Box.createRigidArea(new Dimension(0, 15)));
-        contentPanel.add(titel);
-        contentPanel.add(Box.createRigidArea(new Dimension(0, 15)));
-        JLabel description = new JLabel("A discrete-time simulator for modeling Smart Grids that follow a Holon-based model.");
-        contentPanel.add(description);
-        contentPanel.add(Box.createRigidArea(new Dimension(0, 60)));
-        getContentPane().add(contentPanel, BorderLayout.NORTH);
+    contentPanel.add(Box.createRigidArea(new Dimension(0, 15)));
+    contentPanel.add(titel);
+    contentPanel.add(Box.createRigidArea(new Dimension(0, 15)));
+    JLabel description = new JLabel(
+        "A discrete-time simulator for modeling Smart Grids that follow a Holon-based model.");
+    contentPanel.add(description);
+    contentPanel.add(Box.createRigidArea(new Dimension(0, 60)));
+    getContentPane().add(contentPanel, BorderLayout.NORTH);
 
 
-        contentPanel2.add(h1);
-        JLabel namesManagement = new JLabel("C. Garcia Cordero");
-        contentPanel2.add(namesManagement);
-        contentPanel2.add(Box.createRigidArea(new Dimension(0, 50)));
-        contentPanel2.add(h2);
-        JLabel namesDevelopersUntilV2 = new JLabel("K. Trometer, D. Rieder, T. Zheng, J. Widhalm, E. Palza, I. Dix");
-        contentPanel2.add(namesDevelopersUntilV2);
-        JLabel namesDevelopersV2_1 = new JLabel("A.T. Meyer-Berg, A. Schneider, T. Troppmann and L. Tietze");
-        contentPanel2.add(namesDevelopersV2_1);
-        contentPanel2.add(Box.createRigidArea(new Dimension(0, 50)));
-        contentPanel2.add(h3);
-        JLabel namesDocumentation = new JLabel("E. Palza, C. Garcia Cordero");
-        contentPanel2.add(namesDocumentation);
-        contentPanel2.add(Box.createRigidArea(new Dimension(0, 50)));
-        contentPanel2.add(h4);
-        JLabel namesCollaborators = new JLabel("R. Egert and F. Volk");
-        contentPanel2.add(namesCollaborators);
-        contentPanel2.add(Box.createRigidArea(new Dimension(0, 50)));
-        JLabel credits = new JLabel();
-        contentPanel2.add(credits);
-        getContentPane().add(contentPanel2, BorderLayout.CENTER);
+    contentPanel2.add(h1);
+    JLabel namesManagement = new JLabel("C. Garcia Cordero");
+    contentPanel2.add(namesManagement);
+    contentPanel2.add(Box.createRigidArea(new Dimension(0, 50)));
+    contentPanel2.add(h2);
+    JLabel namesDevelopersUntilV2 = new JLabel(
+        "K. Trometer, D. Rieder, T. Zheng, J. Widhalm, E. Palza, I. Dix");
+    contentPanel2.add(namesDevelopersUntilV2);
+    JLabel namesDevelopersV2_1 = new JLabel(
+        "A.T. Meyer-Berg, A. Schneider, T. Troppmann and L. Tietze");
+    contentPanel2.add(namesDevelopersV2_1);
+    contentPanel2.add(Box.createRigidArea(new Dimension(0, 50)));
+    contentPanel2.add(h3);
+    JLabel namesDocumentation = new JLabel("E. Palza, C. Garcia Cordero");
+    contentPanel2.add(namesDocumentation);
+    contentPanel2.add(Box.createRigidArea(new Dimension(0, 50)));
+    contentPanel2.add(h4);
+    JLabel namesCollaborators = new JLabel("R. Egert and F. Volk");
+    contentPanel2.add(namesCollaborators);
+    contentPanel2.add(Box.createRigidArea(new Dimension(0, 50)));
+    JLabel credits = new JLabel();
+    contentPanel2.add(credits);
+    getContentPane().add(contentPanel2, BorderLayout.CENTER);
 
 
-        contentPanel3.add(Box.createRigidArea(new Dimension(0, 50)));
-        //contentPanel3.add(namesDevelopers);
-        getContentPane().add(contentPanel3, BorderLayout.SOUTH);
-        this.setVisible(true);
-    }
+    contentPanel3.add(Box.createRigidArea(new Dimension(0, 50)));
+    //contentPanel3.add(namesDevelopers);
+    getContentPane().add(contentPanel3, BorderLayout.SOUTH);
+    this.setVisible(true);
+  }
 }
 }

+ 170 - 160
src/holeg/ui/view/dialog/AddElementPopUp.java

@@ -1,11 +1,15 @@
 package holeg.ui.view.dialog;
 package holeg.ui.view.dialog;
 
 
+import holeg.model.HolonElement;
+import holeg.model.HolonObject;
+import holeg.preferences.ColorPreference;
+import holeg.preferences.ImagePreference;
+import holeg.ui.view.image.Import;
 import java.awt.BorderLayout;
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Color;
 import java.awt.FlowLayout;
 import java.awt.FlowLayout;
 import java.awt.event.KeyEvent;
 import java.awt.event.KeyEvent;
 import java.awt.event.KeyListener;
 import java.awt.event.KeyListener;
-
 import javax.swing.JButton;
 import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JCheckBox;
 import javax.swing.JDialog;
 import javax.swing.JDialog;
@@ -16,170 +20,176 @@ import javax.swing.JPanel;
 import javax.swing.JTextField;
 import javax.swing.JTextField;
 import javax.swing.border.EmptyBorder;
 import javax.swing.border.EmptyBorder;
 
 
-import holeg.model.HolonElement;
-import holeg.model.HolonObject;
-import holeg.preferences.ColorPreference;
-import holeg.preferences.ImagePreference;
-import holeg.ui.view.image.Import;
-
 /**
 /**
  * popup for adding an Holon Element to a holon Object.
  * popup for adding an Holon Element to a holon Object.
- * 
+ *
  * @author Gruppe14
  * @author Gruppe14
  * @author improved by A.T.M.-B. (Gruppe007)
  * @author improved by A.T.M.-B. (Gruppe007)
  */
  */
 public class AddElementPopUp extends JDialog {
 public class AddElementPopUp extends JDialog {
 
 
-	/* Data */
-	/** Holon Object the Element should be added to */
-	private HolonObject tempCps;
-	/** Holon Element that should be edited (if in edit Modus */
-	private HolonElement hl;
-	
-	/* GUI */
-	/** Panel containing everything */
-	private final JPanel contentPanel = new JPanel();
-	/** Textfield for entering a Name for the Element */
-	private final JTextField elementName;
-	/** Textfield for the energy the Element consumes/produces */
-	private final JTextField providedEnergy;
-	/** Element is active if checked */
-	JCheckBox checkBoxActive;
-
-	AddElementPopUp(JFrame parentFrame) {
-		super((java.awt.Frame) null, true);
-		this.setIconImage(Import.loadImage(ImagePreference.Logo, 30, 30));
-		setModalityType(java.awt.Dialog.ModalityType.APPLICATION_MODAL);
-		setBounds(100, 100, 400, 245);
-		setLocationRelativeTo(parentFrame);
-		getContentPane().setLayout(new BorderLayout());
-		contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
-		getContentPane().add(contentPanel, BorderLayout.CENTER);
-		contentPanel.setLayout(null);
-		this.setTitle("Add Element to Object");
-
-		
-		/* Element Name Textfield and Label */
-		elementName = new JTextField();
-		elementName.addKeyListener(new KeyListener() {
-			@Override
-			public void keyPressed(KeyEvent arg0) {
-			}
-
-			@Override
-			public void keyReleased(KeyEvent e) {
-			}
-
-			@Override
-			public void keyTyped(KeyEvent e) {
-				elementName.setBackground(Color.WHITE);
-			}
-		});
-		
-		JLabel lblElementName = new JLabel("Element Name:");
-		lblElementName.setBounds(10, 10, 100, 20);
-		contentPanel.add(lblElementName);
-		elementName.setBounds(130, 10, 110, 20);
-		contentPanel.add(elementName);
-		elementName.setColumns(10);
-		
-		/* Add Provided Energy Label and Textfield */
-		JLabel lblProvidedEnergy = new JLabel("Provided Energy:");
-		lblProvidedEnergy.setBounds(10, 50, 120, 20);
-		contentPanel.add(lblProvidedEnergy);
-		
-		providedEnergy = new JTextField();
-		providedEnergy.setBounds(130, 50, 110, 20);
-		contentPanel.add(providedEnergy);
-		providedEnergy.setColumns(10);
-		providedEnergy.setText("0");
-		
-		checkBoxActive = new JCheckBox("Active");
-		checkBoxActive.setSelected(true);
-		checkBoxActive.setBounds(250, 50, 115, 20);
-		contentPanel.add(checkBoxActive);
-
-
-		/* Add Buttons and Actions */
-		JPanel buttonPane = new JPanel();
-		buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
-		getContentPane().add(buttonPane, BorderLayout.SOUTH);
-
-		JButton okButton = new JButton("OK");
-		okButton.addActionListener(arg0 -> okAction());
-		okButton.setActionCommand("OK");
-		buttonPane.add(okButton);
-		getRootPane().setDefaultButton(okButton);
-
-		JButton cancelButton = new JButton("Cancel");
-		cancelButton.setActionCommand("Cancel");
-		buttonPane.add(cancelButton);
-		cancelButton.addActionListener(e -> dispose());
-	}
-
-	/**
-	 * Sets the actual Cps.
-	 * 
-	 * @param cps
-	 *            actual Cps
-	 */
-	void setActualHolonObject(HolonObject cps) {
-		this.tempCps = cps;
-	}
-
-	/**
-	 * Returns the created Element.
-	 * 
-	 * @return the Element
-	 */
-	public HolonElement getElement() {
-		return hl;
-	}
-
-	public void setElement(HolonElement holonElement) {
-		hl = holonElement;
-		elementName.setText(hl.getName());
-		providedEnergy.setText(""+hl.getEnergy());
-		checkBoxActive.setSelected(hl.active);
-		
-	}
-	
-	/**
-	 * Trys to create/edit the Element
-	 */
-	private void okAction() {
-		boolean repeated = false;
-		for (HolonElement e :  tempCps.elementsStream().toList()) {
-			if (elementName.getText().equals(e.getName())&&(hl == null)) {
-				repeated = true;
-				break;
-			}
-		}
-		if (elementName.getText().length() != 0 && !repeated) {
-			try {
-				float energy = Float.parseFloat(providedEnergy.getText());
-				if(hl == null){
-					hl = new HolonElement(this.tempCps, elementName.getText(), energy);
-				} else {
-					hl.setName(elementName.getText());
-					hl.setEnergy(energy);
-					hl.active = checkBoxActive.isSelected();
-				}
-				dispose();
-			} catch (NumberFormatException e) {
-				JOptionPane.showMessageDialog(new JFrame(), "Please enter numbers in the Fields amount and Energy");
-			}
-		} else {
-			if (elementName.getText().isEmpty()) {
-				JLabel errorString = new JLabel("No name");
-				errorString.setBounds(240, 8, 100, 20);
-				contentPanel.add(errorString);
-			} else if (repeated) {
-				JLabel errorString = new JLabel("Name already given");
-				errorString.setBounds(250, 8, 100, 20);
-				contentPanel.add(errorString);
-			}
-			elementName.setBackground(ColorPreference.Dialog.BackgroundColor);
-		}
-	}
+  /* Data */
+  /**
+   * Panel containing everything
+   */
+  private final JPanel contentPanel = new JPanel();
+  /**
+   * Textfield for entering a Name for the Element
+   */
+  private final JTextField elementName;
+
+  /* GUI */
+  /**
+   * Textfield for the energy the Element consumes/produces
+   */
+  private final JTextField providedEnergy;
+  /**
+   * Element is active if checked
+   */
+  JCheckBox checkBoxActive;
+  /**
+   * Holon Object the Element should be added to
+   */
+  private HolonObject tempCps;
+  /**
+   * Holon Element that should be edited (if in edit Modus
+   */
+  private HolonElement hl;
+
+  AddElementPopUp(JFrame parentFrame) {
+    super((java.awt.Frame) null, true);
+    this.setIconImage(Import.loadImage(ImagePreference.Logo, 30, 30));
+    setModalityType(java.awt.Dialog.ModalityType.APPLICATION_MODAL);
+    setBounds(100, 100, 400, 245);
+    setLocationRelativeTo(parentFrame);
+    getContentPane().setLayout(new BorderLayout());
+    contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
+    getContentPane().add(contentPanel, BorderLayout.CENTER);
+    contentPanel.setLayout(null);
+    this.setTitle("Add Element to Object");
+
+
+    /* Element Name Textfield and Label */
+    elementName = new JTextField();
+    elementName.addKeyListener(new KeyListener() {
+      @Override
+      public void keyPressed(KeyEvent arg0) {
+      }
+
+      @Override
+      public void keyReleased(KeyEvent e) {
+      }
+
+      @Override
+      public void keyTyped(KeyEvent e) {
+        elementName.setBackground(Color.WHITE);
+      }
+    });
+
+    JLabel lblElementName = new JLabel("Element Name:");
+    lblElementName.setBounds(10, 10, 100, 20);
+    contentPanel.add(lblElementName);
+    elementName.setBounds(130, 10, 110, 20);
+    contentPanel.add(elementName);
+    elementName.setColumns(10);
+
+    /* Add Provided Energy Label and Textfield */
+    JLabel lblProvidedEnergy = new JLabel("Provided Energy:");
+    lblProvidedEnergy.setBounds(10, 50, 120, 20);
+    contentPanel.add(lblProvidedEnergy);
+
+    providedEnergy = new JTextField();
+    providedEnergy.setBounds(130, 50, 110, 20);
+    contentPanel.add(providedEnergy);
+    providedEnergy.setColumns(10);
+    providedEnergy.setText("0");
+
+    checkBoxActive = new JCheckBox("Active");
+    checkBoxActive.setSelected(true);
+    checkBoxActive.setBounds(250, 50, 115, 20);
+    contentPanel.add(checkBoxActive);
+
+
+    /* Add Buttons and Actions */
+    JPanel buttonPane = new JPanel();
+    buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
+    getContentPane().add(buttonPane, BorderLayout.SOUTH);
+
+    JButton okButton = new JButton("OK");
+    okButton.addActionListener(arg0 -> okAction());
+    okButton.setActionCommand("OK");
+    buttonPane.add(okButton);
+    getRootPane().setDefaultButton(okButton);
+
+    JButton cancelButton = new JButton("Cancel");
+    cancelButton.setActionCommand("Cancel");
+    buttonPane.add(cancelButton);
+    cancelButton.addActionListener(e -> dispose());
+  }
+
+  /**
+   * Sets the actual Cps.
+   *
+   * @param cps actual Cps
+   */
+  void setActualHolonObject(HolonObject cps) {
+    this.tempCps = cps;
+  }
+
+  /**
+   * Returns the created Element.
+   *
+   * @return the Element
+   */
+  public HolonElement getElement() {
+    return hl;
+  }
+
+  public void setElement(HolonElement holonElement) {
+    hl = holonElement;
+    elementName.setText(hl.getName());
+    providedEnergy.setText("" + hl.getEnergy());
+    checkBoxActive.setSelected(hl.active);
+
+  }
+
+  /**
+   * Trys to create/edit the Element
+   */
+  private void okAction() {
+    boolean repeated = false;
+    for (HolonElement e : tempCps.elementsStream().toList()) {
+      if (elementName.getText().equals(e.getName()) && (hl == null)) {
+        repeated = true;
+        break;
+      }
+    }
+    if (elementName.getText().length() != 0 && !repeated) {
+      try {
+        float energy = Float.parseFloat(providedEnergy.getText());
+        if (hl == null) {
+          hl = new HolonElement(this.tempCps, elementName.getText(), energy);
+        } else {
+          hl.setName(elementName.getText());
+          hl.setEnergy(energy);
+          hl.active = checkBoxActive.isSelected();
+        }
+        dispose();
+      } catch (NumberFormatException e) {
+        JOptionPane.showMessageDialog(new JFrame(),
+            "Please enter numbers in the Fields amount and Energy");
+      }
+    } else {
+      if (elementName.getText().isEmpty()) {
+        JLabel errorString = new JLabel("No name");
+        errorString.setBounds(240, 8, 100, 20);
+        contentPanel.add(errorString);
+      } else if (repeated) {
+        JLabel errorString = new JLabel("Name already given");
+        errorString.setBounds(250, 8, 100, 20);
+        contentPanel.add(errorString);
+      }
+      elementName.setBackground(ColorPreference.Dialog.BackgroundColor);
+    }
+  }
 }
 }

+ 264 - 242
src/holeg/ui/view/dialog/AddObjectPopUp.java

@@ -8,282 +8,304 @@ import holeg.preferences.ImagePreference;
 import holeg.ui.controller.Control;
 import holeg.ui.controller.Control;
 import holeg.ui.view.category.Category;
 import holeg.ui.view.category.Category;
 import holeg.ui.view.image.Import;
 import holeg.ui.view.image.Import;
-
-import javax.swing.*;
-import javax.swing.border.EmptyBorder;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import java.awt.*;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.FlowLayout;
 import java.awt.event.KeyEvent;
 import java.awt.event.KeyEvent;
 import java.awt.event.KeyListener;
 import java.awt.event.KeyListener;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseEvent;
-import java.io.*;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.nio.file.Files;
 import java.nio.file.Files;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
+import javax.swing.DefaultListModel;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+import javax.swing.border.EmptyBorder;
+import javax.swing.filechooser.FileNameExtensionFilter;
 
 
 /**
 /**
  * Popup for adding a Holon Object to a Category.
  * Popup for adding a Holon Object to a Category.
- * 
+ *
  * @author Gruppe14
  * @author Gruppe14
  */
  */
 public class AddObjectPopUp extends JDialog {
 public class AddObjectPopUp extends JDialog {
-	private static final Logger log = Logger.getLogger(AddObjectPopUp.class.getName());
-	private AddElementPopUp addElement;
-	private final JTextField objectName;
-	private final JTextField sourcePath;
-	private final ArrayList<HolonElement> hElements;
-	private final DefaultListModel<String> listModel;
-	private final JList<String> list;
-	private String imagePath;
-	// private HolonObject theObject;
-	private final Control control;
-	private File selectedFile = null;
-	private String filePath = " ";
-	private final JLabel lblImagePreview;
-	private final AbstractCanvasObject toEdit;
-	private boolean imageChanged = false;
 
 
-	/**
-	 * Create the dialog.
-	 * @param obj  the object
-	 * @param category  the categorie
-	 */
-	public AddObjectPopUp(Control control, HolonObject obj, Category category, JFrame parentFrame) {
-		this.control = control;
-		toEdit = obj;
-		this.setIconImage(Import.loadImage(ImagePreference.Logo, 30, 30));
-		setBounds(100, 100, 450, 342);
-		setLocationRelativeTo(parentFrame);
-		getContentPane().setLayout(new BorderLayout());
-		JPanel contentPanel = new JPanel();
-		contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
-		getContentPane().add(contentPanel, BorderLayout.CENTER);
-		contentPanel.setLayout(null);
-		hElements = new ArrayList<>();
-		this.setTitle("Add Object Menu");
-		{
-			JLabel lblName = new JLabel("Name:");
-			lblName.setHorizontalAlignment(SwingConstants.CENTER);
-			lblName.setBounds(28, 21, 76, 14);
-			contentPanel.add(lblName);
-		}
-		{
-			objectName = new JTextField();
-			objectName.addKeyListener(new KeyListener() {
-				@Override
-				public void keyPressed(KeyEvent arg0) {
+  private static final Logger log = Logger.getLogger(AddObjectPopUp.class.getName());
+  private final JTextField objectName;
+  private final JTextField sourcePath;
+  private final ArrayList<HolonElement> hElements;
+  private final DefaultListModel<String> listModel;
+  private final JList<String> list;
+  // private HolonObject theObject;
+  private final Control control;
+  private final JLabel lblImagePreview;
+  private final AbstractCanvasObject toEdit;
+  private AddElementPopUp addElement;
+  private String imagePath;
+  private File selectedFile = null;
+  private String filePath = " ";
+  private boolean imageChanged = false;
+
+  /**
+   * Create the dialog.
+   *
+   * @param obj      the object
+   * @param category the categorie
+   */
+  public AddObjectPopUp(Control control, HolonObject obj, Category category, JFrame parentFrame) {
+    this.control = control;
+    toEdit = obj;
+    this.setIconImage(Import.loadImage(ImagePreference.Logo, 30, 30));
+    setBounds(100, 100, 450, 342);
+    setLocationRelativeTo(parentFrame);
+    getContentPane().setLayout(new BorderLayout());
+    JPanel contentPanel = new JPanel();
+    contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
+    getContentPane().add(contentPanel, BorderLayout.CENTER);
+    contentPanel.setLayout(null);
+    hElements = new ArrayList<>();
+    this.setTitle("Add Object Menu");
+    {
+      JLabel lblName = new JLabel("Name:");
+      lblName.setHorizontalAlignment(SwingConstants.CENTER);
+      lblName.setBounds(28, 21, 76, 14);
+      contentPanel.add(lblName);
+    }
+    {
+      objectName = new JTextField();
+      objectName.addKeyListener(new KeyListener() {
+        @Override
+        public void keyPressed(KeyEvent arg0) {
 
 
-				}
+        }
 
 
-				@Override
-				public void keyReleased(KeyEvent e) {
+        @Override
+        public void keyReleased(KeyEvent e) {
 
 
-				}
+        }
 
 
-				@Override
-				public void keyTyped(KeyEvent e) {
-					objectName.setBackground(Color.WHITE);
-				}
-			});
-			objectName.setText(obj.getName());
-			objectName.setBounds(98, 18, 172, 20);
-			contentPanel.add(objectName);
-			objectName.setColumns(10);
-		}
-		{
-			JButton btnBrowseImage = new JButton("Browse Image");
-			btnBrowseImage.setBounds(10, 75, 134, 23);
-			contentPanel.add(btnBrowseImage);
-			btnBrowseImage.addMouseListener(new MouseAdapter() {
-				public void mouseClicked(MouseEvent e) {
-					fileChooser();
-				}
-			});
+        @Override
+        public void keyTyped(KeyEvent e) {
+          objectName.setBackground(Color.WHITE);
+        }
+      });
+      objectName.setText(obj.getName());
+      objectName.setBounds(98, 18, 172, 20);
+      contentPanel.add(objectName);
+      objectName.setColumns(10);
+    }
+    {
+      JButton btnBrowseImage = new JButton("Browse Image");
+      btnBrowseImage.setBounds(10, 75, 134, 23);
+      contentPanel.add(btnBrowseImage);
+      btnBrowseImage.addMouseListener(new MouseAdapter() {
+        public void mouseClicked(MouseEvent e) {
+          fileChooser();
+        }
+      });
 
 
-		}
-		{
-			lblImagePreview = new JLabel("");
-			lblImagePreview.setBounds(295, 3, 50, 50);
-			contentPanel.add(lblImagePreview);
-		}
-		{
-			sourcePath = new JTextField();
-			sourcePath.addKeyListener(new KeyListener() {
-				@Override
-				public void keyPressed(KeyEvent arg0) {
-				}
+    }
+    {
+      lblImagePreview = new JLabel("");
+      lblImagePreview.setBounds(295, 3, 50, 50);
+      contentPanel.add(lblImagePreview);
+    }
+    {
+      sourcePath = new JTextField();
+      sourcePath.addKeyListener(new KeyListener() {
+        @Override
+        public void keyPressed(KeyEvent arg0) {
+        }
 
 
-				@Override
-				public void keyReleased(KeyEvent e) {
-				}
+        @Override
+        public void keyReleased(KeyEvent e) {
+        }
 
 
-				@Override
-				public void keyTyped(KeyEvent e) {
-					sourcePath.setBackground(Color.WHITE);
-				}
-			});
-			if (!obj.getImagePath().equals("")) {
-				log.info("IMAGEPATH:" + obj.getImagePath());
-				lblImagePreview.setIcon(new ImageIcon(Import.loadImage(obj.getImagePath(), 50, 50)));
-				this.filePath = obj.getImagePath();
-				sourcePath.setText(filePath);
-			}
-			sourcePath.setBounds(148, 77, 271, 20);
-			contentPanel.add(sourcePath);
+        @Override
+        public void keyTyped(KeyEvent e) {
+          sourcePath.setBackground(Color.WHITE);
+        }
+      });
+      if (!obj.getImagePath().equals("")) {
+        log.info("IMAGEPATH:" + obj.getImagePath());
+        lblImagePreview.setIcon(new ImageIcon(Import.loadImage(obj.getImagePath(), 50, 50)));
+        this.filePath = obj.getImagePath();
+        sourcePath.setText(filePath);
+      }
+      sourcePath.setBounds(148, 77, 271, 20);
+      contentPanel.add(sourcePath);
 
 
-			sourcePath.setColumns(10);
-		}
-		{
-			JButton btnAddDefaultElement = new JButton("Add Element");
-			btnAddDefaultElement.addActionListener(actionEvent -> {
-				addElement = new AddElementPopUp(parentFrame);
-				addElement.setActualHolonObject((HolonObject) toEdit);
-				addElement.setVisible(true);
-				HolonElement hl = addElement.getElement();
-				// if (hl != null) {
-				// hl.setSav(givenCategory);
-				// }
-				// hl.setObj(objectName.getText());
-				addElement(hl);
-			});
+      sourcePath.setColumns(10);
+    }
+    {
+      JButton btnAddDefaultElement = new JButton("Add Element");
+      btnAddDefaultElement.addActionListener(actionEvent -> {
+        addElement = new AddElementPopUp(parentFrame);
+        addElement.setActualHolonObject((HolonObject) toEdit);
+        addElement.setVisible(true);
+        HolonElement hl = addElement.getElement();
+        // if (hl != null) {
+        // hl.setSav(givenCategory);
+        // }
+        // hl.setObj(objectName.getText());
+        addElement(hl);
+      });
 
 
-			btnAddDefaultElement.setBounds(270, 144, 142, 23);
-			contentPanel.add(btnAddDefaultElement);
-		}
-		{
-			JScrollPane scrollPane = new JScrollPane();
-			scrollPane.setBounds(10, 114, 236, 150);
-			contentPanel.add(scrollPane);
-			{
+      btnAddDefaultElement.setBounds(270, 144, 142, 23);
+      contentPanel.add(btnAddDefaultElement);
+    }
+    {
+      JScrollPane scrollPane = new JScrollPane();
+      scrollPane.setBounds(10, 114, 236, 150);
+      contentPanel.add(scrollPane);
+      {
 
 
-				listModel = new DefaultListModel<>();
+        listModel = new DefaultListModel<>();
 
 
-				/*
-				 * HolonElement hel = new HolonElement("Test", 100, 5); String name =
-				 * hel.getEleName(); for (int i = 0; i < 11; i++) { hel.setEleName(name + i);
-				 * addElement(hel); }
-				 */
-				list = new JList<>(listModel);
-				scrollPane.setViewportView(list);
-			}
-		}
-			obj.elementsStream().forEach(this::addElement);
-		{
-			JButton btnNewButton = new JButton("Delete Element");
-			btnNewButton.addActionListener(actionEvent -> {
-				int selectedIndex = list.getSelectedIndex();
-				if (selectedIndex != -1) {
-					listModel.remove(selectedIndex);
-					hElements.remove(selectedIndex);
-				}
-			});
-			btnNewButton.setBounds(270, 182, 142, 27);
-			contentPanel.add(btnNewButton);
-		}
+        /*
+         * HolonElement hel = new HolonElement("Test", 100, 5); String name =
+         * hel.getEleName(); for (int i = 0; i < 11; i++) { hel.setEleName(name + i);
+         * addElement(hel); }
+         */
+        list = new JList<>(listModel);
+        scrollPane.setViewportView(list);
+      }
+    }
+    obj.elementsStream().forEach(this::addElement);
+    {
+      JButton btnNewButton = new JButton("Delete Element");
+      btnNewButton.addActionListener(actionEvent -> {
+        int selectedIndex = list.getSelectedIndex();
+        if (selectedIndex != -1) {
+          listModel.remove(selectedIndex);
+          hElements.remove(selectedIndex);
+        }
+      });
+      btnNewButton.setBounds(270, 182, 142, 27);
+      contentPanel.add(btnNewButton);
+    }
 
 
-		{
-			JPanel buttonPane = new JPanel();
-			buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
-			getContentPane().add(buttonPane, BorderLayout.SOUTH);
-			{
-				JButton okButton = new JButton("OK");
-				okButton.addMouseListener(new MouseAdapter() {
-					public void mouseClicked(MouseEvent e) {
+    {
+      JPanel buttonPane = new JPanel();
+      buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
+      getContentPane().add(buttonPane, BorderLayout.SOUTH);
+      {
+        JButton okButton = new JButton("OK");
+        okButton.addMouseListener(new MouseAdapter() {
+          public void mouseClicked(MouseEvent e) {
 //						Component frame = null;
 //						Component frame = null;
-						if (objectName.getText().length() > 0) {
-							if (sourcePath.getText().equals(filePath)) {
-								imagePath = filePath;
-								if (imageChanged)
-									copieFile();
-								imageChanged = false;
-								if (category != null) {
-									category.getObjects().remove(toEdit);
-									AddObjectPopUp.this.control.addObject(category, objectName.getText(), hElements, imagePath);
-								}
-								dispose();
-							} else {
-								sourcePath.setBackground(ColorPreference.Dialog.BackgroundColor);
-							}
-						} else {
-							objectName.setBackground(ColorPreference.Dialog.BackgroundColor);
+            if (objectName.getText().length() > 0) {
+              if (sourcePath.getText().equals(filePath)) {
+                imagePath = filePath;
+                if (imageChanged) {
+                  copieFile();
+                }
+                imageChanged = false;
+                if (category != null) {
+                  category.getObjects().remove(toEdit);
+                  AddObjectPopUp.this.control.addObject(category, objectName.getText(), hElements,
+                      imagePath);
+                }
+                dispose();
+              } else {
+                sourcePath.setBackground(ColorPreference.Dialog.BackgroundColor);
+              }
+            } else {
+              objectName.setBackground(ColorPreference.Dialog.BackgroundColor);
 
 
-						}
-					}
-				});
-				okButton.setActionCommand("OK");
-				buttonPane.add(okButton);
-				getRootPane().setDefaultButton(okButton);
-			}
-			{
-				JButton cancelButton = new JButton("Cancel");
-				cancelButton.setActionCommand("Cancel");
-				buttonPane.add(cancelButton);
-				cancelButton.addActionListener(e -> dispose());
-			}
-			setVisible(true);
-		}
-	}
+            }
+          }
+        });
+        okButton.setActionCommand("OK");
+        buttonPane.add(okButton);
+        getRootPane().setDefaultButton(okButton);
+      }
+      {
+        JButton cancelButton = new JButton("Cancel");
+        cancelButton.setActionCommand("Cancel");
+        buttonPane.add(cancelButton);
+        cancelButton.addActionListener(e -> dispose());
+      }
+      setVisible(true);
+    }
+  }
 
 
-	/**
-	 * adds a Holon Element.
-	 *
-	 * @param hl the HolonElement
-	 */
-	private void addElement(HolonElement hl) {
-		hElements.add(hl);
-		listModel.addElement("x: " + hl.getName() + " " + hl.getEnergy() + "U");
-	}
+  /**
+   * adds a Holon Element.
+   *
+   * @param hl the HolonElement
+   */
+  private void addElement(HolonElement hl) {
+    hElements.add(hl);
+    listModel.addElement("x: " + hl.getName() + " " + hl.getEnergy() + "U");
+  }
 
 
-	/**
-	 * Choose the file.
-	 */
-	private void fileChooser() {
-		JFileChooser fileChooser = new JFileChooser();
-		FileNameExtensionFilter filter = new FileNameExtensionFilter("png, jpg or jpeg", "png", "jpg", "jpeg");
-		fileChooser.setFileFilter(filter);
-		int returnValue = fileChooser.showOpenDialog(null);
-		if (returnValue == JFileChooser.APPROVE_OPTION) {
-			selectedFile = fileChooser.getSelectedFile();
-			filePath = selectedFile.getAbsolutePath();
-			sourcePath.setText(filePath);
-			ImageIcon icon = new ImageIcon(Import.loadImage(filePath, 50, 50));
-			lblImagePreview.setIcon(icon);
-			imageChanged = true;
-		} else {
-			System.out.println("Failed to Load");
-		}
+  /**
+   * Choose the file.
+   */
+  private void fileChooser() {
+    JFileChooser fileChooser = new JFileChooser();
+    FileNameExtensionFilter filter = new FileNameExtensionFilter("png, jpg or jpeg", "png", "jpg",
+        "jpeg");
+    fileChooser.setFileFilter(filter);
+    int returnValue = fileChooser.showOpenDialog(null);
+    if (returnValue == JFileChooser.APPROVE_OPTION) {
+      selectedFile = fileChooser.getSelectedFile();
+      filePath = selectedFile.getAbsolutePath();
+      sourcePath.setText(filePath);
+      ImageIcon icon = new ImageIcon(Import.loadImage(filePath, 50, 50));
+      lblImagePreview.setIcon(icon);
+      imageChanged = true;
+    } else {
+      System.out.println("Failed to Load");
+    }
 
 
-	}
+  }
 
 
-	/**
-	 * Copies the File.
-	 */
-	private void copieFile() {
-		InputStream inStream;
-		OutputStream outStream;
-		try {
-			File source = new File(filePath);
-			//TODO: "CopieFile"
-			File dest = new File(System.getProperty("user.home") + "/.config/HolonGUI/Images/");
-			Files.createDirectories(dest.toPath());
-			dest = new File(dest, selectedFile.getName());
-			imagePath = "" + dest;
+  /**
+   * Copies the File.
+   */
+  private void copieFile() {
+    InputStream inStream;
+    OutputStream outStream;
+    try {
+      File source = new File(filePath);
+      //TODO: "CopieFile"
+      File dest = new File(System.getProperty("user.home") + "/.config/HolonGUI/Images/");
+      Files.createDirectories(dest.toPath());
+      dest = new File(dest, selectedFile.getName());
+      imagePath = "" + dest;
 
 
-			inStream = new FileInputStream(source);
-			outStream = new FileOutputStream(dest);
-			byte[] buffer = new byte[1024];
+      inStream = new FileInputStream(source);
+      outStream = new FileOutputStream(dest);
+      byte[] buffer = new byte[1024];
 
 
-			int length;
-			while ((length = inStream.read(buffer)) > 0) {
-				outStream.write(buffer, 0, length);
-			}
+      int length;
+      while ((length = inStream.read(buffer)) > 0) {
+        outStream.write(buffer, 0, length);
+      }
 
 
-			inStream.close();
-			outStream.close();
-		} catch (IOException eex) {
-			eex.printStackTrace();
-		}
-	}
+      inStream.close();
+      outStream.close();
+    } catch (IOException eex) {
+      eex.printStackTrace();
+    }
+  }
 
 
 }
 }

+ 53 - 50
src/holeg/ui/view/dialog/CanvasResizePopUp.java

@@ -1,66 +1,69 @@
 package holeg.ui.view.dialog;
 package holeg.ui.view.dialog;
 
 
-import javax.swing.*;
-
 import holeg.preferences.ImagePreference;
 import holeg.preferences.ImagePreference;
 import holeg.ui.controller.Control;
 import holeg.ui.controller.Control;
 import holeg.ui.model.GuiSettings;
 import holeg.ui.model.GuiSettings;
 import holeg.ui.view.canvas.Canvas;
 import holeg.ui.view.canvas.Canvas;
 import holeg.ui.view.image.Import;
 import holeg.ui.view.image.Import;
 import holeg.ui.view.main.Gui;
 import holeg.ui.view.main.Gui;
-import holeg.utility.math.vector.Vec2i;
-
-import java.awt.*;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
 
 
 public class CanvasResizePopUp extends JDialog {
 public class CanvasResizePopUp extends JDialog {
-	Control controller;
-	private final JTextField widthTextField = new JTextField();
-    private final JTextField heightTextField = new JTextField();
 
 
-	public CanvasResizePopUp(Control controller, Gui gui) {
-        super(gui, true);
-		this.controller = controller;
-		// properties and stuff
-		this.setIconImage(Import.loadImage(ImagePreference.Logo,30,30));
-		this.setTitle("Set the Size of the View");
-		setBounds(200, 100, 200, 100);
-        setLocationRelativeTo(gui);
+  private final JTextField widthTextField = new JTextField();
+  private final JTextField heightTextField = new JTextField();
+  Control controller;
+
+  public CanvasResizePopUp(Control controller, Gui gui) {
+    super(gui, true);
+    this.controller = controller;
+    // properties and stuff
+    this.setIconImage(Import.loadImage(ImagePreference.Logo, 30, 30));
+    this.setTitle("Set the Size of the View");
+    setBounds(200, 100, 200, 100);
+    setLocationRelativeTo(gui);
 
 
-		// MainPanel
-		widthTextField.setText("" + GuiSettings.canvasSize.getX());
-		heightTextField.setText("" + GuiSettings.canvasSize.getY());
-		JPanel mainPanel = new JPanel();
-		JLabel lblWidth = new JLabel("Width:");
-		mainPanel.add(lblWidth);
-		mainPanel.add(widthTextField);
-		JLabel lblHeight = new JLabel("Height:");
-		mainPanel.add(lblHeight);
-		mainPanel.add(heightTextField);
-		mainPanel.setBackground(Color.WHITE);
+    // MainPanel
+    widthTextField.setText("" + GuiSettings.canvasSize.getX());
+    heightTextField.setText("" + GuiSettings.canvasSize.getY());
+    JPanel mainPanel = new JPanel();
+    JLabel lblWidth = new JLabel("Width:");
+    mainPanel.add(lblWidth);
+    mainPanel.add(widthTextField);
+    JLabel lblHeight = new JLabel("Height:");
+    mainPanel.add(lblHeight);
+    mainPanel.add(heightTextField);
+    mainPanel.setBackground(Color.WHITE);
 
 
-		// Button Panel
-		JButton btnOk = new JButton("OK");
-		btnOk.addActionListener(e -> {
-			GuiSettings.canvasSize.setX(Integer.parseInt(widthTextField.getText()));
-			GuiSettings.canvasSize.setY(Integer.parseInt(heightTextField.getText()));
-			gui.canvasCollection.resetCanvasSizes();
-			controller.getModel().getCanvas().getAllObjectsRecursive().forEach(obj -> {
-				obj.setPosition(Canvas.boundsToCanvas(obj.getPosition()));
-			});
-			controller.OnCanvasUpdate.broadcast();
-			dispose();
-		});
-		JButton btnCancel = new JButton("Cancel");
-		btnCancel.addActionListener(clicked -> dispose());
-		JPanel buttonPanel = new JPanel();
-		buttonPanel.add(btnOk);
-		buttonPanel.add(btnCancel);
-		buttonPanel.setBackground(Color.WHITE);
+    // Button Panel
+    JButton btnOk = new JButton("OK");
+    btnOk.addActionListener(e -> {
+      GuiSettings.canvasSize.setX(Integer.parseInt(widthTextField.getText()));
+      GuiSettings.canvasSize.setY(Integer.parseInt(heightTextField.getText()));
+      gui.canvasCollection.resetCanvasSizes();
+      controller.getModel().getCanvas().getAllObjectsRecursive().forEach(obj -> {
+        obj.setPosition(Canvas.boundsToCanvas(obj.getPosition()));
+      });
+      controller.OnCanvasUpdate.broadcast();
+      dispose();
+    });
+    JButton btnCancel = new JButton("Cancel");
+    btnCancel.addActionListener(clicked -> dispose());
+    JPanel buttonPanel = new JPanel();
+    buttonPanel.add(btnOk);
+    buttonPanel.add(btnCancel);
+    buttonPanel.setBackground(Color.WHITE);
 
 
-		// Add to ContentPane
-		getContentPane().add(mainPanel, BorderLayout.CENTER);
-		getContentPane().add(buttonPanel, BorderLayout.SOUTH);
-		this.setVisible(true);
-	}
+    // Add to ContentPane
+    getContentPane().add(mainPanel, BorderLayout.CENTER);
+    getContentPane().add(buttonPanel, BorderLayout.SOUTH);
+    this.setVisible(true);
+  }
 
 
 }
 }

+ 272 - 262
src/holeg/ui/view/dialog/CreateTemplatePopUp.java

@@ -7,276 +7,286 @@ import holeg.ui.controller.Control;
 import holeg.ui.model.GuiSettings;
 import holeg.ui.model.GuiSettings;
 import holeg.ui.view.category.Category;
 import holeg.ui.view.category.Category;
 import holeg.ui.view.image.Import;
 import holeg.ui.view.image.Import;
-
-import javax.swing.*;
-import javax.swing.border.EmptyBorder;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import java.awt.*;
+import java.awt.BorderLayout;
+import java.awt.Choice;
 import java.io.File;
 import java.io.File;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
+import javax.swing.DefaultListModel;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.border.EmptyBorder;
+import javax.swing.filechooser.FileNameExtensionFilter;
 
 
 /**
 /**
  * PopUp for creating Holon Object Template.
  * PopUp for creating Holon Object Template.
  */
  */
 public class CreateTemplatePopUp extends JDialog {
 public class CreateTemplatePopUp extends JDialog {
 
 
-	/**
-	 * Template HolonObject
-	 */
-	private final HolonObject template;
-
-	/**
-	 * HolonElementList
-	 */
-	private final DefaultListModel<String> listModel;
-	private final List<HolonElement> holonElementList = new ArrayList<>();
-
-	/**
-	 * HolonElement List
-	 */
-	private final JList<String> list;
-
-
-	// Template Attributes
-
-	// PopUp Parts
-	private final Control controller;
-
-	/**
-	 * Category Selection
-	 */
-	Choice choice;
-
-	/**
-	 * name textfield
-	 */
-	private final JTextField textField_name;
-
-	/**
-	 * textField for path
-	 */
-	private final JTextField textField_imagePath;
-
-	/**
-	 * Image Preview
-	 */
-	JLabel lblImagePreview;
-
-	/**
-	 * parent Frame
-	 */
-	JFrame parent;
-	/**
-	 * Create the dialog.
-	 *
-	 *            true if edit
-	 * @param obj
-	 *            the object
-	 */
-	public CreateTemplatePopUp(HolonObject obj,
-			JFrame parentFrame, Control controller) {
-		setResizable(false);
-		/*
-		 * use Category Controller an stuff lul
-		 */
-
-		/*
-		 * initialize Data
-		 */
-		template = new HolonObject(obj);
-		this.parent = parentFrame;
-		this.controller = controller;
-		/*
-		 * create Frame and GUI
-		 */
-		setIconImage(Import.loadImage(ImagePreference.Logo, 30, 30));
-		setBounds(100, 100, 476, 344);
-		setLocationRelativeTo(parentFrame);
-		getContentPane().setLayout(new BorderLayout());
-
-		JPanel contentPanel = new JPanel();
-		contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
-		getContentPane().add(contentPanel, BorderLayout.CENTER);
-		contentPanel.setLayout(null);
-
-		JLabel lblCategory = new JLabel("Category:");
-		lblCategory.setBounds(12, 13, 68, 22);
-		contentPanel.add(lblCategory);
-
-		choice = new Choice();
-		choice.setBounds(86, 13, 172, 22);
-		contentPanel.add(choice);
-		// add categories
-		if (GuiSettings.getCategories().isEmpty()){
-			this.controller.createCategoryWithName("Template");			
-		}
-		// add Categories to the choice
-		for (Category c : GuiSettings.getCategories())
-			choice.add(c.getName());
-
-		JLabel lblName = new JLabel("Name:");
-		lblName.setBounds(12, 48, 56, 16);
-		contentPanel.add(lblName);
-
-		textField_name = new JTextField();
-		textField_name.setBounds(86, 48, 172, 22);
-		contentPanel.add(textField_name);
-		textField_name.setColumns(10);
-		textField_name.setText(template.getName());
-
-		JLabel lblImage = new JLabel("Image:");
-		lblImage.setBounds(12, 89, 56, 16);
-		contentPanel.add(lblImage);
-
-		textField_imagePath = new JTextField();
-		textField_imagePath.setBounds(86, 86, 172, 22);
-		contentPanel.add(textField_imagePath);
-		textField_imagePath.setColumns(10);
-		textField_imagePath.setText(template.getImagePath());
-
-		JButton btnBrowseImage = new JButton("BrowseImage");
-		btnBrowseImage.setBounds(268, 85, 117, 25);
-		contentPanel.add(btnBrowseImage);
-		btnBrowseImage.addActionListener(clicked -> fileChooser());
-
-		lblImagePreview = new JLabel("Image Preview");
-		lblImagePreview.setIcon(new ImageIcon(Import.loadImage(
-				template.getImagePath(), 62, 62)));
-		lblImagePreview.setBounds(298, 13, 62, 62);
-		contentPanel.add(lblImagePreview);
-
-		listModel = new DefaultListModel<>();
-
-		template.elementsStream().forEach(hE -> {
-			listModel.addElement(hE.getName()
-					+ ": " + hE.getEnergy() + "U");
-			holonElementList.add(hE);
-		});
-		template.clearElements();
-		JScrollPane scrollPane = new JScrollPane();
-		scrollPane.setBounds(22, 118, 236, 150);
-		contentPanel.add(scrollPane);
-		list = new JList<>(listModel);
-		scrollPane.setViewportView(list);
-
-		JButton btnDeleteElement = new JButton("Delete Element");
-		btnDeleteElement.setBounds(268, 228, 140, 25);
-		contentPanel.add(btnDeleteElement);
-		btnDeleteElement.addActionListener(e -> removeElement());
-
-		JButton btnEditElement = new JButton("Edit Element");
-		btnEditElement.setBounds(268, 190, 140, 25);
-		contentPanel.add(btnEditElement);
-		btnEditElement.addActionListener(e -> editElement());
-
-		JButton btnAddElement = new JButton("Add Element");
-		btnAddElement.setBounds(268, 152, 140, 25);
-		contentPanel.add(btnAddElement);
-		btnAddElement.addActionListener(e -> addElement());
-
-		JButton btnCancel = new JButton("Cancel");
-		btnCancel.setBounds(384, 277, 74, 25);
-		contentPanel.add(btnCancel);
-		btnCancel.addActionListener(e -> dispose());
-
-		/*
-		 * Add Template Button
-		 */
-		JButton btnAddTemplate = new JButton("Add Template");
-		btnAddTemplate.setBounds(75, 271, 113, 25);
-		contentPanel.add(btnAddTemplate);
-		btnAddTemplate.addActionListener(e -> createTemplate());
-
-		/*
-		 * Title
-		 */
-		setTitle("Create Template Menu");
-		this.setVisible(true);
-	}
-
-	/**
-	 * Choose the file.
-	 */
-	private void fileChooser() {
-		JFileChooser fileChooser = new JFileChooser();
-		FileNameExtensionFilter filter = new FileNameExtensionFilter(
-				"png, jpg or jpeg", "png", "jpg", "jpeg");
-		fileChooser.setFileFilter(filter);
-		int returnValue = fileChooser.showOpenDialog(null);
-		if (returnValue == JFileChooser.APPROVE_OPTION) {
-			File selectedFile = fileChooser.getSelectedFile();
-			String filePath = selectedFile.getAbsolutePath();
-			textField_imagePath.setText(filePath);
-			ImageIcon icon = new ImageIcon(Import.loadImage(filePath, 62,
-					62));
-			lblImagePreview.setIcon(icon);
-		} else {
-			System.out.println("Failed to Load");
-		}
-
-	}
-
-	/**
-	 * create the template and add it to the category
-	 */
-	private void createTemplate() {
-		template.setName(textField_name.getText());
-		template.setImagePath(textField_imagePath.getText());
-		template.clearElements();
-		template.add(holonElementList);
-		controller.findCategoryWithName(choice
-				.getItem(choice.getSelectedIndex())).ifPresent(cat -> controller.addObject(cat, template.getName(),
-						template.elementsStream().toList(), template.getImagePath()));
-		this.dispose();
-	}
-
-	/**
-	 * Add an Holon Element to the template
-	 */
-	private void addElement() {
-		AddElementPopUp popUp = new AddElementPopUp(parent);
-		popUp.setActualHolonObject(template);
-		popUp.setVisible(true);
-		HolonElement he = popUp.getElement();
-		if (he != null) {
-			listModel.addElement(he.getName()
-					+ ": " + he.getEnergy() + "U");
-			holonElementList.add(he);
-		}
-	}
-
-	/**
-	 * Removes the Selected Element from the template
-	 */
-	private void removeElement() {
-		int index = list.getSelectedIndex();
-		if (index == -1)
-			return;
-		listModel.remove(index);
-		holonElementList.remove(index);
-	}
-
-	/**
-	 * Edits the selected HolonElement
-	 */
-	private void editElement() {
-		int index = list.getSelectedIndex();
-		if (index == -1)
-			return;
-		
-		AddElementPopUp popUp = new AddElementPopUp(parent);
-		popUp.setActualHolonObject(template);
-		popUp.setElement(template.elementsStream().toList().get(index));
-		popUp.setVisible(true);
-		HolonElement he = popUp.getElement();
-		if (he != null) {
-			listModel.remove(index);
-			holonElementList.remove(index);
-			listModel.addElement(he.getName()
-					+ ": " + he.getEnergy() + "U");
-			holonElementList.add(he);
-		}
-	}
+  /**
+   * Template HolonObject
+   */
+  private final HolonObject template;
+
+  /**
+   * HolonElementList
+   */
+  private final DefaultListModel<String> listModel;
+  private final List<HolonElement> holonElementList = new ArrayList<>();
+
+  /**
+   * HolonElement List
+   */
+  private final JList<String> list;
+
+  // Template Attributes
+
+  // PopUp Parts
+  private final Control controller;
+  /**
+   * name textfield
+   */
+  private final JTextField textField_name;
+  /**
+   * textField for path
+   */
+  private final JTextField textField_imagePath;
+  /**
+   * Category Selection
+   */
+  Choice choice;
+  /**
+   * Image Preview
+   */
+  JLabel lblImagePreview;
+
+  /**
+   * parent Frame
+   */
+  JFrame parent;
+
+  /**
+   * Create the dialog.
+   * <p>
+   * true if edit
+   *
+   * @param obj the object
+   */
+  public CreateTemplatePopUp(HolonObject obj,
+      JFrame parentFrame, Control controller) {
+    setResizable(false);
+    /*
+     * use Category Controller an stuff lul
+     */
+
+    /*
+     * initialize Data
+     */
+    template = new HolonObject(obj);
+    this.parent = parentFrame;
+    this.controller = controller;
+    /*
+     * create Frame and GUI
+     */
+    setIconImage(Import.loadImage(ImagePreference.Logo, 30, 30));
+    setBounds(100, 100, 476, 344);
+    setLocationRelativeTo(parentFrame);
+    getContentPane().setLayout(new BorderLayout());
+
+    JPanel contentPanel = new JPanel();
+    contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
+    getContentPane().add(contentPanel, BorderLayout.CENTER);
+    contentPanel.setLayout(null);
+
+    JLabel lblCategory = new JLabel("Category:");
+    lblCategory.setBounds(12, 13, 68, 22);
+    contentPanel.add(lblCategory);
+
+    choice = new Choice();
+    choice.setBounds(86, 13, 172, 22);
+    contentPanel.add(choice);
+    // add categories
+    if (GuiSettings.getCategories().isEmpty()) {
+      this.controller.createCategoryWithName("Template");
+    }
+    // add Categories to the choice
+    for (Category c : GuiSettings.getCategories()) {
+      choice.add(c.getName());
+    }
+
+    JLabel lblName = new JLabel("Name:");
+    lblName.setBounds(12, 48, 56, 16);
+    contentPanel.add(lblName);
+
+    textField_name = new JTextField();
+    textField_name.setBounds(86, 48, 172, 22);
+    contentPanel.add(textField_name);
+    textField_name.setColumns(10);
+    textField_name.setText(template.getName());
+
+    JLabel lblImage = new JLabel("Image:");
+    lblImage.setBounds(12, 89, 56, 16);
+    contentPanel.add(lblImage);
+
+    textField_imagePath = new JTextField();
+    textField_imagePath.setBounds(86, 86, 172, 22);
+    contentPanel.add(textField_imagePath);
+    textField_imagePath.setColumns(10);
+    textField_imagePath.setText(template.getImagePath());
+
+    JButton btnBrowseImage = new JButton("BrowseImage");
+    btnBrowseImage.setBounds(268, 85, 117, 25);
+    contentPanel.add(btnBrowseImage);
+    btnBrowseImage.addActionListener(clicked -> fileChooser());
+
+    lblImagePreview = new JLabel("Image Preview");
+    lblImagePreview.setIcon(new ImageIcon(Import.loadImage(
+        template.getImagePath(), 62, 62)));
+    lblImagePreview.setBounds(298, 13, 62, 62);
+    contentPanel.add(lblImagePreview);
+
+    listModel = new DefaultListModel<>();
+
+    template.elementsStream().forEach(hE -> {
+      listModel.addElement(hE.getName()
+          + ": " + hE.getEnergy() + "U");
+      holonElementList.add(hE);
+    });
+    template.clearElements();
+    JScrollPane scrollPane = new JScrollPane();
+    scrollPane.setBounds(22, 118, 236, 150);
+    contentPanel.add(scrollPane);
+    list = new JList<>(listModel);
+    scrollPane.setViewportView(list);
+
+    JButton btnDeleteElement = new JButton("Delete Element");
+    btnDeleteElement.setBounds(268, 228, 140, 25);
+    contentPanel.add(btnDeleteElement);
+    btnDeleteElement.addActionListener(e -> removeElement());
+
+    JButton btnEditElement = new JButton("Edit Element");
+    btnEditElement.setBounds(268, 190, 140, 25);
+    contentPanel.add(btnEditElement);
+    btnEditElement.addActionListener(e -> editElement());
+
+    JButton btnAddElement = new JButton("Add Element");
+    btnAddElement.setBounds(268, 152, 140, 25);
+    contentPanel.add(btnAddElement);
+    btnAddElement.addActionListener(e -> addElement());
+
+    JButton btnCancel = new JButton("Cancel");
+    btnCancel.setBounds(384, 277, 74, 25);
+    contentPanel.add(btnCancel);
+    btnCancel.addActionListener(e -> dispose());
+
+    /*
+     * Add Template Button
+     */
+    JButton btnAddTemplate = new JButton("Add Template");
+    btnAddTemplate.setBounds(75, 271, 113, 25);
+    contentPanel.add(btnAddTemplate);
+    btnAddTemplate.addActionListener(e -> createTemplate());
+
+    /*
+     * Title
+     */
+    setTitle("Create Template Menu");
+    this.setVisible(true);
+  }
+
+  /**
+   * Choose the file.
+   */
+  private void fileChooser() {
+    JFileChooser fileChooser = new JFileChooser();
+    FileNameExtensionFilter filter = new FileNameExtensionFilter(
+        "png, jpg or jpeg", "png", "jpg", "jpeg");
+    fileChooser.setFileFilter(filter);
+    int returnValue = fileChooser.showOpenDialog(null);
+    if (returnValue == JFileChooser.APPROVE_OPTION) {
+      File selectedFile = fileChooser.getSelectedFile();
+      String filePath = selectedFile.getAbsolutePath();
+      textField_imagePath.setText(filePath);
+      ImageIcon icon = new ImageIcon(Import.loadImage(filePath, 62,
+          62));
+      lblImagePreview.setIcon(icon);
+    } else {
+      System.out.println("Failed to Load");
+    }
+
+  }
+
+  /**
+   * create the template and add it to the category
+   */
+  private void createTemplate() {
+    template.setName(textField_name.getText());
+    template.setImagePath(textField_imagePath.getText());
+    template.clearElements();
+    template.add(holonElementList);
+    controller.findCategoryWithName(choice
+            .getItem(choice.getSelectedIndex()))
+        .ifPresent(cat -> controller.addObject(cat, template.getName(),
+            template.elementsStream().toList(), template.getImagePath()));
+    this.dispose();
+  }
+
+  /**
+   * Add an Holon Element to the template
+   */
+  private void addElement() {
+    AddElementPopUp popUp = new AddElementPopUp(parent);
+    popUp.setActualHolonObject(template);
+    popUp.setVisible(true);
+    HolonElement he = popUp.getElement();
+    if (he != null) {
+      listModel.addElement(he.getName()
+          + ": " + he.getEnergy() + "U");
+      holonElementList.add(he);
+    }
+  }
+
+  /**
+   * Removes the Selected Element from the template
+   */
+  private void removeElement() {
+    int index = list.getSelectedIndex();
+    if (index == -1) {
+      return;
+    }
+    listModel.remove(index);
+    holonElementList.remove(index);
+  }
+
+  /**
+   * Edits the selected HolonElement
+   */
+  private void editElement() {
+    int index = list.getSelectedIndex();
+    if (index == -1) {
+      return;
+    }
+
+    AddElementPopUp popUp = new AddElementPopUp(parent);
+    popUp.setActualHolonObject(template);
+    popUp.setElement(template.elementsStream().toList().get(index));
+    popUp.setVisible(true);
+    HolonElement he = popUp.getElement();
+    if (he != null) {
+      listModel.remove(index);
+      holonElementList.remove(index);
+      listModel.addElement(he.getName()
+          + ": " + he.getEnergy() + "U");
+      holonElementList.add(he);
+    }
+  }
 
 
 }
 }

+ 139 - 129
src/holeg/ui/view/dialog/EditEdgesPopUp.java

@@ -5,142 +5,152 @@ import holeg.preferences.ImagePreference;
 import holeg.ui.controller.Control;
 import holeg.ui.controller.Control;
 import holeg.ui.model.GuiSettings;
 import holeg.ui.model.GuiSettings;
 import holeg.ui.view.image.Import;
 import holeg.ui.view.image.Import;
-
-import javax.swing.*;
+import java.awt.BorderLayout;
+import java.awt.Font;
+import javax.swing.ButtonGroup;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JTextField;
 import javax.swing.border.EmptyBorder;
 import javax.swing.border.EmptyBorder;
-import java.awt.*;
 
 
 /**
 /**
  * Popup for Editing Edges.
  * Popup for Editing Edges.
- * 
+ *
  * @author Gruppe14
  * @author Gruppe14
  */
  */
 public class EditEdgesPopUp extends JDialog {
 public class EditEdgesPopUp extends JDialog {
-	private final JTextField capacityField;
-	private float capacity;
-	private final JRadioButton existingEdgesRadioButton = new JRadioButton("Change for all existing Edges only");
-	private final JRadioButton newEdgesRadioButton = new JRadioButton("Change for new created Edges only");
-	private final JRadioButton existingAndNewEdgesRadioButton = new JRadioButton("Change for all existing and new created Edges");
-	private final Control control;
-
-
-	/**
-	 * Constructor.
-	 */
-    public EditEdgesPopUp(JFrame parentFrame, Control control) {
-        super((java.awt.Frame) null, true);
-		setModalityType(java.awt.Dialog.ModalityType.APPLICATION_MODAL);
-		this.setTitle("Edit Capacities of Edges");
-		setBounds(100, 100, 400, 220);
-        setLocationRelativeTo(parentFrame);
-        getContentPane().setLayout(new BorderLayout());
-		JPanel contentPanel = new JPanel();
-		contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
-		getContentPane().add(contentPanel, BorderLayout.CENTER);
-		contentPanel.setLayout(null);
-		this.setIconImage(Import.loadImage(ImagePreference.Logo, 30, 30));
-		JLabel lblMaximumCapacity = new JLabel("Maximum Capacity:");
-		lblMaximumCapacity.setFont(new Font("Tahoma", Font.PLAIN, 11));
-		lblMaximumCapacity.setBounds(10, 11, 98, 14);
-		contentPanel.add(lblMaximumCapacity);
-
-		capacityField = new JTextField();
-		capacityField.setBounds(107, 8, 120, 20);
-		contentPanel.add(capacityField);
-		capacityField.setColumns(10);
-
-		existingEdgesRadioButton.setBounds(10, 39, 330, 23);
-		contentPanel.add(existingEdgesRadioButton);
-
-		newEdgesRadioButton.setBounds(10, 65, 330, 23);
-		contentPanel.add(newEdgesRadioButton);
-
-		existingAndNewEdgesRadioButton.setBounds(10, 95, 400, 23);
-		contentPanel.add(existingAndNewEdgesRadioButton);
-
-		JButton btnCancel = new JButton("Cancel");
-		btnCancel.setActionCommand("Cancel");
-		btnCancel.addActionListener(clicked -> dispose());
-
-		btnCancel.setBounds(285, 147, 89, 23);
-		contentPanel.add(btnCancel);
-
-		JButton btnOk1 = new JButton("OK");
-		btnOk1.addActionListener(clicked -> {
-				try {
-					capacity = Float.parseFloat(capacityField.getText());
-					if (capacity < 0) {
-						throw new NumberFormatException();
-					}
-					if (existingEdgesRadioButton.isSelected()) {
-						changeForExisting(capacity);
-						dispose();
-					} else if (newEdgesRadioButton.isSelected()) {
-						changeForNew(capacity);
-						dispose();
-					} else if (existingAndNewEdgesRadioButton.isSelected()) {
-						changeForExAndNew(capacity);
-						dispose();
-					} else {
-						JOptionPane.showMessageDialog(new JFrame(), "Please select one of the options");
-					}
-				} catch (NumberFormatException eex) {
-					JOptionPane.showMessageDialog(new JFrame(), "Please enter a number greater or equal 0 in the Field for Maximum Capacity");
-				}
-		});
-		btnOk1.setBounds(186, 147, 89, 23);
-		contentPanel.add(btnOk1);
-		this.setTitle("Edit Edge Capacities");
-		ButtonGroup bG = new ButtonGroup();
-		bG.add(existingAndNewEdgesRadioButton);
-		bG.add(newEdgesRadioButton);
-		bG.add(existingEdgesRadioButton);
-		existingAndNewEdgesRadioButton.setSelected(true);
-		this.control = control;
-		this.setVisible(true);
-	}
-
-	/**
-	 * set edge capacity for new edges.
-	 * 
-	 * @param cap
-	 *            the capacity
-	 */
-	public void changeForNew(float cap) {
-		GuiSettings.maxCapacityForNewCreatedEdges = cap;
-		control.resetSimulation();
-	}
-
-	/**
-	 * Set Capacity for all existing Edges.
-	 * 
-	 * @param cap
-	 *            the Capacity
-	 */
-	public void changeForExisting(float cap) {
-		/*
-		 * for(SubNet sn: controller.getSimManager().getSubNets()){ for(CpsEdge
-		 * edge: sn.getEdges()){ edge.setCapacity(cap); } } for(CpsEdge edge:
-		 * controller.getSimManager().getBrokenEdges()){ edge.setCapacity(cap);
-		 * }
-		 */
-		for (Edge edge : control.getModel().getEdgesOnCanvas()) {
-			edge.maxCapacity = cap;
+
+  private final JTextField capacityField;
+  private final JRadioButton existingEdgesRadioButton = new JRadioButton(
+      "Change for all existing Edges only");
+  private final JRadioButton newEdgesRadioButton = new JRadioButton(
+      "Change for new created Edges only");
+  private final JRadioButton existingAndNewEdgesRadioButton = new JRadioButton(
+      "Change for all existing and new created Edges");
+  private final Control control;
+  private float capacity;
+
+
+  /**
+   * Constructor.
+   */
+  public EditEdgesPopUp(JFrame parentFrame, Control control) {
+    super((java.awt.Frame) null, true);
+    setModalityType(java.awt.Dialog.ModalityType.APPLICATION_MODAL);
+    this.setTitle("Edit Capacities of Edges");
+    setBounds(100, 100, 400, 220);
+    setLocationRelativeTo(parentFrame);
+    getContentPane().setLayout(new BorderLayout());
+    JPanel contentPanel = new JPanel();
+    contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
+    getContentPane().add(contentPanel, BorderLayout.CENTER);
+    contentPanel.setLayout(null);
+    this.setIconImage(Import.loadImage(ImagePreference.Logo, 30, 30));
+    JLabel lblMaximumCapacity = new JLabel("Maximum Capacity:");
+    lblMaximumCapacity.setFont(new Font("Tahoma", Font.PLAIN, 11));
+    lblMaximumCapacity.setBounds(10, 11, 98, 14);
+    contentPanel.add(lblMaximumCapacity);
+
+    capacityField = new JTextField();
+    capacityField.setBounds(107, 8, 120, 20);
+    contentPanel.add(capacityField);
+    capacityField.setColumns(10);
+
+    existingEdgesRadioButton.setBounds(10, 39, 330, 23);
+    contentPanel.add(existingEdgesRadioButton);
+
+    newEdgesRadioButton.setBounds(10, 65, 330, 23);
+    contentPanel.add(newEdgesRadioButton);
+
+    existingAndNewEdgesRadioButton.setBounds(10, 95, 400, 23);
+    contentPanel.add(existingAndNewEdgesRadioButton);
+
+    JButton btnCancel = new JButton("Cancel");
+    btnCancel.setActionCommand("Cancel");
+    btnCancel.addActionListener(clicked -> dispose());
+
+    btnCancel.setBounds(285, 147, 89, 23);
+    contentPanel.add(btnCancel);
+
+    JButton btnOk1 = new JButton("OK");
+    btnOk1.addActionListener(clicked -> {
+      try {
+        capacity = Float.parseFloat(capacityField.getText());
+        if (capacity < 0) {
+          throw new NumberFormatException();
+        }
+        if (existingEdgesRadioButton.isSelected()) {
+          changeForExisting(capacity);
+          dispose();
+        } else if (newEdgesRadioButton.isSelected()) {
+          changeForNew(capacity);
+          dispose();
+        } else if (existingAndNewEdgesRadioButton.isSelected()) {
+          changeForExAndNew(capacity);
+          dispose();
+        } else {
+          JOptionPane.showMessageDialog(new JFrame(), "Please select one of the options");
         }
         }
-		control.resetSimulation();
-		control.updateStateForCurrentIteration();
-	}
-
-
-	/**
-	 * Set the Capacity for all existing and new edges.
-	 * 
-	 * @param cap
-	 *            the capacity
-	 */
-	public void changeForExAndNew(float cap) {
-		changeForNew(cap);
-		changeForExisting(cap);
-	}
+      } catch (NumberFormatException eex) {
+        JOptionPane.showMessageDialog(new JFrame(),
+            "Please enter a number greater or equal 0 in the Field for Maximum Capacity");
+      }
+    });
+    btnOk1.setBounds(186, 147, 89, 23);
+    contentPanel.add(btnOk1);
+    this.setTitle("Edit Edge Capacities");
+    ButtonGroup bG = new ButtonGroup();
+    bG.add(existingAndNewEdgesRadioButton);
+    bG.add(newEdgesRadioButton);
+    bG.add(existingEdgesRadioButton);
+    existingAndNewEdgesRadioButton.setSelected(true);
+    this.control = control;
+    this.setVisible(true);
+  }
+
+  /**
+   * set edge capacity for new edges.
+   *
+   * @param cap the capacity
+   */
+  public void changeForNew(float cap) {
+    GuiSettings.maxCapacityForNewCreatedEdges = cap;
+    control.resetSimulation();
+  }
+
+  /**
+   * Set Capacity for all existing Edges.
+   *
+   * @param cap the Capacity
+   */
+  public void changeForExisting(float cap) {
+    /*
+     * for(SubNet sn: controller.getSimManager().getSubNets()){ for(CpsEdge
+     * edge: sn.getEdges()){ edge.setCapacity(cap); } } for(CpsEdge edge:
+     * controller.getSimManager().getBrokenEdges()){ edge.setCapacity(cap);
+     * }
+     */
+    for (Edge edge : control.getModel().getEdgesOnCanvas()) {
+      edge.maxCapacity = cap;
+    }
+    control.resetSimulation();
+    control.updateStateForCurrentIteration();
+  }
+
+
+  /**
+   * Set the Capacity for all existing and new edges.
+   *
+   * @param cap the capacity
+   */
+  public void changeForExAndNew(float cap) {
+    changeForNew(cap);
+    changeForExisting(cap);
+  }
 
 
 }
 }

+ 56 - 51
src/holeg/ui/view/dialog/NewCategoryDialog.java

@@ -1,58 +1,63 @@
 package holeg.ui.view.dialog;
 package holeg.ui.view.dialog;
 
 
 import holeg.ui.controller.Control;
 import holeg.ui.controller.Control;
-import holeg.ui.view.canvas.Canvas;
-
-import javax.swing.*;
-import java.awt.*;
-import java.util.logging.Logger;
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridLayout;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
 
 
 public class NewCategoryDialog extends JDialog {
 public class NewCategoryDialog extends JDialog {
 
 
-    private final JPanel contentPanel = new JPanel(new BorderLayout());
-    private final JPanel mainPanel = new JPanel();
-    private final JPanel buttonPanel = new JPanel();
-    private final JLabel categoryLabel = new JLabel("Category:");
-    private final JTextField nameTextField = new JTextField("Name");
-    private final JButton okayButton = new JButton("Okay");
-    private final JButton cancelButton = new JButton("Cancel");
-    private final Control control;
-
-    public NewCategoryDialog(Control control, JFrame parentFrame) {
-        super(parentFrame);
-        this.control = control;
-        init();
-        this.setVisible(true);
-        this.pack();
-        setLocationRelativeTo(parentFrame);
-    }
-
-    private void init() {
-        this.setTitle("Create new category");
-        initLayout();
-        initButtons();
-    }
-
-    private void initLayout() {
-        buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
-        contentPanel.setPreferredSize(new Dimension(200, 60));
-        mainPanel.setLayout(new GridLayout(1, 2));
-        mainPanel.add(categoryLabel);
-        mainPanel.add(nameTextField);
-        okayButton.setDefaultCapable(true);
-        buttonPanel.add(okayButton);
-        buttonPanel.add(cancelButton);
-        contentPanel.add(mainPanel);
-        contentPanel.add(buttonPanel, BorderLayout.PAGE_END);
-
-        this.setContentPane(contentPanel);
-    }
-
-    private void initButtons() {
-        okayButton.addActionListener(clicked -> {
-            control.createCategoryWithName(nameTextField.getText());
-            dispose();
-        });
-        cancelButton.addActionListener(clicked -> dispose());
-    }
+  private final JPanel contentPanel = new JPanel(new BorderLayout());
+  private final JPanel mainPanel = new JPanel();
+  private final JPanel buttonPanel = new JPanel();
+  private final JLabel categoryLabel = new JLabel("Category:");
+  private final JTextField nameTextField = new JTextField("Name");
+  private final JButton okayButton = new JButton("Okay");
+  private final JButton cancelButton = new JButton("Cancel");
+  private final Control control;
+
+  public NewCategoryDialog(Control control, JFrame parentFrame) {
+    super(parentFrame);
+    this.control = control;
+    init();
+    this.setVisible(true);
+    this.pack();
+    setLocationRelativeTo(parentFrame);
+  }
+
+  private void init() {
+    this.setTitle("Create new category");
+    initLayout();
+    initButtons();
+  }
+
+  private void initLayout() {
+    buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+    contentPanel.setPreferredSize(new Dimension(200, 60));
+    mainPanel.setLayout(new GridLayout(1, 2));
+    mainPanel.add(categoryLabel);
+    mainPanel.add(nameTextField);
+    okayButton.setDefaultCapable(true);
+    buttonPanel.add(okayButton);
+    buttonPanel.add(cancelButton);
+    contentPanel.add(mainPanel);
+    contentPanel.add(buttonPanel, BorderLayout.PAGE_END);
+
+    this.setContentPane(contentPanel);
+  }
+
+  private void initButtons() {
+    okayButton.addActionListener(clicked -> {
+      control.createCategoryWithName(nameTextField.getText());
+      dispose();
+    });
+    cancelButton.addActionListener(clicked -> dispose());
+  }
 }
 }

+ 99 - 98
src/holeg/ui/view/image/Import.java

@@ -1,5 +1,6 @@
 package holeg.ui.view.image;
 package holeg.ui.view.image;
 
 
+import holeg.preferences.ImagePreference;
 import java.awt.Image;
 import java.awt.Image;
 import java.awt.image.BufferedImage;
 import java.awt.image.BufferedImage;
 import java.io.File;
 import java.io.File;
@@ -10,110 +11,110 @@ import java.io.InputStream;
 import java.util.HashMap;
 import java.util.HashMap;
 import javax.imageio.ImageIO;
 import javax.imageio.ImageIO;
 
 
-import holeg.preferences.ImagePreference;
-
 /**
 /**
- * 
- * @author TU-Darmstadt BP Gruppe 7 WS17/18 Centralized resource loading methods
- *         for improved performance and easier troubleshooting.
+ * @author TU-Darmstadt BP Gruppe 7 WS17/18 Centralized resource loading methods for improved
+ * performance and easier troubleshooting.
  */
  */
 public class Import {
 public class Import {
-	/*
-	 * Save nothing: Reload every image whenever requested. Save external: Only save
-	 * images that were found as external file. Save raw: Save all non-scaled
-	 * images. Save everything: self-explanatory.
-	 */
-	private static final HashMap<String, Image> imgStorage;
-	static {
-		imgStorage = new HashMap<>();
-	}
 
 
-	/**
-	 * The rawest function replacing the old method without any default parameters.
-	 * Currently not used in HOLEG at all(aside form calls from the convenience
-	 * methods).
-	 * 
-	 * @param url   Path to the image to be loaded.
-	 * @param w     Width the loaded image should be scaled to.
-	 * @param h     Height the loaded image should be scaled to.
-	 * @param hints Hints for the scaling algorithm to be used. Same as the
-	 *              parameter in the getScaledInstance function of Image.
-	 * @return A loaded and scaled image from the requested path.
-	 */
-	static Image loadImage(String url, int w, int h, int hints) {
-		String key = url + "?" + w + "?" + h + "?" + hints;
-		if (imgStorage.containsKey(key))
-			return (imgStorage.get(key));
-		else {
-			Image img = loadImage(url).getScaledInstance(w, h, hints);
-			imgStorage.put(key, img);
-			return img;
-		}
-	}
+  /*
+   * Save nothing: Reload every image whenever requested. Save external: Only save
+   * images that were found as external file. Save raw: Save all non-scaled
+   * images. Save everything: self-explanatory.
+   */
+  private static final HashMap<String, Image> imgStorage;
+
+  static {
+    imgStorage = new HashMap<>();
+  }
+
+  private Import() {
+  }
+
+  /**
+   * The rawest function replacing the old method without any default parameters. Currently not used
+   * in HOLEG at all(aside form calls from the convenience methods).
+   *
+   * @param url   Path to the image to be loaded.
+   * @param w     Width the loaded image should be scaled to.
+   * @param h     Height the loaded image should be scaled to.
+   * @param hints Hints for the scaling algorithm to be used. Same as the parameter in the
+   *              getScaledInstance function of Image.
+   * @return A loaded and scaled image from the requested path.
+   */
+  static Image loadImage(String url, int w, int h, int hints) {
+    String key = url + "?" + w + "?" + h + "?" + hints;
+    if (imgStorage.containsKey(key)) {
+      return (imgStorage.get(key));
+    } else {
+      Image img = loadImage(url).getScaledInstance(w, h, hints);
+      imgStorage.put(key, img);
+      return img;
+    }
+  }
 
 
-	/**
-	 * Loads an image from the given path and scales it using the smooth algorithm.
-	 * 
-	 * @param url Path to the image to be loaded.
-	 * @param w   Width the loaded image should be scaled to.
-	 * @param h   Height the loaded image should be scaled to.
-	 * @return A loaded and (smoothly) scaled image from the requested path.
-	 */
-	public static Image loadImage(String url, int w, int h) {
-		return loadImage(url, w, h, Image.SCALE_SMOOTH);
-	}
+  /**
+   * Loads an image from the given path and scales it using the smooth algorithm.
+   *
+   * @param url Path to the image to be loaded.
+   * @param w   Width the loaded image should be scaled to.
+   * @param h   Height the loaded image should be scaled to.
+   * @return A loaded and (smoothly) scaled image from the requested path.
+   */
+  public static Image loadImage(String url, int w, int h) {
+    return loadImage(url, w, h, Image.SCALE_SMOOTH);
+  }
 
 
-	/**
-	 * Loads an image from the given path and scales it using the smooth algorithm.
-	 * 
-	 * @param url Path to the image to be loaded.
-	 * @return An image loaded from the requested path.
-	 */
-	public static Image loadImage(String url) {
-		if (imgStorage.containsKey(url))
-			return imgStorage.get(url);
-		else {
-			Image img;
-			try {
-				img = ImageIO.read(loadStream(url));
-			} catch (IOException e) {
-				return new BufferedImage(0, 0,
-						BufferedImage.TYPE_INT_RGB);
-			}
-			imgStorage.put(url, img);
-			return img;
-		}
-	}
+  /**
+   * Loads an image from the given path and scales it using the smooth algorithm.
+   *
+   * @param url Path to the image to be loaded.
+   * @return An image loaded from the requested path.
+   */
+  public static Image loadImage(String url) {
+    if (imgStorage.containsKey(url)) {
+      return imgStorage.get(url);
+    } else {
+      Image img;
+      try {
+        img = ImageIO.read(loadStream(url));
+      } catch (IOException e) {
+        return new BufferedImage(0, 0,
+            BufferedImage.TYPE_INT_RGB);
+      }
+      imgStorage.put(url, img);
+      return img;
+    }
+  }
 
 
-	/**
-	 * Loads any resource with a given path, regardless of whether it is inside the
-	 * jar or an external resource. Every loadImage() function uses this as a basis.
-	 * 
-	 * @param url The path (and file name) of the requested resource.
-	 * @return An InputStream from the requested resource.
-	 * @throws FileNotFoundException if file cannot be found
-	 */
-	public static InputStream loadStream(String url) throws FileNotFoundException {
-		InputStream o = InputStream.class.getResourceAsStream(url);
-		if (o != null)
-			return o;
-		else {
-			boolean rootSymbol = switch (url.charAt(0)) { // So we can make sure to construct res/path correctly.
-				case '/', '\\' -> true;
-				default -> false; // Whether url starts with a / or \
-			};
-			File f = new File(url);
-			if (!f.exists()) {
-				url = "res" + (rootSymbol ? "" : "/") + url;
-			}
-			f = new File(url);// Possible bug with duplicate names.
-			if (!f.exists()) {
-				url = "res" + ImagePreference.Canvas.ImageNotFound;
-			}
-			return new FileInputStream(url);
+  /**
+   * Loads any resource with a given path, regardless of whether it is inside the jar or an external
+   * resource. Every loadImage() function uses this as a basis.
+   *
+   * @param url The path (and file name) of the requested resource.
+   * @return An InputStream from the requested resource.
+   * @throws FileNotFoundException if file cannot be found
+   */
+  public static InputStream loadStream(String url) throws FileNotFoundException {
+    InputStream o = InputStream.class.getResourceAsStream(url);
+    if (o != null) {
+      return o;
+    } else {
+      boolean rootSymbol = switch (url.charAt(
+          0)) { // So we can make sure to construct res/path correctly.
+        case '/', '\\' -> true;
+        default -> false; // Whether url starts with a / or \
+      };
+      File f = new File(url);
+      if (!f.exists()) {
+        url = "res" + (rootSymbol ? "" : "/") + url;
+      }
+      f = new File(url);// Possible bug with duplicate names.
+      if (!f.exists()) {
+        url = "res" + ImagePreference.Canvas.ImageNotFound;
+      }
+      return new FileInputStream(url);
 
 
-		}
-	}
-	private Import() {
-	}
+    }
+  }
 }
 }

+ 543 - 501
src/holeg/ui/view/information/HolonInformationPanel.java

@@ -1,13 +1,42 @@
 package holeg.ui.view.information;
 package holeg.ui.view.information;
 
 
-import holeg.model.*;
+import holeg.model.AbstractCanvasObject;
+import holeg.model.Flexibility;
+import holeg.model.GroupNode;
+import holeg.model.HolonElement;
+import holeg.model.HolonObject;
 import holeg.model.HolonObject.HolonObjectState;
 import holeg.model.HolonObject.HolonObjectState;
+import holeg.model.HolonSwitch;
+import holeg.model.Node;
 import holeg.preferences.ColorPreference;
 import holeg.preferences.ColorPreference;
 import holeg.preferences.ImagePreference;
 import holeg.preferences.ImagePreference;
 import holeg.ui.controller.Control;
 import holeg.ui.controller.Control;
 import holeg.ui.model.GuiSettings;
 import holeg.ui.model.GuiSettings;
 import holeg.ui.view.image.Import;
 import holeg.ui.view.image.Import;
 import holeg.utility.math.decimal.Format;
 import holeg.utility.math.decimal.Format;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.GridLayout;
+import java.awt.Insets;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+import javax.swing.BorderFactory;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JLabel;
+import javax.swing.JLayeredPane;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JToggleButton;
+import javax.swing.OverlayLayout;
+import javax.swing.event.PopupMenuEvent;
+import javax.swing.event.PopupMenuListener;
 import org.knowm.xchart.PieChart;
 import org.knowm.xchart.PieChart;
 import org.knowm.xchart.PieChartBuilder;
 import org.knowm.xchart.PieChartBuilder;
 import org.knowm.xchart.PieSeries.PieSeriesRenderStyle;
 import org.knowm.xchart.PieSeries.PieSeriesRenderStyle;
@@ -15,505 +44,518 @@ import org.knowm.xchart.XChartPanel;
 import org.knowm.xchart.style.PieStyler;
 import org.knowm.xchart.style.PieStyler;
 import org.knowm.xchart.style.PieStyler.LabelType;
 import org.knowm.xchart.style.PieStyler.LabelType;
 
 
-import javax.swing.*;
-import javax.swing.event.PopupMenuEvent;
-import javax.swing.event.PopupMenuListener;
-import java.awt.*;
-import java.util.List;
-import java.util.Map;
-import java.util.logging.Logger;
-import java.util.stream.Collectors;
-
 public class HolonInformationPanel extends JPanel {
 public class HolonInformationPanel extends JPanel {
-	private static final Logger log = Logger.getLogger(HolonInformationPanel.class.getName());
-	private final int defaultWidth = 50;
-	private final int defaultHeight = 200;
-
-	private static final Color[] supplyStateColors = new Color[] { ColorPreference.HolonObject.Producer,
-			ColorPreference.HolonObject.OverSupplied, ColorPreference.HolonObject.Supplied,
-			ColorPreference.HolonObject.PartiallySupplied, ColorPreference.HolonObject.NotSupplied,
-			ColorPreference.HolonObject.NoEnergy, ColorPreference.InformationPanel.NoData };
-	private static final Color[] productionColors = new Color[] { ColorPreference.Energy.Production,
-			ColorPreference.Energy.Consumption, ColorPreference.InformationPanel.NoData };
-	private static final Color[] activeColors = new Color[] { ColorPreference.Element.Active,
-			ColorPreference.Element.Inactive, ColorPreference.InformationPanel.NoData };
-	private static final Color[] flexibilityColors = new Color[] { ColorPreference.Flexibility.Offered,
-			ColorPreference.Flexibility.InUse, ColorPreference.Flexibility.OnCooldown,
-			ColorPreference.Flexibility.NotOffered, ColorPreference.Flexibility.Unavailable, ColorPreference.Flexibility.NoFlexibility,
-			ColorPreference.InformationPanel.NoData };
-	private static final Color[] priorityColors = new Color[] { ColorPreference.Element.Priority.Essential,
-			ColorPreference.Element.Priority.High, ColorPreference.Element.Priority.Medium,
-			ColorPreference.Element.Priority.Low, ColorPreference.InformationPanel.NoData };
-	
-	private final PieChart supplyChart = createSupplyStateChart();
-	private final PieChart priorityChart = createPriorityChart();
-	private final PieChart flexibilityChart = createFlexibilityChart();
-	private final PieChart energyChart = createProductionChart();
-	private final PieChart activeChart = createActiveChart();
-
-	private final JPanel graphPanel = new JPanel(new GridLayout(0, 2));
-
-	private final JCheckBoxMenuItem producerCheckBox = new JCheckBoxMenuItem("Producer", true);
-	private final JCheckBoxMenuItem overSuppliedCheckBox = new JCheckBoxMenuItem("Over supplied", true);
-	private final JCheckBoxMenuItem suppliedCheckBox = new JCheckBoxMenuItem("Supplied", true);
-	private final JCheckBoxMenuItem partiallySuppliedCheckBox = new JCheckBoxMenuItem("Partial supplied", true);
-	private final JCheckBoxMenuItem notSuppliedCheckBox = new JCheckBoxMenuItem("Not supplied", true);
-	private final JCheckBoxMenuItem noEnergyCheckBox = new JCheckBoxMenuItem("No energy", true);
-
-	private final JCheckBoxMenuItem essentialCheckBox = new JCheckBoxMenuItem("Essential", true);
-	private final JCheckBoxMenuItem highCheckBox = new JCheckBoxMenuItem("High", true);
-	private final JCheckBoxMenuItem mediumBox = new JCheckBoxMenuItem("Medium", true);
-	private final JCheckBoxMenuItem lowCheckBox = new JCheckBoxMenuItem("Low", true);
-
-	private final JCheckBoxMenuItem activeCheckBox = new JCheckBoxMenuItem("Active", true);
-	private final JCheckBoxMenuItem inactiveCheckBox = new JCheckBoxMenuItem("Inactive", true);
-
-	private final JCheckBoxMenuItem noFlexibilityCheckBox = new JCheckBoxMenuItem("No Flexibility", true);
-	private final JCheckBoxMenuItem inUseCheckBox = new JCheckBoxMenuItem("In use", true);
-	private final JCheckBoxMenuItem offeredCheckBox = new JCheckBoxMenuItem("Offered", true);
-	private final JCheckBoxMenuItem notOfferedCheckBox = new JCheckBoxMenuItem("Not offered", true);
-	private final JCheckBoxMenuItem onCooldownCheckBox = new JCheckBoxMenuItem("On cooldown", true);
-	private final JCheckBoxMenuItem unavailableCheckBox = new JCheckBoxMenuItem("Unavailable", true);
-
-
-	private final Control control;
-	private final JLabel differenceEnergyLabelAmount = new JLabel("");
-
-	public HolonInformationPanel(Control control) {
-		control.OnSelectionChanged.addListener(this::updateCharts);
-		control.OnCanvasUpdate.addListener(this::updateCharts);
-		this.control = control;
-		this.setLayout(new BorderLayout());
-		initGraphPanel();
-		this.setBackground(ColorPreference.Panel.Background);
-		this.add(graphPanel, BorderLayout.CENTER);
-	}
-	
-	public void updateCharts() {
-		TempGroupNode tempGroupNode = new TempGroupNode();
-		if(GuiSettings.getSelectedObjects().isEmpty()){
-			tempGroupNode.add(control.getModel().getCanvas());
-		}else{
-			tempGroupNode.addAll(GuiSettings.getSelectedObjects());
-		}
-
-		List<HolonObject> filteredHolonObjectList = tempGroupNode.getAllHolonObjectsRecursive().filter(this::stateFilter).toList();
-		Map<HolonObjectState, Long> stateMap = filteredHolonObjectList.stream().collect(Collectors.groupingBy(HolonObject::getState, Collectors.counting()));
-		// UPDATE SUPPLY STATE
-		int producerAmount = Math.toIntExact(stateMap.getOrDefault(HolonObjectState.PRODUCER, 0L));
-		int overSuppliedAmount = Math.toIntExact(stateMap.getOrDefault(HolonObjectState.OVER_SUPPLIED, 0L));
-		int suppliedAmount = Math.toIntExact(stateMap.getOrDefault(HolonObjectState.SUPPLIED, 0L));
-		int partiallySuppliedAmount = Math.toIntExact(stateMap.getOrDefault(HolonObjectState.PARTIALLY_SUPPLIED, 0L));
-		int notSuppliedAmount = Math.toIntExact(stateMap.getOrDefault(HolonObjectState.NOT_SUPPLIED, 0L));
-		int noEnergyAmount = Math.toIntExact(stateMap.getOrDefault(HolonObjectState.NO_ENERGY, 0L));
-
-		supplyChart.updatePieSeries("Producer", producerAmount);
-		supplyChart.updatePieSeries("Over supplied", overSuppliedAmount);
-		supplyChart.updatePieSeries("Supplied", suppliedAmount);
-		supplyChart.updatePieSeries("Partial supplied", partiallySuppliedAmount);
-		supplyChart.updatePieSeries("Not supplied", notSuppliedAmount);
-		supplyChart.updatePieSeries("No energy", noEnergyAmount);
-		supplyChart.updatePieSeries("No Data", filteredHolonObjectList.isEmpty() ? 1 : 0);
-		//UPDATE PRIORITIES
-
-		List<HolonElement> filteredHolonElements = filteredHolonObjectList.stream().flatMap(HolonObject::elementsStream)
-				.filter(ele -> priorityFilter(ele) && activeFilter(ele) && flexibilityFilter(ele)).toList();
-		Map<HolonElement.Priority, Long> priorityCounts = filteredHolonElements.stream()
-				.collect(Collectors.groupingBy(HolonElement::getPriority, Collectors.counting()));
-
-		long essential = priorityCounts.getOrDefault(HolonElement.Priority.Essential, 0L);
-		long high = priorityCounts.getOrDefault(HolonElement.Priority.High, 0L);
-		long medium = priorityCounts.getOrDefault(HolonElement.Priority.Medium, 0L);
-		long low = priorityCounts.getOrDefault(HolonElement.Priority.Low, 0L);
-
-
-		priorityChart.updatePieSeries("Essential", essential);
-		priorityChart.updatePieSeries("High", high);
-		priorityChart.updatePieSeries("Medium", medium);
-		priorityChart.updatePieSeries("Low", low);
-		boolean hasPriority = essential + high + medium + low > 0;
-		priorityChart.updatePieSeries("No Data", hasPriority ? 0 : 1);
-
-		// UPDATE PRODUCTION
-		float consumption = filteredHolonElements.stream().filter(element -> element.getActualEnergy() < 0)
-				.map(element -> -element.getActualEnergy()).reduce(0.0f, Float::sum);
-		float production = filteredHolonElements.stream()
-				.map(HolonElement::getActualEnergy).filter(energy -> energy > 0).reduce(0.0f, Float::sum);
-
-		float difference = Math.abs(production - consumption);
-		energyChart.updatePieSeries("Production", production);
-		energyChart.updatePieSeries("Consumption", consumption);
-		energyChart.updatePieSeries("No Data", production + consumption == 0 ? 1 : 0);
-		differenceEnergyLabelAmount.setText(Format.doubleFixedPlaces(1, difference));
-
-		// UPDATE FLEXIBILITIES
-		int inUse = 0;
-		int offered = 0;
-		int onCooldown = 0;
-		int notOffered = 0;
-		int unavailable = 0;
-
-		List<Flexibility> flexList = filteredHolonElements.stream().flatMap(ele -> ele.flexList.stream()).toList();
-		for (Flexibility flex : flexList) {
-			switch (flex.getState()) {
-				case IN_USE -> inUse++;
-				case NOT_OFFERED -> notOffered++;
-				case OFFERED -> offered++;
-				case ON_COOLDOWN -> onCooldown++;
-				case UNAVAILABLE -> unavailable++;
-				default -> {
-				}
-			}
-		}
-		int noFlexibility = (int)filteredHolonElements.stream().filter(ele -> ele.flexList.isEmpty()).count();
-		flexibilityChart.updatePieSeries("No flexibility", noFlexibility);
-		flexibilityChart.updatePieSeries("Offered", offered);
-		flexibilityChart.updatePieSeries("In use", inUse);
-		flexibilityChart.updatePieSeries("On cooldown", onCooldown);
-		flexibilityChart.updatePieSeries("Not offered", notOffered);
-		flexibilityChart.updatePieSeries("Unavailable", unavailable);
-		boolean hasFlex = noFlexibility + offered + inUse + onCooldown + notOffered + unavailable > 0;
-		flexibilityChart.updatePieSeries("No Data", hasFlex ? 0 : 1);
-
-		Map<Boolean, Long> activeCounts = filteredHolonElements.stream()
-				.collect(Collectors.groupingBy(HolonElement::isOn, Collectors.counting()));
-
-		// UPDATE ActiveInActive
-		int activeAmount = Math.toIntExact(activeCounts.getOrDefault(true, 0L));
-		int inactiveAmounts = Math.toIntExact(activeCounts.getOrDefault(false, 0L));
-		activeChart.updatePieSeries("Active", activeAmount);
-		activeChart.updatePieSeries("Inactive", inactiveAmounts);
-		activeChart.updatePieSeries("No Data", activeAmount + inactiveAmounts == 0 ? 1 : 0);
-		this.revalidate();
-		this.repaint();
-	}
-
-
-	private JPopupMenu createHolonStateSelection(){
-		JPopupMenu menu = new JPopupMenu();
-		producerCheckBox.addActionListener(clicked -> updateCharts());
-		overSuppliedCheckBox.addActionListener(clicked -> updateCharts());
-		suppliedCheckBox.addActionListener(clicked -> updateCharts());
-		partiallySuppliedCheckBox.addActionListener(clicked -> updateCharts());
-		notSuppliedCheckBox.addActionListener(clicked -> updateCharts());
-		noEnergyCheckBox.addActionListener(clicked -> updateCharts());
-		menu.add(producerCheckBox);
-		menu.add(overSuppliedCheckBox);
-		menu.add(suppliedCheckBox);
-		menu.add(partiallySuppliedCheckBox);
-		menu.add(notSuppliedCheckBox);
-		menu.add(noEnergyCheckBox);
-		return menu;
-	}
-
-	private JPopupMenu createPrioritySelection(){
-		JPopupMenu menu = new JPopupMenu();
-		essentialCheckBox.addActionListener(clicked -> updateCharts());
-		highCheckBox.addActionListener(clicked -> updateCharts());
-		mediumBox.addActionListener(clicked -> updateCharts());
-		lowCheckBox.addActionListener(clicked -> updateCharts());
-		menu.add(essentialCheckBox);
-		menu.add(highCheckBox);
-		menu.add(mediumBox);
-		menu.add(lowCheckBox);
-		return menu;
-	}
-	private JPopupMenu createActiveSelection(){
-		JPopupMenu menu = new JPopupMenu();
-		activeCheckBox.addActionListener(clicked -> updateCharts());
-		inactiveCheckBox.addActionListener(clicked -> updateCharts());
-		menu.add(activeCheckBox);
-		menu.add(inactiveCheckBox);
-		return menu;
-	}
-
-	private JPopupMenu createFlexibilitySelection(){
-		JPopupMenu menu = new JPopupMenu();
-		noFlexibilityCheckBox.addActionListener(clicked -> updateCharts());
-		offeredCheckBox.addActionListener(clicked -> updateCharts());
-		notOfferedCheckBox.addActionListener(clicked -> updateCharts());
-		unavailableCheckBox.addActionListener(clicked -> updateCharts());
-		inUseCheckBox.addActionListener(clicked -> updateCharts());
-		onCooldownCheckBox.addActionListener(clicked -> updateCharts());
-		menu.add(noFlexibilityCheckBox);
-		menu.add(offeredCheckBox);
-		menu.add(notOfferedCheckBox);
-		menu.add(unavailableCheckBox);
-		menu.add(inUseCheckBox);
-		menu.add(onCooldownCheckBox);
-		return menu;
-	}
-
-
-	private JPanel initMenuButtonPanel(JPopupMenu menu){
-		JPanel buttonPanel = new JPanel(new BorderLayout());
-		MenuButton button = new MenuButton(new ImageIcon(Import.loadImage(ImagePreference.HolonInformationPanel.Filter, 20, 20)), menu);
-		buttonPanel.add(button, BorderLayout.LINE_END);
-		buttonPanel.setOpaque(false);
-		button.setPressedIcon(new ImageIcon(Import.loadImage(ImagePreference.HolonInformationPanel.FilterHovered, 20, 20)));
-		button.setRolloverIcon(new ImageIcon(Import.loadImage(ImagePreference.HolonInformationPanel.FilterHovered, 20, 20)));
-		button.setBorderPainted(false);
-		button.setBorder(null);
-		button.setFocusable(false);
-		button.setMargin(new Insets(0, 0, 0, 0));
-		button.setContentAreaFilled(false);
-		return buttonPanel;
-	}
-
-
-
-	private boolean stateFilter(HolonObject holonObject){
-		return switch (holonObject.getState())	{
-			case PRODUCER -> producerCheckBox.isSelected();
-			case OVER_SUPPLIED -> overSuppliedCheckBox.isSelected();
-			case SUPPLIED -> suppliedCheckBox.isSelected();
-			case PARTIALLY_SUPPLIED -> partiallySuppliedCheckBox.isSelected();
-			case NOT_SUPPLIED -> notSuppliedCheckBox.isSelected();
-			case NO_ENERGY -> noEnergyCheckBox.isSelected();
-		};
- 	}
-
-	private boolean priorityFilter(HolonElement ele){
-		return switch (ele.priority)	{
-			case Essential -> essentialCheckBox.isSelected();
-			case High -> highCheckBox.isSelected();
-			case Medium -> mediumBox.isSelected();
-			case Low -> lowCheckBox.isSelected();
-		};
-	}
-
-	private boolean activeFilter(HolonElement ele){
-		return ele.active ? activeCheckBox.isSelected(): inactiveCheckBox.isSelected();
-	}
-
-	private boolean flexibilityFilter(HolonElement ele){
-		if(ele.flexList.isEmpty()){
-			return noFlexibilityCheckBox.isSelected();
-		}
-		Map<Flexibility.FlexState,Long> flexes =  ele.flexList.stream().collect(Collectors.groupingBy(Flexibility::getState, Collectors.counting()));
-		return  flexes.keySet().stream().anyMatch(flexState -> switch (flexState)	{
-			case IN_USE -> inUseCheckBox.isSelected();
-			case UNAVAILABLE -> unavailableCheckBox.isSelected();
-			case OFFERED -> offeredCheckBox.isSelected();
-			case NOT_OFFERED -> notOfferedCheckBox.isSelected();
-			case ON_COOLDOWN -> onCooldownCheckBox.isSelected();
-		});
-	}
-
-
-
-
-	public static class MenuButton extends JToggleButton {
-
-		JPopupMenu popup;
-
-		public MenuButton(Icon icon, JPopupMenu menu) {
-			super(icon);
-			this.popup = menu;
-			addActionListener(clicked -> {
-				if (MenuButton.this.isSelected()) {
-					popup.show(MenuButton.this, 0, MenuButton.this.getBounds().height);
-				} else {
-					popup.setVisible(false);
-				}
-			});
-			popup.addPopupMenuListener(new PopupMenuListener() {
-				@Override
-				public void popupMenuWillBecomeVisible(PopupMenuEvent e) {}
-				@Override
-				public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
-					MenuButton.this.setSelected(false);
-				}
-				@Override
-				public void popupMenuCanceled(PopupMenuEvent e) {}
-			});
-		}
-	}
-
-
-
-	private void initGraphPanel() {
-		graphPanel.setBackground(ColorPreference.Panel.Background);
-		XChartPanel<PieChart> panelHolonObject = new XChartPanel<>(supplyChart);
-		panelHolonObject.setLayout(new BorderLayout());
-		panelHolonObject.add(initMenuButtonPanel(createHolonStateSelection()), BorderLayout.PAGE_START);
-		panelHolonObject.setBackground(ColorPreference.Panel.Background);
-		graphPanel.add(panelHolonObject);
-		XChartPanel<PieChart> panelPriority = new XChartPanel<>(priorityChart);
-		panelPriority.setLayout(new BorderLayout());
-		panelPriority.add(initMenuButtonPanel(createPrioritySelection()), BorderLayout.PAGE_START);
-		panelPriority.setBackground(ColorPreference.Panel.Background);
-		graphPanel.add(panelPriority);
-		XChartPanel<PieChart> panelFlexibility = new XChartPanel<>(flexibilityChart);
-		panelFlexibility.setLayout(new BorderLayout());
-		panelFlexibility.add(initMenuButtonPanel(createFlexibilitySelection()), BorderLayout.PAGE_START);
-		panelFlexibility.setBackground(ColorPreference.Panel.Background);
-		graphPanel.add(panelFlexibility);
-		Component panel = initEnergyChart();
-		graphPanel.add(panel);
-		XChartPanel<PieChart> panelActive = new XChartPanel<>(activeChart);
-		panelActive.setLayout(new BorderLayout());
-		panelActive.add(initMenuButtonPanel(createActiveSelection()), BorderLayout.PAGE_START);
-		panelActive.setBackground(ColorPreference.Panel.Background);
-		graphPanel.add(panelActive);
-		graphPanel.setBorder(BorderFactory.createLineBorder(Color.lightGray));
-	}
-
-	private JLayeredPane initEnergyChart() {
-		JLayeredPane panel = new JLayeredPane();
-		JPanel panelMiddle = new JPanel(new GridBagLayout());
-		XChartPanel<PieChart> panelEnergy = new XChartPanel<>(energyChart);
-		panelEnergy.setBackground(ColorPreference.Panel.Background);
-		GridBagConstraints c = new GridBagConstraints();
-		c.gridx = 0;
-		c.gridy = 0;
-		c.insets = new Insets(15, 0, 0, 0); // top padding
-		JLabel difference = new JLabel("Difference:");
-		difference.setHorizontalAlignment(JLabel.CENTER);
-		difference.setAlignmentX(Component.CENTER_ALIGNMENT);
-		difference.setForeground(ColorPreference.Panel.Title);
-		difference.setFont(new java.awt.Font("Arial", java.awt.Font.BOLD, 10));
-		panelMiddle.add(difference, c);
-
-		differenceEnergyLabelAmount.setHorizontalAlignment(JLabel.CENTER);
-		differenceEnergyLabelAmount.setForeground(Color.red);
-		differenceEnergyLabelAmount.setAlignmentX(Component.CENTER_ALIGNMENT);
-		differenceEnergyLabelAmount.setFont(new java.awt.Font("Arial", java.awt.Font.BOLD, 12));
-		c.insets = new Insets(0, 0, 0, 0);
-		c.gridy = 1;
-		panelMiddle.add(differenceEnergyLabelAmount, c);
-		panel.setLayout(new OverlayLayout(panel));
-		panelEnergy.setOpaque(false);
-		panelMiddle.setOpaque(false);
-		panel.add(panelMiddle, Integer.valueOf(0));
-		panel.add(panelEnergy, Integer.valueOf(1));
-		return panel;
-	}
-
-	public void setDefaultPieChartSettings(PieChart chart) {
-		PieStyler styler = chart.getStyler();
-		styler.setChartTitleVisible(true);
-		styler.setDefaultSeriesRenderStyle(PieSeriesRenderStyle.Donut);
-		styler.setLabelsFont(new java.awt.Font("Arial", java.awt.Font.PLAIN, 14));
-		styler.setLabelType(LabelType.Percentage);
-		styler.setLabelsFontColor(Color.black);
-		styler.setLabelsFontColorAutomaticEnabled(false);
-		styler.setLabelsDistance(0.8);
-		styler.setChartFontColor(ColorPreference.Panel.Title);
-		styler.setToolTipsEnabled(true);
-		styler.setPlotContentSize(0.9);
-		styler.setPlotBackgroundColor(ColorPreference.Panel.Transparent);
-		styler.setPlotBorderColor(ColorPreference.Panel.Transparent);
-		styler.setLegendVisible(false);
-		styler.setChartBackgroundColor(ColorPreference.Panel.Transparent);
-	}
-
-	public PieChart createSupplyStateChart() {
-		PieChart chart = new PieChartBuilder().width(defaultWidth).height(defaultHeight).title("HolonObjects").build();
-		setDefaultPieChartSettings(chart);
-
-		chart.getStyler().setSeriesColors(supplyStateColors);
-
-		// Series
-		chart.addSeries("Producer", 0);
-		chart.addSeries("Over supplied", 0);
-		chart.addSeries("Supplied", 0);
-		chart.addSeries("Partial supplied", 0);
-		chart.addSeries("Not supplied", 0);
-		chart.addSeries("No energy", 0);
-		chart.addSeries("No Data", 0);
-		return chart;
-	}
-
-	public PieChart createPriorityChart() {
-		PieChart chart = new PieChartBuilder().width(defaultWidth).height(defaultHeight).title("Priorities").build();
-		setDefaultPieChartSettings(chart);
-		// Customize Chart
-
-		chart.getStyler().setSeriesColors(priorityColors);
-		// Series
-		chart.addSeries("Essential", 0);
-		chart.addSeries("High", 0);
-		chart.addSeries("Medium", 0);
-		chart.addSeries("Low", 0);
-		chart.addSeries("No Data", 0);
-		return chart;
-	}
-
-	public PieChart createFlexibilityChart() {
-		PieChart chart = new PieChartBuilder().width(defaultWidth).height(defaultHeight).title("Flexibilities").build();
-		setDefaultPieChartSettings(chart);
-		// Customize Chart
-
-		chart.getStyler().setSeriesColors(flexibilityColors);
-		// Series
-		chart.addSeries("Offered", 0);
-		chart.addSeries("In use", 0);
-		chart.addSeries("On cooldown", 0);
-		chart.addSeries("Not offered", 0);
-		chart.addSeries("Unavailable", 0);
-		chart.addSeries("No flexibility", 0);
-		chart.addSeries("No Data", 0);
-		return chart;
-	}
-
-	public PieChart createProductionChart() {
-		PieChart chart = new PieChartBuilder().width(defaultWidth).height(defaultHeight)
-				.title("Production vs. Consumption").build();
-		setDefaultPieChartSettings(chart);
-
-		// Customize Chart
-		// Customize Chart
-
-		chart.getStyler().setSeriesColors(productionColors);
-		// Series
-		chart.addSeries("Production", 0);
-		chart.addSeries("Consumption", 0);
-		chart.addSeries("No Data", 0);
-		return chart;
-	}
-
-	public PieChart createActiveChart() {
-		PieChart chart = new PieChartBuilder().width(defaultWidth).height(defaultHeight).title("Active").build();
-		setDefaultPieChartSettings(chart);
-		// Customize Chart
-		// Customize Chart
-
-		chart.getStyler().setSeriesColors(activeColors);
-		// Series
-		chart.addSeries("Active", 0);
-		chart.addSeries("Inactive", 0);
-		chart.addSeries("No Data", 0);
-		return chart;
-	}
-
-	private static class TempGroupNode extends GroupNode {
-		public TempGroupNode() {
-			super("temp");
-		}
-
-		public void add(AbstractCanvasObject object) {
-			if (object instanceof HolonObject hObject) {
-				objectList.add(hObject);
-			}else if(object instanceof HolonSwitch hSwitch) {
-				switchList.add(hSwitch);
-			}else if(object instanceof Node node) {
-				nodeList.add(node);
-			}else if(object instanceof GroupNode groupNode) {
-				groupNodeList.add(groupNode);
-			}
-		}
-
-		public void remove(AbstractCanvasObject object) {
-			if (object instanceof HolonObject hObject) {
-				objectList.remove(hObject);
-			}else if(object instanceof HolonSwitch hSwitch) {
-				switchList.remove(hSwitch);
-			}else if(object instanceof Node node) {
-				nodeList.remove(node);
-			}else if(object instanceof GroupNode groupNode) {
-				groupNodeList.remove(groupNode);
-			}
-		}
-	}
+
+  private static final Logger log = Logger.getLogger(HolonInformationPanel.class.getName());
+  private static final Color[] supplyStateColors = new Color[]{ColorPreference.HolonObject.Producer,
+      ColorPreference.HolonObject.OverSupplied, ColorPreference.HolonObject.Supplied,
+      ColorPreference.HolonObject.PartiallySupplied, ColorPreference.HolonObject.NotSupplied,
+      ColorPreference.HolonObject.NoEnergy, ColorPreference.InformationPanel.NoData};
+  private static final Color[] productionColors = new Color[]{ColorPreference.Energy.Production,
+      ColorPreference.Energy.Consumption, ColorPreference.InformationPanel.NoData};
+  private static final Color[] activeColors = new Color[]{ColorPreference.Element.Active,
+      ColorPreference.Element.Inactive, ColorPreference.InformationPanel.NoData};
+  private static final Color[] flexibilityColors = new Color[]{ColorPreference.Flexibility.Offered,
+      ColorPreference.Flexibility.InUse, ColorPreference.Flexibility.OnCooldown,
+      ColorPreference.Flexibility.NotOffered, ColorPreference.Flexibility.Unavailable,
+      ColorPreference.Flexibility.NoFlexibility,
+      ColorPreference.InformationPanel.NoData};
+  private static final Color[] priorityColors = new Color[]{
+      ColorPreference.Element.Priority.Essential,
+      ColorPreference.Element.Priority.High, ColorPreference.Element.Priority.Medium,
+      ColorPreference.Element.Priority.Low, ColorPreference.InformationPanel.NoData};
+  private final int defaultWidth = 50;
+  private final int defaultHeight = 200;
+  private final PieChart supplyChart = createSupplyStateChart();
+  private final PieChart priorityChart = createPriorityChart();
+  private final PieChart flexibilityChart = createFlexibilityChart();
+  private final PieChart energyChart = createProductionChart();
+  private final PieChart activeChart = createActiveChart();
+
+  private final JPanel graphPanel = new JPanel(new GridLayout(0, 2));
+
+  private final JCheckBoxMenuItem producerCheckBox = new JCheckBoxMenuItem("Producer", true);
+  private final JCheckBoxMenuItem overSuppliedCheckBox = new JCheckBoxMenuItem("Over supplied",
+      true);
+  private final JCheckBoxMenuItem suppliedCheckBox = new JCheckBoxMenuItem("Supplied", true);
+  private final JCheckBoxMenuItem partiallySuppliedCheckBox = new JCheckBoxMenuItem(
+      "Partial supplied", true);
+  private final JCheckBoxMenuItem notSuppliedCheckBox = new JCheckBoxMenuItem("Not supplied", true);
+  private final JCheckBoxMenuItem noEnergyCheckBox = new JCheckBoxMenuItem("No energy", true);
+
+  private final JCheckBoxMenuItem essentialCheckBox = new JCheckBoxMenuItem("Essential", true);
+  private final JCheckBoxMenuItem highCheckBox = new JCheckBoxMenuItem("High", true);
+  private final JCheckBoxMenuItem mediumBox = new JCheckBoxMenuItem("Medium", true);
+  private final JCheckBoxMenuItem lowCheckBox = new JCheckBoxMenuItem("Low", true);
+
+  private final JCheckBoxMenuItem activeCheckBox = new JCheckBoxMenuItem("Active", true);
+  private final JCheckBoxMenuItem inactiveCheckBox = new JCheckBoxMenuItem("Inactive", true);
+
+  private final JCheckBoxMenuItem noFlexibilityCheckBox = new JCheckBoxMenuItem("No Flexibility",
+      true);
+  private final JCheckBoxMenuItem inUseCheckBox = new JCheckBoxMenuItem("In use", true);
+  private final JCheckBoxMenuItem offeredCheckBox = new JCheckBoxMenuItem("Offered", true);
+  private final JCheckBoxMenuItem notOfferedCheckBox = new JCheckBoxMenuItem("Not offered", true);
+  private final JCheckBoxMenuItem onCooldownCheckBox = new JCheckBoxMenuItem("On cooldown", true);
+  private final JCheckBoxMenuItem unavailableCheckBox = new JCheckBoxMenuItem("Unavailable", true);
+
+
+  private final Control control;
+  private final JLabel differenceEnergyLabelAmount = new JLabel("");
+
+  public HolonInformationPanel(Control control) {
+    control.OnSelectionChanged.addListener(this::updateCharts);
+    control.OnCanvasUpdate.addListener(this::updateCharts);
+    this.control = control;
+    this.setLayout(new BorderLayout());
+    initGraphPanel();
+    this.setBackground(ColorPreference.Panel.Background);
+    this.add(graphPanel, BorderLayout.CENTER);
+  }
+
+  public void updateCharts() {
+    TempGroupNode tempGroupNode = new TempGroupNode();
+    if (GuiSettings.getSelectedObjects().isEmpty()) {
+      tempGroupNode.add(control.getModel().getCanvas());
+    } else {
+      tempGroupNode.addAll(GuiSettings.getSelectedObjects());
+    }
+
+    List<HolonObject> filteredHolonObjectList = tempGroupNode.getAllHolonObjectsRecursive()
+        .filter(this::stateFilter).toList();
+    Map<HolonObjectState, Long> stateMap = filteredHolonObjectList.stream()
+        .collect(Collectors.groupingBy(HolonObject::getState, Collectors.counting()));
+    // UPDATE SUPPLY STATE
+    int producerAmount = Math.toIntExact(stateMap.getOrDefault(HolonObjectState.PRODUCER, 0L));
+    int overSuppliedAmount = Math.toIntExact(
+        stateMap.getOrDefault(HolonObjectState.OVER_SUPPLIED, 0L));
+    int suppliedAmount = Math.toIntExact(stateMap.getOrDefault(HolonObjectState.SUPPLIED, 0L));
+    int partiallySuppliedAmount = Math.toIntExact(
+        stateMap.getOrDefault(HolonObjectState.PARTIALLY_SUPPLIED, 0L));
+    int notSuppliedAmount = Math.toIntExact(
+        stateMap.getOrDefault(HolonObjectState.NOT_SUPPLIED, 0L));
+    int noEnergyAmount = Math.toIntExact(stateMap.getOrDefault(HolonObjectState.NO_ENERGY, 0L));
+
+    supplyChart.updatePieSeries("Producer", producerAmount);
+    supplyChart.updatePieSeries("Over supplied", overSuppliedAmount);
+    supplyChart.updatePieSeries("Supplied", suppliedAmount);
+    supplyChart.updatePieSeries("Partial supplied", partiallySuppliedAmount);
+    supplyChart.updatePieSeries("Not supplied", notSuppliedAmount);
+    supplyChart.updatePieSeries("No energy", noEnergyAmount);
+    supplyChart.updatePieSeries("No Data", filteredHolonObjectList.isEmpty() ? 1 : 0);
+    //UPDATE PRIORITIES
+
+    List<HolonElement> filteredHolonElements = filteredHolonObjectList.stream()
+        .flatMap(HolonObject::elementsStream)
+        .filter(ele -> priorityFilter(ele) && activeFilter(ele) && flexibilityFilter(ele)).toList();
+    Map<HolonElement.Priority, Long> priorityCounts = filteredHolonElements.stream()
+        .collect(Collectors.groupingBy(HolonElement::getPriority, Collectors.counting()));
+
+    long essential = priorityCounts.getOrDefault(HolonElement.Priority.Essential, 0L);
+    long high = priorityCounts.getOrDefault(HolonElement.Priority.High, 0L);
+    long medium = priorityCounts.getOrDefault(HolonElement.Priority.Medium, 0L);
+    long low = priorityCounts.getOrDefault(HolonElement.Priority.Low, 0L);
+
+    priorityChart.updatePieSeries("Essential", essential);
+    priorityChart.updatePieSeries("High", high);
+    priorityChart.updatePieSeries("Medium", medium);
+    priorityChart.updatePieSeries("Low", low);
+    boolean hasPriority = essential + high + medium + low > 0;
+    priorityChart.updatePieSeries("No Data", hasPriority ? 0 : 1);
+
+    // UPDATE PRODUCTION
+    float consumption = filteredHolonElements.stream()
+        .filter(element -> element.getActualEnergy() < 0)
+        .map(element -> -element.getActualEnergy()).reduce(0.0f, Float::sum);
+    float production = filteredHolonElements.stream()
+        .map(HolonElement::getActualEnergy).filter(energy -> energy > 0).reduce(0.0f, Float::sum);
+
+    float difference = Math.abs(production - consumption);
+    energyChart.updatePieSeries("Production", production);
+    energyChart.updatePieSeries("Consumption", consumption);
+    energyChart.updatePieSeries("No Data", production + consumption == 0 ? 1 : 0);
+    differenceEnergyLabelAmount.setText(Format.doubleFixedPlaces(1, difference));
+
+    // UPDATE FLEXIBILITIES
+    int inUse = 0;
+    int offered = 0;
+    int onCooldown = 0;
+    int notOffered = 0;
+    int unavailable = 0;
+
+    List<Flexibility> flexList = filteredHolonElements.stream()
+        .flatMap(ele -> ele.flexList.stream()).toList();
+    for (Flexibility flex : flexList) {
+      switch (flex.getState()) {
+        case IN_USE -> inUse++;
+        case NOT_OFFERED -> notOffered++;
+        case OFFERED -> offered++;
+        case ON_COOLDOWN -> onCooldown++;
+        case UNAVAILABLE -> unavailable++;
+        default -> {
+        }
+      }
+    }
+    int noFlexibility = (int) filteredHolonElements.stream().filter(ele -> ele.flexList.isEmpty())
+        .count();
+    flexibilityChart.updatePieSeries("No flexibility", noFlexibility);
+    flexibilityChart.updatePieSeries("Offered", offered);
+    flexibilityChart.updatePieSeries("In use", inUse);
+    flexibilityChart.updatePieSeries("On cooldown", onCooldown);
+    flexibilityChart.updatePieSeries("Not offered", notOffered);
+    flexibilityChart.updatePieSeries("Unavailable", unavailable);
+    boolean hasFlex = noFlexibility + offered + inUse + onCooldown + notOffered + unavailable > 0;
+    flexibilityChart.updatePieSeries("No Data", hasFlex ? 0 : 1);
+
+    Map<Boolean, Long> activeCounts = filteredHolonElements.stream()
+        .collect(Collectors.groupingBy(HolonElement::isOn, Collectors.counting()));
+
+    // UPDATE ActiveInActive
+    int activeAmount = Math.toIntExact(activeCounts.getOrDefault(true, 0L));
+    int inactiveAmounts = Math.toIntExact(activeCounts.getOrDefault(false, 0L));
+    activeChart.updatePieSeries("Active", activeAmount);
+    activeChart.updatePieSeries("Inactive", inactiveAmounts);
+    activeChart.updatePieSeries("No Data", activeAmount + inactiveAmounts == 0 ? 1 : 0);
+    this.revalidate();
+    this.repaint();
+  }
+
+
+  private JPopupMenu createHolonStateSelection() {
+    JPopupMenu menu = new JPopupMenu();
+    producerCheckBox.addActionListener(clicked -> updateCharts());
+    overSuppliedCheckBox.addActionListener(clicked -> updateCharts());
+    suppliedCheckBox.addActionListener(clicked -> updateCharts());
+    partiallySuppliedCheckBox.addActionListener(clicked -> updateCharts());
+    notSuppliedCheckBox.addActionListener(clicked -> updateCharts());
+    noEnergyCheckBox.addActionListener(clicked -> updateCharts());
+    menu.add(producerCheckBox);
+    menu.add(overSuppliedCheckBox);
+    menu.add(suppliedCheckBox);
+    menu.add(partiallySuppliedCheckBox);
+    menu.add(notSuppliedCheckBox);
+    menu.add(noEnergyCheckBox);
+    return menu;
+  }
+
+  private JPopupMenu createPrioritySelection() {
+    JPopupMenu menu = new JPopupMenu();
+    essentialCheckBox.addActionListener(clicked -> updateCharts());
+    highCheckBox.addActionListener(clicked -> updateCharts());
+    mediumBox.addActionListener(clicked -> updateCharts());
+    lowCheckBox.addActionListener(clicked -> updateCharts());
+    menu.add(essentialCheckBox);
+    menu.add(highCheckBox);
+    menu.add(mediumBox);
+    menu.add(lowCheckBox);
+    return menu;
+  }
+
+  private JPopupMenu createActiveSelection() {
+    JPopupMenu menu = new JPopupMenu();
+    activeCheckBox.addActionListener(clicked -> updateCharts());
+    inactiveCheckBox.addActionListener(clicked -> updateCharts());
+    menu.add(activeCheckBox);
+    menu.add(inactiveCheckBox);
+    return menu;
+  }
+
+  private JPopupMenu createFlexibilitySelection() {
+    JPopupMenu menu = new JPopupMenu();
+    noFlexibilityCheckBox.addActionListener(clicked -> updateCharts());
+    offeredCheckBox.addActionListener(clicked -> updateCharts());
+    notOfferedCheckBox.addActionListener(clicked -> updateCharts());
+    unavailableCheckBox.addActionListener(clicked -> updateCharts());
+    inUseCheckBox.addActionListener(clicked -> updateCharts());
+    onCooldownCheckBox.addActionListener(clicked -> updateCharts());
+    menu.add(noFlexibilityCheckBox);
+    menu.add(offeredCheckBox);
+    menu.add(notOfferedCheckBox);
+    menu.add(unavailableCheckBox);
+    menu.add(inUseCheckBox);
+    menu.add(onCooldownCheckBox);
+    return menu;
+  }
+
+
+  private JPanel initMenuButtonPanel(JPopupMenu menu) {
+    JPanel buttonPanel = new JPanel(new BorderLayout());
+    MenuButton button = new MenuButton(
+        new ImageIcon(Import.loadImage(ImagePreference.HolonInformationPanel.Filter, 20, 20)),
+        menu);
+    buttonPanel.add(button, BorderLayout.LINE_END);
+    buttonPanel.setOpaque(false);
+    button.setPressedIcon(new ImageIcon(
+        Import.loadImage(ImagePreference.HolonInformationPanel.FilterHovered, 20, 20)));
+    button.setRolloverIcon(new ImageIcon(
+        Import.loadImage(ImagePreference.HolonInformationPanel.FilterHovered, 20, 20)));
+    button.setBorderPainted(false);
+    button.setBorder(null);
+    button.setFocusable(false);
+    button.setMargin(new Insets(0, 0, 0, 0));
+    button.setContentAreaFilled(false);
+    return buttonPanel;
+  }
+
+
+  private boolean stateFilter(HolonObject holonObject) {
+    return switch (holonObject.getState()) {
+      case PRODUCER -> producerCheckBox.isSelected();
+      case OVER_SUPPLIED -> overSuppliedCheckBox.isSelected();
+      case SUPPLIED -> suppliedCheckBox.isSelected();
+      case PARTIALLY_SUPPLIED -> partiallySuppliedCheckBox.isSelected();
+      case NOT_SUPPLIED -> notSuppliedCheckBox.isSelected();
+      case NO_ENERGY -> noEnergyCheckBox.isSelected();
+    };
+  }
+
+  private boolean priorityFilter(HolonElement ele) {
+    return switch (ele.priority) {
+      case Essential -> essentialCheckBox.isSelected();
+      case High -> highCheckBox.isSelected();
+      case Medium -> mediumBox.isSelected();
+      case Low -> lowCheckBox.isSelected();
+    };
+  }
+
+  private boolean activeFilter(HolonElement ele) {
+    return ele.active ? activeCheckBox.isSelected() : inactiveCheckBox.isSelected();
+  }
+
+  private boolean flexibilityFilter(HolonElement ele) {
+    if (ele.flexList.isEmpty()) {
+      return noFlexibilityCheckBox.isSelected();
+    }
+    Map<Flexibility.FlexState, Long> flexes = ele.flexList.stream()
+        .collect(Collectors.groupingBy(Flexibility::getState, Collectors.counting()));
+    return flexes.keySet().stream().anyMatch(flexState -> switch (flexState) {
+      case IN_USE -> inUseCheckBox.isSelected();
+      case UNAVAILABLE -> unavailableCheckBox.isSelected();
+      case OFFERED -> offeredCheckBox.isSelected();
+      case NOT_OFFERED -> notOfferedCheckBox.isSelected();
+      case ON_COOLDOWN -> onCooldownCheckBox.isSelected();
+    });
+  }
+
+  private void initGraphPanel() {
+    graphPanel.setBackground(ColorPreference.Panel.Background);
+    XChartPanel<PieChart> panelHolonObject = new XChartPanel<>(supplyChart);
+    panelHolonObject.setLayout(new BorderLayout());
+    panelHolonObject.add(initMenuButtonPanel(createHolonStateSelection()), BorderLayout.PAGE_START);
+    panelHolonObject.setBackground(ColorPreference.Panel.Background);
+    graphPanel.add(panelHolonObject);
+    XChartPanel<PieChart> panelPriority = new XChartPanel<>(priorityChart);
+    panelPriority.setLayout(new BorderLayout());
+    panelPriority.add(initMenuButtonPanel(createPrioritySelection()), BorderLayout.PAGE_START);
+    panelPriority.setBackground(ColorPreference.Panel.Background);
+    graphPanel.add(panelPriority);
+    XChartPanel<PieChart> panelFlexibility = new XChartPanel<>(flexibilityChart);
+    panelFlexibility.setLayout(new BorderLayout());
+    panelFlexibility.add(initMenuButtonPanel(createFlexibilitySelection()),
+        BorderLayout.PAGE_START);
+    panelFlexibility.setBackground(ColorPreference.Panel.Background);
+    graphPanel.add(panelFlexibility);
+    Component panel = initEnergyChart();
+    graphPanel.add(panel);
+    XChartPanel<PieChart> panelActive = new XChartPanel<>(activeChart);
+    panelActive.setLayout(new BorderLayout());
+    panelActive.add(initMenuButtonPanel(createActiveSelection()), BorderLayout.PAGE_START);
+    panelActive.setBackground(ColorPreference.Panel.Background);
+    graphPanel.add(panelActive);
+    graphPanel.setBorder(BorderFactory.createLineBorder(Color.lightGray));
+  }
+
+  private JLayeredPane initEnergyChart() {
+    JLayeredPane panel = new JLayeredPane();
+    JPanel panelMiddle = new JPanel(new GridBagLayout());
+    XChartPanel<PieChart> panelEnergy = new XChartPanel<>(energyChart);
+    panelEnergy.setBackground(ColorPreference.Panel.Background);
+    GridBagConstraints c = new GridBagConstraints();
+    c.gridx = 0;
+    c.gridy = 0;
+    c.insets = new Insets(15, 0, 0, 0); // top padding
+    JLabel difference = new JLabel("Difference:");
+    difference.setHorizontalAlignment(JLabel.CENTER);
+    difference.setAlignmentX(Component.CENTER_ALIGNMENT);
+    difference.setForeground(ColorPreference.Panel.Title);
+    difference.setFont(new java.awt.Font("Arial", java.awt.Font.BOLD, 10));
+    panelMiddle.add(difference, c);
+
+    differenceEnergyLabelAmount.setHorizontalAlignment(JLabel.CENTER);
+    differenceEnergyLabelAmount.setForeground(Color.red);
+    differenceEnergyLabelAmount.setAlignmentX(Component.CENTER_ALIGNMENT);
+    differenceEnergyLabelAmount.setFont(new java.awt.Font("Arial", java.awt.Font.BOLD, 12));
+    c.insets = new Insets(0, 0, 0, 0);
+    c.gridy = 1;
+    panelMiddle.add(differenceEnergyLabelAmount, c);
+    panel.setLayout(new OverlayLayout(panel));
+    panelEnergy.setOpaque(false);
+    panelMiddle.setOpaque(false);
+    panel.add(panelMiddle, Integer.valueOf(0));
+    panel.add(panelEnergy, Integer.valueOf(1));
+    return panel;
+  }
+
+  public void setDefaultPieChartSettings(PieChart chart) {
+    PieStyler styler = chart.getStyler();
+    styler.setChartTitleVisible(true);
+    styler.setDefaultSeriesRenderStyle(PieSeriesRenderStyle.Donut);
+    styler.setLabelsFont(new java.awt.Font("Arial", java.awt.Font.PLAIN, 14));
+    styler.setLabelType(LabelType.Percentage);
+    styler.setLabelsFontColor(Color.black);
+    styler.setLabelsFontColorAutomaticEnabled(false);
+    styler.setLabelsDistance(0.8);
+    styler.setChartFontColor(ColorPreference.Panel.Title);
+    styler.setToolTipsEnabled(true);
+    styler.setPlotContentSize(0.9);
+    styler.setPlotBackgroundColor(ColorPreference.Panel.Transparent);
+    styler.setPlotBorderColor(ColorPreference.Panel.Transparent);
+    styler.setLegendVisible(false);
+    styler.setChartBackgroundColor(ColorPreference.Panel.Transparent);
+  }
+
+  public PieChart createSupplyStateChart() {
+    PieChart chart = new PieChartBuilder().width(defaultWidth).height(defaultHeight)
+        .title("HolonObjects").build();
+    setDefaultPieChartSettings(chart);
+
+    chart.getStyler().setSeriesColors(supplyStateColors);
+
+    // Series
+    chart.addSeries("Producer", 0);
+    chart.addSeries("Over supplied", 0);
+    chart.addSeries("Supplied", 0);
+    chart.addSeries("Partial supplied", 0);
+    chart.addSeries("Not supplied", 0);
+    chart.addSeries("No energy", 0);
+    chart.addSeries("No Data", 0);
+    return chart;
+  }
+
+  public PieChart createPriorityChart() {
+    PieChart chart = new PieChartBuilder().width(defaultWidth).height(defaultHeight)
+        .title("Priorities").build();
+    setDefaultPieChartSettings(chart);
+    // Customize Chart
+
+    chart.getStyler().setSeriesColors(priorityColors);
+    // Series
+    chart.addSeries("Essential", 0);
+    chart.addSeries("High", 0);
+    chart.addSeries("Medium", 0);
+    chart.addSeries("Low", 0);
+    chart.addSeries("No Data", 0);
+    return chart;
+  }
+
+  public PieChart createFlexibilityChart() {
+    PieChart chart = new PieChartBuilder().width(defaultWidth).height(defaultHeight)
+        .title("Flexibilities").build();
+    setDefaultPieChartSettings(chart);
+    // Customize Chart
+
+    chart.getStyler().setSeriesColors(flexibilityColors);
+    // Series
+    chart.addSeries("Offered", 0);
+    chart.addSeries("In use", 0);
+    chart.addSeries("On cooldown", 0);
+    chart.addSeries("Not offered", 0);
+    chart.addSeries("Unavailable", 0);
+    chart.addSeries("No flexibility", 0);
+    chart.addSeries("No Data", 0);
+    return chart;
+  }
+
+  public PieChart createProductionChart() {
+    PieChart chart = new PieChartBuilder().width(defaultWidth).height(defaultHeight)
+        .title("Production vs. Consumption").build();
+    setDefaultPieChartSettings(chart);
+
+    // Customize Chart
+    // Customize Chart
+
+    chart.getStyler().setSeriesColors(productionColors);
+    // Series
+    chart.addSeries("Production", 0);
+    chart.addSeries("Consumption", 0);
+    chart.addSeries("No Data", 0);
+    return chart;
+  }
+
+  public PieChart createActiveChart() {
+    PieChart chart = new PieChartBuilder().width(defaultWidth).height(defaultHeight).title("Active")
+        .build();
+    setDefaultPieChartSettings(chart);
+    // Customize Chart
+    // Customize Chart
+
+    chart.getStyler().setSeriesColors(activeColors);
+    // Series
+    chart.addSeries("Active", 0);
+    chart.addSeries("Inactive", 0);
+    chart.addSeries("No Data", 0);
+    return chart;
+  }
+
+  public static class MenuButton extends JToggleButton {
+
+    JPopupMenu popup;
+
+    public MenuButton(Icon icon, JPopupMenu menu) {
+      super(icon);
+      this.popup = menu;
+      addActionListener(clicked -> {
+        if (MenuButton.this.isSelected()) {
+          popup.show(MenuButton.this, 0, MenuButton.this.getBounds().height);
+        } else {
+          popup.setVisible(false);
+        }
+      });
+      popup.addPopupMenuListener(new PopupMenuListener() {
+        @Override
+        public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
+        }
+
+        @Override
+        public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
+          MenuButton.this.setSelected(false);
+        }
+
+        @Override
+        public void popupMenuCanceled(PopupMenuEvent e) {
+        }
+      });
+    }
+  }
+
+  private static class TempGroupNode extends GroupNode {
+
+    public TempGroupNode() {
+      super("temp");
+    }
+
+    public void add(AbstractCanvasObject object) {
+      if (object instanceof HolonObject hObject) {
+        objectList.add(hObject);
+      } else if (object instanceof HolonSwitch hSwitch) {
+        switchList.add(hSwitch);
+      } else if (object instanceof Node node) {
+        nodeList.add(node);
+      } else if (object instanceof GroupNode groupNode) {
+        groupNodeList.add(groupNode);
+      }
+    }
+
+    public void remove(AbstractCanvasObject object) {
+      if (object instanceof HolonObject hObject) {
+        objectList.remove(hObject);
+      } else if (object instanceof HolonSwitch hSwitch) {
+        switchList.remove(hSwitch);
+      } else if (object instanceof Node node) {
+        nodeList.remove(node);
+      } else if (object instanceof GroupNode groupNode) {
+        groupNodeList.remove(groupNode);
+      }
+    }
+  }
 }
 }

+ 197 - 189
src/holeg/ui/view/inspector/Inspector.java

@@ -1,5 +1,17 @@
 package holeg.ui.view.inspector;
 package holeg.ui.view.inspector;
 
 
+import holeg.interfaces.LocalMode;
+import holeg.interfaces.TimelineDependent;
+import holeg.model.HolonElement;
+import holeg.model.HolonSwitch;
+import holeg.preferences.ColorPreference;
+import holeg.preferences.ImagePreference;
+import holeg.ui.controller.Control;
+import holeg.ui.model.GuiSettings;
+import holeg.ui.view.image.Import;
+import holeg.utility.listener.ResizeListener;
+import holeg.utility.math.Maths;
+import holeg.utility.math.decimal.Format;
 import java.awt.BorderLayout;
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Color;
 import java.awt.Component;
 import java.awt.Component;
@@ -8,7 +20,6 @@ import java.awt.event.ItemEvent;
 import java.util.Set;
 import java.util.Set;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
-
 import javax.swing.Box;
 import javax.swing.Box;
 import javax.swing.GrayFilter;
 import javax.swing.GrayFilter;
 import javax.swing.ImageIcon;
 import javax.swing.ImageIcon;
@@ -21,198 +32,195 @@ import javax.swing.JScrollPane;
 import javax.swing.JSplitPane;
 import javax.swing.JSplitPane;
 import javax.swing.JToolBar;
 import javax.swing.JToolBar;
 
 
-import holeg.interfaces.LocalMode;
-import holeg.interfaces.TimelineDependent;
-import holeg.model.HolonElement;
-import holeg.model.HolonSwitch;
-import holeg.model.Model;
-import holeg.preferences.ImagePreference;
-import holeg.ui.controller.Control;
-import holeg.ui.model.GuiSettings;
-import holeg.ui.view.image.Import;
-import holeg.utility.listener.ResizeListener;
-import holeg.utility.math.Maths;
-import holeg.utility.math.decimal.Format;
-
 public class Inspector extends JSplitPane {
 public class Inspector extends JSplitPane {
-	private static final Logger log = Logger.getLogger(Inspector.class.getName());
-	private final UnitGraph unitGraph;
-	private final InspectorTable table;
-	private final JPanel scrollGraph = new JPanel();
-	private final JPanel graphLabel = new JPanel();
-	private final JLabel maxGraph = new JLabel("100%");
-	private final JLabel medGraph = new JLabel("50%");
-	private final JLabel minGraph = new JLabel("0%");
-	private final JPanel globalCurveLabel = new JPanel();
-	private final JLabel minEnergy = new JLabel("0.0");
-	private final JLabel maxEnergy = new JLabel("0.0");
-	private final JLabel zeroEnergy = new JLabel("0.0");
-	private final JToolBar toolBarGraph = new JToolBar();
-	private String[] comboContext = { "", "5", "10", "20", "100", "1000" };
-	private JComboBox<String> localPeriodInput = new JComboBox<String>(comboContext);
-	private JButton resetButton = new JButton("", new ImageIcon(Import.loadImage(ImagePreference.Button.Inspector.Reset)));
-	private final ImageIcon localPeriodButtonImageEnabled = new ImageIcon(Import.loadImage(ImagePreference.Button.Inspector.Graph));
-
-	private final ImageIcon localPeriodButtonImageDisabled = new ImageIcon(
-			GrayFilter.createDisabledImage(Import.loadImage(ImagePreference.Button.Inspector.Graph)));
-	private JButton localPeriodButton = new JButton("", localPeriodButtonImageEnabled);
-
-	public Inspector(Control control) {
-		table = new InspectorTable(control);
-		unitGraph = new UnitGraph(control);
-		table.OnElementSelectionChanged.addListener(this::updateUnitGraph);
-		initUI();
-		control.OnSelectionChanged.addListener(this::updateGlobalCurve);
-	}
-
-	private void initUI() {
-		this.setOrientation(JSplitPane.VERTICAL_SPLIT);
-		JScrollPane scrollPane = new JScrollPane(table);
-		scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
-		this.setTopComponent(scrollPane);
-		this.setBottomComponent(scrollGraph);
-		this.setDividerLocation(550);
-		scrollGraph.setLayout(new BorderLayout());
-		scrollGraph.add(unitGraph, BorderLayout.CENTER);
-		// Set up of the Properties section
-
-		graphLabel.setLayout(new BorderLayout(0, 10));
-		graphLabel.add(maxGraph, BorderLayout.NORTH);
-		graphLabel.add(medGraph, BorderLayout.CENTER);
-		graphLabel.add(minGraph, BorderLayout.SOUTH);
-
-		globalCurveLabel.setLayout(null);
-		globalCurveLabel.setMinimumSize(new Dimension(20, 0));
-		globalCurveLabel.setPreferredSize(new Dimension(20, 0));
-		maxEnergy.setForeground(Color.red);
-		minEnergy.setForeground(Color.red);
-		zeroEnergy.setForeground(Color.red);
-		globalCurveLabel.add(maxEnergy);
-		globalCurveLabel.add(zeroEnergy);
-		globalCurveLabel.add(minEnergy);
-		this.globalCurveLabel.addComponentListener((ResizeListener)resize -> updateGlobalCurve() );
-
-		toolBarGraph.setFloatable(false);
-		toolBarGraph.setAlignmentY(Component.RIGHT_ALIGNMENT);
-
-		localPeriodButton.setToolTipText("Toggle Local/Global Mode");
-		toolBarGraph.add(localPeriodButton);
-		// ComboBox
-		localPeriodInput.setEditable(true);
-		localPeriodInput.setVisible(false);
-		localPeriodInput.setMaximumSize(new Dimension(20, 23));
-		localPeriodInput.addItemListener(aListener -> {
-			if (aListener.getStateChange() == ItemEvent.DESELECTED) {
-				validateInput(localPeriodInput.getEditor().getItem().toString(), true);
-			}
-
-		});
-
-		toolBarGraph.add(localPeriodInput);
-
-		// localPeriodButtonFunction
-		localPeriodButton.addActionListener(actionEvent -> {
-			boolean newState = !localPeriodInput.isVisible();
-			changeLocalPeriodButtonAppeareance(newState);
-			log.info("LocalPeriodButton");
-		});
-
-		toolBarGraph.add(Box.createHorizontalGlue());
-		resetButton.setToolTipText("Reset");
-		resetButton.addActionListener(actionEvent -> unitGraph.reset());
-		toolBarGraph.add(resetButton);
-		scrollGraph.add(graphLabel, BorderLayout.WEST);
-		scrollGraph.add(globalCurveLabel, BorderLayout.EAST);
-		scrollGraph.add(toolBarGraph, BorderLayout.NORTH);
-
-	}
-
-	/**
-	 * Validate the LocalMode Input and when its valid save on the Element.
-	 * 
-	 * @param text         the inputText to validate.
-	 * @param bShowMessage when true, open a MessageDialog when text invalid.
-	 */
-	private void validateInput(String text, boolean bShowMessage) {
-		int localPeriodInputValue;
-		try {
-			localPeriodInputValue = Integer.parseInt(text);
-		} catch (NumberFormatException e) {
-			if (bShowMessage)
-				JOptionPane.showMessageDialog(null, '"' + text + '"' + " is not a valid Input. \n Use whole numbers.");
-			return;
-		}
-		LocalMode.Period period = new LocalMode.Period(7);
-		period.setInterval(localPeriodInputValue);
-		unitGraph.setPeriod(period);
-	}
-
-	/**
-	 * This Method updates the UnitGraph, saves the old LocalModeState and load the
-	 * new LocalModeState.
-	 * 
-	 * @param elements The new Element to load the UnitGraph
-	 */
-	private void updateUnitGraph(Set<HolonElement> elements) {
-		// SaveOld LocalMode State.
-		if (localPeriodInput.isVisible()) {
-			// Save Old State
-			validateInput(localPeriodInput.getEditor().getItem().toString(), false);
-		}
-		// Update UnitGraph
-		unitGraph.clearSeries();
-		for (TimelineDependent element : elements) {
-			unitGraph.addNewSeries(element);
-		}
-
-		if (elements.isEmpty()) {
-			GuiSettings.getSelectedObjects().stream().filter(obj -> obj instanceof HolonSwitch)
-					.forEach(obj -> unitGraph.addNewSeries((HolonSwitch) obj));
-		}
+
+  private static final Logger log = Logger.getLogger(Inspector.class.getName());
+  private final UnitGraph unitGraph;
+  private final InspectorTable table;
+  private final JPanel scrollGraph = new JPanel();
+  private final JPanel graphLabel = new JPanel();
+  private final JLabel maxGraph = new JLabel("100%");
+  private final JLabel medGraph = new JLabel("50%");
+  private final JLabel minGraph = new JLabel("0%");
+  private final JPanel globalCurveLabel = new JPanel();
+  private final JLabel minEnergy = new JLabel("0.0");
+  private final JLabel maxEnergy = new JLabel("0.0");
+  private final JLabel zeroEnergy = new JLabel("0.0");
+  private final JToolBar toolBarGraph = new JToolBar();
+  private final ImageIcon localPeriodButtonImageEnabled = new ImageIcon(
+      Import.loadImage(ImagePreference.Button.Inspector.Graph));
+  private final ImageIcon localPeriodButtonImageDisabled = new ImageIcon(
+      GrayFilter.createDisabledImage(Import.loadImage(ImagePreference.Button.Inspector.Graph)));
+  private String[] comboContext = {"", "5", "10", "20", "100", "1000"};
+  private JComboBox<String> localPeriodInput = new JComboBox<String>(comboContext);
+  private JButton resetButton = new JButton("",
+      new ImageIcon(Import.loadImage(ImagePreference.Button.Inspector.Reset)));
+  private JButton localPeriodButton = new JButton("", localPeriodButtonImageEnabled);
+
+  public Inspector(Control control) {
+    table = new InspectorTable(control);
+    unitGraph = new UnitGraph(control);
+    table.OnElementSelectionChanged.addListener(this::updateUnitGraph);
+    initUI();
+    control.OnSelectionChanged.addListener(this::updateGlobalCurve);
+  }
+
+  private void initUI() {
+    this.setOrientation(JSplitPane.VERTICAL_SPLIT);
+    JScrollPane scrollPane = new JScrollPane(table);
+    scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+    this.setTopComponent(scrollPane);
+    this.setBottomComponent(scrollGraph);
+    this.setDividerLocation(550);
+    scrollGraph.setLayout(new BorderLayout());
+    scrollGraph.add(unitGraph, BorderLayout.CENTER);
+    // Set up of the Properties section
+
+    graphLabel.setLayout(new BorderLayout(0, 10));
+    graphLabel.add(maxGraph, BorderLayout.NORTH);
+    graphLabel.add(medGraph, BorderLayout.CENTER);
+    graphLabel.add(minGraph, BorderLayout.SOUTH);
+
+    globalCurveLabel.setLayout(null);
+    globalCurveLabel.setMinimumSize(new Dimension(20, 0));
+    globalCurveLabel.setPreferredSize(new Dimension(20, 0));
+    maxEnergy.setForeground(Color.red);
+    minEnergy.setForeground(Color.red);
+    zeroEnergy.setForeground(ColorPreference.UnitGraph.ZeroLineColor);
+    globalCurveLabel.add(maxEnergy);
+    globalCurveLabel.add(zeroEnergy);
+    globalCurveLabel.add(minEnergy);
+    this.globalCurveLabel.addComponentListener((ResizeListener) resize -> updateGlobalCurve());
+
+    toolBarGraph.setFloatable(false);
+    toolBarGraph.setAlignmentY(Component.RIGHT_ALIGNMENT);
+
+    localPeriodButton.setToolTipText("Toggle Local/Global Mode");
+    toolBarGraph.add(localPeriodButton);
+    // ComboBox
+    localPeriodInput.setEditable(true);
+    localPeriodInput.setVisible(false);
+    localPeriodInput.setMaximumSize(new Dimension(20, 23));
+    localPeriodInput.addItemListener(aListener -> {
+      if (aListener.getStateChange() == ItemEvent.DESELECTED) {
+        validateInput(localPeriodInput.getEditor().getItem().toString(), true);
+      }
+
+    });
+
+    toolBarGraph.add(localPeriodInput);
+
+    // localPeriodButtonFunction
+    localPeriodButton.addActionListener(actionEvent -> {
+      boolean newState = !localPeriodInput.isVisible();
+      changeLocalPeriodButtonAppearance(newState);
+      log.info("LocalPeriodButton");
+    });
+
+    toolBarGraph.add(Box.createHorizontalGlue());
+    resetButton.setToolTipText("Reset");
+    resetButton.addActionListener(actionEvent -> unitGraph.reset());
+    toolBarGraph.add(resetButton);
+    scrollGraph.add(graphLabel, BorderLayout.WEST);
+    scrollGraph.add(globalCurveLabel, BorderLayout.EAST);
+    scrollGraph.add(toolBarGraph, BorderLayout.NORTH);
+
+  }
+
+  /**
+   * Validate the LocalMode Input and when its valid save on the Element.
+   *
+   * @param text         the inputText to validate.
+   * @param bShowMessage when true, open a MessageDialog when text invalid.
+   */
+  private void validateInput(String text, boolean bShowMessage) {
+    int localPeriodInputValue;
+    try {
+      localPeriodInputValue = Integer.parseInt(text);
+    } catch (NumberFormatException e) {
+      if (bShowMessage) {
+        JOptionPane.showMessageDialog(null,
+            '"' + text + '"' + " is not a valid Input. \n Use whole numbers.");
+      }
+      return;
+    }
+    LocalMode.Period period = new LocalMode.Period(7);
+    period.setInterval(localPeriodInputValue);
+    unitGraph.setPeriod(period);
+  }
+
+  /**
+   * This Method updates the UnitGraph, saves the old LocalModeState and load the new
+   * LocalModeState.
+   *
+   * @param elements The new Element to load the UnitGraph
+   */
+  private void updateUnitGraph(Set<HolonElement> elements) {
+    // SaveOld LocalMode State.
+    if (localPeriodInput.isVisible()) {
+      // Save Old State
+      validateInput(localPeriodInput.getEditor().getItem().toString(), false);
+    }
+    // Update UnitGraph
+    unitGraph.clearSeries();
+    for (TimelineDependent element : elements) {
+      unitGraph.addNewSeries(element);
+    }
+
+    if (elements.isEmpty()) {
+      GuiSettings.getSelectedObjects().stream().filter(obj -> obj instanceof HolonSwitch)
+          .forEach(obj -> unitGraph.addNewSeries((HolonSwitch) obj));
+    }
 
 
 //		if (elements.isEmpty()) {
 //		if (elements.isEmpty()) {
 //			this.setDividerLocation(1.0);
 //			this.setDividerLocation(1.0);
 //		}
 //		}
-		// Load LocalMode State.
-		changeLocalPeriodButtonAppeareance(unitGraph.isUsingLocalPeriod());
-		localPeriodInput.getEditor()
-				.setItem(unitGraph.isLocalPeriedDifferentInSeries() ? "-" : unitGraph.getFirstLocalPeriod());
-	}
-
-	private void updateGlobalCurve() {
-		Set<HolonElement> elements = InspectorTable.extractElements(GuiSettings.getSelectedObjects())
-				.collect(Collectors.toSet());
-		unitGraph.setGlobalCurve(elements);
-		double maxEnergy = elements.stream().map(ele -> ele.getEnergy()).filter(energy -> energy > 0).reduce(0.0f,
-				Float::sum);
-		double minEnergy = elements.stream().map(ele -> ele.getEnergy()).filter(energy -> energy < 0).reduce(0.0f,
-				Float::sum);
-		double percentage = Maths.invLerp(maxEnergy, minEnergy, 0.0);
-		int widgetHeight = this.globalCurveLabel.getHeight();
-		int textMiddle = this.zeroEnergy.getPreferredSize().height / 4;
-		int zeroYPos = (int)(widgetHeight * percentage) - textMiddle;
-		this.minEnergy.setText(Format.doubleTwoPlaces(minEnergy));
-		this.maxEnergy.setText(Format.doubleTwoPlaces(maxEnergy));
-		this.maxEnergy.setBounds(0, 0, this.maxEnergy.getPreferredSize().width,
-				this.maxEnergy.getPreferredSize().height);
-		this.minEnergy.setBounds(0, widgetHeight - this.minEnergy.getPreferredSize().height, this.minEnergy.getPreferredSize().width,
-				this.minEnergy.getPreferredSize().height);
-		this.zeroEnergy.setBounds(0, zeroYPos, this.zeroEnergy.getPreferredSize().width,
-				this.zeroEnergy.getPreferredSize().height);
-		this.globalCurveLabel.setPreferredSize(new Dimension(
-				Math.max(this.zeroEnergy.getPreferredSize().width,
-						Math.max(this.maxEnergy.getPreferredSize().width, this.minEnergy.getPreferredSize().width)),
-				0));
-	}
-
-	/**
-	 * Displayed the actual LocalModeState.
-	 * 
-	 * @param enabled
-	 */
-	private void changeLocalPeriodButtonAppeareance(boolean enabled) {
-		localPeriodInput.setVisible(enabled);
-		localPeriodButton.setIcon(enabled ? localPeriodButtonImageEnabled : localPeriodButtonImageDisabled);
-	}
+    // Load LocalMode State.
+    changeLocalPeriodButtonAppearance(unitGraph.isUsingLocalPeriod());
+    localPeriodInput.getEditor()
+        .setItem(
+            unitGraph.isLocalPeriedDifferentInSeries() ? "-" : unitGraph.getFirstLocalPeriod());
+  }
+
+  private void updateGlobalCurve() {
+    Set<HolonElement> elements = InspectorTable.extractElements(GuiSettings.getSelectedObjects())
+        .collect(Collectors.toSet());
+    unitGraph.setGlobalCurve(elements);
+    double maxEnergy = elements.stream().map(HolonElement::getEnergy).filter(energy -> energy > 0)
+        .reduce(0.0f,
+            Float::sum);
+    double minEnergy = elements.stream().map(HolonElement::getEnergy).filter(energy -> energy < 0)
+        .reduce(0.0f,
+            Float::sum);
+    double percentage = Maths.invLerp(maxEnergy, minEnergy, 0.0);
+    int widgetHeight = this.globalCurveLabel.getHeight();
+    int textMiddle = this.zeroEnergy.getPreferredSize().height / 4;
+    int zeroYPos = (int) (widgetHeight * percentage) - 5;
+    this.minEnergy.setText(Format.doubleTwoPlaces(minEnergy));
+    this.maxEnergy.setText(Format.doubleTwoPlaces(maxEnergy));
+    this.maxEnergy.setBounds(0, 0, this.maxEnergy.getPreferredSize().width,
+        this.maxEnergy.getPreferredSize().height);
+    this.minEnergy.setBounds(0, widgetHeight - this.minEnergy.getPreferredSize().height,
+        this.minEnergy.getPreferredSize().width,
+        this.minEnergy.getPreferredSize().height);
+    this.zeroEnergy.setBounds(0, zeroYPos, this.zeroEnergy.getPreferredSize().width,
+        this.zeroEnergy.getPreferredSize().height);
+    this.globalCurveLabel.setPreferredSize(new Dimension(
+        Math.max(this.zeroEnergy.getPreferredSize().width,
+            Math.max(this.maxEnergy.getPreferredSize().width,
+                this.minEnergy.getPreferredSize().width)),
+        0));
+  }
+
+  /**
+   * Displayed the actual LocalModeState.
+   *
+   * @param enabled
+   */
+  private void changeLocalPeriodButtonAppearance(boolean enabled) {
+    localPeriodInput.setVisible(enabled);
+    localPeriodButton.setIcon(
+        enabled ? localPeriodButtonImageEnabled : localPeriodButtonImageDisabled);
+  }
 
 
 }
 }

+ 561 - 530
src/holeg/ui/view/inspector/InspectorTable.java

@@ -1,5 +1,20 @@
 package holeg.ui.view.inspector;
 package holeg.ui.view.inspector;
 
 
+import holeg.model.AbstractCanvasObject;
+import holeg.model.GroupNode;
+import holeg.model.HolonElement;
+import holeg.model.HolonElement.Priority;
+import holeg.model.HolonObject;
+import holeg.preferences.ColorPreference;
+import holeg.preferences.ImagePreference;
+import holeg.ui.controller.Control;
+import holeg.ui.model.GuiSettings;
+import holeg.ui.view.component.TrippleCheckBox;
+import holeg.ui.view.component.TrippleCheckBox.State;
+import holeg.ui.view.image.Import;
+import holeg.utility.events.Action;
+import holeg.utility.listener.SimpleDocumentListener;
+import holeg.utility.pooling.Pool;
 import java.awt.BorderLayout;
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Color;
 import java.awt.Container;
 import java.awt.Container;
@@ -9,6 +24,7 @@ import java.awt.event.InputEvent;
 import java.awt.event.KeyEvent;
 import java.awt.event.KeyEvent;
 import java.math.RoundingMode;
 import java.math.RoundingMode;
 import java.text.NumberFormat;
 import java.text.NumberFormat;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.Comparator;
 import java.util.HashSet;
 import java.util.HashSet;
@@ -19,8 +35,6 @@ import java.util.Set;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import java.util.stream.Stream;
-import java.util.ArrayList;
-
 import javax.swing.AbstractAction;
 import javax.swing.AbstractAction;
 import javax.swing.BorderFactory;
 import javax.swing.BorderFactory;
 import javax.swing.Box;
 import javax.swing.Box;
@@ -36,535 +50,552 @@ import javax.swing.JTextField;
 import javax.swing.KeyStroke;
 import javax.swing.KeyStroke;
 import javax.swing.SwingConstants;
 import javax.swing.SwingConstants;
 import javax.swing.text.NumberFormatter;
 import javax.swing.text.NumberFormatter;
-
-import holeg.model.AbstractCanvasObject;
-import holeg.model.GroupNode;
-import holeg.model.HolonElement;
-import holeg.model.HolonObject;
-import holeg.model.HolonElement.Priority;
-import holeg.preferences.ColorPreference;
-import holeg.preferences.ImagePreference;
-import holeg.ui.controller.Control;
-import holeg.ui.model.GuiSettings;
-import holeg.ui.view.component.TrippleCheckBox;
-import holeg.ui.view.component.TrippleCheckBox.State;
-import holeg.utility.events.Action;
-import holeg.ui.view.image.Import;
-import holeg.utility.listener.SimpleDocumentListener;
-import holeg.utility.pooling.Pool;
 import net.miginfocom.swing.MigLayout;
 import net.miginfocom.swing.MigLayout;
 
 
 public class InspectorTable extends JPanel {
 public class InspectorTable extends JPanel {
-	private static final Logger log = Logger.getLogger(InspectorTable.class.getName());
-	private final Pool<ElementRow> rowPool = new Pool<>() {
-		@Override
-		public ElementRow create() {
-			return new ElementRow();
-		}
-	};
-
-	private final int maxDisplayedRowsNumber = 100;
-	private int actualPage = 0;
-	private int maxPageNumberForThisSelection = 0;
-	private final Control control;
-	// UI
-	private final TrippleCheckBox selectAllCheckBox = new TrippleCheckBox();
-	private final JButton addButton = new JButton();
-	private final JButton duplicateButton = new JButton();
-	private final JButton deleteButton = new JButton();
-	private final JPanel buttonPanel = new JPanel();
-
-	private final JButton pageIncreaseButton = new JButton();
-	private final JButton pageDecreaseButton = new JButton();
-	private final JLabel pageInformationLabel = new JLabel();
-	private final JPanel pageSelectionPanel = new JPanel();
-	private final ArrayList<SortButton<ElementRow>> headerButtonList = new ArrayList<>();
-	private final static NumberFormatter doubleFormatter = generateNumberFormatter();
-
-	// sorting
-	private Comparator<ElementRow> actual_comp = (ElementRow a, ElementRow b) -> Float.compare(a.element.getEnergy(),
-			b.element.getEnergy());
-
-	// Colors
-
-	// Events
-	public Action<Set<HolonElement>> OnElementSelectionChanged = new Action<>();
-	private Thread populateRowsThread;
-	private boolean abortThread = false;
-
-	public InspectorTable(Control control) {
-		control.OnSelectionChanged.addListener(this::updateInspectorUi);
-		this.control = control;
-		init();
-		addHeader();
-	}
-
-	private void init() {
-		MigLayout layout = new MigLayout("insets 0,gap 0,wrap 7", // Layout Constraints
-				"[][fill, grow][fill][fill, grow][fill, grow][][fill]", // Column constraints
-				"[25!][20:20:20]"); // Row constraints
-		this.setLayout(layout);
-		initSelectAllCheckBox();
-		initButtons();
-		initKeyControls();
-		initHeaderButtons();
-	}
-
-	private void initKeyControls() {
-		this.getInputMap(WHEN_IN_FOCUSED_WINDOW)
-				.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, InputEvent.ALT_DOWN_MASK), "PageRight");
-		this.getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, InputEvent.ALT_DOWN_MASK),
-				"PageLeft");
-
-		this.getActionMap().put("PageRight", new AbstractAction() {
-
-			@Override
-			public void actionPerformed(ActionEvent e) {
-				performPageAction(PageAction.Increase);
-			}
-
-		});
-		this.getActionMap().put("PageLeft", new AbstractAction() {
-			@Override
-			public void actionPerformed(ActionEvent e) {
-				performPageAction(PageAction.Decrease);
-			}
-
-		});
-	}
-
-	private enum PageAction {
-		Increase, Decrease
-	};
-
-	private void performPageAction(PageAction action) {
-		int newPageNumber = switch (action) {
-			case Decrease -> Math.max(actualPage - 1, 0);
-			default -> Math.min(actualPage + 1, maxPageNumberForThisSelection);
-		};
-		if (newPageNumber != actualPage) {
-			actualPage = newPageNumber;
-			updateTableUi();
-			updatePageButtonAppearance();
-		}
-
-	}
-
-	private void updatePageButtonAppearance() {
-		this.pageDecreaseButton.setEnabled(actualPage != 0);
-		this.pageIncreaseButton.setEnabled(actualPage != maxPageNumberForThisSelection);
-	}
-
-	private static NumberFormatter generateNumberFormatter() {
-		NumberFormat doubleFormat = NumberFormat.getNumberInstance(Locale.US);
-		doubleFormat.setMinimumFractionDigits(1);
-		doubleFormat.setMaximumFractionDigits(10);
-		doubleFormat.setRoundingMode(RoundingMode.HALF_UP);
-		doubleFormat.setGroupingUsed(false);
-		NumberFormatter doubleFormatter = new NumberFormatter(doubleFormat);
-		doubleFormatter.setCommitsOnValidEdit(true);
-		doubleFormatter.setValueClass(Double.class);
-		return doubleFormatter;
-	}
-
-	private void initHeaderButtons() {
-		Comparator<ElementRow> objectComp = Comparator.comparing((ElementRow a) -> a.element.parentObject.getName());
-		Comparator<ElementRow> idComp = Comparator.comparingInt((ElementRow a) -> a.element.parentObject.getId());
-		Comparator<ElementRow> deviceComp = Comparator.comparing((ElementRow a) -> a.element.getName());
-		Comparator<ElementRow> energyComp = (ElementRow a, ElementRow b) -> Float.compare(a.element.getEnergy(),
-				b.element.getEnergy());
-		Comparator<ElementRow> priorityComp = Comparator.comparing((ElementRow a) -> a.element.getPriority());
-		Comparator<ElementRow> activeComp = (ElementRow a, ElementRow b) -> Boolean.compare(a.element.active,
-				b.element.active);
-
-		headerButtonList.add(new SortButton<>("Object", objectComp));
-		headerButtonList.add(new SortButton<>("Id", idComp));
-		headerButtonList.add(new SortButton<>("Device", deviceComp));
-		headerButtonList.add(new SortButton<>("Energy", energyComp));
-		headerButtonList.add(new SortButton<>("Priority", priorityComp));
-		headerButtonList.add(new SortButton<>("Active", activeComp));
-	}
-
-	private void addHeader() {
-		this.add(selectAllCheckBox);
-		for (SortButton<ElementRow> button : headerButtonList) {
-			this.add(button);
-		}
-	}
-
-	private void initSelectAllCheckBox() {
-		selectAllCheckBox.setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 0));
-		// Pixel Perfect alignment
-		selectAllCheckBox.setBorder(BorderFactory.createEmptyBorder(2, 3, 0, 0));
-		selectAllCheckBox.addActionListener(clicked -> {
-			switch (selectAllCheckBox.getSelectionState()) {
-			case mid_state_selection:
-			case selected: {
-				rowPool.getBorrowedStream().forEach(row -> row.setSelected(false));
-				duplicateButton.setEnabled(false);
-				deleteButton.setEnabled(false);
-			}
-				break;
-			case unselected:
-				if (rowPool.getBorrowedCount() != 0) {
-					rowPool.getBorrowedStream().forEach(row -> row.setSelected(true));
-					duplicateButton.setEnabled(true);
-					deleteButton.setEnabled(true);
-				}
-			default:
-				break;
-			}
-			updateElementSelection();
-		});
-	}
-
-	private void initButtons() {
-		buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.LINE_AXIS));
-		buttonPanel.add(Box.createRigidArea(new Dimension(2, 0)));
-
-		addButton.setIcon(new ImageIcon(Import.loadImage(ImagePreference.Button.Inspector.Add, 16, 16)));
-		addButton.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
-		addButton.addActionListener(clicked -> {
-			Optional<HolonObject> last = GuiSettings.getSelectedObjects().stream()
-					.filter(obj -> obj instanceof HolonObject).reduce((prev, next) -> next)
-					.map(obj -> (HolonObject) obj);
-			last.ifPresent(obj -> {
-				obj.add(new HolonElement(obj, "Element", 0.0f));
-				control.updateStateForCurrentIteration();
-				control.OnSelectionChanged.broadcast();
-			});
-		});
-		buttonPanel.add(addButton);
-
-		duplicateButton.setIcon(new ImageIcon(Import.loadImage(ImagePreference.Button.Inspector.Duplicate, 16, 16)));
-		duplicateButton.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
-		duplicateButton.addActionListener(clicked -> {
-			rowPool.getBorrowedStream().forEach(row -> {
-				if (row.isSelected()) {
-					row.element.parentObject.add(new HolonElement(row.element));
-				}
-			});
-			control.updateStateForCurrentIteration();
-			control.OnSelectionChanged.broadcast();
-		});
-		buttonPanel.add(duplicateButton);
-
-		deleteButton.setIcon(new ImageIcon(Import.loadImage(ImagePreference.Button.Inspector.Remove, 16, 16)));
-		deleteButton.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
-		deleteButton.addActionListener(clicked -> {
-			log.info("DeleteButton");
-			rowPool.getBorrowedStream().forEach(row -> {
-				if (row.isSelected()) {
-					row.element.parentObject.remove(row.element);
-				}
-			});
-			log.info("row deleted");
-			control.updateStateForCurrentIteration();
-			log.info("updated");
-			control.OnSelectionChanged.broadcast();
-			log.info("selectionChanged");
-		});
-		buttonPanel.add(deleteButton);
-
-		pageIncreaseButton.setIcon(new ImageIcon(Import.loadImage("images/buttons/page_increase.png", 16, 16)));
-		pageIncreaseButton.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
-		pageIncreaseButton.addActionListener(clicked -> this.performPageAction(PageAction.Increase));
-
-		pageDecreaseButton.setIcon(new ImageIcon(Import.loadImage("images/buttons/page_decrease.png", 16, 16)));
-		pageDecreaseButton.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
-		pageDecreaseButton.addActionListener(clicked -> this.performPageAction(PageAction.Decrease));
-
-		pageInformationLabel.setForeground(Color.gray);
-
-		pageSelectionPanel.setLayout(new BoxLayout(pageSelectionPanel, BoxLayout.LINE_AXIS));
-		pageSelectionPanel.add(Box.createRigidArea(new Dimension(2, 0)));
-		pageSelectionPanel.add(this.pageInformationLabel);
-		pageSelectionPanel.add(Box.createHorizontalGlue());
-		pageSelectionPanel.add(this.pageDecreaseButton);
-		pageSelectionPanel.add(this.pageIncreaseButton);
-	}
-
-	private void assignElementsToRowPool(Set<AbstractCanvasObject> selection) {
-		List<HolonElement> elementList = extractElements(selection).toList();
-		rowPool.getBorrowedStream().forEach(InspectorTable.ElementRow::clear);
-		rowPool.clear();
-		for (HolonElement element : elementList) {
-			ElementRow row = rowPool.get();
-			row.setElement(element);
-		}
-		actualPage = 0;
-		this.maxPageNumberForThisSelection = elementList.size() / this.maxDisplayedRowsNumber;
-		updatePageButtonAppearance();
-	}
-
-	private void updateTableUi() {
-
-		// Maybe abort current thread and join them
-		if (populateRowsThread != null) {
-			try {
-				abortThread = true;
-				populateRowsThread.join();
-				abortThread = false;
-			} catch (InterruptedException e) {
-				e.printStackTrace();
-			}
-		}
-		populateRowsThread = new Thread(() -> {
-			int numberOfRows = rowPool.getBorrowedCount();
-			this.removeAll();
-			addHeader();
-			rowPool.getBorrowedStream().sorted(actual_comp).skip((long) actualPage * maxDisplayedRowsNumber)
-					.limit(maxDisplayedRowsNumber).takeWhile(row -> !abortThread).forEach(ElementRow::addContainerToInspector);
-			if (numberOfRows > maxDisplayedRowsNumber) {
-				int lastDisplayedElementNumber = Math.min(numberOfRows, (actualPage + 1) * maxDisplayedRowsNumber);
-				pageInformationLabel.setText(String.format("%d - %d from %d", 1 + actualPage * maxDisplayedRowsNumber,
-						lastDisplayedElementNumber, numberOfRows));
-				this.add(pageSelectionPanel, "span, grow");
-			}
-
-			this.add(buttonPanel, "span");
-			boolean isAtLeastOneHolonObjectSelected = GuiSettings.getSelectedObjects().stream()
-					.anyMatch(object -> object instanceof HolonObject);
-			this.addButton.setEnabled(isAtLeastOneHolonObjectSelected);
-			duplicateButton.setEnabled(false);
-			deleteButton.setEnabled(false);
-			selectAllCheckBox.setSelectionState(State.unselected);
-			revalidate();
-			repaint();
-			this.OnElementSelectionChanged.broadcast(new HashSet<>());
-		});
-		populateRowsThread.start();
-
-	}
-
-	private void updateInspectorUi() {
-		// clone for concurrency
-		Set<AbstractCanvasObject> selection = new HashSet<>(GuiSettings.getSelectedObjects());
-		assignElementsToRowPool(selection);
-		updateTableUi();
-	}
-
-	private void updateElementSelection() {
-		Set<HolonElement> eleSet = rowPool.getBorrowedStream().filter(ElementRow::isSelected).map(row -> row.element)
-				.collect(Collectors.toSet());
-		this.OnElementSelectionChanged.broadcast(eleSet);
-	}
-
-	private void updateButtonAppearance() {
-		long count = rowPool.getBorrowedStream().filter(ElementRow::isSelected).count();
-		if (count == rowPool.getBorrowedCount()) {
-			selectAllCheckBox.setSelectionState(State.selected);
-		} else if (count == 0) {
-			selectAllCheckBox.setSelectionState(State.unselected);
-		} else {
-			selectAllCheckBox.setSelectionState(State.mid_state_selection);
-		}
-		duplicateButton.setEnabled(count != 0);
-		deleteButton.setEnabled(count != 0);
-	}
-
-	// Extract elements from a list of AbstractCanvasObjects
-	static Stream<HolonElement> extractElements(Collection<AbstractCanvasObject> toInspect) {
-		Stream<HolonElement> recursiveLayer = toInspect.stream().filter(object -> object instanceof GroupNode).flatMap(
-				obj -> ((GroupNode) obj).getAllHolonObjectsRecursive().flatMap(HolonObject::elementsStream));
-		Stream<HolonElement> thisLayer = toInspect.stream().filter(obj -> obj instanceof HolonObject).flatMap(obj -> {
-			HolonObject ho = (HolonObject) obj;
-			return ho.elementsStream();
-		});
-		return Stream.concat(thisLayer, recursiveLayer);
-	}
-
-	private class ElementRow {
-		private HolonElement element = null;
-		private final Container[] cellsInRow = new Container[7];
-		// TextBoxes
-		private JTextField elementNameTextField;
-		private JCheckBox selectionBox;
-		private JTextField idObjectTextField;
-		private JFormattedTextField energyTextField;
-		private JComboBox<Priority> comboBox;
-		private JCheckBox activeCheckBox;
-		private JTextField objectNameTextField;
-
-		public ElementRow() {
-			this.createEditFields();
-		}
-
-		public void addContainerToInspector() {
-			for (Container cell : cellsInRow) {
-				InspectorTable.this.add(cell);
-			}
-		}
-
-		public void setSelected(boolean value) {
-			selectionBox.setSelected(value);
-			// Color row
-			for (Container cell : cellsInRow) {
-				cell.setBackground(selectionBox.isSelected() ? ColorPreference.Inspector.Selected : Color.white);
-			}
-		}
-
-		public boolean isSelected() {
-			return selectionBox.isSelected();
-		}
-
-		public void setElement(HolonElement element) {
-			objectNameTextField.setText(element.parentObject.getName());
-			idObjectTextField.setText(Integer.toString(element.parentObject.getId()));
-			elementNameTextField.setText(element.getName());
-			comboBox.setSelectedItem(element.getPriority());
-			activeCheckBox.setSelected(element.active);
-			energyTextField.setValue(element.getEnergy());
-			this.element = element;
-			setSelected(false);
-		}
-		public void clear(){
-			this.element = null;
-		}
-
-		private void createEditFields() {
-			// Selected
-			JPanel selectedColumnPanel = new JPanel(new BorderLayout());
-			selectedColumnPanel.setBackground(Color.white);
-			selectedColumnPanel.setBorder(BorderFactory.createLineBorder(ColorPreference.Inspector.Border));
-			selectionBox = new JCheckBox();
-			selectionBox.addActionListener(clicked -> {
-				setSelected(selectionBox.isSelected());
-				updateButtonAppearance();
-				updateElementSelection();
-			});
-			int columnHeight = 20;
-			selectedColumnPanel.setMinimumSize(new Dimension(columnHeight, columnHeight));
-			selectedColumnPanel.setPreferredSize(new Dimension(columnHeight, columnHeight));
-			selectedColumnPanel.setMaximumSize(new Dimension(columnHeight, columnHeight));
-			selectionBox.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 0));
-			selectionBox.setOpaque(false);
-			selectedColumnPanel.add(selectionBox, BorderLayout.CENTER);
-			cellsInRow[0] = selectedColumnPanel;
-
-			// ObjectName and ID
-			objectNameTextField = new JTextField();
-			objectNameTextField.getDocument().addDocumentListener((SimpleDocumentListener) e -> {
-				if(this.element != null){
-					this.element.parentObject.setName(objectNameTextField.getText());
-				}
-			});
-			objectNameTextField.addActionListener(ae -> updateInspectorUi());
-			cellsInRow[1] = objectNameTextField;
-			idObjectTextField = new JTextField();
-			idObjectTextField.setMinimumSize(idObjectTextField.getPreferredSize());
-			idObjectTextField.setBackground(Color.white);
-			idObjectTextField.setEditable(false);
-			idObjectTextField.setEnabled(false);
-			cellsInRow[2] = idObjectTextField;
-			// Name
-			elementNameTextField = new JTextField();
-			elementNameTextField.getDocument().addDocumentListener((SimpleDocumentListener) e -> {
-				if(this.element != null){
-					this.element.setName(elementNameTextField.getText());
-				}
-			});
-			elementNameTextField.setBackground(Color.white);
-			cellsInRow[3] = elementNameTextField;
-			// Energy
-
-			energyTextField = new JFormattedTextField(doubleFormatter);
-			energyTextField.setInputVerifier(getInputVerifier());
-
-			energyTextField.setBackground(Color.white);
-			energyTextField.addPropertyChangeListener(actionEvent -> {
-				try {
-					float energy = Float.parseFloat(energyTextField.getText());
-					if (this.element != null && this.element.getEnergy() != energy) {
-						this.element.setEnergy(energy);
-						control.updateStateForCurrentIteration();
-					}
-				} catch (NumberFormatException e) {
-					// Dont Update
-				}
-
-			});
-			cellsInRow[4] = energyTextField;
-
-			// Priority
-			comboBox = new JComboBox<>(Priority.values());
-			comboBox.setBackground(Color.white);
-			comboBox.setEditable(false);
-			comboBox.addActionListener(ae -> {
-				if(this.element != null){
-					this.element.setPriority((Priority) comboBox.getSelectedItem());
-					control.updateStateForCurrentIteration();
-				}
-			});
-			cellsInRow[5] = comboBox;
-
-			JPanel checkBoxWrapperPanel = new JPanel(new BorderLayout());
-			checkBoxWrapperPanel.setBorder(BorderFactory.createLineBorder(ColorPreference.Inspector.Border));
-			checkBoxWrapperPanel.setBackground(Color.white);
-			checkBoxWrapperPanel.setMinimumSize(new Dimension(columnHeight, columnHeight));
-			checkBoxWrapperPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, columnHeight));
-			// Active
-			activeCheckBox = new JCheckBox();
-			activeCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 0));
-			activeCheckBox.setOpaque(false);
-			activeCheckBox.addActionListener(actionEvent -> {
-				if(this.element != null){
-					this.element.active = activeCheckBox.isSelected();
-					control.updateStateForCurrentIteration();
-				}
-			});
-			checkBoxWrapperPanel.add(activeCheckBox, BorderLayout.CENTER);
-			cellsInRow[6] = checkBoxWrapperPanel;
-		}
-
-	}
-
-	private enum SortState {
-		None, Descending, Ascending
-	};
-
-	private class SortButton<T> extends JButton {
-		private SortState state = SortState.None;
-		private final Comparator<T> comp;
-
-		public SortButton(String text, Comparator<T> comp) {
-			super(text);
-			this.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
-			this.setContentAreaFilled(false);
-			this.setBorderPainted(false);
-			this.setFocusPainted(false);
-			this.setHorizontalAlignment(SwingConstants.LEFT);
-			this.comp = comp;
-			this.addActionListener(onClick -> changeStateOnClick());
-		}
-
-		@SuppressWarnings("unchecked")
-		private void changeStateOnClick() {
-			setState((this.state == SortState.Ascending) ? SortState.Descending : SortState.Ascending);
-			headerButtonList.stream().filter(button -> (button != this))
-					.forEach(button -> button.setState(SortState.None));
-			actual_comp = (Comparator<ElementRow>) getComp();
-			updateInspectorUi();
-		}
-
-		public void setState(SortState state) {
-			this.state = state;
-			String text = this.getText();
-			// remove order symbols from text
-			text = text.replaceAll("[\u25bc\u25b2]", "");
-			// update text
-			switch (state) {
-				case Descending -> this.setText(text + "\u25bc");
-				case Ascending -> this.setText(text + "\u25b2");
-				default -> this.setText(text);
-			}
-		}
-
-		public Comparator<T> getComp() {
-			return switch (state) {
-				case Descending -> comp.reversed();
-				default -> comp;
-			};
-		}
-	}
+
+  private static final Logger log = Logger.getLogger(InspectorTable.class.getName());
+  private final static NumberFormatter doubleFormatter = generateNumberFormatter();
+  private final Pool<ElementRow> rowPool = new Pool<>() {
+    @Override
+    public ElementRow create() {
+      return new ElementRow();
+    }
+  };
+  private final int maxDisplayedRowsNumber = 100;
+  private final Control control;
+  // UI
+  private final TrippleCheckBox selectAllCheckBox = new TrippleCheckBox();
+  private final JButton addButton = new JButton();
+  private final JButton duplicateButton = new JButton();
+  private final JButton deleteButton = new JButton();
+  private final JPanel buttonPanel = new JPanel();
+  private final JButton pageIncreaseButton = new JButton();
+  private final JButton pageDecreaseButton = new JButton();
+  private final JLabel pageInformationLabel = new JLabel();
+  private final JPanel pageSelectionPanel = new JPanel();
+  private final ArrayList<SortButton<ElementRow>> headerButtonList = new ArrayList<>();
+  // Events
+  public Action<Set<HolonElement>> OnElementSelectionChanged = new Action<>();
+  private int actualPage = 0;
+  private int maxPageNumberForThisSelection = 0;
+
+  // Colors
+  // sorting
+  private Comparator<ElementRow> actual_comp = (ElementRow a, ElementRow b) -> Float.compare(
+      a.element.getEnergy(),
+      b.element.getEnergy());
+  private Thread populateRowsThread;
+  private boolean abortThread = false;
+
+  public InspectorTable(Control control) {
+    control.OnSelectionChanged.addListener(this::updateInspectorUi);
+    this.control = control;
+    init();
+    addHeader();
+  }
+
+  private static NumberFormatter generateNumberFormatter() {
+    NumberFormat doubleFormat = NumberFormat.getNumberInstance(Locale.US);
+    doubleFormat.setMinimumFractionDigits(1);
+    doubleFormat.setMaximumFractionDigits(10);
+    doubleFormat.setRoundingMode(RoundingMode.HALF_UP);
+    doubleFormat.setGroupingUsed(false);
+    NumberFormatter doubleFormatter = new NumberFormatter(doubleFormat);
+    doubleFormatter.setCommitsOnValidEdit(true);
+    doubleFormatter.setValueClass(Double.class);
+    return doubleFormatter;
+  }
+
+  // Extract elements from a list of AbstractCanvasObjects
+  static Stream<HolonElement> extractElements(Collection<AbstractCanvasObject> toInspect) {
+    Stream<HolonElement> recursiveLayer = toInspect.stream()
+        .filter(object -> object instanceof GroupNode).flatMap(
+            obj -> ((GroupNode) obj).getAllHolonObjectsRecursive()
+                .flatMap(HolonObject::elementsStream));
+    Stream<HolonElement> thisLayer = toInspect.stream().filter(obj -> obj instanceof HolonObject)
+        .flatMap(obj -> {
+          HolonObject ho = (HolonObject) obj;
+          return ho.elementsStream();
+        });
+    return Stream.concat(thisLayer, recursiveLayer);
+  }
+
+  private void init() {
+    MigLayout layout = new MigLayout("insets 0,gap 0,wrap 7", // Layout Constraints
+        "[][fill, grow][fill][fill, grow][fill, grow][][fill]", // Column constraints
+        "[25!][20:20:20]"); // Row constraints
+    this.setLayout(layout);
+    initSelectAllCheckBox();
+    initButtons();
+    initKeyControls();
+    initHeaderButtons();
+  }
+
+  ;
+
+  private void initKeyControls() {
+    this.getInputMap(WHEN_IN_FOCUSED_WINDOW)
+        .put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, InputEvent.ALT_DOWN_MASK), "PageRight");
+    this.getInputMap(WHEN_IN_FOCUSED_WINDOW)
+        .put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, InputEvent.ALT_DOWN_MASK),
+            "PageLeft");
+
+    this.getActionMap().put("PageRight", new AbstractAction() {
+
+      @Override
+      public void actionPerformed(ActionEvent e) {
+        performPageAction(PageAction.Increase);
+      }
+
+    });
+    this.getActionMap().put("PageLeft", new AbstractAction() {
+      @Override
+      public void actionPerformed(ActionEvent e) {
+        performPageAction(PageAction.Decrease);
+      }
+
+    });
+  }
+
+  private void performPageAction(PageAction action) {
+    int newPageNumber = switch (action) {
+      case Decrease -> Math.max(actualPage - 1, 0);
+      default -> Math.min(actualPage + 1, maxPageNumberForThisSelection);
+    };
+    if (newPageNumber != actualPage) {
+      actualPage = newPageNumber;
+      updateTableUi();
+      updatePageButtonAppearance();
+    }
+
+  }
+
+  private void updatePageButtonAppearance() {
+    this.pageDecreaseButton.setEnabled(actualPage != 0);
+    this.pageIncreaseButton.setEnabled(actualPage != maxPageNumberForThisSelection);
+  }
+
+  private void initHeaderButtons() {
+    Comparator<ElementRow> objectComp = Comparator.comparing(
+        (ElementRow a) -> a.element.parentObject.getName());
+    Comparator<ElementRow> idComp = Comparator.comparingInt(
+        (ElementRow a) -> a.element.parentObject.getId());
+    Comparator<ElementRow> deviceComp = Comparator.comparing((ElementRow a) -> a.element.getName());
+    Comparator<ElementRow> energyComp = (ElementRow a, ElementRow b) -> Float.compare(
+        a.element.getEnergy(),
+        b.element.getEnergy());
+    Comparator<ElementRow> priorityComp = Comparator.comparing(
+        (ElementRow a) -> a.element.getPriority());
+    Comparator<ElementRow> activeComp = (ElementRow a, ElementRow b) -> Boolean.compare(
+        a.element.active,
+        b.element.active);
+
+    headerButtonList.add(new SortButton<>("Object", objectComp));
+    headerButtonList.add(new SortButton<>("Id", idComp));
+    headerButtonList.add(new SortButton<>("Device", deviceComp));
+    headerButtonList.add(new SortButton<>("Energy", energyComp));
+    headerButtonList.add(new SortButton<>("Priority", priorityComp));
+    headerButtonList.add(new SortButton<>("Active", activeComp));
+  }
+
+  private void addHeader() {
+    this.add(selectAllCheckBox);
+    for (SortButton<ElementRow> button : headerButtonList) {
+      this.add(button);
+    }
+  }
+
+  private void initSelectAllCheckBox() {
+    selectAllCheckBox.setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 0));
+    // Pixel Perfect alignment
+    selectAllCheckBox.setBorder(BorderFactory.createEmptyBorder(2, 3, 0, 0));
+    selectAllCheckBox.addActionListener(clicked -> {
+      selectAllChanges(selectAllCheckBox.getSelectionState());
+    });
+  }
+
+  void selectAllChanges(TrippleCheckBox.State oldState) {
+    switch (oldState) {
+      case mid_state_selection:
+      case selected: {
+        rowPool.getBorrowedStream().forEach(row -> row.setSelected(false));
+        duplicateButton.setEnabled(false);
+        deleteButton.setEnabled(false);
+      }
+      break;
+      case unselected:
+        if (rowPool.getBorrowedCount() != 0) {
+          rowPool.getBorrowedStream().forEach(row -> row.setSelected(true));
+          duplicateButton.setEnabled(true);
+          deleteButton.setEnabled(true);
+        }
+      default:
+        break;
+    }
+    updateElementSelection();
+  }
+
+
+  private void initButtons() {
+    buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.LINE_AXIS));
+    buttonPanel.add(Box.createRigidArea(new Dimension(2, 0)));
+
+    addButton.setIcon(
+        new ImageIcon(Import.loadImage(ImagePreference.Button.Inspector.Add, 16, 16)));
+    addButton.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
+    addButton.addActionListener(clicked -> {
+      Optional<HolonObject> last = GuiSettings.getSelectedObjects().stream()
+          .filter(obj -> obj instanceof HolonObject).reduce((prev, next) -> next)
+          .map(obj -> (HolonObject) obj);
+      last.ifPresent(obj -> {
+        obj.add(new HolonElement(obj, "Element", 0.0f));
+        control.updateStateForCurrentIteration();
+        control.OnSelectionChanged.broadcast();
+      });
+    });
+    buttonPanel.add(addButton);
+
+    duplicateButton.setIcon(
+        new ImageIcon(Import.loadImage(ImagePreference.Button.Inspector.Duplicate, 16, 16)));
+    duplicateButton.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
+    duplicateButton.addActionListener(clicked -> {
+      rowPool.getBorrowedStream().forEach(row -> {
+        if (row.isSelected()) {
+          row.element.parentObject.add(new HolonElement(row.element));
+        }
+      });
+      control.updateStateForCurrentIteration();
+      control.OnSelectionChanged.broadcast();
+    });
+    buttonPanel.add(duplicateButton);
+
+    deleteButton.setIcon(
+        new ImageIcon(Import.loadImage(ImagePreference.Button.Inspector.Remove, 16, 16)));
+    deleteButton.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
+    deleteButton.addActionListener(clicked -> {
+      log.info("DeleteButton");
+      rowPool.getBorrowedStream().forEach(row -> {
+        if (row.isSelected()) {
+          row.element.parentObject.remove(row.element);
+        }
+      });
+      log.info("row deleted");
+      control.updateStateForCurrentIteration();
+      log.info("updated");
+      control.OnSelectionChanged.broadcast();
+      log.info("selectionChanged");
+    });
+    buttonPanel.add(deleteButton);
+
+    pageIncreaseButton.setIcon(
+        new ImageIcon(Import.loadImage("images/buttons/page_increase.png", 16, 16)));
+    pageIncreaseButton.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
+    pageIncreaseButton.addActionListener(clicked -> this.performPageAction(PageAction.Increase));
+
+    pageDecreaseButton.setIcon(
+        new ImageIcon(Import.loadImage("images/buttons/page_decrease.png", 16, 16)));
+    pageDecreaseButton.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
+    pageDecreaseButton.addActionListener(clicked -> this.performPageAction(PageAction.Decrease));
+
+    pageInformationLabel.setForeground(Color.gray);
+
+    pageSelectionPanel.setLayout(new BoxLayout(pageSelectionPanel, BoxLayout.LINE_AXIS));
+    pageSelectionPanel.add(Box.createRigidArea(new Dimension(2, 0)));
+    pageSelectionPanel.add(this.pageInformationLabel);
+    pageSelectionPanel.add(Box.createHorizontalGlue());
+    pageSelectionPanel.add(this.pageDecreaseButton);
+    pageSelectionPanel.add(this.pageIncreaseButton);
+  }
+
+  private void assignElementsToRowPool(Set<AbstractCanvasObject> selection) {
+    List<HolonElement> elementList = extractElements(selection).toList();
+    rowPool.getBorrowedStream().forEach(InspectorTable.ElementRow::clear);
+    rowPool.clear();
+    for (HolonElement element : elementList) {
+      ElementRow row = rowPool.get();
+      row.setElement(element);
+    }
+    actualPage = 0;
+    this.maxPageNumberForThisSelection = elementList.size() / this.maxDisplayedRowsNumber;
+    updatePageButtonAppearance();
+  }
+
+  private void updateTableUi() {
+
+    // Maybe abort current thread and join them
+    if (populateRowsThread != null) {
+      try {
+        abortThread = true;
+        populateRowsThread.join();
+        abortThread = false;
+      } catch (InterruptedException e) {
+        e.printStackTrace();
+      }
+    }
+    populateRowsThread = new Thread(() -> {
+      int numberOfRows = rowPool.getBorrowedCount();
+      this.removeAll();
+      addHeader();
+      rowPool.getBorrowedStream().sorted(actual_comp)
+          .skip((long) actualPage * maxDisplayedRowsNumber)
+          .limit(maxDisplayedRowsNumber).takeWhile(row -> !abortThread)
+          .forEach(ElementRow::addContainerToInspector);
+      if (numberOfRows > maxDisplayedRowsNumber) {
+        int lastDisplayedElementNumber = Math.min(numberOfRows,
+            (actualPage + 1) * maxDisplayedRowsNumber);
+        pageInformationLabel.setText(
+            String.format("%d - %d from %d", 1 + actualPage * maxDisplayedRowsNumber,
+                lastDisplayedElementNumber, numberOfRows));
+        this.add(pageSelectionPanel, "span, grow");
+      }
+
+      this.add(buttonPanel, "span");
+      boolean isAtLeastOneHolonObjectSelected = GuiSettings.getSelectedObjects().stream()
+          .anyMatch(object -> object instanceof HolonObject);
+      this.addButton.setEnabled(isAtLeastOneHolonObjectSelected);
+      duplicateButton.setEnabled(false);
+      deleteButton.setEnabled(false);
+      this.OnElementSelectionChanged.broadcast(new HashSet<>());
+      selectAllCheckBox.setSelectionState(State.selected);
+      selectAllChanges(State.unselected);
+      revalidate();
+      repaint();
+    });
+    populateRowsThread.start();
+
+  }
+
+  private void updateInspectorUi() {
+    // clone for concurrency
+    Set<AbstractCanvasObject> selection = new HashSet<>(GuiSettings.getSelectedObjects());
+    assignElementsToRowPool(selection);
+    updateTableUi();
+  }
+
+  private void updateElementSelection() {
+    Set<HolonElement> eleSet = rowPool.getBorrowedStream().filter(ElementRow::isSelected)
+        .map(row -> row.element)
+        .collect(Collectors.toSet());
+    this.OnElementSelectionChanged.broadcast(eleSet);
+  }
+
+  private void updateButtonAppearance() {
+    long count = rowPool.getBorrowedStream().filter(ElementRow::isSelected).count();
+    if (count == rowPool.getBorrowedCount()) {
+      selectAllCheckBox.setSelectionState(State.selected);
+    } else if (count == 0) {
+      selectAllCheckBox.setSelectionState(State.unselected);
+    } else {
+      selectAllCheckBox.setSelectionState(State.mid_state_selection);
+    }
+    duplicateButton.setEnabled(count != 0);
+    deleteButton.setEnabled(count != 0);
+  }
+
+  private enum PageAction {
+    Increase, Decrease
+  }
+
+  private enum SortState {
+    None, Descending, Ascending
+  }
+
+  private class ElementRow {
+
+    private final Container[] cellsInRow = new Container[7];
+    private HolonElement element = null;
+    // TextBoxes
+    private JTextField elementNameTextField;
+    private JCheckBox selectionBox;
+    private JTextField idObjectTextField;
+    private JFormattedTextField energyTextField;
+    private JComboBox<Priority> comboBox;
+    private JCheckBox activeCheckBox;
+    private JTextField objectNameTextField;
+
+    public ElementRow() {
+      this.createEditFields();
+    }
+
+    public void addContainerToInspector() {
+      for (Container cell : cellsInRow) {
+        InspectorTable.this.add(cell);
+      }
+    }
+
+    public boolean isSelected() {
+      return selectionBox.isSelected();
+    }
+
+    public void setSelected(boolean value) {
+      selectionBox.setSelected(value);
+      // Color row
+      for (Container cell : cellsInRow) {
+        cell.setBackground(
+            selectionBox.isSelected() ? ColorPreference.Inspector.Selected : Color.white);
+      }
+    }
+
+    public void setElement(HolonElement element) {
+      objectNameTextField.setText(element.parentObject.getName());
+      idObjectTextField.setText(Integer.toString(element.parentObject.getId()));
+      elementNameTextField.setText(element.getName());
+      comboBox.setSelectedItem(element.getPriority());
+      activeCheckBox.setSelected(element.active);
+      energyTextField.setValue(element.getEnergy());
+      this.element = element;
+      setSelected(false);
+    }
+
+    public void clear() {
+      this.element = null;
+    }
+
+    private void createEditFields() {
+      // Selected
+      JPanel selectedColumnPanel = new JPanel(new BorderLayout());
+      selectedColumnPanel.setBackground(Color.white);
+      selectedColumnPanel.setBorder(
+          BorderFactory.createLineBorder(ColorPreference.Inspector.Border));
+      selectionBox = new JCheckBox();
+      selectionBox.addActionListener(clicked -> {
+        setSelected(selectionBox.isSelected());
+        updateButtonAppearance();
+        updateElementSelection();
+      });
+      int columnHeight = 20;
+      selectedColumnPanel.setMinimumSize(new Dimension(columnHeight, columnHeight));
+      selectedColumnPanel.setPreferredSize(new Dimension(columnHeight, columnHeight));
+      selectedColumnPanel.setMaximumSize(new Dimension(columnHeight, columnHeight));
+      selectionBox.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 0));
+      selectionBox.setOpaque(false);
+      selectedColumnPanel.add(selectionBox, BorderLayout.CENTER);
+      cellsInRow[0] = selectedColumnPanel;
+
+      // ObjectName and ID
+      objectNameTextField = new JTextField();
+      objectNameTextField.getDocument().addDocumentListener((SimpleDocumentListener) e -> {
+        if (this.element != null) {
+          this.element.parentObject.setName(objectNameTextField.getText());
+        }
+      });
+      objectNameTextField.addActionListener(ae -> updateInspectorUi());
+      cellsInRow[1] = objectNameTextField;
+      idObjectTextField = new JTextField();
+      idObjectTextField.setMinimumSize(idObjectTextField.getPreferredSize());
+      idObjectTextField.setBackground(Color.white);
+      idObjectTextField.setEditable(false);
+      idObjectTextField.setEnabled(false);
+      cellsInRow[2] = idObjectTextField;
+      // Name
+      elementNameTextField = new JTextField();
+      elementNameTextField.getDocument().addDocumentListener((SimpleDocumentListener) e -> {
+        if (this.element != null) {
+          this.element.setName(elementNameTextField.getText());
+        }
+      });
+      elementNameTextField.setBackground(Color.white);
+      cellsInRow[3] = elementNameTextField;
+      // Energy
+
+      energyTextField = new JFormattedTextField(doubleFormatter);
+      energyTextField.setInputVerifier(getInputVerifier());
+
+      energyTextField.setBackground(Color.white);
+      energyTextField.addPropertyChangeListener(actionEvent -> {
+        try {
+          float energy = Float.parseFloat(energyTextField.getText());
+          if (this.element != null && this.element.getEnergy() != energy) {
+            this.element.setEnergy(energy);
+            control.updateStateForCurrentIteration();
+          }
+        } catch (NumberFormatException e) {
+          // Dont Update
+        }
+
+      });
+      cellsInRow[4] = energyTextField;
+
+      // Priority
+      comboBox = new JComboBox<>(Priority.values());
+      comboBox.setBackground(Color.white);
+      comboBox.setEditable(false);
+      comboBox.addActionListener(ae -> {
+        if (this.element != null) {
+          this.element.setPriority((Priority) comboBox.getSelectedItem());
+          control.updateStateForCurrentIteration();
+        }
+      });
+      cellsInRow[5] = comboBox;
+
+      JPanel checkBoxWrapperPanel = new JPanel(new BorderLayout());
+      checkBoxWrapperPanel.setBorder(
+          BorderFactory.createLineBorder(ColorPreference.Inspector.Border));
+      checkBoxWrapperPanel.setBackground(Color.white);
+      checkBoxWrapperPanel.setMinimumSize(new Dimension(columnHeight, columnHeight));
+      checkBoxWrapperPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, columnHeight));
+      // Active
+      activeCheckBox = new JCheckBox();
+      activeCheckBox.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 0));
+      activeCheckBox.setOpaque(false);
+      activeCheckBox.addActionListener(actionEvent -> {
+        if (this.element != null) {
+          this.element.active = activeCheckBox.isSelected();
+          control.updateStateForCurrentIteration();
+        }
+      });
+      checkBoxWrapperPanel.add(activeCheckBox, BorderLayout.CENTER);
+      cellsInRow[6] = checkBoxWrapperPanel;
+    }
+
+  }
+
+  ;
+
+  private class SortButton<T> extends JButton {
+
+    private final Comparator<T> comp;
+    private SortState state = SortState.None;
+
+    public SortButton(String text, Comparator<T> comp) {
+      super(text);
+      this.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
+      this.setContentAreaFilled(false);
+      this.setBorderPainted(false);
+      this.setFocusPainted(false);
+      this.setHorizontalAlignment(SwingConstants.LEFT);
+      this.comp = comp;
+      this.addActionListener(onClick -> changeStateOnClick());
+    }
+
+    @SuppressWarnings("unchecked")
+    private void changeStateOnClick() {
+      setState((this.state == SortState.Ascending) ? SortState.Descending : SortState.Ascending);
+      headerButtonList.stream().filter(button -> (button != this))
+          .forEach(button -> button.setState(SortState.None));
+      actual_comp = (Comparator<ElementRow>) getComp();
+      updateInspectorUi();
+    }
+
+    public void setState(SortState state) {
+      this.state = state;
+      String text = this.getText();
+      // remove order symbols from text
+      text = text.replaceAll("[\u25bc\u25b2]", "");
+      // update text
+      switch (state) {
+        case Descending -> this.setText(text + "\u25bc");
+        case Ascending -> this.setText(text + "\u25b2");
+        default -> this.setText(text);
+      }
+    }
+
+    public Comparator<T> getComp() {
+      return switch (state) {
+        case Descending -> comp.reversed();
+        default -> comp;
+      };
+    }
+  }
 }
 }

+ 915 - 911
src/holeg/ui/view/inspector/UnitGraph.java

@@ -1,5 +1,15 @@
 package holeg.ui.view.inspector;
 package holeg.ui.view.inspector;
 
 
+import holeg.interfaces.GraphEditable.GraphType;
+import holeg.interfaces.LocalMode;
+import holeg.interfaces.TimelineDependent;
+import holeg.model.HolonElement;
+import holeg.model.Model;
+import holeg.preferences.ColorPreference;
+import holeg.ui.controller.Control;
+import holeg.utility.math.Maths;
+import holeg.utility.math.vector.Vec2f;
+import holeg.utility.math.vector.Vec2i;
 import java.awt.BasicStroke;
 import java.awt.BasicStroke;
 import java.awt.Color;
 import java.awt.Color;
 import java.awt.Cursor;
 import java.awt.Cursor;
@@ -19,946 +29,940 @@ import java.util.ListIterator;
 import java.util.Optional;
 import java.util.Optional;
 import java.util.Set;
 import java.util.Set;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
-
 import javax.swing.JPanel;
 import javax.swing.JPanel;
 
 
-import holeg.interfaces.LocalMode;
-import holeg.interfaces.TimelineDependent;
-import holeg.interfaces.GraphEditable.GraphType;
-import holeg.model.HolonElement;
-import holeg.model.Model;
-import holeg.preferences.ColorPreference;
-import holeg.ui.controller.Control;
-import holeg.utility.math.Maths;
-import holeg.utility.math.vector.Vec2f;
-import holeg.utility.math.vector.Vec2i;
-
 
 
 /**
 /**
- * This Class represents a Graph where the User can model the behavior of
- * elements and switches over time.
+ * This Class represents a Graph where the User can model the behavior of elements and switches over
+ * time.
  *
  *
  * @author Tom Troppmann
  * @author Tom Troppmann
  */
  */
-public class UnitGraph extends JPanel implements MouseListener, MouseMotionListener, ComponentListener {
-	private static final Logger log = Logger.getLogger(UnitGraph.class.getName());
-	// Normal Settings
-	private static final int border = 4;
-	private static final int clickThresholdSquared = 25;
-
-	// Display Settings
-	/**
-	 * The size of a dot in the graph. It should be at least 1.
-	 */
-	private static final int dotSize = 8;
-
-	/** The Color of a dot in the graph. */
-
-	private final Control control;
-
-	// Intern Variables
-	private static class Series {
-		public LinkedList<UnitGraphPoint> points = new LinkedList<UnitGraphPoint>();
-		public TimelineDependent element;
-		public GraphType type;
-		public Color color;
-	}
-
-	private final ArrayList<Series> seriesList = new ArrayList<>();
-	private Vec2i editPosition;
-	private Series actualSeries = null;
-
-	private static class GlobalCurve {
-		public LinkedList<UnitGraphPoint> points = new LinkedList<UnitGraphPoint>();
-		public float minEnergy;
-		public float maxEnergy;
-		public LinkedList<UnitGraphPoint> zeroLinePoints = new LinkedList<UnitGraphPoint>();
-	}
-
-	private GlobalCurve globalCurve = null;
-	private boolean editMode = false;
-	private Set<HolonElement> elements;
-	
-	private enum EditPointType {
-		Normal, StartPoint, EndPoint
-	};
-
-	private int widthWithBorder, heightWithBorder;
-
-	private EditPointType editPointType;
-	
-	
-
-	/**
-	 * Constructor.
-	 * @param control the Controller
-	 */
-	public UnitGraph(Control control) {
-		setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
-		this.setBackground(Color.WHITE);
-		this.control = control;
-		this.addMouseListener(this);
-		this.addMouseMotionListener(this);
-		this.addComponentListener(this);
-		control.OnCanvasUpdate.addListener(this::repaint);
-	}
-
-	/**
-	 * When the UnitGraph should represent a new GraphEditable Element. Its Updates
-	 * the Graph and give access to the Element.
-	 * 
-	 * @param element
-	 */
-	public void addNewSeries(TimelineDependent element) {
-		Series series = new Series();
-		overrideUnitGraph(series, element.getStateGraph());
-		series.element = element;
-		series.type = element.getGraphType();
-		series.color = ColorPreference.UnitGraph.SeriesColorArray[element.hashCode() % ColorPreference.UnitGraph.SeriesColorArray.length];
-		seriesList.add(series);
-		repaint();
-	}
-
-	public void clearSeries() {
-		seriesList.clear();
-		repaint();
-	}
-
-	public void setGlobalCurve(Set<HolonElement> elements) {
-		if( elements == null || elements.isEmpty()) {
-			this.globalCurve = null;
-			return;
-		}
-		GlobalCurve curve = new GlobalCurve();
-		curve.maxEnergy = elements.stream().map(HolonElement::getEnergy).filter(energy -> energy > 0).reduce(0.0f,
-				Float::sum);
-		curve.minEnergy = elements.stream().map(HolonElement::getEnergy).filter(energy -> energy < 0).reduce(0.0f,
-				Float::sum);
-		Model model = control.getModel();
-		float[] sample = new float[model.getMaxIterations()];
-		// sample energy
-		for (HolonElement element : elements) {
-			for (int i = 0; i < model.getMaxIterations(); i++) {
-				sample[i] += element.calculateExpectedEnergyAtTimeStep(i);
-			}
-		}
-		
-		// sample curve
-		for (int i = 0; i < model.getMaxIterations(); i++) {
-			curve.points.add(new UnitGraphPoint((double) i / (double)model.getMaxIterations(),
-					Maths.invLerp(curve.minEnergy, curve.maxEnergy, sample[i]), false));
-		}
-		// update displayPosition
-		for (UnitGraphPoint p : curve.points) {
-			p.calcDisplayedPosition(border, widthWithBorder, heightWithBorder);
-		}
-		double zeroLineYPos = Maths.invLerp(curve.minEnergy, curve.maxEnergy, 0.0);
-		curve.zeroLinePoints.add(new UnitGraphPoint(0.0,zeroLineYPos, false));
-		curve.zeroLinePoints.add(new UnitGraphPoint(1.0,zeroLineYPos, false));
-		for (UnitGraphPoint p : curve.zeroLinePoints) {
-			p.calcDisplayedPosition(border, widthWithBorder, heightWithBorder);
-		}
-		// set global curve
-		this.globalCurve = curve;
-		this.elements = elements;
-		
-	}
-
-	private void updateGlobalCurve() {
-		setGlobalCurve(this.elements);
-	}
-	
-	
-	
-	/**
-	 * Paints the Graph, the Grid, the actual Line from the currentIteration
-	 * 
-	 * @param g Graphics
-	 */
-	public void paintComponent(Graphics g) {
-		super.paintComponent(g);
-		Graphics2D g2d = (Graphics2D) g;
-		drawGrid(g2d);
-		g2d.setColor(Color.BLACK);
-		g2d.setRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));
-		g2d.setStroke(new BasicStroke(2f));
-		drawUnitGraph(g2d);
-		g2d.setColor(ColorPreference.UnitGraph.DotColor);
-		if (editMode) {
-			drawUnitGraphPointsReleased(g2d);
-		} else {
-			drawUnitGraphPoints(g2d);
-		}
-		g2d.setColor(ColorPreference.UnitGraph.DotColor);
-		g2d.setStroke(new BasicStroke(1));
-		drawCurrentIterationLine(g2d);
-		g2d.setStroke(new BasicStroke(1, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND, 1.0f, new float[]{6}, 3));
-		Optional.ofNullable(this.globalCurve).ifPresent(curve -> {
-			g2d.setColor(ColorPreference.UnitGraph.GlobalCurveColor);
-			drawDoubleGraph(g2d, curve.points);
-			g2d.setColor(ColorPreference.UnitGraph.ZeroLineColor);
-			g2d.setStroke(new BasicStroke(1));
-			drawDoubleGraph(g2d, curve.zeroLinePoints);
-		});
-	}
-
-	// Draw Methods only to let the User see the changes. Nothing its saved here or
-	// changed.
-	/**
-	 * Helper Method to draw the UnitGraphPanel.
-	 * {@link UnitGraph#paintComponent(Graphics)}
-	 * <p>
-	 * This Methods draws the UnitGraph whether its a boolGraph or a doubleGraph.
-	 * 
-	 * @param g to draw.
-	 */
-	private void drawUnitGraph(Graphics2D g) {
-		boolean drawSnappingHintFlag = false;
-		for (Series series : this.seriesList) {
-			g.setColor(series.color);
-			switch (series.type) {
-			case boolGraph:
-				if (editMode) {
-					drawBoolGraphInEditMode(g, series);
-					drawSnappingHintFlag = true;
-				} else
-					drawBoolGraph(g, series);
-				break;
-			case doubleGraph:
-				if (editMode)
-					drawDoubleGraphInEditMode(g, series);
-				else
-					drawDoubleGraph(g, series.points);
-				break;
-			default:
-				throw new UnsupportedOperationException();
-			}
-		}
-		if (drawSnappingHintFlag) {
-			drawSnappingHint(g);
-		}
-
-	}
-
-	/**
-	 * Helper Method to draw the UnitGraphPanel.
-	 * {@link UnitGraph#paintComponent(Graphics)}
-	 * <p>
-	 * This Methods draws the UnitGraphPoints of the UnitGraph.
-	 * 
-	 * @param g to draw.
-	 */
-	private void drawUnitGraphPoints(Graphics2D g) {
-		g.setColor(ColorPreference.UnitGraph.DotColor);
-		for (Series series : seriesList) {
-			for (UnitGraphPoint p : series.points) {
-				drawDot(g, p.displayedPosition);
-			}
-		}
-
-	}
-
-	/**
-	 * Helper Method to draw the UnitGraphPanel.
-	 * {@link UnitGraph#paintComponent(Graphics)}
-	 * <p>
-	 * This Methods draws the UnitGraphPoints of the UnitGraph when its in EditMode.
-	 * 
-	 * @param g to draw.
-	 */
-	private void drawUnitGraphPointsReleased(Graphics2D g) {
-		drawUnitGraphPoints(g);
-		g.setColor(ColorPreference.UnitGraph.EditDotColor);
-		drawDot(g, editPosition);
-	}
-
-	/**
-	 * Helper Method to draw the UnitGraphPanel.
-	 * {@link UnitGraph#paintComponent(Graphics)}
-	 * <p>
-	 * This Methods draws the Grid on the Canvas.
-	 * 
-	 * @param g to draw.
-	 */
-	private void drawGrid(Graphics2D g) {
-		g.setStroke(new BasicStroke(1));
-		g.setColor(Color.lightGray);
-		int amountOfLines = 10;
-		int width = widthWithBorder + 2 * border;
-		int height = heightWithBorder;
-		for (int i = 0; i <= amountOfLines; i++) {
-			int linehieght = (int) (((double) i / (double) amountOfLines) * (double) height) + border;
-			g.drawLine(0, linehieght, width, linehieght);
-		}
-	}
-
-	/**
-	 * Helper Method to draw the UnitGraphPanel.
-	 * {@link UnitGraph#paintComponent(Graphics)}
-	 * <p>
-	 * This Method draws the CurrentIterationLine.
-	 * 
-	 * @param g to draw.
-	 */
-	private void drawCurrentIterationLine(Graphics2D g) {
-		Model model = control.getModel();
-		int cur = model.getCurrentIteration();
-		int max = model.getMaxIterations();
-		if (isLocalPeriedDifferentInSeries()) {
-			for (Series series : seriesList) {
-				double where = switch(series.element.getPeriod().getType()){
-					case Local -> {
-						int interval = series.element.getPeriod().getInterval();
-						yield ((double) cur % interval) / ((double) interval);
+public class UnitGraph extends JPanel implements MouseListener, MouseMotionListener,
+    ComponentListener {
+
+  private static final Logger log = Logger.getLogger(UnitGraph.class.getName());
+  // Normal Settings
+  private static final int border = 4;
+  private static final int clickThresholdSquared = 25;
+
+  // Display Settings
+  /**
+   * The size of a dot in the graph. It should be at least 1.
+   */
+  private static final int dotSize = 8;
+
+  /**
+   * The Color of a dot in the graph.
+   */
+
+  private final Control control;
+  private final ArrayList<Series> seriesList = new ArrayList<>();
+  private Vec2i editPosition;
+  private Series actualSeries = null;
+  private GlobalCurve globalCurve = null;
+  private boolean editMode = false;
+  private Set<HolonElement> elements;
+  private int widthWithBorder, heightWithBorder;
+  private EditPointType editPointType;
+
+  /**
+   * Constructor.
+   *
+   * @param control the Controller
+   */
+  public UnitGraph(Control control) {
+    setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
+    this.setBackground(Color.WHITE);
+    this.control = control;
+    this.addMouseListener(this);
+    this.addMouseMotionListener(this);
+    this.addComponentListener(this);
+    control.OnCanvasUpdate.addListener(this::repaint);
+  }
+
+  ;
+
+  /**
+   * When the UnitGraph should represent a new GraphEditable Element. Its Updates the Graph and give
+   * access to the Element.
+   *
+   * @param element
+   */
+  public void addNewSeries(TimelineDependent element) {
+    Series series = new Series();
+    overrideUnitGraph(series, element.getStateGraph());
+    series.element = element;
+    series.type = element.getGraphType();
+    series.color = ColorPreference.UnitGraph.SeriesColorArray[element.hashCode()
+        % ColorPreference.UnitGraph.SeriesColorArray.length];
+    seriesList.add(series);
+    repaint();
+  }
+
+  public void clearSeries() {
+    seriesList.clear();
+    repaint();
+  }
+
+  public void setGlobalCurve(Set<HolonElement> elements) {
+    if (elements == null || elements.isEmpty()) {
+      this.globalCurve = null;
+      return;
+    }
+    GlobalCurve curve = new GlobalCurve();
+    curve.maxEnergy = elements.stream().map(HolonElement::getEnergy).filter(energy -> energy > 0)
+        .reduce(0.0f,
+            Float::sum);
+    curve.minEnergy = elements.stream().map(HolonElement::getEnergy).filter(energy -> energy < 0)
+        .reduce(0.0f,
+            Float::sum);
+    Model model = control.getModel();
+    float[] sample = new float[model.getMaxIterations()];
+    // sample energy
+    for (HolonElement element : elements) {
+      for (int i = 0; i < model.getMaxIterations(); i++) {
+        sample[i] += element.calculateExpectedEnergyAtTimeStep(i);
+      }
+    }
+
+    // sample curve
+    for (int i = 0; i < model.getMaxIterations(); i++) {
+      curve.points.add(new UnitGraphPoint((double) i / (double) model.getMaxIterations(),
+          Maths.invLerp(curve.minEnergy, curve.maxEnergy, sample[i]), false));
+    }
+    // update displayPosition
+    for (UnitGraphPoint p : curve.points) {
+      p.calcDisplayedPosition(border, widthWithBorder, heightWithBorder);
+    }
+    double zeroLineYPos = Maths.invLerp(curve.minEnergy, curve.maxEnergy, 0.0);
+    curve.zeroLinePoints.add(new UnitGraphPoint(0.0, zeroLineYPos, false));
+    curve.zeroLinePoints.add(new UnitGraphPoint(1.0, zeroLineYPos, false));
+    for (UnitGraphPoint p : curve.zeroLinePoints) {
+      p.calcDisplayedPosition(border, widthWithBorder, heightWithBorder);
+    }
+    // set global curve
+    this.globalCurve = curve;
+    this.elements = elements;
+
+  }
+
+  private void updateGlobalCurve() {
+    setGlobalCurve(this.elements);
+  }
+
+  /**
+   * Paints the Graph, the Grid, the actual Line from the currentIteration
+   *
+   * @param g Graphics
+   */
+  public void paintComponent(Graphics g) {
+    super.paintComponent(g);
+    Graphics2D g2d = (Graphics2D) g;
+    drawGrid(g2d);
+    g2d.setColor(Color.BLACK);
+    g2d.setRenderingHints(
+        new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));
+    g2d.setStroke(new BasicStroke(2f));
+    drawUnitGraph(g2d);
+    g2d.setColor(ColorPreference.UnitGraph.DotColor);
+    if (editMode) {
+      drawUnitGraphPointsReleased(g2d);
+    } else {
+      drawUnitGraphPoints(g2d);
+    }
+    g2d.setColor(ColorPreference.UnitGraph.DotColor);
+    g2d.setStroke(new BasicStroke(1));
+    drawCurrentIterationLine(g2d);
+    g2d.setStroke(
+        new BasicStroke(1, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND, 1.0f, new float[]{6},
+            3));
+    Optional.ofNullable(this.globalCurve).ifPresent(curve -> {
+      g2d.setColor(ColorPreference.UnitGraph.GlobalCurveColor);
+      drawDoubleGraph(g2d, curve.points);
+      g2d.setColor(ColorPreference.UnitGraph.ZeroLineColor);
+      g2d.setStroke(new BasicStroke(1));
+      drawDoubleGraph(g2d, curve.zeroLinePoints);
+    });
+  }
+
+  /**
+   * Helper Method to draw the UnitGraphPanel. {@link UnitGraph#paintComponent(Graphics)}
+   * <p>
+   * This Methods draws the UnitGraph whether its a boolGraph or a doubleGraph.
+   *
+   * @param g to draw.
+   */
+  private void drawUnitGraph(Graphics2D g) {
+    boolean drawSnappingHintFlag = false;
+    for (Series series : this.seriesList) {
+      g.setColor(series.color);
+      switch (series.type) {
+        case boolGraph:
+					if (editMode) {
+						drawBoolGraphInEditMode(g, series);
+						drawSnappingHintFlag = true;
+					} else {
+						drawBoolGraph(g, series);
 					}
 					}
-					case Global -> ((double) cur) / ((double) max);
-				};
-				Vec2i oben = new Vec2i(border + (int) (where * widthWithBorder), 0);
-				Vec2i unten = new Vec2i(border + (int) (where * widthWithBorder),
-						2 * border + heightWithBorder);
-				g.setColor(series.color);
-				drawLine(g, oben, unten);
-			}
-		} else {
-			double where;
-			if (!isUsingLocalPeriod()) {
-				where = ((double) cur) / ((double) max);
-			} else {
-				int lPeriod = getFirstLocalPeriod();
-				where = ((double) cur % lPeriod) / ((double) lPeriod);
-			}
-			Vec2i oben = new Vec2i(border + (int) (where * widthWithBorder), 0);
-			Vec2i unten = new Vec2i(border + (int) (where * widthWithBorder), 2 * border + heightWithBorder);
-			g.setColor(ColorPreference.UnitGraph.DotColor);
-			drawLine(g, oben, unten);
-		}
-
-	}
-
-	/**
-	 * Helper Method to draw the UnitGraphPanel.
-	 * {@link UnitGraph#paintComponent(Graphics)}
-	 * <p>
-	 * This Method draws a line between two Positions on the Canvas.
-	 * 
-	 * @param g   to draw.
-	 * @param start the Position of one end of the line to draw.
-	 * @param end   the other Ends Position of the Line to draw.
-	 */
-	private void drawLine(Graphics2D g, Vec2i start, Vec2i end) {
-		Path2D.Double path = new Path2D.Double();
-		path.moveTo(start.getX(), start.getY());
-		path.lineTo(end.getX(), end.getY());
-		g.draw(path);
-	}
-
-	/**
-	 * Helper Method to draw the UnitGraphPanel.
-	 * {@link UnitGraph#paintComponent(Graphics)}
-	 * <p>
-	 * Initialize a Cubic BezierCurve.
-	 * 
-	 * @param start The Position to start the Curve.
-	 */
-	private Path2D.Double initBezier(Vec2i start) {
-		// Good Source for basic understanding for Bezier Curves
-		// http://www.theappguruz.com/blog/bezier-curve-in-games
-		Path2D.Double path = new Path2D.Double();
-		path.moveTo(start.getX(), start.getY());
-		return path;
-	}
-
-	/**
-	 * Helper Method to draw the UnitGraphPanel.
-	 * {@link UnitGraph#paintComponent(Graphics)}
-	 * <p>
-	 * Calculate the Path of a the Cubic BezierCurve with the special controlPoints
-	 * to make the wanted behavior.
-	 * 
-	 * @param path   the path of the Bezier.
-	 * @param actual the actual Position of the Path.
-	 * @param target the end Position of the Curve.
-	 */
-	private void curveTo(Path2D.Double path, Vec2i actual, Vec2i target) {
-		double mitte = (actual.getX() + target.getX()) * 0.5;
-		path.curveTo(mitte, actual.getY(), mitte, target.getY(), target.getX(), target.getY());
-	}
-
-	/**
-	 * Helper Method to draw the UnitGraphPanel.
-	 * {@link UnitGraph#paintComponent(Graphics)}
-	 * <p>
-	 * Draws a Dot at a Position.
-	 * 
-	 * @param g to draw.
-	 * @param p the position of the Dot.
-	 */
-	private void drawDot(Graphics2D g, Vec2i p) {
-		g.fillOval(p.getX() - dotSize / 2, p.getY() - dotSize / 2, dotSize, dotSize);
-	}
-
-	/**
-	 * Helper Method to draw the UnitGraphPanel.
-	 * {@link UnitGraph#paintComponent(Graphics)}
-	 * <p>
-	 * This Method draws the UnitGraph as BoolGraph.
-	 * 
-	 * @param g to draw.
-	 */
-	private void drawBoolGraph(Graphics2D g, Series series) {
-		if (series.points.size() <= 1)
+          break;
+        case doubleGraph:
+					if (editMode) {
+						drawDoubleGraphInEditMode(g, series);
+					} else {
+						drawDoubleGraph(g, series.points);
+					}
+          break;
+        default:
+          throw new UnsupportedOperationException();
+      }
+    }
+    if (drawSnappingHintFlag) {
+      drawSnappingHint(g);
+    }
+
+  }
+
+  /**
+   * Helper Method to draw the UnitGraphPanel. {@link UnitGraph#paintComponent(Graphics)}
+   * <p>
+   * This Methods draws the UnitGraphPoints of the UnitGraph.
+   *
+   * @param g to draw.
+   */
+  private void drawUnitGraphPoints(Graphics2D g) {
+    g.setColor(ColorPreference.UnitGraph.DotColor);
+    for (Series series : seriesList) {
+      for (UnitGraphPoint p : series.points) {
+        drawDot(g, p.displayedPosition);
+      }
+    }
+
+  }
+
+  /**
+   * Helper Method to draw the UnitGraphPanel. {@link UnitGraph#paintComponent(Graphics)}
+   * <p>
+   * This Methods draws the UnitGraphPoints of the UnitGraph when its in EditMode.
+   *
+   * @param g to draw.
+   */
+  private void drawUnitGraphPointsReleased(Graphics2D g) {
+    drawUnitGraphPoints(g);
+    g.setColor(ColorPreference.UnitGraph.EditDotColor);
+    drawDot(g, editPosition);
+  }
+
+  // Draw Methods only to let the User see the changes. Nothing its saved here or
+  // changed.
+
+  /**
+   * Helper Method to draw the UnitGraphPanel. {@link UnitGraph#paintComponent(Graphics)}
+   * <p>
+   * This Methods draws the Grid on the Canvas.
+   *
+   * @param g to draw.
+   */
+  private void drawGrid(Graphics2D g) {
+    g.setStroke(new BasicStroke(1));
+    g.setColor(Color.lightGray);
+    int amountOfLines = 10;
+    int width = widthWithBorder + 2 * border;
+    int height = heightWithBorder;
+    for (int i = 0; i <= amountOfLines; i++) {
+      int linehieght = (int) (((double) i / (double) amountOfLines) * (double) height) + border;
+      g.drawLine(0, linehieght, width, linehieght);
+    }
+  }
+
+  /**
+   * Helper Method to draw the UnitGraphPanel. {@link UnitGraph#paintComponent(Graphics)}
+   * <p>
+   * This Method draws the CurrentIterationLine.
+   *
+   * @param g to draw.
+   */
+  private void drawCurrentIterationLine(Graphics2D g) {
+    Model model = control.getModel();
+    int cur = model.getCurrentIteration();
+    int max = model.getMaxIterations();
+    if (isLocalPeriedDifferentInSeries()) {
+      for (Series series : seriesList) {
+        double where = switch (series.element.getPeriod().getType()) {
+          case Local -> {
+            int interval = series.element.getPeriod().getInterval();
+            yield ((double) cur % interval) / ((double) interval);
+          }
+          case Global -> ((double) cur) / ((double) max);
+        };
+        Vec2i oben = new Vec2i(border + (int) (where * widthWithBorder), 0);
+        Vec2i unten = new Vec2i(border + (int) (where * widthWithBorder),
+            2 * border + heightWithBorder);
+        g.setColor(series.color);
+        drawLine(g, oben, unten);
+      }
+    } else {
+      double where;
+      if (!isUsingLocalPeriod()) {
+        where = ((double) cur) / ((double) max);
+      } else {
+        int lPeriod = getFirstLocalPeriod();
+        where = ((double) cur % lPeriod) / ((double) lPeriod);
+      }
+      Vec2i upPoint = new Vec2i(border + (int) (where * widthWithBorder), 0);
+      Vec2i downPoint = new Vec2i(border + (int) (where * widthWithBorder),
+          2 * border + heightWithBorder);
+      g.setColor(ColorPreference.UnitGraph.DotColor);
+      drawLine(g, upPoint, downPoint);
+    }
+
+  }
+
+  /**
+   * Helper Method to draw the UnitGraphPanel. {@link UnitGraph#paintComponent(Graphics)}
+   * <p>
+   * This Method draws a line between two Positions on the Canvas.
+   *
+   * @param g     to draw.
+   * @param start the Position of one end of the line to draw.
+   * @param end   the other Ends Position of the Line to draw.
+   */
+  private void drawLine(Graphics2D g, Vec2i start, Vec2i end) {
+    Path2D.Double path = new Path2D.Double();
+    path.moveTo(start.getX(), start.getY());
+    path.lineTo(end.getX(), end.getY());
+    g.draw(path);
+  }
+
+  /**
+   * Helper Method to draw the UnitGraphPanel. {@link UnitGraph#paintComponent(Graphics)}
+   * <p>
+   * Initialize a Cubic BezierCurve.
+   *
+   * @param start The Position to start the Curve.
+   */
+  private Path2D.Double initBezier(Vec2i start) {
+    // Good Source for basic understanding for Bezier Curves
+    // http://www.theappguruz.com/blog/bezier-curve-in-games
+    Path2D.Double path = new Path2D.Double();
+    path.moveTo(start.getX(), start.getY());
+    return path;
+  }
+
+  /**
+   * Helper Method to draw the UnitGraphPanel. {@link UnitGraph#paintComponent(Graphics)}
+   * <p>
+   * Calculate the Path of a the Cubic BezierCurve with the special controlPoints to make the wanted
+   * behavior.
+   *
+   * @param path   the path of the Bezier.
+   * @param actual the actual Position of the Path.
+   * @param target the end Position of the Curve.
+   */
+  private void curveTo(Path2D.Double path, Vec2i actual, Vec2i target) {
+    double mitte = (actual.getX() + target.getX()) * 0.5;
+    path.curveTo(mitte, actual.getY(), mitte, target.getY(), target.getX(), target.getY());
+  }
+
+  /**
+   * Helper Method to draw the UnitGraphPanel. {@link UnitGraph#paintComponent(Graphics)}
+   * <p>
+   * Draws a Dot at a Position.
+   *
+   * @param g to draw.
+   * @param p the position of the Dot.
+   */
+  private void drawDot(Graphics2D g, Vec2i p) {
+    g.fillOval(p.getX() - dotSize / 2, p.getY() - dotSize / 2, dotSize, dotSize);
+  }
+
+  /**
+   * Helper Method to draw the UnitGraphPanel. {@link UnitGraph#paintComponent(Graphics)}
+   * <p>
+   * This Method draws the UnitGraph as BoolGraph.
+   *
+   * @param g to draw.
+   */
+  private void drawBoolGraph(Graphics2D g, Series series) {
+		if (series.points.size() <= 1) {
 			return;
 			return;
-		LinkedList<Vec2i> cornerPoints = new LinkedList<Vec2i>();
-		ListIterator<UnitGraphPoint> iter = series.points.listIterator();
-		Vec2i actual = series.points.getFirst().displayedPosition;
-		Path2D.Double path = new Path2D.Double();
-		path.moveTo(actual.getX(), actual.getY());
-		while (iter.hasNext()) {
-			Vec2i target = iter.next().displayedPosition;
-			// BooleanConnection
-			path.lineTo(target.getX(), actual.getY()); // line to corner
-			cornerPoints.add(new Vec2i(target.getX(), actual.getY())); // save corner
-			path.lineTo(target.getX(), target.getY()); // line to next Point
-
-			actual = target;
-		}
-		g.draw(path);
-		// Draw the Points on the Corner that dont exist in Data but should be visual
-		g.setColor(ColorPreference.UnitGraph.DotColor);
-		for (Vec2i p : cornerPoints) {
-			drawDot(g, p);
 		}
 		}
-
-	}
-
-	/**
-	 * Helper Method to draw the UnitGraphPanel.
-	 * {@link UnitGraph#paintComponent(Graphics)}
-	 * <p>
-	 * This Method draws the UnitGraph as BoolGraph in EditMode.
-	 * 
-	 * @param g to draw.
-	 */
-	private void drawBoolGraphInEditMode(Graphics2D g, Series series) {
-		LinkedList<Vec2i> before = new LinkedList<Vec2i>();
-		LinkedList<Vec2i> after = new LinkedList<Vec2i>();
-		for (UnitGraphPoint p : series.points) {
-			if (p.displayedPosition.getX() < editPosition.getX())
+    LinkedList<Vec2i> cornerPoints = new LinkedList<Vec2i>();
+    ListIterator<UnitGraphPoint> iter = series.points.listIterator();
+    Vec2i actual = series.points.getFirst().displayedPosition;
+    Path2D.Double path = new Path2D.Double();
+    path.moveTo(actual.getX(), actual.getY());
+    while (iter.hasNext()) {
+      Vec2i target = iter.next().displayedPosition;
+      // BooleanConnection
+      path.lineTo(target.getX(), actual.getY()); // line to corner
+      cornerPoints.add(new Vec2i(target.getX(), actual.getY())); // save corner
+      path.lineTo(target.getX(), target.getY()); // line to next Point
+
+      actual = target;
+    }
+    g.draw(path);
+    // Draw the Points on the Corner that dont exist in Data but should be visual
+    g.setColor(ColorPreference.UnitGraph.DotColor);
+    for (Vec2i p : cornerPoints) {
+      drawDot(g, p);
+    }
+
+  }
+
+  /**
+   * Helper Method to draw the UnitGraphPanel. {@link UnitGraph#paintComponent(Graphics)}
+   * <p>
+   * This Method draws the UnitGraph as BoolGraph in EditMode.
+   *
+   * @param g to draw.
+   */
+  private void drawBoolGraphInEditMode(Graphics2D g, Series series) {
+    LinkedList<Vec2i> before = new LinkedList<Vec2i>();
+    LinkedList<Vec2i> after = new LinkedList<Vec2i>();
+    for (UnitGraphPoint p : series.points) {
+			if (p.displayedPosition.getX() < editPosition.getX()) {
 				before.add(p.displayedPosition);
 				before.add(p.displayedPosition);
-			else
+			} else {
 				after.add(p.displayedPosition);
 				after.add(p.displayedPosition);
-		}
-		g.setColor(series.color);
-		drawBoolGraphFromList(g, before);
-		g.setColor(series.color);
-		drawBoolGraphFromList(g, after);
-		// EditGraph
-		LinkedList<Vec2i> middle = new LinkedList<Vec2i>();
-		if (!before.isEmpty())
+			}
+    }
+    g.setColor(series.color);
+    drawBoolGraphFromList(g, before);
+    g.setColor(series.color);
+    drawBoolGraphFromList(g, after);
+    // EditGraph
+    LinkedList<Vec2i> middle = new LinkedList<Vec2i>();
+		if (!before.isEmpty()) {
 			middle.add(before.getLast());
 			middle.add(before.getLast());
-		middle.add(editPosition);
-		if (!after.isEmpty())
+		}
+    middle.add(editPosition);
+		if (!after.isEmpty()) {
 			middle.add(after.getFirst());
 			middle.add(after.getFirst());
+		}
 
 
-		g.setColor(ColorPreference.UnitGraph.EditDotColor);
-		drawBoolGraphFromList(g, middle);
-
-	}
-
-	/**
-	 * Helper Method to draw the UnitGraphPanel.
-	 * {@link UnitGraph#paintComponent(Graphics)}
-	 * <p>
-	 * This Method draws a red Hint to signal the User the snapping of the hovered
-	 * Point under the Cursor in EditMode.
-	 * 
-	 * @param g to draw.
-	 */
-	private void drawSnappingHint(Graphics2D g) {
-		// ColorHint
-		g.setColor(Color.RED);
-		// Threshhold Line
-		final float dash1[] = { 10.0f };
-		final BasicStroke dashed = new BasicStroke(2.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, dash1,
-				0.0f);
-		g.setStroke(dashed);
-
-		int halfheight = border + heightWithBorder / 2;
-		g.drawLine(0, halfheight, widthWithBorder + 2 * border, halfheight);
-		// Threshhold Text
-		g.drawString("Snapping Threshold", 10, halfheight - 2);
-	}
-
-	/**
-	 * Helper Method to draw the UnitGraphPanel.
-	 * {@link UnitGraph#paintComponent(Graphics)}
-	 * <p>
-	 * This Method draws a partial Graph from a Position List as BoolGraph.
-	 * 
-	 * @param g  to draw.
-	 * @param list the PositionList to draw a BoolGraph
-	 */
-	private void drawBoolGraphFromList(Graphics2D g, LinkedList<Vec2i> list) {
-		if (list.size() <= 1)
+    g.setColor(ColorPreference.UnitGraph.EditDotColor);
+    drawBoolGraphFromList(g, middle);
+
+  }
+
+  /**
+   * Helper Method to draw the UnitGraphPanel. {@link UnitGraph#paintComponent(Graphics)}
+   * <p>
+   * This Method draws a red Hint to signal the User the snapping of the hovered Point under the
+   * Cursor in EditMode.
+   *
+   * @param g to draw.
+   */
+  private void drawSnappingHint(Graphics2D g) {
+    // ColorHint
+    g.setColor(Color.RED);
+    // Threshhold Line
+    final float dash1[] = {10.0f};
+    final BasicStroke dashed = new BasicStroke(2.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
+        10.0f, dash1,
+        0.0f);
+    g.setStroke(dashed);
+
+    int halfheight = border + heightWithBorder / 2;
+    g.drawLine(0, halfheight, widthWithBorder + 2 * border, halfheight);
+    // Threshhold Text
+    g.drawString("Snapping Threshold", 10, halfheight - 2);
+  }
+
+  /**
+   * Helper Method to draw the UnitGraphPanel. {@link UnitGraph#paintComponent(Graphics)}
+   * <p>
+   * This Method draws a partial Graph from a Position List as BoolGraph.
+   *
+   * @param g    to draw.
+   * @param list the PositionList to draw a BoolGraph
+   */
+  private void drawBoolGraphFromList(Graphics2D g, LinkedList<Vec2i> list) {
+		if (list.size() <= 1) {
 			return;
 			return;
-		ListIterator<Vec2i> iter = list.listIterator();
-		LinkedList<Vec2i> cornerPoints = new LinkedList<Vec2i>();
-		Vec2i actual = list.getFirst();
-		Path2D.Double path = new Path2D.Double();
-		path.moveTo(actual.getX(), actual.getY());
-		while (iter.hasNext()) {
-			Vec2i target = iter.next();
-			// BooleanConnection
-			path.lineTo(target.getX(), actual.getY()); // line to corner
-			cornerPoints.add(new Vec2i(target.getX(), actual.getY())); // save corner
-			path.lineTo(target.getX(), target.getY()); // line to next Point
-			actual = target;
-		}
-		g.draw(path);
-		g.setColor(ColorPreference.UnitGraph.DotColor);
-		for (Vec2i p : cornerPoints) {
-			drawDot(g, p);
 		}
 		}
-	}
-
-	/**
-	 * Helper Method to draw the UnitGraphPanel.
-	 * {@link UnitGraph#paintComponent(Graphics)}
-	 * <p>
-	 * This Method draws the UnitGraph as DoubleGraph.
-	 * 
-	 * @param g to draw.
-	 */
-	private void drawDoubleGraph(Graphics2D g, List<UnitGraphPoint> points) {
-		if (points.isEmpty())
+    ListIterator<Vec2i> iter = list.listIterator();
+    LinkedList<Vec2i> cornerPoints = new LinkedList<Vec2i>();
+    Vec2i actual = list.getFirst();
+    Path2D.Double path = new Path2D.Double();
+    path.moveTo(actual.getX(), actual.getY());
+    while (iter.hasNext()) {
+      Vec2i target = iter.next();
+      // BooleanConnection
+      path.lineTo(target.getX(), actual.getY()); // line to corner
+      cornerPoints.add(new Vec2i(target.getX(), actual.getY())); // save corner
+      path.lineTo(target.getX(), target.getY()); // line to next Point
+      actual = target;
+    }
+    g.draw(path);
+    g.setColor(ColorPreference.UnitGraph.DotColor);
+    for (Vec2i p : cornerPoints) {
+      drawDot(g, p);
+    }
+  }
+
+  /**
+   * Helper Method to draw the UnitGraphPanel. {@link UnitGraph#paintComponent(Graphics)}
+   * <p>
+   * This Method draws the UnitGraph as DoubleGraph.
+   *
+   * @param g to draw.
+   */
+  private void drawDoubleGraph(Graphics2D g, List<UnitGraphPoint> points) {
+		if (points.isEmpty()) {
 			return;
 			return;
-		ListIterator<UnitGraphPoint> iter = points.listIterator();
-		Vec2i actual = iter.next().displayedPosition;
-		Path2D.Double path = this.initBezier(actual);
-		while (iter.hasNext()) {
-			Vec2i target = iter.next().displayedPosition;
-			this.curveTo(path, actual, target);
-			actual = target;
 		}
 		}
-		g.draw(path);
-
-	}
-
-	/**
-	 * Helper Method to draw the UnitGraphPanel.
-	 * {@link UnitGraph#paintComponent(Graphics)}
-	 * <p>
-	 * This Method draws the UnitGraph as DoubleGraph in EditMode.
-	 * 
-	 * @param g to draw.
-	 */
-	private void drawDoubleGraphInEditMode(Graphics2D g, Series series) {
-		LinkedList<Vec2i> before = new LinkedList<Vec2i>();
-		LinkedList<Vec2i> after = new LinkedList<Vec2i>();
-		for (UnitGraphPoint p : series.points) {
-			if (p.displayedPosition.getX() < editPosition.getX())
+    ListIterator<UnitGraphPoint> iter = points.listIterator();
+    Vec2i actual = iter.next().displayedPosition;
+    Path2D.Double path = this.initBezier(actual);
+    while (iter.hasNext()) {
+      Vec2i target = iter.next().displayedPosition;
+      this.curveTo(path, actual, target);
+      actual = target;
+    }
+    g.draw(path);
+
+  }
+
+  /**
+   * Helper Method to draw the UnitGraphPanel. {@link UnitGraph#paintComponent(Graphics)}
+   * <p>
+   * This Method draws the UnitGraph as DoubleGraph in EditMode.
+   *
+   * @param g to draw.
+   */
+  private void drawDoubleGraphInEditMode(Graphics2D g, Series series) {
+    LinkedList<Vec2i> before = new LinkedList<Vec2i>();
+    LinkedList<Vec2i> after = new LinkedList<Vec2i>();
+    for (UnitGraphPoint p : series.points) {
+			if (p.displayedPosition.getX() < editPosition.getX()) {
 				before.add(p.displayedPosition);
 				before.add(p.displayedPosition);
-			else
+			} else {
 				after.add(p.displayedPosition);
 				after.add(p.displayedPosition);
-		}
-		drawUnitGraphFromList(g, before);
-		drawUnitGraphFromList(g, after);
-		// EditGraph
-		LinkedList<Vec2i> middle = new LinkedList<Vec2i>();
-		if (!before.isEmpty())
-			middle.add(before.getLast());
-		middle.add(editPosition);
-		if (!after.isEmpty())
-			middle.add(after.getFirst());
-
-		g.setColor(ColorPreference.UnitGraph.EditDotColor);
-		drawUnitGraphFromList(g, middle);
-	}
-
-	/**
-	 * Helper Method to draw the UnitGraphPanel.
-	 * {@link UnitGraph#paintComponent(Graphics)}
-	 * <p>
-	 * This Method draws a partial Graph from a Position List as DoubleGraph.
-	 * 
-	 * @param g  to draw.
-	 * @param list the PositionList to draw a DoubleGraph
-	 */
-	private void drawUnitGraphFromList(Graphics2D g, LinkedList<Vec2i> list) {
-		if (list.size() <= 1)
-			return;
-		ListIterator<Vec2i> iter = list.listIterator();
-		Vec2i actual = list.getFirst();
-		Path2D.Double path = this.initBezier(actual);
-		while (iter.hasNext()) {
-			Vec2i target = iter.next();
-			curveTo(path, actual, target);
-			actual = target;
-		}
-		g.draw(path);
-	}
-
-	// Under the hood functions to calculate and function the
-	/**
-	 * A unitgraphpoint have a x and y position to store the data of a graph point.
-	 * Also it have a displayposition to store the Position of the GraphPoints on
-	 * the Canvas. e.g. when the canvas has 500 width and 200 height a GraphPoint
-	 * with the X=0.5 and Y=1.0 should have a displayposition of (250,3) when border
-	 * is 3.
-	 */
-	private void updateRepresentativePositions() {
-		for (Series series : seriesList) {
-			for (UnitGraphPoint p : series.points) {
-				p.calcDisplayedPosition(border, widthWithBorder, heightWithBorder);
 			}
 			}
+    }
+    drawUnitGraphFromList(g, before);
+    drawUnitGraphFromList(g, after);
+    // EditGraph
+    LinkedList<Vec2i> middle = new LinkedList<Vec2i>();
+		if (!before.isEmpty()) {
+			middle.add(before.getLast());
 		}
 		}
-		Optional.ofNullable(this.globalCurve).ifPresent(curve -> {
-			for (UnitGraphPoint p : curve.points) {
-				p.calcDisplayedPosition(border, widthWithBorder, heightWithBorder);
-			}
-			for (UnitGraphPoint p : curve.zeroLinePoints) {
-				p.calcDisplayedPosition(border, widthWithBorder, heightWithBorder);
-			}
-		});
-		
-	}
-
-	/**
-	 * Takes a List of GraphPoints and convert it to the actual UnitGraphPoints with
-	 * displayposition in the {@link #seriesList}
-	 * 
-	 * @param stateCurve the list of GraphPoint
-	 */
-	private void overrideUnitGraph(Series series, LinkedList<Vec2f> stateCurve) {
-		series.points.clear();
-		for (Vec2f p : stateCurve) {
-			UnitGraphPoint point = new UnitGraphPoint(p);
-			point.calcDisplayedPosition(border, widthWithBorder, heightWithBorder);
-			series.points.add(point);
-		}
-	}
-
-	/**
-	 * When the PanelSize Change the width and height to calculate the drawings have
-	 * to be adjusted.
-	 */
-	private void calculateWidthHeight() {
-		widthWithBorder = this.getWidth() - 2 * border;
-		heightWithBorder = this.getHeight() - 2 * border;
-	}
-
-	/**
-	 * Save the actualGraphPoint List to the GraphEditable Element.
-	 */
-	private void saveGraph() {
-		for (Series series : seriesList) {
-			LinkedList<Vec2f> actual = series.element.getStateGraph();
-			actual.clear();
-			for (UnitGraphPoint p : series.points) {
-				actual.add(p.getPoint());
-			}
-			series.element.sampleGraph();
-		}
-	}
-
-	/**
-	 * Remove a UnitGraphPoint from the UnitGraphPoint list ({@link #seriesList}
-	 * when its near a given Position.
-	 * 
-	 * @param mPosition
-	 */
-	private void removePointNearPosition(Series series, Vec2i mPosition) {
-		ListIterator<UnitGraphPoint> iter = series.points.listIterator();
-		while (iter.hasNext()) {
-			if (near(mPosition, iter.next().displayedPosition, series.type)) {
-				iter.remove();
-				break;
-			}
+    middle.add(editPosition);
+		if (!after.isEmpty()) {
+			middle.add(after.getFirst());
 		}
 		}
 
 
-	}
-
-	private void removePointsNearPosition(Vec2i mPosition) {
-		for (Series series : seriesList) {
-			removePointNearPosition(series, mPosition);
+    g.setColor(ColorPreference.UnitGraph.EditDotColor);
+    drawUnitGraphFromList(g, middle);
+  }
+
+  /**
+   * Helper Method to draw the UnitGraphPanel. {@link UnitGraph#paintComponent(Graphics)}
+   * <p>
+   * This Method draws a partial Graph from a Position List as DoubleGraph.
+   *
+   * @param g    to draw.
+   * @param list the PositionList to draw a DoubleGraph
+   */
+  private void drawUnitGraphFromList(Graphics2D g, LinkedList<Vec2i> list) {
+		if (list.size() <= 1) {
+			return;
 		}
 		}
-	}
-
-	private Optional<Series> detectSeries(Vec2i mPosition) {
-		return seriesList.stream().min((a, b) -> {
-			float minDistanceA = a.points.stream().map(point -> point.displayedPosition.getSquaredDistance(mPosition))
-					.min(Float::compare).get();
-			float minDistanceB = b.points.stream().map(point -> point.displayedPosition.getSquaredDistance(mPosition))
-					.min(Float::compare).get();
-			return Float.compare(minDistanceA, minDistanceB);
-		});
-	}
-
-	/**
-	 * Determine if the Point is a StartPoint , EndPoint or a NormalPoint a.k.a. in
-	 * between Points.
-	 * 
-	 * @param mPosition The Position to check.
-	 */
-	private EditPointType detectStartEndPoint(Series series, Vec2i mPosition) {
-		UnitGraphPoint first = series.points.getFirst();
-		UnitGraphPoint last = series.points.getLast();
-		if (near(mPosition, first.displayedPosition, series.type))
+    ListIterator<Vec2i> iter = list.listIterator();
+    Vec2i actual = list.getFirst();
+    Path2D.Double path = this.initBezier(actual);
+    while (iter.hasNext()) {
+      Vec2i target = iter.next();
+      curveTo(path, actual, target);
+      actual = target;
+    }
+    g.draw(path);
+  }
+
+  /**
+   * A unitgraphpoint have a x and y position to store the data of a graph point. Also it have a
+   * displayposition to store the Position of the GraphPoints on the Canvas. e.g. when the canvas
+   * has 500 width and 200 height a GraphPoint with the X=0.5 and Y=1.0 should have a
+   * displayposition of (250,3) when border is 3.
+   */
+  private void updateRepresentativePositions() {
+    for (Series series : seriesList) {
+      for (UnitGraphPoint p : series.points) {
+        p.calcDisplayedPosition(border, widthWithBorder, heightWithBorder);
+      }
+    }
+    Optional.ofNullable(this.globalCurve).ifPresent(curve -> {
+      for (UnitGraphPoint p : curve.points) {
+        p.calcDisplayedPosition(border, widthWithBorder, heightWithBorder);
+      }
+      for (UnitGraphPoint p : curve.zeroLinePoints) {
+        p.calcDisplayedPosition(border, widthWithBorder, heightWithBorder);
+      }
+    });
+
+  }
+
+  /**
+   * Takes a List of GraphPoints and convert it to the actual UnitGraphPoints with displayposition
+   * in the {@link #seriesList}
+   *
+   * @param stateCurve the list of GraphPoint
+   */
+  private void overrideUnitGraph(Series series, LinkedList<Vec2f> stateCurve) {
+    series.points.clear();
+    for (Vec2f p : stateCurve) {
+      UnitGraphPoint point = new UnitGraphPoint(p);
+      point.calcDisplayedPosition(border, widthWithBorder, heightWithBorder);
+      series.points.add(point);
+    }
+  }
+
+  /**
+   * When the PanelSize Change the width and height to calculate the drawings have to be adjusted.
+   */
+  private void calculateWidthHeight() {
+    widthWithBorder = this.getWidth() - 2 * border;
+    heightWithBorder = this.getHeight() - 2 * border;
+  }
+
+  // Under the hood functions to calculate and function the
+
+  /**
+   * Save the actualGraphPoint List to the GraphEditable Element.
+   */
+  private void saveGraph() {
+    for (Series series : seriesList) {
+      LinkedList<Vec2f> actual = series.element.getStateGraph();
+      actual.clear();
+      for (UnitGraphPoint p : series.points) {
+        actual.add(p.getPoint());
+      }
+      series.element.sampleGraph();
+    }
+  }
+
+  /**
+   * Remove a UnitGraphPoint from the UnitGraphPoint list ({@link #seriesList} when its near a given
+   * Position.
+   *
+   * @param mPosition
+   */
+  private void removePointNearPosition(Series series, Vec2i mPosition) {
+    ListIterator<UnitGraphPoint> iter = series.points.listIterator();
+    while (iter.hasNext()) {
+      if (near(mPosition, iter.next().displayedPosition, series.type)) {
+        iter.remove();
+        break;
+      }
+    }
+
+  }
+
+  private void removePointsNearPosition(Vec2i mPosition) {
+    for (Series series : seriesList) {
+      removePointNearPosition(series, mPosition);
+    }
+  }
+
+  private Optional<Series> detectSeries(Vec2i mPosition) {
+    return seriesList.stream().min((a, b) -> {
+      float minDistanceA = a.points.stream()
+          .map(point -> point.displayedPosition.getSquaredDistance(mPosition))
+          .min(Float::compare).get();
+      float minDistanceB = b.points.stream()
+          .map(point -> point.displayedPosition.getSquaredDistance(mPosition))
+          .min(Float::compare).get();
+      return Float.compare(minDistanceA, minDistanceB);
+    });
+  }
+
+  /**
+   * Determine if the Point is a StartPoint , EndPoint or a NormalPoint a.k.a. in between Points.
+   *
+   * @param mPosition The Position to check.
+   */
+  private EditPointType detectStartEndPoint(Series series, Vec2i mPosition) {
+    UnitGraphPoint first = series.points.getFirst();
+    UnitGraphPoint last = series.points.getLast();
+		if (near(mPosition, first.displayedPosition, series.type)) {
 			return EditPointType.StartPoint;
 			return EditPointType.StartPoint;
-		else if (near(mPosition, last.displayedPosition, series.type))
+		} else if (near(mPosition, last.displayedPosition, series.type)) {
 			return EditPointType.EndPoint;
 			return EditPointType.EndPoint;
-		else
-			return EditPointType.Normal;
-	}
-
-	/**
-	 * Determine if a Point is near the Cursor (depends on Mode what near means). To
-	 * detect if it should grab the Point or create a new Point.
-	 *
-	 */
-	private boolean near(Vec2i actual, Vec2i target, GraphType graphType) {
-		switch (graphType) {
-		case boolGraph: // Distance only with X
-			int xDis = target.getX() - actual.getX();
-			return xDis * xDis < clickThresholdSquared;
-		case doubleGraph:
-			return actual.getSquaredDistance(target) < clickThresholdSquared;
-		default:
-			return false;
-		}
-	}
-
-	/**
-	 * When the Mouse Drag a Point it updates each time the position.
-	 *
-	 */
-	private void updateEditPointPosition(Vec2i newPosition, EditPointType editPointType, GraphType graphType) {
-		// make it in the bounds of the UnitGraph no Point out of the Border
-		Vec2i currentPosition = setInBounds(newPosition);
-		if (editPointType != EditPointType.Normal) {
-			attachToBorder(currentPosition, editPointType);
-		}
-		if (graphType == GraphType.boolGraph) {
-			snapBoolean(currentPosition);
-		}
-		editPosition = currentPosition;
-	}
-
-	/**
-	 * No Point on the UnitGraph should exit the UnitGraph.
-	 * 
-	 * @param p the Position
-	 * @return the updated Position.
-	 */
-	private Vec2i setInBounds(Vec2i p) {
-		p.clampX(border, border + widthWithBorder);
-		p.clampY(border, border + heightWithBorder);
-		return p;
-	}
-
-	/**
-	 * For Switches the Point have to be Snap to the Top or the Bottem.
-	 * 
-	 * @param p the Position
-	 * @return the updated Position.
-	 */
-	private Vec2i snapBoolean(Vec2i p) {
-		if (p.getY() < border + heightWithBorder / 2) {
-			p.setY(border);
 		} else {
 		} else {
-			p.setY(border + heightWithBorder);
-		}
-		return p;
-	}
-
-	/**
-	 * The First Point has to be at 0(LeftSide) and Last Point has to be at
-	 * 1(RightSide).
-	 * 
-	 * @param p the Position
-	 * @return the updated Position.
-	 */
-	private Vec2i attachToBorder(Vec2i p, EditPointType editPointType) {
-		switch (editPointType) {
-		case StartPoint:
-			p.setX(border);
-			break;
-		case EndPoint:
-			p.setX(border + widthWithBorder);
-			break;
-		default:
-			break;
-		}
-		return p;
-	}
-
-	/**
-	 * Insert a Position in the UnitGraphList at the right order. Its sorted based
-	 * on the xValues.
-	 * 
-	 * @param pos The new UnitGraphPoints Position
-	 */
-	private void insertNewGraphPoint(Series series, Vec2i pos) {
-		setInBounds(pos);
-		ListIterator<UnitGraphPoint> iter = series.points.listIterator();
-		while (iter.hasNext()) {
-			Vec2i tempPosition = iter.next().displayedPosition;
-			if (pos.getX() <= tempPosition.getX()) {
-				// previous to go back a position to make the new point before the the Position
-				// with greater X
-				iter.previous();
-				iter.add(generateUnitGraphPoint(pos));
-				break;
-			}
-		}
-		if (!iter.hasNext()) // if behind last point
-		{
-			iter.add(generateUnitGraphPoint(pos));
-		}
-	}
-
-	/**
-	 * Generate a UnitGraphPoint from a normal Position in the UnitGraph.
-	 * 
-	 * @param pos the normal pos with xValues from 0..Width and yValues from
-	 *            0..Height
-	 * @return a UnitGraphPoint
-	 */
-	private UnitGraphPoint generateUnitGraphPoint(Vec2i pos) {
-		UnitGraphPoint temp = new UnitGraphPoint((double) (pos.getX() - border) / (double) widthWithBorder,
-				1 - (double) (pos.getY() - border) / (double) heightWithBorder, true);
-		temp.displayedPosition = pos;
-		return temp;
-	}
-
-	/**
-	 * Update the Point Position
-	 */
-	@Override
-	public void mouseDragged(MouseEvent e) {
-		Optional.ofNullable(this.actualSeries).ifPresent(series -> {
-			updateEditPointPosition(new Vec2i(e.getPoint().x, e.getPoint().y), this.editPointType, series.type);
-			updateGlobalCurve();
-			repaint();
-		});
-
-	}
-
-	@Override
-	public void mouseMoved(MouseEvent e) {
-	}
-
-	@Override
-	public void mouseClicked(MouseEvent e) {
-	}
-
-	@Override
-	public void mouseEntered(MouseEvent e) {
-	}
-
-	@Override
-	public void mouseExited(MouseEvent e) {
-	}
-
-	/**
-	 * The First Step. When LeftMouseButton its checks if a point is to grab under
-	 * the cursor or create a new Point. Then enter EditMode. When RightMouseButton
-	 * its delete a point if its under the Curser.
-	 */
-	@Override
-	public void mousePressed(MouseEvent e) {
-		Vec2i mPosition = new Vec2i(e.getPoint().x, e.getPoint().y);
-		detectSeries(mPosition).ifPresent(series -> {
-			actualSeries = series;
-			if (e.getButton() == MouseEvent.BUTTON3) {
-				// RightMouseButtonEvent
-				editPointType = detectStartEndPoint(series, mPosition);
-				if (editPointType == EditPointType.Normal) {
-					removePointsNearPosition(mPosition);
-					repaint();
-				}
-				editMode = false;
-
-			} else if (e.getButton() == MouseEvent.BUTTON1) {
-				// LeftMouseButtonEvent
-				editPointType = detectStartEndPoint(series, mPosition);
-				removePointsNearPosition(mPosition);
-				updateEditPointPosition(mPosition, editPointType, series.type);
-				editMode = true;
-				repaint();
-			}
-		});
-
-	}
-
-	/**
-	 * The last step to save the Changes. Its insert the Hovering Point and exit
-	 * EditMode.
-	 */
-	@Override
-	public void mouseReleased(MouseEvent e) {
-		if (editMode && actualSeries != null) {
-			for (Series series : seriesList) {
-				this.insertNewGraphPoint(series, editPosition);
-			}
-			editMode = false;
-		}
-		saveGraph();
-		updateGlobalCurve();
-		repaint();
-	}
-
-	/**
-	 * When the Component is Resized.
-	 *
-	 * @param e ComponentEvent
-	 */
-	public void componentResized(ComponentEvent e) {
-		calculateWidthHeight();
-		updateRepresentativePositions();
-		repaint();
-	}
-
-	@Override
-	public void componentHidden(ComponentEvent e) {
-	}
-
-	@Override
-	public void componentMoved(ComponentEvent e) {
-
-	}
-
-	@Override
-	public void componentShown(ComponentEvent e) {
-	}
-
-	/**
-	 * Resets the graph to normal.
-	 */
-	public void reset() {
-		for (Series series : seriesList) {
-			series.element.reset();
-			overrideUnitGraph(series, series.element.getStateGraph());
-		}
-		repaint();
-	}
-
-	public void setPeriod(LocalMode.Period period) {
-		for (Series series : seriesList) {
-			series.element.setPeriod(new LocalMode.Period(period));
+			return EditPointType.Normal;
 		}
 		}
-	}
-
-	public boolean isLocalPeriedDifferentInSeries() {
-		return seriesList.stream().map(series -> series.element.getPeriod().getInterval()).distinct().count() > 1;
-	}
-
-	public int getFirstLocalPeriod() {
-		return seriesList.isEmpty() ? 0 : seriesList.get(0).element.getPeriod().getInterval();
-	}
-
-	public boolean isUsingLocalPeriod() {
-		return seriesList.stream().anyMatch(series -> series.element.getPeriod().getType() != LocalMode.Period.PeriodType.Global);
-	}
+  }
+
+  /**
+   * Determine if a Point is near the Cursor (depends on Mode what near means). To detect if it
+   * should grab the Point or create a new Point.
+   */
+  private boolean near(Vec2i actual, Vec2i target, GraphType graphType) {
+    switch (graphType) {
+      case boolGraph: // Distance only with X
+        int xDis = target.getX() - actual.getX();
+        return xDis * xDis < clickThresholdSquared;
+      case doubleGraph:
+        return actual.getSquaredDistance(target) < clickThresholdSquared;
+      default:
+        return false;
+    }
+  }
+
+  /**
+   * When the Mouse Drag a Point it updates each time the position.
+   */
+  private void updateEditPointPosition(Vec2i newPosition, EditPointType editPointType,
+      GraphType graphType) {
+    // make it in the bounds of the UnitGraph no Point out of the Border
+    Vec2i currentPosition = setInBounds(newPosition);
+    if (editPointType != EditPointType.Normal) {
+      attachToBorder(currentPosition, editPointType);
+    }
+    if (graphType == GraphType.boolGraph) {
+      snapBoolean(currentPosition);
+    }
+    editPosition = currentPosition;
+  }
+
+  /**
+   * No Point on the UnitGraph should exit the UnitGraph.
+   *
+   * @param p the Position
+   * @return the updated Position.
+   */
+  private Vec2i setInBounds(Vec2i p) {
+    p.clampX(border, border + widthWithBorder);
+    p.clampY(border, border + heightWithBorder);
+    return p;
+  }
+
+  /**
+   * For Switches the Point have to be Snap to the Top or the Bottem.
+   *
+   * @param p the Position
+   * @return the updated Position.
+   */
+  private Vec2i snapBoolean(Vec2i p) {
+    if (p.getY() < border + heightWithBorder / 2) {
+      p.setY(border);
+    } else {
+      p.setY(border + heightWithBorder);
+    }
+    return p;
+  }
+
+  /**
+   * The First Point has to be at 0(LeftSide) and Last Point has to be at 1(RightSide).
+   *
+   * @param p the Position
+   * @return the updated Position.
+   */
+  private Vec2i attachToBorder(Vec2i p, EditPointType editPointType) {
+    switch (editPointType) {
+      case StartPoint:
+        p.setX(border);
+        break;
+      case EndPoint:
+        p.setX(border + widthWithBorder);
+        break;
+      default:
+        break;
+    }
+    return p;
+  }
+
+  /**
+   * Insert a Position in the UnitGraphList at the right order. Its sorted based on the xValues.
+   *
+   * @param pos The new UnitGraphPoints Position
+   */
+  private void insertNewGraphPoint(Series series, Vec2i pos) {
+    setInBounds(pos);
+    ListIterator<UnitGraphPoint> iter = series.points.listIterator();
+    while (iter.hasNext()) {
+      Vec2i tempPosition = iter.next().displayedPosition;
+      if (pos.getX() <= tempPosition.getX()) {
+        // previous to go back a position to make the new point before the the Position
+        // with greater X
+        iter.previous();
+        iter.add(generateUnitGraphPoint(pos));
+        break;
+      }
+    }
+    if (!iter.hasNext()) // if behind last point
+    {
+      iter.add(generateUnitGraphPoint(pos));
+    }
+  }
+
+  /**
+   * Generate a UnitGraphPoint from a normal Position in the UnitGraph.
+   *
+   * @param pos the normal pos with xValues from 0..Width and yValues from 0..Height
+   * @return a UnitGraphPoint
+   */
+  private UnitGraphPoint generateUnitGraphPoint(Vec2i pos) {
+    UnitGraphPoint temp = new UnitGraphPoint(
+        (double) (pos.getX() - border) / (double) widthWithBorder,
+        1 - (double) (pos.getY() - border) / (double) heightWithBorder, true);
+    temp.displayedPosition = pos;
+    return temp;
+  }
+
+  /**
+   * Update the Point Position
+   */
+  @Override
+  public void mouseDragged(MouseEvent e) {
+    Optional.ofNullable(this.actualSeries).ifPresent(series -> {
+      updateEditPointPosition(new Vec2i(e.getPoint().x, e.getPoint().y), this.editPointType,
+          series.type);
+      updateGlobalCurve();
+      repaint();
+    });
+
+  }
+
+  @Override
+  public void mouseMoved(MouseEvent e) {
+  }
+
+  @Override
+  public void mouseClicked(MouseEvent e) {
+  }
+
+  @Override
+  public void mouseEntered(MouseEvent e) {
+  }
+
+  @Override
+  public void mouseExited(MouseEvent e) {
+  }
+
+  /**
+   * The First Step. When LeftMouseButton its checks if a point is to grab under the cursor or
+   * create a new Point. Then enter EditMode. When RightMouseButton its delete a point if its under
+   * the Curser.
+   */
+  @Override
+  public void mousePressed(MouseEvent e) {
+    Vec2i mPosition = new Vec2i(e.getPoint().x, e.getPoint().y);
+    detectSeries(mPosition).ifPresent(series -> {
+      actualSeries = series;
+      if (e.getButton() == MouseEvent.BUTTON3) {
+        // RightMouseButtonEvent
+        editPointType = detectStartEndPoint(series, mPosition);
+        if (editPointType == EditPointType.Normal) {
+          removePointsNearPosition(mPosition);
+          repaint();
+        }
+        editMode = false;
+
+      } else if (e.getButton() == MouseEvent.BUTTON1) {
+        // LeftMouseButtonEvent
+        editPointType = detectStartEndPoint(series, mPosition);
+        removePointsNearPosition(mPosition);
+        updateEditPointPosition(mPosition, editPointType, series.type);
+        editMode = true;
+        repaint();
+      }
+    });
+
+  }
+
+  /**
+   * The last step to save the Changes. Its insert the Hovering Point and exit EditMode.
+   */
+  @Override
+  public void mouseReleased(MouseEvent e) {
+    if (editMode && actualSeries != null) {
+      for (Series series : seriesList) {
+        this.insertNewGraphPoint(series, editPosition);
+      }
+      editMode = false;
+    }
+    saveGraph();
+    updateGlobalCurve();
+    repaint();
+  }
+
+  /**
+   * When the Component is Resized.
+   *
+   * @param e ComponentEvent
+   */
+  public void componentResized(ComponentEvent e) {
+    calculateWidthHeight();
+    updateRepresentativePositions();
+    repaint();
+  }
+
+  @Override
+  public void componentHidden(ComponentEvent e) {
+  }
+
+  @Override
+  public void componentMoved(ComponentEvent e) {
+
+  }
+
+  @Override
+  public void componentShown(ComponentEvent e) {
+  }
+
+  /**
+   * Resets the graph to normal.
+   */
+  public void reset() {
+    for (Series series : seriesList) {
+      series.element.reset();
+      overrideUnitGraph(series, series.element.getStateGraph());
+    }
+    repaint();
+  }
+
+  public void setPeriod(LocalMode.Period period) {
+    for (Series series : seriesList) {
+      series.element.setPeriod(new LocalMode.Period(period));
+    }
+  }
+
+  public boolean isLocalPeriedDifferentInSeries() {
+    return seriesList.stream().map(series -> series.element.getPeriod().getInterval()).distinct()
+        .count() > 1;
+  }
+
+  public int getFirstLocalPeriod() {
+    return seriesList.isEmpty() ? 0 : seriesList.get(0).element.getPeriod().getInterval();
+  }
+
+  public boolean isUsingLocalPeriod() {
+    return seriesList.stream().anyMatch(
+        series -> series.element.getPeriod().getType() != LocalMode.Period.PeriodType.Global);
+  }
+
+  private enum EditPointType {
+    Normal, StartPoint, EndPoint
+  }
+
+  // Intern Variables
+  private static class Series {
+
+    public LinkedList<UnitGraphPoint> points = new LinkedList<UnitGraphPoint>();
+    public TimelineDependent element;
+    public GraphType type;
+    public Color color;
+  }
+
+  private static class GlobalCurve {
+
+    public LinkedList<UnitGraphPoint> points = new LinkedList<UnitGraphPoint>();
+    public float minEnergy;
+    public float maxEnergy;
+    public LinkedList<UnitGraphPoint> zeroLinePoints = new LinkedList<UnitGraphPoint>();
+  }
 
 
 }
 }

+ 58 - 45
src/holeg/ui/view/inspector/UnitGraphPoint.java

@@ -4,52 +4,65 @@ import holeg.utility.math.vector.Vec2f;
 import holeg.utility.math.vector.Vec2i;
 import holeg.utility.math.vector.Vec2i;
 
 
 /**
 /**
- * A class for saving all points of a Object with a editable state.
- * e.g HolonElement, HolonSwitch
- * @author Tom Troppmann
+ * A class for saving all points of a Object with a editable state. e.g HolonElement, HolonSwitch
  *
  *
+ * @author Tom Troppmann
  */
  */
 public class UnitGraphPoint {
 public class UnitGraphPoint {
-	/** Relative position in the UnitGraphCanvas */
-	public double x,y;
-	/** To determine if this point has changed to only write back points that are changed.*/
-	public boolean changed;
-	/** The displayed Position of the UnitGraphPoint*/
-	public Vec2i displayedPosition;
-	
-	/** Default Constructor */
-	public UnitGraphPoint(double x, double y, boolean changed){
-		this.x = x;
-		this.y = y;
-		this.changed = changed;
-	}
-	/** Constructor with a Point2D.Double*/
-	public UnitGraphPoint(Vec2f pos, boolean changed){
-		this.x = pos.getX();
-		this.y = pos.getY();
-		this.changed = changed;
-	}
-	/** Constructor with a Point2D.Double
-	 * when changed not specified is false;
-	 * */
-	public UnitGraphPoint(Vec2f pos){
-		this.x = pos.getX();
-		this.y = pos.getY();
-		this.changed = false;
-	}
-	
-	public void calcDisplayedPosition(int border, int widthWithBorder, int heightWithBorder) {
-    	//Relativ to Border
-    	//1-p.y because its on the Top
-		displayedPosition =  new Vec2i((int) (x * widthWithBorder) + border, (int) ((1-y) * heightWithBorder) + border);
-    }
-	
-	public Vec2f getPoint()
-	{
-		 return new Vec2f((float)x, (float)y);
-	}
-	@Override
-	public String toString() {
-		return "[" + x + ":" + y + "]";
-	}
+
+  /**
+   * Relative position in the UnitGraphCanvas
+   */
+  public double x, y;
+  /**
+   * To determine if this point has changed to only write back points that are changed.
+   */
+  public boolean changed;
+  /**
+   * The displayed Position of the UnitGraphPoint
+   */
+  public Vec2i displayedPosition;
+
+  /**
+   * Default Constructor
+   */
+  public UnitGraphPoint(double x, double y, boolean changed) {
+    this.x = x;
+    this.y = y;
+    this.changed = changed;
+  }
+
+  /**
+   * Constructor with a Point2D.Double
+   */
+  public UnitGraphPoint(Vec2f pos, boolean changed) {
+    this.x = pos.getX();
+    this.y = pos.getY();
+    this.changed = changed;
+  }
+
+  /**
+   * Constructor with a Point2D.Double when changed not specified is false;
+   */
+  public UnitGraphPoint(Vec2f pos) {
+    this.x = pos.getX();
+    this.y = pos.getY();
+    this.changed = false;
+  }
+
+  public void calcDisplayedPosition(int border, int widthWithBorder, int heightWithBorder) {
+    //Relativ to Border
+    //1-p.y because its on the Top
+    displayedPosition = new Vec2i((int) (x * widthWithBorder) + border,
+        (int) ((1 - y) * heightWithBorder) + border);
+  }
+
+  public Vec2f getPoint() {
+    return new Vec2f((float) x, (float) y);
+  }
+
+  @Override
+  public String toString() {
+    return "[" + x + ":" + y + "]";
+  }
 }
 }

+ 18 - 15
src/holeg/ui/view/main/Appearance.java

@@ -1,23 +1,26 @@
 package holeg.ui.view.main;
 package holeg.ui.view.main;
 
 
 import holeg.preferences.PreferenceKeys;
 import holeg.preferences.PreferenceKeys;
-
 import java.util.prefs.Preferences;
 import java.util.prefs.Preferences;
 
 
 public class Appearance {
 public class Appearance {
-    private static final Preferences prefs = Preferences.userNodeForPackage(Appearance.class);
-    public static boolean supplyBarVisible = true;
-    public static boolean edgeCapacityVisible = true;
-    public static boolean canvasObjectEnergyVisible = true;
 
 
-    public static void loadPrefs(){
-        supplyBarVisible = prefs.getBoolean(PreferenceKeys.Appearance.SupplyBarVisible, true);
-        edgeCapacityVisible = prefs.getBoolean(PreferenceKeys.Appearance.EdgeCapacityVisible, true);
-        canvasObjectEnergyVisible = prefs.getBoolean(PreferenceKeys.Appearance.EdgeCapacityVisible, true);
-    }
-    public static void savePrefs(){
-        prefs.putBoolean(PreferenceKeys.Appearance.SupplyBarVisible, supplyBarVisible);
-        prefs.putBoolean(PreferenceKeys.Appearance.EdgeCapacityVisible, edgeCapacityVisible);
-        prefs.putBoolean(PreferenceKeys.Appearance.CanvasObjectEnergyVisible, canvasObjectEnergyVisible);
-    }
+  private static final Preferences prefs = Preferences.userNodeForPackage(Appearance.class);
+  public static boolean supplyBarVisible = true;
+  public static boolean edgeCapacityVisible = true;
+  public static boolean canvasObjectEnergyVisible = true;
+
+  public static void loadPrefs() {
+    supplyBarVisible = prefs.getBoolean(PreferenceKeys.Appearance.SupplyBarVisible, true);
+    edgeCapacityVisible = prefs.getBoolean(PreferenceKeys.Appearance.EdgeCapacityVisible, true);
+    canvasObjectEnergyVisible = prefs.getBoolean(PreferenceKeys.Appearance.EdgeCapacityVisible,
+        true);
+  }
+
+  public static void savePrefs() {
+    prefs.putBoolean(PreferenceKeys.Appearance.SupplyBarVisible, supplyBarVisible);
+    prefs.putBoolean(PreferenceKeys.Appearance.EdgeCapacityVisible, edgeCapacityVisible);
+    prefs.putBoolean(PreferenceKeys.Appearance.CanvasObjectEnergyVisible,
+        canvasObjectEnergyVisible);
+  }
 }
 }

+ 382 - 368
src/holeg/ui/view/main/Gui.java

@@ -20,11 +20,11 @@ import holeg.ui.view.window.FlexWindow;
 import holeg.ui.view.window.Outliner;
 import holeg.ui.view.window.Outliner;
 import holeg.utility.listener.WindowClosingListener;
 import holeg.utility.listener.WindowClosingListener;
 import holeg.utility.math.vector.Vec2i;
 import holeg.utility.math.vector.Vec2i;
-
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
-import javax.swing.filechooser.FileSystemView;
-import java.awt.*;
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Rectangle;
+import java.awt.Toolkit;
 import java.awt.event.InputEvent;
 import java.awt.event.InputEvent;
 import java.awt.event.KeyEvent;
 import java.awt.event.KeyEvent;
 import java.io.File;
 import java.io.File;
@@ -33,393 +33,407 @@ import java.util.Optional;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
 import java.util.prefs.Preferences;
 import java.util.prefs.Preferences;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
+import javax.swing.ImageIcon;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.KeyStroke;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.filechooser.FileSystemView;
 
 
 public class Gui extends JFrame {
 public class Gui extends JFrame {
-    private static final Logger log = Logger.getLogger(Model.class.getName());
-    private static final Preferences prefs = Preferences.userNodeForPackage(Gui.class);
-    private final Control control;
-
-    private final CategoryPanel categoryPanel;
-    public final CanvasCollectionPanel canvasCollection;
-    private final Inspector inspector;
-    private final HolonInformationPanel informationPanel;
-    private final TimePanel timePanel;
-
-    /**
-     * Create the application.
-     *
-     * @param control the Controller
-     */
-    public Gui(Control control) {
-        super("HOLEG Simulator");
-        this.control = control;
-        this.informationPanel = new HolonInformationPanel(control);
-        this.inspector = new Inspector(control);
-        this.categoryPanel = new CategoryPanel(control, this);
-        this.canvasCollection = new CanvasCollectionPanel(control);
-        this.timePanel = new TimePanel(control);
-        init();
-    }
 
 
-    private void init() {
-        initFrame();
-        initLayout();
+  private static final Logger log = Logger.getLogger(Model.class.getName());
+  private static final Preferences prefs = Preferences.userNodeForPackage(Gui.class);
+  public final CanvasCollectionPanel canvasCollection;
+  private final Control control;
+  private final CategoryPanel categoryPanel;
+  private final Inspector inspector;
+  private final HolonInformationPanel informationPanel;
+  private final TimePanel timePanel;
+
+  /**
+   * Create the application.
+   *
+   * @param control the Controller
+   */
+  public Gui(Control control) {
+    super("HOLEG Simulator");
+    this.control = control;
+    this.informationPanel = new HolonInformationPanel(control);
+    this.inspector = new Inspector(control);
+    this.categoryPanel = new CategoryPanel(control, this);
+    this.canvasCollection = new CanvasCollectionPanel(control);
+    this.timePanel = new TimePanel(control);
+    init();
+  }
+
+  private void init() {
+    initFrame();
+    initLayout();
+  }
+
+  private void initFrame() {
+    this.setIconImage(Import.loadImage(ImagePreference.Logo, 30, 30));
+    this.setBounds(new Rectangle(prefs.getInt(PreferenceKeys.Gui.Width, 1200),
+        prefs.getInt(PreferenceKeys.Gui.Height, 800)));
+    Appearance.loadPrefs();
+    if (prefs.get(PreferenceKeys.Gui.Width, null) != null) {
+      this.setLocation(prefs.getInt(PreferenceKeys.Gui.XPos, 1200),
+          prefs.getInt(PreferenceKeys.Gui.YPos, 800));
+    } else {
+      this.setLocationRelativeTo(null);
     }
     }
-
-    private void initFrame() {
-        this.setIconImage(Import.loadImage(ImagePreference.Logo, 30, 30));
-        this.setBounds(new Rectangle(prefs.getInt(PreferenceKeys.Gui.Width, 1200), prefs.getInt(PreferenceKeys.Gui.Height, 800)));
-        Appearance.loadPrefs();
-        if (prefs.get(PreferenceKeys.Gui.Width, null) != null) {
-            this.setLocation(prefs.getInt(PreferenceKeys.Gui.XPos, 1200), prefs.getInt(PreferenceKeys.Gui.YPos, 800));
-        } else {
-            this.setLocationRelativeTo(null);
-        }
-        this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
-        this.addWindowListener((WindowClosingListener) e -> {
-            Rectangle bounds = this.getBounds();
-            prefs.putInt(PreferenceKeys.Gui.XPos, bounds.x);
-            prefs.putInt(PreferenceKeys.Gui.YPos, bounds.y);
-            prefs.putInt(PreferenceKeys.Gui.Width, bounds.width);
-            prefs.putInt(PreferenceKeys.Gui.Height, bounds.height);
-            Appearance.savePrefs();
-            control.saveCategories();
-            if (JOptionPane.showConfirmDialog(this, "Are you sure you want to exit?", "HOLEG",
-                    JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
-                System.exit(0);
-            }
-        });
+    this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+    this.addWindowListener((WindowClosingListener) e -> {
+      Rectangle bounds = this.getBounds();
+      prefs.putInt(PreferenceKeys.Gui.XPos, bounds.x);
+      prefs.putInt(PreferenceKeys.Gui.YPos, bounds.y);
+      prefs.putInt(PreferenceKeys.Gui.Width, bounds.width);
+      prefs.putInt(PreferenceKeys.Gui.Height, bounds.height);
+      Appearance.savePrefs();
+      control.saveCategories();
+      if (JOptionPane.showConfirmDialog(this, "Are you sure you want to exit?", "HOLEG",
+          JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
+        System.exit(0);
+      }
+    });
+  }
+
+  private void initLayout() {
+    this.setJMenuBar(new GuiMenuBar());
+
+    final JSplitPane categorySplit = new JSplitPane();
+    final JSplitPane canvasSplit = new JSplitPane();
+    final JSplitPane elementSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
+    final JScrollPane informationPanelScrollPane = new JScrollPane();
+    Container contentPanel = this.getContentPane();
+    contentPanel.setLayout(new BorderLayout(0, 0));
+    contentPanel.add(categorySplit);
+    categorySplit.setLeftComponent(categoryPanel);
+    categorySplit.setRightComponent(canvasSplit);
+    categorySplit.setDividerLocation(200);
+    categorySplit.setBorder(null);
+
+    canvasSplit.setMinimumSize(new Dimension(0, 25));
+    canvasSplit.setDividerLocation(500);
+    canvasSplit.setLeftComponent(canvasCollection);
+    canvasSplit.setRightComponent(elementSplit);
+    canvasSplit.setResizeWeight(0.9);
+    canvasSplit.setBorder(null);
+
+    elementSplit.setDividerLocation(700);
+    elementSplit.setTopComponent(inspector);
+    elementSplit.setBottomComponent(informationPanelScrollPane);
+    elementSplit.setBorder(null);
+
+    informationPanelScrollPane.setViewportView(this.informationPanel);
+    informationPanelScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+    informationPanelScrollPane.getVerticalScrollBar().setUnitIncrement(16);
+    informationPanelScrollPane.setBorder(null);
+
+    contentPanel.add(timePanel, BorderLayout.SOUTH);
+  }
+
+  public Canvas getActualCanvas() {
+    return this.canvasCollection.getActualCanvas();
+  }
+
+
+  private class GuiMenuBar extends JMenuBar {
+
+    private final static int IconSize = 15;
+    private final static Vec2i DefaultOffset = new Vec2i(20, 20);
+    //Menus
+    private final JMenu fileMenu = new JMenu("File");
+    private final JMenu editMenu = new JMenu("Edit");
+    private final JMenu viewMenu = new JMenu("View");
+    private final JMenu windowMenu = new JMenu("Window");
+    private final JMenu helpMenu = new JMenu("Help");
+    // FileMenu
+    private final JMenuItem newMenuButton = new JMenuItem("New");
+    private final JMenuItem openMenuButton = new JMenuItem("Open..");
+    private final JMenuItem saveMenuButton = new JMenuItem("Save");
+    private final JMenuItem saveAsMenuButton = new JMenuItem("Save..");
+    // EditMenu
+    private final JMenuItem undoButton = new JMenuItem("Undo");
+    private final JMenuItem redoButton = new JMenuItem("Redo");
+    private final JMenuItem copyButton = new JMenuItem("Copy");
+    private final JMenuItem pasteButton = new JMenuItem("Paste");
+    private final JMenuItem cutButton = new JMenuItem("Cut");
+    private final JMenu selectionMenu = new JMenu("Selection");
+    private final JMenuItem selectAllButton = new JMenuItem("All");
+    private final JMenuItem clearSelectionButton = new JMenuItem("Clear");
+    private final JMenuItem invertSelectionButton = new JMenuItem("Invert");
+    private final JMenuItem groupButton = new JMenuItem("Group");
+    private final JMenuItem ungroupButton = new JMenuItem("Ungroup");
+    private final JMenuItem removeButton = new JMenuItem("Remove");
+    private final JMenuItem edgePropertiesButton = new JMenuItem("Edge Properties");
+    private final JMenuItem alignAllButton = new JMenuItem("Align All");
+    private final JMenu resetMenu = new JMenu("Reset");
+    private final JMenuItem resetCategoryButton = new JMenuItem("Categories");
+    //HelpMenu
+    private final JMenuItem introductionButton = new JMenuItem("Introduction");
+    private final JMenuItem userManualButton = new JMenuItem("User Manual");
+    private final JMenuItem algorithmHelpButton = new JMenuItem("Algorithm Introduction");
+    private final JMenuItem codeDocumentationButton = new JMenuItem("Code Documentation");
+    private final JMenuItem aboutUsButton = new JMenuItem("About Us");
+    //ViewMenu
+    private final JMenu appearanceMenu = new JMenu("Appearance");
+    private final JMenuItem canvasSizeButton = new JMenuItem("Set View Size");
+    private final JCheckBoxMenuItem showSupplyBarsCheckBox = new JCheckBoxMenuItem("Supply bars",
+        Appearance.supplyBarVisible);
+    private final JCheckBoxMenuItem edgeCapacityVisibleCheckBox = new JCheckBoxMenuItem(
+        "Edge capacity", Appearance.edgeCapacityVisible);
+    private final JCheckBoxMenuItem canvasObjectEnergyVisibleCheckBox = new JCheckBoxMenuItem(
+        "HolonObject energy", Appearance.canvasObjectEnergyVisible);
+    private final JFileChooser fileChooser = initFileChooser();
+    //WindowMenu
+    JMenuItem algorithmButton = new JMenuItem("Algorithm Panel", new ImageIcon(Import
+        .loadImage(ImagePreference.Button.Menu.Algo)
+        .getScaledInstance(IconSize, IconSize, java.awt.Image.SCALE_SMOOTH)));
+    JMenuItem outlinerButton = new JMenuItem("Outliner", new ImageIcon(Import
+        .loadImage(ImagePreference.Button.Menu.Outliner)
+        .getScaledInstance(IconSize, IconSize, java.awt.Image.SCALE_SMOOTH)));
+    JMenuItem flexMenuButton = new JMenuItem("Flexibility Panel", new ImageIcon(Import
+        .loadImage(ImagePreference.Button.Menu.Algo)
+        .getScaledInstance(IconSize, IconSize, java.awt.Image.SCALE_SMOOTH)));
+
+    GuiMenuBar() {
+      initMenuLayout();
+      initButtonActions();
+      initButtonShortCuts();
     }
     }
 
 
-    private void initLayout() {
-        this.setJMenuBar(new GuiMenuBar());
-
-        final JSplitPane categorySplit = new JSplitPane();
-        final JSplitPane canvasSplit = new JSplitPane();
-        final JSplitPane elementSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
-        final JScrollPane informationPanelScrollPane = new JScrollPane();
-        Container contentPanel = this.getContentPane();
-        contentPanel.setLayout(new BorderLayout(0, 0));
-        contentPanel.add(categorySplit);
-        categorySplit.setLeftComponent(categoryPanel);
-        categorySplit.setRightComponent(canvasSplit);
-        categorySplit.setDividerLocation(200);
-        categorySplit.setBorder(null);
-
-        canvasSplit.setMinimumSize(new Dimension(0, 25));
-        canvasSplit.setDividerLocation(500);
-        canvasSplit.setLeftComponent(canvasCollection);
-        canvasSplit.setRightComponent(elementSplit);
-        canvasSplit.setResizeWeight(0.9);
-        canvasSplit.setBorder(null);
-
-        elementSplit.setDividerLocation(700);
-        elementSplit.setTopComponent(inspector);
-        elementSplit.setBottomComponent(informationPanelScrollPane);
-        elementSplit.setBorder(null);
-
-        informationPanelScrollPane.setViewportView(this.informationPanel);
-        informationPanelScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
-        informationPanelScrollPane.getVerticalScrollBar().setUnitIncrement(16);
-        informationPanelScrollPane.setBorder(null);
-
-        contentPanel.add(timePanel, BorderLayout.SOUTH);
+    private static JFileChooser initFileChooser() {
+      JFileChooser safeLoadFileChooser = new JFileChooser(
+          prefs.get(PreferenceKeys.Gui.DefaultFolder,
+              FileSystemView.getFileSystemView().getDefaultDirectory().getPath()));
+      safeLoadFileChooser.setFileFilter(new FileNameExtensionFilter("Holeg json files", "json"));
+      safeLoadFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+      safeLoadFileChooser.setAcceptAllFileFilterUsed(false);
+      return safeLoadFileChooser;
     }
     }
 
 
-    public Canvas getActualCanvas() {
-        return this.canvasCollection.getActualCanvas();
+    private void initMenuLayout() {
+      add(fileMenu);
+      add(editMenu);
+      add(viewMenu);
+      add(windowMenu);
+      add(helpMenu);
+      fileMenu.add(newMenuButton);
+      fileMenu.add(openMenuButton);
+      fileMenu.addSeparator();
+      fileMenu.add(saveMenuButton);
+      fileMenu.add(saveAsMenuButton);
+
+      editMenu.add(undoButton);
+      editMenu.add(redoButton);
+      editMenu.addSeparator();
+      editMenu.add(copyButton);
+      editMenu.add(pasteButton);
+      editMenu.add(cutButton);
+      editMenu.addSeparator();
+      editMenu.add(selectionMenu);
+      selectionMenu.add(selectAllButton);
+      selectionMenu.add(clearSelectionButton);
+      selectionMenu.add(invertSelectionButton);
+      editMenu.addSeparator();
+      editMenu.add(groupButton);
+      editMenu.add(ungroupButton);
+      editMenu.addSeparator();
+      editMenu.add(removeButton);
+      editMenu.addSeparator();
+      editMenu.add(edgePropertiesButton);
+      editMenu.add(alignAllButton);
+      editMenu.add(resetMenu);
+
+      resetMenu.add(resetCategoryButton);
+
+      helpMenu.add(introductionButton);
+      helpMenu.add(userManualButton);
+      helpMenu.add(algorithmHelpButton);
+      helpMenu.add(codeDocumentationButton);
+      helpMenu.add(aboutUsButton);
+
+      viewMenu.add(appearanceMenu);
+      appearanceMenu.add(showSupplyBarsCheckBox);
+      appearanceMenu.add(edgeCapacityVisibleCheckBox);
+      appearanceMenu.add(canvasObjectEnergyVisibleCheckBox);
+      viewMenu.add(canvasSizeButton);
+
+      windowMenu.add(algorithmButton);
+      windowMenu.add(outlinerButton);
+      windowMenu.add(flexMenuButton);
     }
     }
 
 
-
-
-
-
-
-    private class GuiMenuBar extends JMenuBar {
-        //Menus
-        private final JMenu fileMenu = new JMenu("File");
-        private final JMenu editMenu = new JMenu("Edit");
-        private final JMenu viewMenu = new JMenu("View");
-        private final JMenu windowMenu = new JMenu("Window");
-        private final JMenu helpMenu = new JMenu("Help");
-
-        // FileMenu
-        private final JMenuItem newMenuButton = new JMenuItem("New");
-        private final JMenuItem openMenuButton = new JMenuItem("Open..");
-        private final JMenuItem saveMenuButton = new JMenuItem("Save");
-        private final JMenuItem saveAsMenuButton = new JMenuItem("Save..");
-
-        // EditMenu
-        private final JMenuItem undoButton = new JMenuItem("Undo");
-        private final JMenuItem redoButton = new JMenuItem("Redo");
-        private final JMenuItem copyButton = new JMenuItem("Copy");
-        private final JMenuItem pasteButton = new JMenuItem("Paste");
-        private final JMenuItem cutButton = new JMenuItem("Cut");
-        private final JMenu selectionMenu = new JMenu("Selection");
-        private final JMenuItem selectAllButton = new JMenuItem("All");
-        private final JMenuItem clearSelectionButton = new JMenuItem("Clear");
-        private final JMenuItem invertSelectionButton = new JMenuItem("Invert");
-        private final JMenuItem groupButton = new JMenuItem("Group");
-        private final JMenuItem ungroupButton = new JMenuItem("Ungroup");
-        private final JMenuItem removeButton = new JMenuItem("Remove");
-
-
-        private final JMenuItem edgePropertiesButton = new JMenuItem("Edge Properties");
-        private final JMenuItem alignAllButton = new JMenuItem("Align All");
-        private final JMenu resetMenu = new JMenu("Reset");
-        private final JMenuItem resetCategoryButton = new JMenuItem("Categories");
-
-
-        //HelpMenu
-        private final JMenuItem introductionButton = new JMenuItem("Introduction");
-        private final JMenuItem userManualButton = new JMenuItem("User Manual");
-        private final JMenuItem algorithmHelpButton = new JMenuItem("Algorithm Introduction");
-        private final JMenuItem codeDocumentationButton = new JMenuItem("Code Documentation");
-        private final JMenuItem aboutUsButton = new JMenuItem("About Us");
-
-        //ViewMenu
-        private final JMenu appearanceMenu = new JMenu("Appearance");
-        private final JMenuItem canvasSizeButton = new JMenuItem("Set View Size");
-        private final JCheckBoxMenuItem showSupplyBarsCheckBox = new JCheckBoxMenuItem("Supply bars", Appearance.supplyBarVisible);
-        private final JCheckBoxMenuItem edgeCapacityVisibleCheckBox = new JCheckBoxMenuItem("Edge capacity", Appearance.edgeCapacityVisible);
-        private final JCheckBoxMenuItem canvasObjectEnergyVisibleCheckBox = new JCheckBoxMenuItem("HolonObject energy", Appearance.canvasObjectEnergyVisible);
-        private final JFileChooser fileChooser = initFileChooser();
-
-        private final static int IconSize = 15;
-        //WindowMenu
-        JMenuItem algorithmButton = new JMenuItem("Algorithm Panel", new ImageIcon(Import
-                .loadImage(ImagePreference.Button.Menu.Algo).getScaledInstance(IconSize, IconSize, java.awt.Image.SCALE_SMOOTH)));
-        JMenuItem outlinerButton = new JMenuItem("Outliner", new ImageIcon(Import
-                .loadImage(ImagePreference.Button.Menu.Outliner).getScaledInstance(IconSize, IconSize, java.awt.Image.SCALE_SMOOTH)));
-        JMenuItem flexMenuButton = new JMenuItem("Flexibility Panel", new ImageIcon(Import
-                .loadImage(ImagePreference.Button.Menu.Algo).getScaledInstance(IconSize, IconSize, java.awt.Image.SCALE_SMOOTH)));
-
-        private final static Vec2i DefaultOffset = new Vec2i(20,20);
-
-        GuiMenuBar() {
-            initMenuLayout();
-            initButtonActions();
-            initButtonShortCuts();
-        }
-
-        private static JFileChooser initFileChooser() {
-            JFileChooser safeLoadFileChooser = new JFileChooser(prefs.get(PreferenceKeys.Gui.DefaultFolder,
-                    FileSystemView.getFileSystemView().getDefaultDirectory().getPath()));
-            safeLoadFileChooser.setFileFilter(new FileNameExtensionFilter("Holeg json files", "json"));
-            safeLoadFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
-            safeLoadFileChooser.setAcceptAllFileFilterUsed(false);
-            return safeLoadFileChooser;
-        }
-
-        private void initMenuLayout() {
-            add(fileMenu);
-            add(editMenu);
-            add(viewMenu);
-            add(windowMenu);
-            add(helpMenu);
-            fileMenu.add(newMenuButton);
-            fileMenu.add(openMenuButton);
-            fileMenu.addSeparator();
-            fileMenu.add(saveMenuButton);
-            fileMenu.add(saveAsMenuButton);
-
-            editMenu.add(undoButton);
-            editMenu.add(redoButton);
-            editMenu.addSeparator();
-            editMenu.add(copyButton);
-            editMenu.add(pasteButton);
-            editMenu.add(cutButton);
-            editMenu.addSeparator();
-            editMenu.add(selectionMenu);
-            selectionMenu.add(selectAllButton);
-            selectionMenu.add(clearSelectionButton);
-            selectionMenu.add(invertSelectionButton);
-            editMenu.addSeparator();
-            editMenu.add(groupButton);
-            editMenu.add(ungroupButton);
-            editMenu.addSeparator();
-            editMenu.add(removeButton);
-            editMenu.addSeparator();
-            editMenu.add(edgePropertiesButton);
-            editMenu.add(alignAllButton);
-            editMenu.add(resetMenu);
-
-            resetMenu.add(resetCategoryButton);
-
-            helpMenu.add(introductionButton);
-            helpMenu.add(userManualButton);
-            helpMenu.add(algorithmHelpButton);
-            helpMenu.add(codeDocumentationButton);
-            helpMenu.add(aboutUsButton);
-
-            viewMenu.add(appearanceMenu);
-            appearanceMenu.add(showSupplyBarsCheckBox);
-            appearanceMenu.add(edgeCapacityVisibleCheckBox);
-            appearanceMenu.add(canvasObjectEnergyVisibleCheckBox);
-            viewMenu.add(canvasSizeButton);
-
-            windowMenu.add(algorithmButton);
-            windowMenu.add(outlinerButton);
-            windowMenu.add(flexMenuButton);
-        }
-
-        private void initButtonActions() {
-            newMenuButton.addActionListener(clicked -> newFile());
-            openMenuButton.addActionListener(clicked -> openFile());
-            saveMenuButton.addActionListener(clicked -> saveFile());
-            saveAsMenuButton.addActionListener(clicked -> saveNewFile());
-            groupButton.addActionListener(clicked -> control.group());
-            ungroupButton.addActionListener(clicked -> control.ungroup());
-
-            edgePropertiesButton.addActionListener(actionEvent -> new EditEdgesPopUp(Gui.this, control));
-            alignAllButton.addActionListener(clicked -> {
-                getActualCanvas().getGroupNode()
-                        .getObjectsInThisLayer().forEach(obj -> {
-                            int distance = GuiSettings.getPictureScaleDiv2() * 3;
-                            Vec2i pos = obj.getPosition();
-                            // offset relative to a grid with lines every distance pixels
-                            Vec2i offset = new Vec2i(pos.getX() % distance, pos.getY() % distance);
-
-                            //align to the other Line, if it is nearer
-                            if(offset.getX() > distance/2){
-                                offset.setX(offset.getX() - distance);
-                            }
-                            if(offset.getY() > distance/2){
-                                offset.setY(offset.getY() - distance);
-                            }
-                            obj.setPosition(obj.getPosition().subtract(offset));
-                        });
-                control.OnCanvasUpdate.broadcast();
-            });
-            resetCategoryButton.addActionListener(clicked -> control.resetCategories());
-
-            showSupplyBarsCheckBox.addActionListener(clicked -> {
-                Appearance.supplyBarVisible = showSupplyBarsCheckBox.isSelected();
-                control.OnCanvasUpdate.broadcast();
-            });
-            edgeCapacityVisibleCheckBox.addActionListener(clicked -> {
-                Appearance.edgeCapacityVisible = edgeCapacityVisibleCheckBox.isSelected();
-                control.OnCanvasUpdate.broadcast();
-            });
-            canvasObjectEnergyVisibleCheckBox.addActionListener(clicked -> {
-                Appearance.canvasObjectEnergyVisible = canvasObjectEnergyVisibleCheckBox.isSelected();
-                control.OnCanvasUpdate.broadcast();
+    private void initButtonActions() {
+      newMenuButton.addActionListener(clicked -> newFile());
+      openMenuButton.addActionListener(clicked -> openFile());
+      saveMenuButton.addActionListener(clicked -> saveFile());
+      saveAsMenuButton.addActionListener(clicked -> saveNewFile());
+      groupButton.addActionListener(clicked -> control.group());
+      ungroupButton.addActionListener(clicked -> control.ungroup());
+
+      edgePropertiesButton.addActionListener(actionEvent -> new EditEdgesPopUp(Gui.this, control));
+      alignAllButton.addActionListener(clicked -> {
+        getActualCanvas().getGroupNode()
+            .getObjectsInThisLayer().forEach(obj -> {
+              int distance = GuiSettings.getPictureScaleDiv2() * 3;
+              Vec2i pos = obj.getPosition();
+              // offset relative to a grid with lines every distance pixels
+              Vec2i offset = new Vec2i(pos.getX() % distance, pos.getY() % distance);
+
+              //align to the other Line, if it is nearer
+              if (offset.getX() > distance / 2) {
+                offset.setX(offset.getX() - distance);
+              }
+              if (offset.getY() > distance / 2) {
+                offset.setY(offset.getY() - distance);
+              }
+              obj.setPosition(obj.getPosition().subtract(offset));
             });
             });
-            canvasSizeButton.addActionListener(clicked -> new CanvasResizePopUp(control, Gui.this));
-            algorithmButton.addActionListener(clicked -> new AddOnWindow(Gui.this, control));
-            outlinerButton.addActionListener(clicked -> new Outliner(Gui.this, control));
-            flexMenuButton.addActionListener(clicked -> new FlexWindow(Gui.this, control));
-
-            selectAllButton.addActionListener(clicked -> selectAll());
-            clearSelectionButton.addActionListener(clicked -> control.clearSelection());
-            invertSelectionButton.addActionListener(clicked -> invertSelection());
-
-            copyButton.addActionListener(clicked -> control.copy());
-            cutButton.addActionListener(clicked -> control.cut());
-            pasteButton.addActionListener(clicked -> paste());
-
-            undoButton.addActionListener(clicked -> control.undo());
-            redoButton.addActionListener(clicked -> control.redo());
-
-            removeButton.addActionListener(clicked -> removeSelectedObjects());
-
-            String tkWikiWebpage = "https://git.tk.informatik.tu-darmstadt.de/carlos.garcia/praktikum-holons/wiki/";
-            introductionButton.addActionListener(clicked -> openWebpage(tkWikiWebpage + "Introduction+V2.1"));
-            userManualButton.addActionListener(clicked -> openWebpage(tkWikiWebpage + "User+Manual+V2.1"));
-            algorithmHelpButton.addActionListener(clicked -> openWebpage(tkWikiWebpage + "Algorithms+V2.1"));
-            codeDocumentationButton.addActionListener(clicked -> openWebpage(tkWikiWebpage + "Code+documentation+V2.1"));
-            aboutUsButton.addActionListener(clicked -> new AboutUsPopUp(Gui.this));
-        }
-
-
-        private void openWebpage(String URL) {
-            try {
-                java.awt.Desktop.getDesktop().browse(new URI(URL));
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-        }
+        control.OnCanvasUpdate.broadcast();
+      });
+      resetCategoryButton.addActionListener(clicked -> control.resetCategories());
+
+      showSupplyBarsCheckBox.addActionListener(clicked -> {
+        Appearance.supplyBarVisible = showSupplyBarsCheckBox.isSelected();
+        control.OnCanvasUpdate.broadcast();
+      });
+      edgeCapacityVisibleCheckBox.addActionListener(clicked -> {
+        Appearance.edgeCapacityVisible = edgeCapacityVisibleCheckBox.isSelected();
+        control.OnCanvasUpdate.broadcast();
+      });
+      canvasObjectEnergyVisibleCheckBox.addActionListener(clicked -> {
+        Appearance.canvasObjectEnergyVisible = canvasObjectEnergyVisibleCheckBox.isSelected();
+        control.OnCanvasUpdate.broadcast();
+      });
+      canvasSizeButton.addActionListener(clicked -> new CanvasResizePopUp(control, Gui.this));
+      algorithmButton.addActionListener(clicked -> new AddOnWindow(Gui.this, control));
+      outlinerButton.addActionListener(clicked -> new Outliner(Gui.this, control));
+      flexMenuButton.addActionListener(clicked -> new FlexWindow(Gui.this, control));
+
+      selectAllButton.addActionListener(clicked -> selectAll());
+      clearSelectionButton.addActionListener(clicked -> control.clearSelection());
+      invertSelectionButton.addActionListener(clicked -> invertSelection());
+
+      copyButton.addActionListener(clicked -> control.copy());
+      cutButton.addActionListener(clicked -> control.cut());
+      pasteButton.addActionListener(clicked -> paste());
+
+      undoButton.addActionListener(clicked -> control.undo());
+      redoButton.addActionListener(clicked -> control.redo());
+
+      removeButton.addActionListener(clicked -> removeSelectedObjects());
+
+      String tkWikiWebpage = "https://git.tk.informatik.tu-darmstadt.de/carlos.garcia/praktikum-holons/wiki/";
+      introductionButton.addActionListener(
+          clicked -> openWebpage(tkWikiWebpage + "Introduction+V2.1"));
+      userManualButton.addActionListener(
+          clicked -> openWebpage(tkWikiWebpage + "User+Manual+V2.1"));
+      algorithmHelpButton.addActionListener(
+          clicked -> openWebpage(tkWikiWebpage + "Algorithms+V2.1"));
+      codeDocumentationButton.addActionListener(
+          clicked -> openWebpage(tkWikiWebpage + "Code+documentation+V2.1"));
+      aboutUsButton.addActionListener(clicked -> new AboutUsPopUp(Gui.this));
+    }
 
 
-        private void initButtonShortCuts() {
-            int defaultModifier = Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx();
-            int defaultShiftModifier = defaultModifier + InputEvent.SHIFT_DOWN_MASK;
-            saveMenuButton.setAccelerator(KeyStroke.getKeyStroke('S', defaultModifier));
-            saveAsMenuButton.setAccelerator(KeyStroke.getKeyStroke('S', defaultShiftModifier));
-            openMenuButton.setAccelerator(KeyStroke.getKeyStroke('O', defaultModifier));
-            newMenuButton.setAccelerator(KeyStroke.getKeyStroke('N', defaultModifier));
-            undoButton.setAccelerator(KeyStroke.getKeyStroke('Z', defaultModifier));
-            redoButton.setAccelerator(KeyStroke.getKeyStroke('Y', defaultModifier));
-            copyButton.setAccelerator(KeyStroke.getKeyStroke('C', defaultModifier));
-            pasteButton.setAccelerator(KeyStroke.getKeyStroke('V', defaultModifier));
-            cutButton.setAccelerator(KeyStroke.getKeyStroke('X', defaultModifier));
-            selectAllButton.setAccelerator(KeyStroke.getKeyStroke('A', defaultModifier));
-            clearSelectionButton.setAccelerator(KeyStroke.getKeyStroke('A', defaultShiftModifier));
-            invertSelectionButton.setAccelerator(KeyStroke.getKeyStroke('I', defaultModifier));
-            groupButton.setAccelerator(KeyStroke.getKeyStroke('G', defaultModifier));
-            ungroupButton.setAccelerator(KeyStroke.getKeyStroke('U', defaultModifier));
-            alignAllButton.setAccelerator(KeyStroke.getKeyStroke('L', defaultModifier));
-            removeButton.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0));
-            algorithmButton.setAccelerator(KeyStroke.getKeyStroke('A', InputEvent.ALT_DOWN_MASK));
-            outlinerButton.setAccelerator(KeyStroke.getKeyStroke('O', InputEvent.ALT_DOWN_MASK));
-            flexMenuButton.setAccelerator(KeyStroke.getKeyStroke('F', InputEvent.ALT_DOWN_MASK));
-        }
 
 
+    private void openWebpage(String URL) {
+      try {
+        java.awt.Desktop.getDesktop().browse(new URI(URL));
+      } catch (Exception e) {
+        e.printStackTrace();
+      }
+    }
 
 
+    private void initButtonShortCuts() {
+      int defaultModifier = Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx();
+      int defaultShiftModifier = defaultModifier + InputEvent.SHIFT_DOWN_MASK;
+      saveMenuButton.setAccelerator(KeyStroke.getKeyStroke('S', defaultModifier));
+      saveAsMenuButton.setAccelerator(KeyStroke.getKeyStroke('S', defaultShiftModifier));
+      openMenuButton.setAccelerator(KeyStroke.getKeyStroke('O', defaultModifier));
+      newMenuButton.setAccelerator(KeyStroke.getKeyStroke('N', defaultModifier));
+      undoButton.setAccelerator(KeyStroke.getKeyStroke('Z', defaultModifier));
+      redoButton.setAccelerator(KeyStroke.getKeyStroke('Y', defaultModifier));
+      copyButton.setAccelerator(KeyStroke.getKeyStroke('C', defaultModifier));
+      pasteButton.setAccelerator(KeyStroke.getKeyStroke('V', defaultModifier));
+      cutButton.setAccelerator(KeyStroke.getKeyStroke('X', defaultModifier));
+      selectAllButton.setAccelerator(KeyStroke.getKeyStroke('A', defaultModifier));
+      clearSelectionButton.setAccelerator(KeyStroke.getKeyStroke('A', defaultShiftModifier));
+      invertSelectionButton.setAccelerator(KeyStroke.getKeyStroke('I', defaultModifier));
+      groupButton.setAccelerator(KeyStroke.getKeyStroke('G', defaultModifier));
+      ungroupButton.setAccelerator(KeyStroke.getKeyStroke('U', defaultModifier));
+      alignAllButton.setAccelerator(KeyStroke.getKeyStroke('L', defaultModifier));
+      removeButton.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0));
+      algorithmButton.setAccelerator(KeyStroke.getKeyStroke('A', InputEvent.ALT_DOWN_MASK));
+      outlinerButton.setAccelerator(KeyStroke.getKeyStroke('O', InputEvent.ALT_DOWN_MASK));
+      flexMenuButton.setAccelerator(KeyStroke.getKeyStroke('F', InputEvent.ALT_DOWN_MASK));
+    }
 
 
 
 
-        private void saveFile() {
-            GuiSettings.getActualSaveFile().ifPresentOrElse(control::saveFile, this::saveNewFile);
-        }
+    private void saveFile() {
+      GuiSettings.getActualSaveFile().ifPresentOrElse(control::saveFile, this::saveNewFile);
+    }
 
 
-        private void saveNewFile() {
-            if (fileChooser.showSaveDialog(Gui.this) == JFileChooser.APPROVE_OPTION) {
-                String path = fileChooser.getSelectedFile().getPath();
-                if (!path.endsWith(".json")) {
-                    path += ".json";
-                }
-                prefs.put(PreferenceKeys.Gui.DefaultFolder, fileChooser.getCurrentDirectory().getPath());
-                control.saveFile(new File(path));
-            }
+    private void saveNewFile() {
+      if (fileChooser.showSaveDialog(Gui.this) == JFileChooser.APPROVE_OPTION) {
+        String path = fileChooser.getSelectedFile().getPath();
+        if (!path.endsWith(".json")) {
+          path += ".json";
         }
         }
+        prefs.put(PreferenceKeys.Gui.DefaultFolder, fileChooser.getCurrentDirectory().getPath());
+        control.saveFile(new File(path));
+      }
+    }
 
 
-        private void openFile() {
-            if (fileChooser.showOpenDialog(Gui.this) == JFileChooser.APPROVE_OPTION) {
-                prefs.put(PreferenceKeys.Gui.DefaultFolder, fileChooser.getCurrentDirectory().getPath());
-                control.loadFile(fileChooser.getSelectedFile());
-            }
-        }
+    private void openFile() {
+      if (fileChooser.showOpenDialog(Gui.this) == JFileChooser.APPROVE_OPTION) {
+        prefs.put(PreferenceKeys.Gui.DefaultFolder, fileChooser.getCurrentDirectory().getPath());
+        control.loadFile(fileChooser.getSelectedFile());
+      }
+    }
 
 
-        private void newFile() {
-            if (control.getModel().getCanvas().getObjectsInThisLayer().findAny().isPresent()) {
-                int selectedOption = JOptionPane.showConfirmDialog(Gui.this, "Do you want to save your current model?",
-                        "Warning", JOptionPane.YES_NO_OPTION);
-                if (selectedOption == JOptionPane.YES_OPTION) {
-                    saveNewFile();
-                }
-            }
-            control.clearModel();
+    private void newFile() {
+      if (control.getModel().getCanvas().getObjectsInThisLayer().findAny().isPresent()) {
+        int selectedOption = JOptionPane.showConfirmDialog(Gui.this,
+            "Do you want to save your current model?",
+            "Warning", JOptionPane.YES_NO_OPTION);
+        if (selectedOption == JOptionPane.YES_OPTION) {
+          saveNewFile();
         }
         }
+      }
+      control.clearModel();
+    }
 
 
-        private void selectAll(){
-            control.setSelection(getActualCanvas().getGroupNode()
-                    .getObjectsInThisLayer().collect(Collectors.toSet()));
-        }
+    private void selectAll() {
+      control.setSelection(getActualCanvas().getGroupNode()
+          .getObjectsInThisLayer().collect(Collectors.toSet()));
+    }
 
 
-        private void invertSelection() {
-            control.toggleSelectedObjects(getActualCanvas().getGroupNode()
-                    .getObjectsInThisLayer().collect(Collectors.toSet()));
-        }
-        private void removeSelectedObjects() {
-            control.deleteCanvasObjects(GuiSettings.getSelectedObjects());
-            control.clearSelection();
-        }
+    private void invertSelection() {
+      control.toggleSelectedObjects(getActualCanvas().getGroupNode()
+          .getObjectsInThisLayer().collect(Collectors.toSet()));
+    }
 
 
-        private void paste() {
-            Vec2i middlePosition = GroupNode.calculateMiddlePosition(GuiSettings.getClipboardObjects());
-            Optional<Vec2i> offset = Optional.ofNullable(getActualCanvas().getMousePosition())
-                    .map(point -> new Vec2i(point).subtract(middlePosition));
-            control.paste(getActualCanvas().getGroupNode(), offset.orElse(DefaultOffset));
-        }
+    private void removeSelectedObjects() {
+      control.deleteCanvasObjects(GuiSettings.getSelectedObjects());
+      control.clearSelection();
+    }
 
 
+    private void paste() {
+      Vec2i middlePosition = GroupNode.calculateMiddlePosition(GuiSettings.getClipboardObjects());
+      Optional<Vec2i> offset = Optional.ofNullable(getActualCanvas().getMousePosition())
+          .map(point -> new Vec2i(point).subtract(middlePosition));
+      control.paste(getActualCanvas().getGroupNode(), offset.orElse(DefaultOffset));
     }
     }
+
+  }
 }
 }

+ 365 - 352
src/holeg/ui/view/main/TimePanel.java

@@ -1,5 +1,11 @@
 package holeg.ui.view.main;
 package holeg.ui.view.main;
 
 
+import holeg.preferences.ColorPreference;
+import holeg.preferences.ImagePreference;
+import holeg.ui.controller.Control;
+import holeg.ui.model.GuiSettings;
+import holeg.ui.view.image.Import;
+import holeg.utility.listener.LostFocusListener;
 import java.awt.BorderLayout;
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.Dimension;
@@ -17,7 +23,6 @@ import java.util.Hashtable;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeUnit;
-
 import javax.swing.AbstractAction;
 import javax.swing.AbstractAction;
 import javax.swing.Box;
 import javax.swing.Box;
 import javax.swing.ImageIcon;
 import javax.swing.ImageIcon;
@@ -33,360 +38,368 @@ import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 import javax.swing.event.ChangeListener;
 import javax.swing.plaf.basic.BasicSliderUI;
 import javax.swing.plaf.basic.BasicSliderUI;
 
 
-import holeg.preferences.ColorPreference;
-import holeg.preferences.ImagePreference;
-import holeg.ui.controller.Control;
-import holeg.ui.model.GuiSettings;
-import holeg.ui.view.image.Import;
-import holeg.utility.listener.LostFocusListener;
-
 /**
 /**
- * This Class represents a Panel where the User can start and stop the
- * Simulation. He Can also reset the Simulation and click through every
- * Iteration.
- * 
+ * This Class represents a Panel where the User can start and stop the Simulation. He Can also reset
+ * the Simulation and click through every Iteration.
+ *
  * @author Gruppe14
  * @author Gruppe14
  */
  */
 public class TimePanel extends JPanel implements ActionListener {
 public class TimePanel extends JPanel implements ActionListener {
 
 
-	private static final int MAX_ITERATIONS = 100000;
-	/*
-	 * variable for calculating the performance
-	 */
-	// private long performanceTime;
-	final JButton playBtn = new JButton();
-	final JButton timeResetBtn = new JButton();
-	final JButton timeForwardBtn = new JButton();
-
-	final JButton timeBackwardBtn = new JButton();
-	JTextField iterationsField;
-	final JLabel iterationsLabel = new JLabel("Iterations:", SwingConstants.CENTER);
-	JLabel hint = new JLabel("Invalid", SwingConstants.RIGHT);
-	private ScheduledFuture<?> futureTask;
-	// private LabelHint iterationsLblHint;
-	JSlider timeSlider = new JSlider() {
-
-		{
-			// Make the slider jump to mouse position on left click
-			MouseListener[] listeners = getMouseListeners();
-			for (MouseListener l : listeners)
-				removeMouseListener(l); // remove UI-installed TrackListener
-			final BasicSliderUI ui = (BasicSliderUI) getUI();
-			BasicSliderUI.TrackListener tl = ui.new TrackListener() {
-				// this is where we jump to absolute value of click
-				@Override
-				public void mouseClicked(MouseEvent e) {
-					Point p = e.getPoint();
-					int value = ui.valueForXPosition(p.x);
-
-					setValue(value);
-				}
-
-				// disable check that will invoke scrollDueToClickInTrack
-				@Override
-				public boolean shouldScroll(int dir) {
-					return false;
-				}
-			};
-			addMouseListener(tl);
-		}
-	};
-	private final Control control;
-	private int dragResetIteration = 0;
-	private final JSlider speedSlider = new JSlider();
-	private final Timer timer;
-	private boolean running = false;
-
-	/**
-	 * Constructor
-	 * @param cont the Controller
-	 */
-	public TimePanel(Control cont) {
-		super();
-		this.control = cont;
-		// One Iteration
-		timer = new Timer(0, clicked -> timerAction());
-		// Time Slider. Panels and Buttons
-		this.setLayout(new BorderLayout(0, 0));
-		this.setBorder(null);
-		// Slider
-		timeSlider.setPaintTicks(true);
-		timeSlider.setPaintLabels(true);
-		timeSlider.setMajorTickSpacing((int) Math.ceil(((double) cont.getModel().getMaxIterations()) / 20));
-		timeSlider.setMinorTickSpacing((int) Math.ceil(((double) cont.getModel().getMaxIterations()) / 100));
-		timeSlider.setToolTipText("Time Slider");
-		timeSlider.setMaximum(cont.getModel().getMaxIterations() - 1);
-		timeSlider.setValue(0);
-		timeSlider.addChangeListener(changeEvent -> control.getModel().setCurrentIteration(timeSlider.getValue()));
-
-		this.setBorder(null);
-		timeSlider.addChangeListener(changeEvent -> {
-			control.updateStateForIteration(timeSlider.getValue());
-		});
-
-		timeSlider.addMouseListener(new MouseAdapter() {
-			@Override
-			public void mousePressed(MouseEvent e) {
-				dragResetIteration = cont.getModel().getCurrentIteration();
-			}
-		});
-
-		timeSlider.addMouseMotionListener(new MouseAdapter() {
-			@Override
-			public void mouseDragged(MouseEvent e) {
-				if (dragResetIteration != cont.getModel().getCurrentIteration()) {
-					if (running) {
-						play();
-					}
-				}
-			}
-		});
-
-		// Panel
-		JPanel timeBtnPanel = new JPanel();
-		timeBtnPanel.setBorder(null);
-		timeBtnPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
-
-		// Buttons
-		playBtn.setToolTipText("Play");
-
-		playBtn.setContentAreaFilled(false);
-		playBtn.setBorderPainted(false);
-		playBtn.setBorder(null);
-		playBtn.setIcon(new ImageIcon(Import.loadImage(ImagePreference.Button.TimePanel.Play, 30, 30)));
-		playBtn.addActionListener(clicked -> play());
-		timeResetBtn.setToolTipText("Reset");
-
-		timeResetBtn.setContentAreaFilled(false);
-		timeResetBtn.setBorder(null);
-		timeResetBtn.setIcon(new ImageIcon(Import.loadImage(ImagePreference.Button.TimePanel.Reset, 30, 30)));
-		timeResetBtn.addActionListener(new ActionListener() {
-			public void actionPerformed(ActionEvent ae) {
-				timeSlider.setValue(timeSlider.getMinimum());
-				control.getModel().setCurrentIteration(timeSlider.getValue());
-				control.resetSimulation();
-				control.updateStateForCurrentIteration();
-				if (running) {
-					play();
-				}
-			}
-		});
-		timeForwardBtn.setToolTipText("Forward");
-
-		timeForwardBtn.setContentAreaFilled(false);
-		timeForwardBtn.setBorder(null);
-		timeForwardBtn.setIcon(new ImageIcon(Import.loadImage(ImagePreference.Button.TimePanel.Forward, 30, 30)));
-		timeForwardBtn.addActionListener(new ActionListener() {
-			public void actionPerformed(ActionEvent ae) {
-				timeSlider.setValue(timeSlider.getValue() + 1);
-				control.getModel().setCurrentIteration(timeSlider.getValue());
-			}
-		});
-		timeBackwardBtn.setToolTipText("Backward");
-
-		timeBackwardBtn.setBorder(null);
-		timeBackwardBtn.setIcon(new ImageIcon(Import.loadImage(ImagePreference.Button.TimePanel.Backward, 30, 30)));
-		timeBackwardBtn.addActionListener(new ActionListener() {
-			public void actionPerformed(ActionEvent ae) {
-				timeSlider.setValue(timeSlider.getValue() - 1);
-				control.getModel().setCurrentIteration(timeSlider.getValue());
-			}
-		});
-
-		timeBtnPanel.add(playBtn);
-		timeBtnPanel.add(Box.createRigidArea(new Dimension(10, 0)));
-		timeBtnPanel.add(timeResetBtn);
-		timeBtnPanel.add(Box.createRigidArea(new Dimension(10, 0)));
-		timeBtnPanel.add(timeForwardBtn);
-
-		// Speed Panel
-		JPanel speedPanel = new JPanel();
-		JLabel simSpeedLabel = new JLabel("Speed:");
-		speedPanel.add(simSpeedLabel);
-		speedPanel.add(speedSlider);
-		speedSlider.setPaintTicks(true);
-		speedSlider.setPaintLabels(true);
-		speedSlider.setMaximum(6);
-		speedSlider.setMinimum(0);
-		speedSlider.setValue(1);
-
-		speedSlider.setPaintLabels(true);
-		Hashtable<Integer, JLabel> table = new Hashtable<Integer, JLabel>();
-		table.put(0, new JLabel("1x"));
-		table.put(1, new JLabel("2x"));
-		table.put(2, new JLabel("4x"));
-		table.put(3, new JLabel("8x"));
-		table.put(4, new JLabel("16x"));
-		table.put(5, new JLabel("32x"));
-		table.put(6, new JLabel("64x"));
-
-		speedSlider.setLabelTable(table);
-
-		speedSlider.addChangeListener(new ChangeListener() {
-			@Override
-			public void stateChanged(ChangeEvent e) {
-				/**
-				 * Shifting Powers of two: e.g. 1<<0 -> 1 step per Second 1<<3 -> 8 steps per
-				 * Second and so on,
-				 */
-				int calculationsPerSecond = 1 << speedSlider.getValue();
-				GuiSettings.timerSpeed = (1024 >> speedSlider.getValue());
-				speedSlider.setToolTipText("Speed: " + calculationsPerSecond + " Calculations per Second.");
-			}
-		});
-
-		speedSlider.setToolTipText("Change the Number of Calculations per Secons");
-
-		// Buttons and Speed Panel
-		JPanel btnAndSpeedPanel = new JPanel();
-		btnAndSpeedPanel.setLayout(new BorderLayout(0, 0));
-		btnAndSpeedPanel.setBorder(null);
-		btnAndSpeedPanel.add(timeBtnPanel, BorderLayout.NORTH);
-		btnAndSpeedPanel.add(speedPanel, BorderLayout.CENTER);
-		JPanel iterationsPanel = new JPanel();
-		iterationsPanel.setLayout(new GridBagLayout());
-		GridBagConstraints c = new GridBagConstraints();
-		c.anchor = GridBagConstraints.CENTER;
-		c.fill = GridBagConstraints.HORIZONTAL;
-		c.gridx = 0;
-		c.gridy = 0;
-		iterationsPanel.add(iterationsLabel, c);
-		// iterationsLblHint=new LabelHint(iterationsLabel);
-		hint.setForeground(Color.red);
-		hint.setText(" ");
-		iterationsField = new JTextField(6);// Considering hundreds of thousands in an extreme case
-		iterationsField.setText("" + cont.getModel().getMaxIterations());
-		iterationsField.setToolTipText("0-" + MAX_ITERATIONS);
-		iterationsField.addActionListener(this);
-		ScheduledThreadPoolExecutor s = new ScheduledThreadPoolExecutor(1);
-		iterationsField.addCaretListener((e) -> {
-			try {
-				iterationsField.setBackground(Color.WHITE);// red stings
-				if (futureTask != null) {
-					futureTask.cancel(true);
-				}
-				futureTask = s.schedule((Runnable) this::updateIterationsInput, 1, TimeUnit.SECONDS);
-				hint.setText(" ");
-			} catch (NumberFormatException n) {
-				iterationsField.setBackground(ColorPreference.TimePanel.Invalid);// red stings
-				hint.setText("Invalid");
-			}
-		});
-		iterationsField.addFocusListener((LostFocusListener) (e) -> updateIterationsInput());
-		c.gridy = 1;
-		iterationsPanel.add(iterationsField, c);
-		c.gridy = 2;
-		iterationsPanel.add(hint, c);
-		// iterationsPanel.add(new JLabel(), BorderLayout.SOUTH);
-		JPanel timePanel = new JPanel();
-		timePanel.setLayout(new BorderLayout());
-		;
-		timePanel.add(iterationsPanel, BorderLayout.WEST);
-		timePanel.add(timeSlider, BorderLayout.CENTER);
-		this.add(btnAndSpeedPanel, BorderLayout.WEST);
-		add(timePanel);
-
-		// Disable Keys
-		timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "UP_ARROW");
-		timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "DOWN_ARROW");
-		timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0, false), "PAGE_DOWN");
-		timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0, false), "PAGE_UP");
-		timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0, false), "END");
-		timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0, false), "HOME");
-
-		// Left arrow Key
-		timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "LEFT_ARROW");
-		timeSlider.getActionMap().put("LEFT_ARROW", new AbstractAction() {
-			private static final long serialVersionUID = 1L;
-
-			@Override
-			public void actionPerformed(ActionEvent e) {
-				timeSlider.setValue(timeSlider.getValue() - 1);
-				control.resetSimulation();
-				control.calculateStateForCurrentIteration();
-			}
-		});
-
-		// Right arrow Key
-		timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "Right_ARROW");
-		timeSlider.getActionMap().put("Right_ARROW", new AbstractAction() {
-			private static final long serialVersionUID = 1L;
-
-			@Override
-			public void actionPerformed(ActionEvent e) {
-				timeSlider.setValue(timeSlider.getValue() + 1);
-			}
-		});
-	}
-
-	
-	public void timerAction() {
-		timeSlider.setValue(timeSlider.getValue() + 1);
-		control.getModel().setCurrentIteration(timeSlider.getValue());
-		timer.setDelay(GuiSettings.timerSpeed);
-		if (timeSlider.getValue() >= control.getModel().getMaxIterations() - 1) {
-			running = false;
-			playBtn.setIcon(new ImageIcon(Import.loadImage(ImagePreference.Button.TimePanel.Play, 30, 30)));
-			timer.stop();
-		}
-	}
-	
-	public void play() {
-		if (control.getModel().getCurrentIteration() == control.getModel().getMaxIterations() - 1)
-			timeSlider.setValue(timeSlider.getMinimum());
-		running = !running;
-		if (running) {
-			timer.setDelay(GuiSettings.timerSpeed);
-			timer.start();
-			playBtn.setIcon(new ImageIcon(Import.loadImage(ImagePreference.Button.TimePanel.Pause, 30, 30)));
-		} else {
-			timer.stop();
-			playBtn.setIcon(new ImageIcon(Import.loadImage(ImagePreference.Button.TimePanel.Play, 30, 30)));
-		}
-	}
-	
-	
-	/**
-	 * Returns the TimeSlider.
-	 * 
-	 * @return the TimeSlider
-	 */
-	public JSlider getTimeSlider() {
-		return timeSlider;
-	}
-
-	@Override
-	public void actionPerformed(ActionEvent arg0) {
-		updateIterationsInput();
-	}
-
-	/**
-	 * Update the Text field and apply valid changes to update Iterations from to
-	 * model.
-	 * <p>
-	 * Executed by user input.
-	 */
-	private void updateIterationsInput() {
-		try {
-			int iterations = Integer.parseInt(iterationsField.getText());
-			// iterationsLblHint.reset();
-			boolean resetField = true;
-			if (iterations < 1)
-				iterations = 1;
-			else if (iterations > MAX_ITERATIONS)
-				iterations = MAX_ITERATIONS;
-			else
-				resetField = false;
-			if (resetField)
-				iterationsField.setText("" + iterations);
-			control.getModel().setIterations(Integer.parseInt(iterationsField.getText()));
-			timeSlider.setMaximum(control.getModel().getMaxIterations() - 1);
-			timeSlider.setLabelTable(null);// Otherwise the ticks won't update
-			timeSlider.setMajorTickSpacing((int) Math.ceil(((double) iterations) / 20));
-			timeSlider.setMinorTickSpacing((int) Math.ceil(((double) iterations) / 100));// Even though the final mark
-																							// can't actually be
-																							// reached.
-		} catch (NumberFormatException e) {
-		}
-	}
+  private static final int MAX_ITERATIONS = 100000;
+  /*
+   * variable for calculating the performance
+   */
+  // private long performanceTime;
+  final JButton playBtn = new JButton();
+  final JButton timeResetBtn = new JButton();
+  final JButton timeForwardBtn = new JButton();
+
+  final JButton timeBackwardBtn = new JButton();
+  final JLabel iterationsLabel = new JLabel("Iterations:", SwingConstants.CENTER);
+  private final Control control;
+  private final JSlider speedSlider = new JSlider();
+  private final Timer timer;
+  JTextField iterationsField;
+  JLabel hint = new JLabel("Invalid", SwingConstants.RIGHT);
+  // private LabelHint iterationsLblHint;
+  JSlider timeSlider = new JSlider() {
+
+    {
+      // Make the slider jump to mouse position on left click
+      MouseListener[] listeners = getMouseListeners();
+      for (MouseListener l : listeners) {
+        removeMouseListener(l); // remove UI-installed TrackListener
+      }
+      final BasicSliderUI ui = (BasicSliderUI) getUI();
+      BasicSliderUI.TrackListener tl = ui.new TrackListener() {
+        // this is where we jump to absolute value of click
+        @Override
+        public void mouseClicked(MouseEvent e) {
+          Point p = e.getPoint();
+          int value = ui.valueForXPosition(p.x);
+
+          setValue(value);
+        }
+
+        // disable check that will invoke scrollDueToClickInTrack
+        @Override
+        public boolean shouldScroll(int dir) {
+          return false;
+        }
+      };
+      addMouseListener(tl);
+    }
+  };
+  private ScheduledFuture<?> futureTask;
+  private int dragResetIteration = 0;
+  private boolean running = false;
+
+  /**
+   * Constructor
+   *
+   * @param cont the Controller
+   */
+  public TimePanel(Control cont) {
+    super();
+    this.control = cont;
+    // One Iteration
+    timer = new Timer(0, clicked -> timerAction());
+    // Time Slider. Panels and Buttons
+    this.setLayout(new BorderLayout(0, 0));
+    this.setBorder(null);
+    // Slider
+    timeSlider.setPaintTicks(true);
+    timeSlider.setPaintLabels(true);
+    timeSlider.setMajorTickSpacing(
+        (int) Math.ceil(((double) cont.getModel().getMaxIterations()) / 20));
+    timeSlider.setMinorTickSpacing(
+        (int) Math.ceil(((double) cont.getModel().getMaxIterations()) / 100));
+    timeSlider.setToolTipText("Time Slider");
+    timeSlider.setMaximum(cont.getModel().getMaxIterations() - 1);
+    timeSlider.setValue(0);
+    timeSlider.addChangeListener(
+        changeEvent -> control.getModel().setCurrentIteration(timeSlider.getValue()));
+
+    this.setBorder(null);
+    timeSlider.addChangeListener(changeEvent -> {
+      control.updateStateForIteration(timeSlider.getValue());
+    });
+
+    timeSlider.addMouseListener(new MouseAdapter() {
+      @Override
+      public void mousePressed(MouseEvent e) {
+        dragResetIteration = cont.getModel().getCurrentIteration();
+      }
+    });
+
+    timeSlider.addMouseMotionListener(new MouseAdapter() {
+      @Override
+      public void mouseDragged(MouseEvent e) {
+        if (dragResetIteration != cont.getModel().getCurrentIteration()) {
+          if (running) {
+            play();
+          }
+        }
+      }
+    });
+
+    // Panel
+    JPanel timeBtnPanel = new JPanel();
+    timeBtnPanel.setBorder(null);
+    timeBtnPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
+
+    // Buttons
+    playBtn.setToolTipText("Play");
+
+    playBtn.setContentAreaFilled(false);
+    playBtn.setBorderPainted(false);
+    playBtn.setBorder(null);
+    playBtn.setIcon(new ImageIcon(Import.loadImage(ImagePreference.Button.TimePanel.Play, 30, 30)));
+    playBtn.addActionListener(clicked -> play());
+    timeResetBtn.setToolTipText("Reset");
+
+    timeResetBtn.setContentAreaFilled(false);
+    timeResetBtn.setBorder(null);
+    timeResetBtn.setIcon(
+        new ImageIcon(Import.loadImage(ImagePreference.Button.TimePanel.Reset, 30, 30)));
+    timeResetBtn.addActionListener(new ActionListener() {
+      public void actionPerformed(ActionEvent ae) {
+        timeSlider.setValue(timeSlider.getMinimum());
+        control.getModel().setCurrentIteration(timeSlider.getValue());
+        control.resetSimulation();
+        control.updateStateForCurrentIteration();
+        if (running) {
+          play();
+        }
+      }
+    });
+    timeForwardBtn.setToolTipText("Forward");
+
+    timeForwardBtn.setContentAreaFilled(false);
+    timeForwardBtn.setBorder(null);
+    timeForwardBtn.setIcon(
+        new ImageIcon(Import.loadImage(ImagePreference.Button.TimePanel.Forward, 30, 30)));
+    timeForwardBtn.addActionListener(new ActionListener() {
+      public void actionPerformed(ActionEvent ae) {
+        timeSlider.setValue(timeSlider.getValue() + 1);
+        control.getModel().setCurrentIteration(timeSlider.getValue());
+      }
+    });
+    timeBackwardBtn.setToolTipText("Backward");
+
+    timeBackwardBtn.setBorder(null);
+    timeBackwardBtn.setIcon(
+        new ImageIcon(Import.loadImage(ImagePreference.Button.TimePanel.Backward, 30, 30)));
+    timeBackwardBtn.addActionListener(new ActionListener() {
+      public void actionPerformed(ActionEvent ae) {
+        timeSlider.setValue(timeSlider.getValue() - 1);
+        control.getModel().setCurrentIteration(timeSlider.getValue());
+      }
+    });
+
+    timeBtnPanel.add(playBtn);
+    timeBtnPanel.add(Box.createRigidArea(new Dimension(10, 0)));
+    timeBtnPanel.add(timeResetBtn);
+    timeBtnPanel.add(Box.createRigidArea(new Dimension(10, 0)));
+    timeBtnPanel.add(timeForwardBtn);
+
+    // Speed Panel
+    JPanel speedPanel = new JPanel();
+    JLabel simSpeedLabel = new JLabel("Speed:");
+    speedPanel.add(simSpeedLabel);
+    speedPanel.add(speedSlider);
+    speedSlider.setPaintTicks(true);
+    speedSlider.setPaintLabels(true);
+    speedSlider.setMaximum(6);
+    speedSlider.setMinimum(0);
+    speedSlider.setValue(1);
+
+    speedSlider.setPaintLabels(true);
+    Hashtable<Integer, JLabel> table = new Hashtable<Integer, JLabel>();
+    table.put(0, new JLabel("1x"));
+    table.put(1, new JLabel("2x"));
+    table.put(2, new JLabel("4x"));
+    table.put(3, new JLabel("8x"));
+    table.put(4, new JLabel("16x"));
+    table.put(5, new JLabel("32x"));
+    table.put(6, new JLabel("64x"));
+
+    speedSlider.setLabelTable(table);
+
+    speedSlider.addChangeListener(new ChangeListener() {
+      @Override
+      public void stateChanged(ChangeEvent e) {
+        /**
+         * Shifting Powers of two: e.g. 1<<0 -> 1 step per Second 1<<3 -> 8 steps per
+         * Second and so on,
+         */
+        int calculationsPerSecond = 1 << speedSlider.getValue();
+        GuiSettings.timerSpeed = (1024 >> speedSlider.getValue());
+        speedSlider.setToolTipText("Speed: " + calculationsPerSecond + " Calculations per Second.");
+      }
+    });
+
+    speedSlider.setToolTipText("Change the Number of Calculations per Secons");
+
+    // Buttons and Speed Panel
+    JPanel btnAndSpeedPanel = new JPanel();
+    btnAndSpeedPanel.setLayout(new BorderLayout(0, 0));
+    btnAndSpeedPanel.setBorder(null);
+    btnAndSpeedPanel.add(timeBtnPanel, BorderLayout.NORTH);
+    btnAndSpeedPanel.add(speedPanel, BorderLayout.CENTER);
+    JPanel iterationsPanel = new JPanel();
+    iterationsPanel.setLayout(new GridBagLayout());
+    GridBagConstraints c = new GridBagConstraints();
+    c.anchor = GridBagConstraints.CENTER;
+    c.fill = GridBagConstraints.HORIZONTAL;
+    c.gridx = 0;
+    c.gridy = 0;
+    iterationsPanel.add(iterationsLabel, c);
+    // iterationsLblHint=new LabelHint(iterationsLabel);
+    hint.setForeground(Color.red);
+    hint.setText(" ");
+    iterationsField = new JTextField(6);// Considering hundreds of thousands in an extreme case
+    iterationsField.setText("" + cont.getModel().getMaxIterations());
+    iterationsField.setToolTipText("0-" + MAX_ITERATIONS);
+    iterationsField.addActionListener(this);
+    ScheduledThreadPoolExecutor s = new ScheduledThreadPoolExecutor(1);
+    iterationsField.addCaretListener((e) -> {
+      try {
+        iterationsField.setBackground(Color.WHITE);// red stings
+        if (futureTask != null) {
+          futureTask.cancel(true);
+        }
+        futureTask = s.schedule((Runnable) this::updateIterationsInput, 1, TimeUnit.SECONDS);
+        hint.setText(" ");
+      } catch (NumberFormatException n) {
+        iterationsField.setBackground(ColorPreference.TimePanel.Invalid);// red stings
+        hint.setText("Invalid");
+      }
+    });
+    iterationsField.addFocusListener((LostFocusListener) (e) -> updateIterationsInput());
+    c.gridy = 1;
+    iterationsPanel.add(iterationsField, c);
+    c.gridy = 2;
+    iterationsPanel.add(hint, c);
+    // iterationsPanel.add(new JLabel(), BorderLayout.SOUTH);
+    JPanel timePanel = new JPanel();
+    timePanel.setLayout(new BorderLayout());
+    ;
+    timePanel.add(iterationsPanel, BorderLayout.WEST);
+    timePanel.add(timeSlider, BorderLayout.CENTER);
+    this.add(btnAndSpeedPanel, BorderLayout.WEST);
+    add(timePanel);
+
+    // Disable Keys
+    timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "UP_ARROW");
+    timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "DOWN_ARROW");
+    timeSlider.getInputMap()
+        .put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0, false), "PAGE_DOWN");
+    timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0, false), "PAGE_UP");
+    timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0, false), "END");
+    timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0, false), "HOME");
+
+    // Left arrow Key
+    timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "LEFT_ARROW");
+    timeSlider.getActionMap().put("LEFT_ARROW", new AbstractAction() {
+      private static final long serialVersionUID = 1L;
+
+      @Override
+      public void actionPerformed(ActionEvent e) {
+        timeSlider.setValue(timeSlider.getValue() - 1);
+        control.resetSimulation();
+        control.calculateStateForCurrentIteration();
+      }
+    });
+
+    // Right arrow Key
+    timeSlider.getInputMap()
+        .put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "Right_ARROW");
+    timeSlider.getActionMap().put("Right_ARROW", new AbstractAction() {
+      private static final long serialVersionUID = 1L;
+
+      @Override
+      public void actionPerformed(ActionEvent e) {
+        timeSlider.setValue(timeSlider.getValue() + 1);
+      }
+    });
+  }
+
+
+  public void timerAction() {
+    timeSlider.setValue(timeSlider.getValue() + 1);
+    control.getModel().setCurrentIteration(timeSlider.getValue());
+    timer.setDelay(GuiSettings.timerSpeed);
+    if (timeSlider.getValue() >= control.getModel().getMaxIterations() - 1) {
+      running = false;
+      playBtn.setIcon(
+          new ImageIcon(Import.loadImage(ImagePreference.Button.TimePanel.Play, 30, 30)));
+      timer.stop();
+    }
+  }
+
+  public void play() {
+    if (control.getModel().getCurrentIteration() == control.getModel().getMaxIterations() - 1) {
+      timeSlider.setValue(timeSlider.getMinimum());
+    }
+    running = !running;
+    if (running) {
+      timer.setDelay(GuiSettings.timerSpeed);
+      timer.start();
+      playBtn.setIcon(
+          new ImageIcon(Import.loadImage(ImagePreference.Button.TimePanel.Pause, 30, 30)));
+    } else {
+      timer.stop();
+      playBtn.setIcon(
+          new ImageIcon(Import.loadImage(ImagePreference.Button.TimePanel.Play, 30, 30)));
+    }
+  }
+
+
+  /**
+   * Returns the TimeSlider.
+   *
+   * @return the TimeSlider
+   */
+  public JSlider getTimeSlider() {
+    return timeSlider;
+  }
+
+  @Override
+  public void actionPerformed(ActionEvent arg0) {
+    updateIterationsInput();
+  }
+
+  /**
+   * Update the Text field and apply valid changes to update Iterations from to model.
+   * <p>
+   * Executed by user input.
+   */
+  private void updateIterationsInput() {
+    try {
+      int iterations = Integer.parseInt(iterationsField.getText());
+      // iterationsLblHint.reset();
+      boolean resetField = true;
+      if (iterations < 1) {
+        iterations = 1;
+      } else if (iterations > MAX_ITERATIONS) {
+        iterations = MAX_ITERATIONS;
+      } else {
+        resetField = false;
+      }
+      if (resetField) {
+        iterationsField.setText("" + iterations);
+      }
+      control.getModel().setIterations(Integer.parseInt(iterationsField.getText()));
+      timeSlider.setMaximum(control.getModel().getMaxIterations() - 1);
+      timeSlider.setLabelTable(null);// Otherwise the ticks won't update
+      timeSlider.setMajorTickSpacing((int) Math.ceil(((double) iterations) / 20));
+      timeSlider.setMinorTickSpacing(
+          (int) Math.ceil(((double) iterations) / 100));// Even though the final mark
+      // can't actually be
+      // reached.
+    } catch (NumberFormatException e) {
+    }
+  }
 }
 }

+ 176 - 165
src/holeg/ui/view/window/AddOnWindow.java

@@ -1,5 +1,9 @@
 package holeg.ui.view.window;
 package holeg.ui.view.window;
 
 
+import holeg.api.AddOn;
+import holeg.preferences.ImagePreference;
+import holeg.ui.controller.Control;
+import holeg.ui.view.image.Import;
 import java.awt.BorderLayout;
 import java.awt.BorderLayout;
 import java.awt.Dimension;
 import java.awt.Dimension;
 import java.awt.Font;
 import java.awt.Font;
@@ -10,7 +14,6 @@ import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.net.URLClassLoader;
 import java.util.Scanner;
 import java.util.Scanner;
-
 import javax.swing.JFileChooser;
 import javax.swing.JFileChooser;
 import javax.swing.JFrame;
 import javax.swing.JFrame;
 import javax.swing.JMenu;
 import javax.swing.JMenu;
@@ -25,169 +28,177 @@ import javax.swing.text.StyleConstants;
 import javax.tools.JavaCompiler;
 import javax.tools.JavaCompiler;
 import javax.tools.ToolProvider;
 import javax.tools.ToolProvider;
 
 
-import holeg.api.AddOn;
-import holeg.preferences.ImagePreference;
-import holeg.ui.controller.Control;
-import holeg.ui.view.image.Import;
+public class AddOnWindow extends JFrame {
+
+  private AddOn actual;
+  private Control control;
+  private JPanel content = new JPanel();
+
+  public AddOnWindow(JFrame parentFrame, Control control) {
+    this.control = control;
+    this.setTitle("Add-Ons");
+    this.setVisible(true);
+    this.setContentPane(content);
+    this.setIconImage(Import.loadImage(ImagePreference.Logo, 30, 30));
+    initMenuBar();
+    initDefaultContentPanel();
+    this.pack();
+    this.setLocationRelativeTo(parentFrame);
+  }
+
+  private void initMenuBar() {
+    JMenuBar menuBar = new JMenuBar();
+    JMenu menuSelect = new JMenu("File");
+    JMenuItem menuItemAlgorithm = new JMenuItem("Open .java-File..");
+    menuItemAlgorithm.addActionListener(actionEvent -> openJavaFile());
+    menuSelect.add(menuItemAlgorithm);
+    JMenuItem menuItemFolder = new JMenuItem("Open Folder..");
+    menuItemFolder.addActionListener(actionEvent -> openFolder(menuSelect));
+    menuSelect.add(menuItemFolder);
+    menuSelect.addSeparator();
+    JMenu menuHelp = new JMenu("Help");
+    menuBar.add(menuSelect);
+    menuBar.add(menuHelp);
+    this.setJMenuBar(menuBar);
+  }
+
+  private void initDefaultContentPanel() {
+    content.setLayout(new BorderLayout());
+    JTextPane textPane = new JTextPane();
+    SimpleAttributeSet attribs = new SimpleAttributeSet();
+    StyleConstants.setAlignment(attribs, StyleConstants.ALIGN_JUSTIFIED);
+    textPane.setParagraphAttributes(attribs, true);
+    textPane.setText("No algorithm is loaded."
+        + "\n OPTION[1]:"
+        + "\n  Select '.java'-file via the file browser. (File\u2192Open .jave-File..)"
+        + "\n"
+        + "\n OPTION[2]:"
+        + "\n First select the folder where the addon '.java'-file is located. (File\u2192Open Folder..)"
+        + "\n Second load the algorithm. (File\u2192'YourAlgo')");
+    textPane.setFont(new Font("Serif", Font.PLAIN, 16));
+
+    content.add(textPane, BorderLayout.CENTER);
+    content.setPreferredSize(new Dimension(500, 500));
+  }
+
+  /**
+   *
+   */
+  private void openJavaFile() {
+    JFileChooser fileChooser = new JFileChooser();
+    fileChooser.setCurrentDirectory(
+        new File(System.getProperty("user.dir") + "/src/holeg/algorithm/"));
+    fileChooser.setFileFilter(new FileNameExtensionFilter("JAVA Source Files", "java"));
+    fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+    fileChooser.setAcceptAllFileFilterUsed(false);
+    int result = fileChooser.showOpenDialog(this);
+    if (result == JFileChooser.APPROVE_OPTION) {
+      //Found a file
+      loadAlgorithm(fileChooser.getSelectedFile());
+    }
+  }
+
+  private void openFolder(JMenu menuSelect) {
+    JFileChooser fileChooser = new JFileChooser();
+    fileChooser.setCurrentDirectory(new File(System.getProperty("user.dir") + "/src/"));
+    fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+    fileChooser.setAcceptAllFileFilterUsed(false);
+    int result = fileChooser.showOpenDialog(this);
+    if (result == JFileChooser.APPROVE_OPTION) {
+      File[] files = fileChooser.getSelectedFile()
+          .listFiles(file -> file.getName().endsWith(".java"));
+
+      //Remove all Index from old Folder
+      for (int i = menuSelect.getItemCount() - 1; i > 2; i--) {
+        menuSelect.remove(i);
+      }
+      for (File file : files) {
+        JMenuItem insertMenuItem = new JMenuItem(getNameWithoutExtension(file));
+        insertMenuItem.addActionListener(actionEvent -> loadAlgorithm(file));
+        menuSelect.add(insertMenuItem);
+      }
+    }
+  }
+
+  /**
+   * Compile and load a java File.
+   *
+   * @param javafile
+   */
+
+  private void loadAlgorithm(File javafile) {
+    //Get Class name:
+    String name = getNameWithoutExtension(javafile);
+    //get Package name
+    String packageName = "";
+    Scanner in = null;
+    try {
+      in = new Scanner(javafile);
+    } catch (FileNotFoundException e) {
+      generateErrorDialog("File not Found");
+    }
+    while (in.hasNext()) {
+      String line = in.nextLine().trim();
+      if (line.startsWith("package")) {
+        packageName = line.substring(8, line.length() - 1);
+        break;
+      }
+    }
+    //GetPathName
+    //String path =  javafile.getParentFile().isDirectory() ? javafile.getParentFile().getAbsolutePath() : "";
+    File folder = javafile.getParentFile();
+    // Compile source file.
+    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+    if (ToolProvider.getSystemJavaCompiler() == null) {
+      generateErrorDialog("Please install the JDK on your system.");
+    } else {
+      compiler.run(null, null, null, javafile.getAbsolutePath());
+    }
+    try {
+      URLClassLoader classLoader = URLClassLoader.newInstance(new URL[]{folder.toURI().toURL()});
+      Class<?> cls = Class.forName(packageName.isEmpty() ? name : packageName + "." + name, true,
+          classLoader);
+      Object object = cls.getDeclaredConstructor().newInstance();
+      if (object instanceof AddOn addon) {
+        actual = addon;
+        actual.setController(control);
+        this.setContentPane(actual.getPanel());
+        this.pack();
+      } else {
+        generateErrorDialog("Class does not implement CpsAlgorithm!");
+      }
+    } catch (MalformedURLException e) {
+      generateErrorDialog("URLClassLoader error");
+    } catch (ClassNotFoundException e) {
+      generateErrorDialog("ClassNotFound error" + e.getMessage());
+    } catch (InstantiationException e) {
+      generateErrorDialog("Class does not implement a Constructor." + e.getMessage());
+    } catch (IllegalAccessException e) {
+      generateErrorDialog(
+          "Class set this method privat or protected needs to be public." + e.getMessage());
+    } catch (IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
+      e.printStackTrace();
+    }
+  }
+
+  /**
+   * Returns the Name of a file without Extension.
+   *
+   * @param file
+   * @return
+   */
+  private String getNameWithoutExtension(File file) {
+    return file.getName().substring(0, file.getName().lastIndexOf("."));
+  }
 
 
-public class AddOnWindow extends JFrame{
-	private AddOn actual;
-	private Control control;
-	private JPanel content = new JPanel();
-	public AddOnWindow(JFrame parentFrame, Control control){
-		this.control = control;
-		this.setTitle("Add-Ons");
-		this.setVisible(true);
-		this.setContentPane(content);
-		this.setIconImage(Import.loadImage(ImagePreference.Logo, 30, 30));
-		initMenuBar();
-		initDefaultContentPanel();
-		this.pack();
-		this.setLocationRelativeTo(parentFrame);
-	}
-	private void initMenuBar() {
-		JMenuBar menuBar = new JMenuBar();
-		JMenu menuSelect = new JMenu("File");
-		JMenuItem menuItemAlgorithm= new JMenuItem("Open .java-File..");
-		menuItemAlgorithm.addActionListener(actionEvent -> openJavaFile());
-		menuSelect.add(menuItemAlgorithm);
-		JMenuItem menuItemFolder= new JMenuItem("Open Folder..");
-		menuItemFolder.addActionListener(actionEvent->openFolder(menuSelect));
-		menuSelect.add(menuItemFolder);
-		menuSelect.addSeparator();
-		JMenu menuHelp = new JMenu("Help");
-		menuBar.add(menuSelect);
-		menuBar.add(menuHelp);
-		this.setJMenuBar(menuBar);
-	}
-	
-	private void initDefaultContentPanel() {
-		content.setLayout(new BorderLayout());
-		JTextPane textPane = new JTextPane();
-		SimpleAttributeSet attribs = new SimpleAttributeSet();  
-		StyleConstants.setAlignment(attribs , StyleConstants.ALIGN_JUSTIFIED);
-		textPane.setParagraphAttributes(attribs, true);
-		textPane.setText("No algorithm is loaded."
-				+"\n OPTION[1]:"
-				+"\n  Select '.java'-file via the file browser. (File\u2192Open .jave-File..)"
-				+"\n"
-				+"\n OPTION[2]:"
-				+"\n First select the folder where the addon '.java'-file is located. (File\u2192Open Folder..)"
-				+"\n Second load the algorithm. (File\u2192'YourAlgo')");
-		textPane.setFont(new Font("Serif", Font.PLAIN, 16));
-		
-		
-		content.add(textPane, BorderLayout.CENTER);
-		content.setPreferredSize(new Dimension(500, 500));
-	}
-	
-	/**
-	 * 
-	 */
-	private void openJavaFile() {
-		JFileChooser fileChooser = new JFileChooser();
-		fileChooser.setCurrentDirectory(new File(System.getProperty("user.dir")+"/src/holeg/algorithm/"));
-		fileChooser.setFileFilter(new FileNameExtensionFilter("JAVA Source Files", "java"));
-		fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
-		fileChooser.setAcceptAllFileFilterUsed(false);
-		int result = fileChooser.showOpenDialog(this);
-		if(result == JFileChooser.APPROVE_OPTION) {
-			//Found a file
-			loadAlgorithm(fileChooser.getSelectedFile());
-		}
-	}
-	
-	private void openFolder(JMenu menuSelect) {
-		JFileChooser fileChooser = new JFileChooser();
-		fileChooser.setCurrentDirectory(new File(System.getProperty("user.dir")+"/src/"));
-		fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
-		fileChooser.setAcceptAllFileFilterUsed(false);
-		int result = fileChooser.showOpenDialog(this);
-		if(result == JFileChooser.APPROVE_OPTION) {
-			File[] files = fileChooser.getSelectedFile().listFiles(file -> file.getName().endsWith(".java"));
-			
-			//Remove all Index from old Folder
-			for(int i= menuSelect.getItemCount()-1; i> 2; i--) {
-				menuSelect.remove(i);
-			}
-			for(File file: files) {
-				JMenuItem insertMenuItem = new JMenuItem(getNameWithoutExtension(file));
-				insertMenuItem.addActionListener(actionEvent -> loadAlgorithm(file));
-				menuSelect.add(insertMenuItem);
-			}
-		}
-	}
-	/**
-	 * Compile and load a java File.
-	 * @param javafile
-	 */
-	
-	private void loadAlgorithm(File javafile) {
-		//Get Class name:
-		String name = getNameWithoutExtension(javafile);
-		//get Package name
-		String packageName = "";
-		Scanner in = null;
-		try {
-			in = new Scanner(javafile);
-		} catch (FileNotFoundException e) {
-			generateErrorDialog("File not Found");
-		}
-		while(in.hasNext()) {
-			String line = in.nextLine().trim();
-			if(line.startsWith("package")) {
-				packageName = line.substring(8, line.length()-1);
-				break;
-			}
-		}
-		//GetPathName
-		//String path =  javafile.getParentFile().isDirectory() ? javafile.getParentFile().getAbsolutePath() : "";
-		File folder = javafile.getParentFile();
-		// Compile source file.
-		JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
-		if (ToolProvider.getSystemJavaCompiler() == null) {
-			generateErrorDialog("Please install the JDK on your system.");
-		}else {
-			compiler.run(null, null, null, javafile.getAbsolutePath());					
-		}
-		try {
-		URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { folder.toURI().toURL() });
-		Class<?> cls = Class.forName(packageName.isEmpty()?name:packageName + "." +name, true, classLoader);
-		Object object = cls.getDeclaredConstructor().newInstance();
-		if(object instanceof AddOn addon) {
-			actual = addon;
-			actual.setController(control);
-			this.setContentPane(actual.getPanel());
-			this.pack();
-		}else {
-			generateErrorDialog("Class does not implement CpsAlgorithm!");
-		}
-		} catch (MalformedURLException e) {
-			generateErrorDialog("URLClassLoader error");
-		} catch (ClassNotFoundException e) {
-			generateErrorDialog("ClassNotFound error" + e.getMessage());
-		} catch (InstantiationException e) {
-			generateErrorDialog("Class does not implement a Constructor." + e.getMessage());
-		} catch (IllegalAccessException e) {
-			generateErrorDialog("Class set this method privat or protected needs to be public." + e.getMessage());
-		}	catch (IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
-			e.printStackTrace();
-		}
-	}
-	/**
-	 * Returns the Name of a file without Extension.
-	 * @param file
-	 * @return
-	 */
-	private String getNameWithoutExtension(File file) {
-		return file.getName().substring(0, file.getName().lastIndexOf("."));
-	}
-	/**
-	 * Generate a little Error Dialog to inform the User.
-	 * @param message
-	 */
-	private void generateErrorDialog(String message) {
-		System.out.println(message);
-		JOptionPane.showConfirmDialog(this, message, "Error", JOptionPane.OK_OPTION, JOptionPane.ERROR_MESSAGE);
-	}
+  /**
+   * Generate a little Error Dialog to inform the User.
+   *
+   * @param message
+   */
+  private void generateErrorDialog(String message) {
+    System.out.println(message);
+    JOptionPane.showConfirmDialog(this, message, "Error", JOptionPane.OK_OPTION,
+        JOptionPane.ERROR_MESSAGE);
+  }
 }
 }

+ 605 - 555
src/holeg/ui/view/window/FlexWindow.java

@@ -1,22 +1,27 @@
 package holeg.ui.view.window;
 package holeg.ui.view.window;
 
 
-import holeg.model.*;
+import holeg.model.Constrain;
+import holeg.model.Flexibility;
 import holeg.model.Flexibility.FlexState;
 import holeg.model.Flexibility.FlexState;
+import holeg.model.GroupNode;
+import holeg.model.HolonElement;
 import holeg.model.HolonElement.Priority;
 import holeg.model.HolonElement.Priority;
+import holeg.model.HolonObject;
 import holeg.preferences.ColorPreference;
 import holeg.preferences.ColorPreference;
 import holeg.preferences.ImagePreference;
 import holeg.preferences.ImagePreference;
 import holeg.ui.controller.Control;
 import holeg.ui.controller.Control;
 import holeg.ui.view.image.Import;
 import holeg.ui.view.image.Import;
 import holeg.utility.listener.WindowClosingListener;
 import holeg.utility.listener.WindowClosingListener;
-
-import javax.swing.*;
-import javax.swing.border.EmptyBorder;
-import javax.swing.text.NumberFormatter;
-import javax.swing.tree.DefaultMutableTreeNode;
-import javax.swing.tree.DefaultTreeModel;
-import javax.swing.tree.TreePath;
-import java.awt.*;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
 import java.awt.Dialog.ModalityType;
 import java.awt.Dialog.ModalityType;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.Rectangle;
 import java.awt.event.ItemEvent;
 import java.awt.event.ItemEvent;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseEvent;
@@ -27,579 +32,624 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Locale;
 import java.util.Optional;
 import java.util.Optional;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JDialog;
+import javax.swing.JFormattedTextField;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JScrollPane;
+import javax.swing.JTabbedPane;
+import javax.swing.JTree;
+import javax.swing.SwingUtilities;
+import javax.swing.border.EmptyBorder;
+import javax.swing.text.NumberFormatter;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreePath;
 
 
 
 
 public class FlexWindow extends JFrame {
 public class FlexWindow extends JFrame {
-    private final static int boxSideLength = 70;
-    private final JTabbedPane contentPanel = new JTabbedPane();
-    private final Control control;
-    //Flexibility Intermediate
-    private final Flexibility intermediateFlex = new Flexibility(null);
-    //Tabs
-    String gridTabString = "Grid";
-    String orderTabString = "Order";
-    private JPanel nothingSelectedPanel;
-    private JPanel selectedPanel;
-    private JScrollPane usageViewPanel;
-    private boolean offered = true, onConstrain = true, offConstrain = false;
-    //JTree
-    private DefaultMutableTreeNode listOfAllSelectedHolonObjects;
-    private JTree stateTree;
-    private DefaultTreeModel treeModel;
-	private final JPopupMenu menu = new JPopupMenu();
-	private final JMenuItem priorityItem = new JMenuItem("EditPriorities");
-	private final JMenuItem flexItem = new JMenuItem("AddFlex");
-
-
-    Runnable update = this::update;
-
-    public FlexWindow(JFrame parentFrame, Control control) {
-        this.intermediateFlex.name = "name";
-        this.control = control;
-        //InitWindow
-        createMenuBar();
-        initWindowPanel(parentFrame);
-        this.addWindowListener((WindowClosingListener) e -> control.OnCanvasUpdate.removeListener(update));
-        updateSelectedPanel();
-        control.OnCanvasUpdate.addListener(update);
-    }
-
-
-    private void initWindowPanel(JFrame parentFrame) {
-        this.setBounds(0, 0, 400, parentFrame.getHeight() > 20 ? parentFrame.getHeight() - 20 : parentFrame.getHeight());
-        this.setIconImage(Import.loadImage(ImagePreference.Logo, 30, 30));
-        this.setTitle("Flexibility");
-        this.setLocationRelativeTo(parentFrame);
-        this.setVisible(true);
-        //this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
-        createNothingSelectedPanel();
-        createSelectedPanel();
-        createUsageViewPanel();
-        contentPanel.addTab(gridTabString, nothingSelectedPanel);
-        contentPanel.addTab(orderTabString, usageViewPanel);
-        contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
-        this.setContentPane(contentPanel);
-        this.revalidate();
-
-    }
-
-    private void createMenuBar() {
-        JMenuBar menuBar = new JMenuBar();
-        JMenu canvas = new JMenu("Canvas");
-        menuBar.add(canvas);
-        JMenuItem updateMenuItem = new JMenuItem("Update");
-        updateMenuItem.addActionListener(clicked -> updateSelectedPanel());
-        canvas.add(updateMenuItem);
-        JMenu flex = new JMenu("Flex");
-        menuBar.add(flex);
-        JMenuItem addMenuItem = new JMenuItem("Add Flexibility");
-        addMenuItem.addActionListener(clicked -> createAddDialog(null));
-        flex.add(addMenuItem);
-        JMenuItem deleteMenuItem = new JMenuItem("Delete Flexibility");
-        deleteMenuItem.addActionListener(clicked -> createDeleteDialog());
-        flex.add(deleteMenuItem);
-
-        this.setJMenuBar(menuBar);
-    }
-
 
 
-    private void createUsageViewPanel() {
-        JPanel panel = new JPanel(new GridBagLayout());
-        usageViewPanel = new JScrollPane(panel);
-        panel.setBackground(Color.white);
-        FlexState[] titles = FlexState.values();
-
-
-        for (int i = 0; i < 5; i++) {
-            final int titleIndex = i;
-            List<Flexibility> flexList = control.getModel().getAllFlexibilities();
-            List<Flexibility> listOfFlexWithState = flexList.stream().filter(flex -> flex.getState().equals(titles[titleIndex])).toList();
-            JLabel label = new JLabel(titles[i].toString() + "[" + listOfFlexWithState.size() + "]");
-            GridBagConstraints labelC = new GridBagConstraints();
-            labelC.gridx = 1;
-            labelC.gridy = i * 2;
-            labelC.anchor = GridBagConstraints.LINE_START;
-            labelC.fill = GridBagConstraints.HORIZONTAL;
-            labelC.weightx = 0.5;
-            labelC.weighty = 0.0;
-            panel.add(label, labelC);
-
-            JPanel listPanel = new JPanel(new GridBagLayout());
-            createFlexPanel(listPanel, listOfFlexWithState);
-            GridBagConstraints panelC = new GridBagConstraints();
-            panelC.gridx = 0;
-            panelC.gridwidth = 2;
-            panelC.gridy = i * 2 + 1;
-            panelC.fill = GridBagConstraints.BOTH;
-            panel.add(listPanel, panelC);
-
-
-            JButton expandButton = new JButton("-");
-            GridBagConstraints buttonC = new GridBagConstraints();
-            buttonC.gridx = 0;
-            buttonC.gridy = i * 2;
-            panel.add(expandButton, buttonC);
-            expandButton.addActionListener(clicked -> {
-                listPanel.setVisible(!listPanel.isVisible());
-                expandButton.setText(listPanel.isVisible() ? "-" : "+");
-            });
+  private final static int boxSideLength = 70;
+  private final JTabbedPane contentPanel = new JTabbedPane();
+  private final Control control;
+  //Flexibility Intermediate
+  private final Flexibility intermediateFlex = new Flexibility(null);
+  private final JPopupMenu menu = new JPopupMenu();
+  private final JMenuItem priorityItem = new JMenuItem("EditPriorities");
+  private final JMenuItem flexItem = new JMenuItem("AddFlex");
+  //Tabs
+  String gridTabString = "Grid";
+  String orderTabString = "Order";
+  private JPanel nothingSelectedPanel;
+  private JPanel selectedPanel;
+  private JScrollPane usageViewPanel;
+  private boolean offered = true, onConstrain = true, offConstrain = false;
+  //JTree
+  private DefaultMutableTreeNode listOfAllSelectedHolonObjects;
+  private JTree stateTree;
+  private DefaultTreeModel treeModel;
+  Runnable update = this::update;
+
+  public FlexWindow(JFrame parentFrame, Control control) {
+    this.intermediateFlex.name = "name";
+    this.control = control;
+    //InitWindow
+    createMenuBar();
+    initWindowPanel(parentFrame);
+    this.addWindowListener(
+        (WindowClosingListener) e -> control.OnCanvasUpdate.removeListener(update));
+    updateSelectedPanel();
+    control.OnCanvasUpdate.addListener(update);
+  }
+
+
+  private void initWindowPanel(JFrame parentFrame) {
+    this.setBounds(0, 0, 400,
+        parentFrame.getHeight() > 20 ? parentFrame.getHeight() - 20 : parentFrame.getHeight());
+    this.setIconImage(Import.loadImage(ImagePreference.Logo, 30, 30));
+    this.setTitle("Flexibility");
+    this.setLocationRelativeTo(parentFrame);
+    this.setVisible(true);
+    //this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
+    createNothingSelectedPanel();
+    createSelectedPanel();
+    createUsageViewPanel();
+    contentPanel.addTab(gridTabString, nothingSelectedPanel);
+    contentPanel.addTab(orderTabString, usageViewPanel);
+    contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
+    this.setContentPane(contentPanel);
+    this.revalidate();
+
+  }
+
+  private void createMenuBar() {
+    JMenuBar menuBar = new JMenuBar();
+    JMenu canvas = new JMenu("Canvas");
+    menuBar.add(canvas);
+    JMenuItem updateMenuItem = new JMenuItem("Update");
+    updateMenuItem.addActionListener(clicked -> updateSelectedPanel());
+    canvas.add(updateMenuItem);
+    JMenu flex = new JMenu("Flex");
+    menuBar.add(flex);
+    JMenuItem addMenuItem = new JMenuItem("Add Flexibility");
+    addMenuItem.addActionListener(clicked -> createAddDialog(null));
+    flex.add(addMenuItem);
+    JMenuItem deleteMenuItem = new JMenuItem("Delete Flexibility");
+    deleteMenuItem.addActionListener(clicked -> createDeleteDialog());
+    flex.add(deleteMenuItem);
+
+    this.setJMenuBar(menuBar);
+  }
+
+
+  private void createUsageViewPanel() {
+    JPanel panel = new JPanel(new GridBagLayout());
+    usageViewPanel = new JScrollPane(panel);
+    panel.setBackground(Color.white);
+    FlexState[] titles = FlexState.values();
+
+    for (int i = 0; i < 5; i++) {
+      final int titleIndex = i;
+      List<Flexibility> flexList = control.getModel().getAllFlexibilities();
+      List<Flexibility> listOfFlexWithState = flexList.stream()
+          .filter(flex -> flex.getState().equals(titles[titleIndex])).toList();
+      JLabel label = new JLabel(titles[i].toString() + "[" + listOfFlexWithState.size() + "]");
+      GridBagConstraints labelC = new GridBagConstraints();
+      labelC.gridx = 1;
+      labelC.gridy = i * 2;
+      labelC.anchor = GridBagConstraints.LINE_START;
+      labelC.fill = GridBagConstraints.HORIZONTAL;
+      labelC.weightx = 0.5;
+      labelC.weighty = 0.0;
+      panel.add(label, labelC);
+
+      JPanel listPanel = new JPanel(new GridBagLayout());
+      createFlexPanel(listPanel, listOfFlexWithState);
+      GridBagConstraints panelC = new GridBagConstraints();
+      panelC.gridx = 0;
+      panelC.gridwidth = 2;
+      panelC.gridy = i * 2 + 1;
+      panelC.fill = GridBagConstraints.BOTH;
+      panel.add(listPanel, panelC);
+
+      JButton expandButton = new JButton("-");
+      GridBagConstraints buttonC = new GridBagConstraints();
+      buttonC.gridx = 0;
+      buttonC.gridy = i * 2;
+      panel.add(expandButton, buttonC);
+      expandButton.addActionListener(clicked -> {
+        listPanel.setVisible(!listPanel.isVisible());
+        expandButton.setText(listPanel.isVisible() ? "-" : "+");
+      });
 
 
-        }
-        //Add Spacer
-        JLabel spacer = new JLabel();
-        GridBagConstraints c = new GridBagConstraints();
-        c.gridx = 0;
-        c.gridy = 5 * 2;
-        c.fill = GridBagConstraints.VERTICAL;
-        c.weightx = 0.0;
-        c.weighty = 1;
-        panel.add(spacer, c);
     }
     }
-
-
-    private void createFlexPanel(JPanel listPanel, List<Flexibility> flexList) {
-        listPanel.setBackground(Color.white);
-        Insets insets = new Insets(2, 2, 2, 2);
-        int panelWidth = Math.max(boxSideLength, this.getWidth() - 90);
-        int maxButtonsPerLine = panelWidth / boxSideLength;
-
-
-        int i = 0;
-        for (Flexibility flex : flexList) {
-            GridBagConstraints c = new GridBagConstraints();
-            c.gridx = Math.floorMod(i, maxButtonsPerLine);
-            c.weightx = 0.0;
-            c.insets = insets;
-            JButton labelButton = new JButton(flex.name);
-            labelButton.setPreferredSize(new Dimension(boxSideLength, boxSideLength));
-            labelButton.setBorder(BorderFactory.createLineBorder(Color.black));
-            listPanel.add(labelButton, c);
-            labelButton.addActionListener(clicked -> {
-                flex.order();
-                control.calculateStateForCurrentIteration();
-            });
-            labelButton.setToolTipText(createToolTip(flex));
-            i++;
-        }
-        //AddSpacer
-        JLabel spacer = new JLabel();
-        GridBagConstraints c = new GridBagConstraints();
-        c.gridx = maxButtonsPerLine;
-        c.gridy = 0;
-        c.fill = GridBagConstraints.VERTICAL;
-        c.weightx = 1;
-        c.weighty = 0;
-
-        listPanel.add(spacer, c);
-    }
-
-
-    private String createToolTip(Flexibility actual) {
-        return "<html>" +
-                "<b>" + actual.name + "( </b>" + actual.getElement().getName() + "<b> )</b><br>"
-                + ((actual.remainingDuration() != 0) ? "<i>Remaining Duration:" + actual.remainingDuration() + "</i><br>" : "")
-                + ((actual.remainingTimeTillActivation() != 0) ? "<i>Remaining TimeTillActivation:" + actual.remainingTimeTillActivation() + "</i><br>" : "")
-                + "Duration: " + actual.getDuration() + "<br>"
-                + "Cooldown: " + actual.getCooldown() + "<br>"
-                + "Cost: " + actual.cost + "<br>"
-                + "EnergyReleased: " + actual.energyReleased() + "<br>"
-                + "Constrains: " + actual.constrainList.stream().map(Constrain::getName).collect(Collectors.joining(",")) + "<br>"
-                + "</html>";
+    //Add Spacer
+    JLabel spacer = new JLabel();
+    GridBagConstraints c = new GridBagConstraints();
+    c.gridx = 0;
+    c.gridy = 5 * 2;
+    c.fill = GridBagConstraints.VERTICAL;
+    c.weightx = 0.0;
+    c.weighty = 1;
+    panel.add(spacer, c);
+  }
+
+
+  private void createFlexPanel(JPanel listPanel, List<Flexibility> flexList) {
+    listPanel.setBackground(Color.white);
+    Insets insets = new Insets(2, 2, 2, 2);
+    int panelWidth = Math.max(boxSideLength, this.getWidth() - 90);
+    int maxButtonsPerLine = panelWidth / boxSideLength;
+
+    int i = 0;
+    for (Flexibility flex : flexList) {
+      GridBagConstraints c = new GridBagConstraints();
+      c.gridx = Math.floorMod(i, maxButtonsPerLine);
+      c.weightx = 0.0;
+      c.insets = insets;
+      JButton labelButton = new JButton(flex.name);
+      labelButton.setPreferredSize(new Dimension(boxSideLength, boxSideLength));
+      labelButton.setBorder(BorderFactory.createLineBorder(Color.black));
+      listPanel.add(labelButton, c);
+      labelButton.addActionListener(clicked -> {
+        flex.order();
+        control.calculateStateForCurrentIteration();
+      });
+      labelButton.setToolTipText(createToolTip(flex));
+      i++;
     }
     }
-
-
-    public void update() {
-        updateSelectedPanel();
-        createUsageViewPanel();
-        contentPanel.setComponentAt(contentPanel.indexOfTab(orderTabString), usageViewPanel);
-        contentPanel.revalidate();
-    }
-
-
-    private void createSelectedPanel() {
-        listOfAllSelectedHolonObjects = new DefaultMutableTreeNode("HolonObjects");
-        treeModel = new DefaultTreeModel(listOfAllSelectedHolonObjects);
-        stateTree = new JTree(treeModel);
-		JPopupMenu menu = createPopUpMenu();
-
-
-		stateTree.addMouseListener(new MouseAdapter() {
-            public void mousePressed(MouseEvent e) {
-                if (SwingUtilities.isRightMouseButton(e)) {
-
-
-                    TreePath pathUnderCursor = stateTree.getPathForLocation(e.getX(), e.getY());
-                    Rectangle pathBounds = stateTree.getUI().getPathBounds(stateTree, pathUnderCursor);
-                    if (pathBounds != null && pathBounds.contains(e.getX(), e.getY())) {
-                        TreePath[] selectedPaths = stateTree.getSelectionPaths();
-                        if (selectedPaths == null) {
-                            stateTree.addSelectionPath(pathUnderCursor);
-                        } else {
-                            boolean isInSelectedPaths = false;
-                            for (TreePath path : stateTree.getSelectionPaths()) {
-                                if (path.equals(pathUnderCursor)) {
-                                    isInSelectedPaths = true;
-                                    break;
-                                }
-                            }
-                            if (!isInSelectedPaths) {
-                                stateTree.clearSelection();
-                                stateTree.addSelectionPath(pathUnderCursor);
-                            }
-                        }
-
-                        menu.show(stateTree, pathBounds.x, pathBounds.y + pathBounds.height);
-                    }
+    //AddSpacer
+    JLabel spacer = new JLabel();
+    GridBagConstraints c = new GridBagConstraints();
+    c.gridx = maxButtonsPerLine;
+    c.gridy = 0;
+    c.fill = GridBagConstraints.VERTICAL;
+    c.weightx = 1;
+    c.weighty = 0;
+
+    listPanel.add(spacer, c);
+  }
+
+
+  private String createToolTip(Flexibility actual) {
+    return "<html>" +
+        "<b>" + actual.name + "( </b>" + actual.getElement().getName() + "<b> )</b><br>"
+        + ((actual.remainingDuration() != 0) ? "<i>Remaining Duration:" + actual.remainingDuration()
+        + "</i><br>" : "")
+        + ((actual.remainingTimeTillActivation() != 0) ? "<i>Remaining TimeTillActivation:"
+        + actual.remainingTimeTillActivation() + "</i><br>" : "")
+        + "Duration: " + actual.getDuration() + "<br>"
+        + "Cooldown: " + actual.getCooldown() + "<br>"
+        + "Cost: " + actual.cost + "<br>"
+        + "EnergyReleased: " + actual.energyReleased() + "<br>"
+        + "Constrains: " + actual.constrainList.stream().map(Constrain::getName)
+        .collect(Collectors.joining(",")) + "<br>"
+        + "</html>";
+  }
+
+
+  public void update() {
+    updateSelectedPanel();
+    createUsageViewPanel();
+    contentPanel.setComponentAt(contentPanel.indexOfTab(orderTabString), usageViewPanel);
+    contentPanel.revalidate();
+  }
+
+
+  private void createSelectedPanel() {
+    listOfAllSelectedHolonObjects = new DefaultMutableTreeNode("HolonObjects");
+    treeModel = new DefaultTreeModel(listOfAllSelectedHolonObjects);
+    stateTree = new JTree(treeModel);
+    JPopupMenu menu = createPopUpMenu();
+
+    stateTree.addMouseListener(new MouseAdapter() {
+      public void mousePressed(MouseEvent e) {
+        if (SwingUtilities.isRightMouseButton(e)) {
+
+          TreePath pathUnderCursor = stateTree.getPathForLocation(e.getX(), e.getY());
+          Rectangle pathBounds = stateTree.getUI().getPathBounds(stateTree, pathUnderCursor);
+          if (pathBounds != null && pathBounds.contains(e.getX(), e.getY())) {
+            TreePath[] selectedPaths = stateTree.getSelectionPaths();
+            if (selectedPaths == null) {
+              stateTree.addSelectionPath(pathUnderCursor);
+            } else {
+              boolean isInSelectedPaths = false;
+              for (TreePath path : stateTree.getSelectionPaths()) {
+                if (path.equals(pathUnderCursor)) {
+                  isInSelectedPaths = true;
+                  break;
                 }
                 }
+              }
+              if (!isInSelectedPaths) {
+                stateTree.clearSelection();
+                stateTree.addSelectionPath(pathUnderCursor);
+              }
             }
             }
-        });
-        selectedPanel = new JPanel(new BorderLayout());
-        selectedPanel.add(new JScrollPane(stateTree));
-    }
 
 
-	private JPopupMenu createPopUpMenu() {
-		priorityItem.addActionListener(clicked -> getInfoFromSelection().ifPresent(eleInfo -> {
-			Priority priority = (Priority) JOptionPane.showInputDialog(stateTree,
-						"Select the Priority:", "Priority?", JOptionPane.INFORMATION_MESSAGE,
-						new ImageIcon(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)),
-						Priority.values(), "");
-			if (priority == null){
-				return;
-			}
-			eleInfo.ele.setPriority(priority);
-			control.updateStateForCurrentIteration();
-		}));
-		flexItem.addActionListener(clicked -> getInfoFromSelection().ifPresent(eleInfo -> createAddDialog(eleInfo.ele)));
-		menu.add(priorityItem);
-		menu.add(flexItem);
-		return menu;
-	}
-
-	private Optional<ElementInfo> getInfoFromSelection(){
-		TreePath path = stateTree.getSelectionPath();
-		if (path == null){
-			return Optional.empty();
-		}
-		Object userObject = ((DefaultMutableTreeNode) path.getLastPathComponent()).getUserObject();
-		if(userObject instanceof ElementInfo eleInfo){
-			return Optional.of(eleInfo);
-		}
-		return Optional.empty();
-	}
-
-
-
-	private void createNothingSelectedPanel() {
-        nothingSelectedPanel = new JPanel();
-        nothingSelectedPanel.setLayout(new BoxLayout(nothingSelectedPanel, BoxLayout.PAGE_AXIS));
-        JLabel nothingSelectedTextLabel = new JLabel("No HolonObject exist.");
-        nothingSelectedTextLabel.setForeground(Color.gray);
-        nothingSelectedTextLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
-        nothingSelectedPanel.add(Box.createVerticalGlue());
-        nothingSelectedPanel.add(nothingSelectedTextLabel);
-        nothingSelectedPanel.add(Box.createVerticalGlue());
+            menu.show(stateTree, pathBounds.x, pathBounds.y + pathBounds.height);
+          }
+        }
+      }
+    });
+    selectedPanel = new JPanel(new BorderLayout());
+    selectedPanel.add(new JScrollPane(stateTree));
+  }
+
+  private JPopupMenu createPopUpMenu() {
+    priorityItem.addActionListener(clicked -> getInfoFromSelection().ifPresent(eleInfo -> {
+      Priority priority = (Priority) JOptionPane.showInputDialog(stateTree,
+          "Select the Priority:", "Priority?", JOptionPane.INFORMATION_MESSAGE,
+          new ImageIcon(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)),
+          Priority.values(), "");
+      if (priority == null) {
+        return;
+      }
+      eleInfo.ele.setPriority(priority);
+      control.updateStateForCurrentIteration();
+    }));
+    flexItem.addActionListener(
+        clicked -> getInfoFromSelection().ifPresent(eleInfo -> createAddDialog(eleInfo.ele)));
+    menu.add(priorityItem);
+    menu.add(flexItem);
+    return menu;
+  }
+
+  private Optional<ElementInfo> getInfoFromSelection() {
+    TreePath path = stateTree.getSelectionPath();
+    if (path == null) {
+      return Optional.empty();
     }
     }
-
-    public void updateSelectedPanel() {
-        //Should not remove add so many Components
-
-        listOfAllSelectedHolonObjects.removeAllChildren();
-        //Init with HolonObjects
-        control.getModel().getCanvas().getObjectsInThisLayer().forEach(aCps -> {
-            DefaultMutableTreeNode newObjectChild = new DefaultMutableTreeNode(aCps.getName() + " ID:" + aCps.getId());
-            if (aCps instanceof HolonObject hO) expandTreeHolonObject(hO, newObjectChild);
-            if (aCps instanceof GroupNode groupnode) expandTreeUpperNode(groupnode, newObjectChild);
-            listOfAllSelectedHolonObjects.add(newObjectChild);
-        });
-        treeModel.nodeStructureChanged(listOfAllSelectedHolonObjects);
-
-        stateTree.revalidate();
-        expandAll(stateTree);
-        selectedPanel.revalidate();
-        contentPanel.setComponentAt(contentPanel.indexOfTab(gridTabString), selectedPanel);
-        contentPanel.revalidate();
-        this.revalidate();
+    Object userObject = ((DefaultMutableTreeNode) path.getLastPathComponent()).getUserObject();
+    if (userObject instanceof ElementInfo eleInfo) {
+      return Optional.of(eleInfo);
     }
     }
-
-
-    private void expandAll(JTree tree) {
-        for (int i = 0; i < tree.getRowCount(); i++) {
-            tree.expandRow(i);
-        }
-
+    return Optional.empty();
+  }
+
+
+  private void createNothingSelectedPanel() {
+    nothingSelectedPanel = new JPanel();
+    nothingSelectedPanel.setLayout(new BoxLayout(nothingSelectedPanel, BoxLayout.PAGE_AXIS));
+    JLabel nothingSelectedTextLabel = new JLabel("No HolonObject exist.");
+    nothingSelectedTextLabel.setForeground(Color.gray);
+    nothingSelectedTextLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
+    nothingSelectedPanel.add(Box.createVerticalGlue());
+    nothingSelectedPanel.add(nothingSelectedTextLabel);
+    nothingSelectedPanel.add(Box.createVerticalGlue());
+  }
+
+  public void updateSelectedPanel() {
+    //Should not remove add so many Components
+
+    listOfAllSelectedHolonObjects.removeAllChildren();
+    //Init with HolonObjects
+    control.getModel().getCanvas().getObjectsInThisLayer().forEach(aCps -> {
+      DefaultMutableTreeNode newObjectChild = new DefaultMutableTreeNode(
+          aCps.getName() + " ID:" + aCps.getId());
+      if (aCps instanceof HolonObject hO) {
+        expandTreeHolonObject(hO, newObjectChild);
+      }
+      if (aCps instanceof GroupNode groupnode) {
+        expandTreeUpperNode(groupnode, newObjectChild);
+      }
+      listOfAllSelectedHolonObjects.add(newObjectChild);
+    });
+    treeModel.nodeStructureChanged(listOfAllSelectedHolonObjects);
+
+    stateTree.revalidate();
+    expandAll(stateTree);
+    selectedPanel.revalidate();
+    contentPanel.setComponentAt(contentPanel.indexOfTab(gridTabString), selectedPanel);
+    contentPanel.revalidate();
+    this.revalidate();
+  }
+
+
+  private void expandAll(JTree tree) {
+    for (int i = 0; i < tree.getRowCount(); i++) {
+      tree.expandRow(i);
     }
     }
 
 
-
-    private void expandTreeUpperNode(GroupNode groupNode, DefaultMutableTreeNode root) {
-        groupNode.getHolonObjects().forEach(object -> {
-            DefaultMutableTreeNode newObjectChild = new DefaultMutableTreeNode(object.getName() + " ID:" + object.getId());
-            root.add(newObjectChild);
-        });
-        groupNode.getGroupNodes().forEach(childGroupNode -> {
-            DefaultMutableTreeNode newObjectChild = new DefaultMutableTreeNode(childGroupNode.getName() + " ID:" + childGroupNode.getId());
-            expandTreeUpperNode(childGroupNode, newObjectChild);
-            root.add(newObjectChild);
-        });
+  }
+
+
+  private void expandTreeUpperNode(GroupNode groupNode, DefaultMutableTreeNode root) {
+    groupNode.getHolonObjects().forEach(object -> {
+      DefaultMutableTreeNode newObjectChild = new DefaultMutableTreeNode(
+          object.getName() + " ID:" + object.getId());
+      root.add(newObjectChild);
+    });
+    groupNode.getGroupNodes().forEach(childGroupNode -> {
+      DefaultMutableTreeNode newObjectChild = new DefaultMutableTreeNode(
+          childGroupNode.getName() + " ID:" + childGroupNode.getId());
+      expandTreeUpperNode(childGroupNode, newObjectChild);
+      root.add(newObjectChild);
+    });
+  }
+
+
+  private void expandTreeHolonObject(HolonObject hObject, DefaultMutableTreeNode root) {
+    hObject.elementsStream().forEach(hE -> {
+      DefaultMutableTreeNode newChild = new DefaultMutableTreeNode(new ElementInfo(hE));
+      expandTreeFlex(hE, newChild);
+      root.add(newChild);
+    });
+  }
+
+  private void expandTreeFlex(HolonElement hElement, DefaultMutableTreeNode root) {
+    for (Flexibility flex : hElement.flexList) {
+      String flexState;
+      Color color = ColorPreference.Flexibility.getStateColor(flex.getState());
+      flexState = "<font bgcolor='#" + Integer.toHexString(color.getRGB()).substring(2) + "'>"
+          + flex.getState().name() + "</font>";
+      DefaultMutableTreeNode newChild = new DefaultMutableTreeNode(
+          "<html>" + flexState + " <b>" + flex.name + "</b>" + "</html>");
+      root.add(newChild);
     }
     }
+  }
 
 
 
 
-    private void expandTreeHolonObject(HolonObject hObject, DefaultMutableTreeNode root) {
-        hObject.elementsStream().forEach(hE -> {
-            DefaultMutableTreeNode newChild = new DefaultMutableTreeNode(new ElementInfo(hE));
-            expandTreeFlex(hE, newChild);
-            root.add(newChild);
-        });
+  private void createDeleteDialog() {
+    Object[] allFlexes = control.getModel().getAllFlexibilities().toArray();
+    if (allFlexes.length == 0) {
+      JOptionPane.showMessageDialog(this,
+          "No Flexibility exist.",
+          "Warning",
+          JOptionPane.WARNING_MESSAGE);
+      return;
     }
     }
 
 
-    private void expandTreeFlex(HolonElement hElement, DefaultMutableTreeNode root) {
-        for (Flexibility flex : hElement.flexList) {
-            String flexState;
-            Color color = ColorPreference.Flexibility.getStateColor(flex.getState());
-            flexState = "<font bgcolor='#" + Integer.toHexString(color.getRGB()).substring(2) + "'>" + flex.getState().name() + "</font>";
-            DefaultMutableTreeNode newChild = new DefaultMutableTreeNode("<html>" + flexState + " <b>" + flex.name + "</b>" + "</html>");
-            root.add(newChild);
-        }
+    Flexibility toDeleteFlex = (Flexibility) JOptionPane.showInputDialog(this,
+        "Select to Delete Flexibility:", "Flexibility?", JOptionPane.INFORMATION_MESSAGE,
+        new ImageIcon(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)), allFlexes, "");
+    if (toDeleteFlex != null) {
+      toDeleteFlex.getElement().flexList.remove(toDeleteFlex);
+      control.calculateStateForCurrentIteration();
+      updateSelectedPanel();
     }
     }
+  }
 
 
 
 
-    private void createDeleteDialog() {
-        Object[] allFlexes = control.getModel().getAllFlexibilities().toArray();
-        if (allFlexes.length == 0) {
-            JOptionPane.showMessageDialog(this,
-                    "No Flexibility exist.",
-                    "Warning",
-                    JOptionPane.WARNING_MESSAGE);
-            return;
-        }
-
-        Flexibility toDeleteFlex = (Flexibility) JOptionPane.showInputDialog(this, "Select to Delete Flexibility:", "Flexibility?", JOptionPane.INFORMATION_MESSAGE, new ImageIcon(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)), allFlexes, "");
-        if (toDeleteFlex != null) {
-            toDeleteFlex.getElement().flexList.remove(toDeleteFlex);
-            control.calculateStateForCurrentIteration();
-            updateSelectedPanel();
-        }
+  //Add Element
+  private void createAddDialog(HolonElement element) {
+    if (control.getModel().getCanvas().getAllHolonObjectsRecursive().findAny().isEmpty()) {
+      JOptionPane.showMessageDialog(this,
+          "No HolonObject exist.",
+          "Warning",
+          JOptionPane.WARNING_MESSAGE);
+      return;
     }
     }
-
-
-    //Add Element
-    private void createAddDialog(HolonElement element) {
-        if (control.getModel().getCanvas().getAllHolonObjectsRecursive().findAny().isEmpty()) {
-            JOptionPane.showMessageDialog(this,
-                    "No HolonObject exist.",
-                    "Warning",
-                    JOptionPane.WARNING_MESSAGE);
-            return;
-        }
-        JDialog addDialog = new JDialog();
-        addDialog.setTitle("Create Flexibility");
-        addDialog.setBounds(0, 0, 820, 400);
-        addDialog.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
-        JPanel dialogPanel = new JPanel(new BorderLayout());
-        addDialog.setContentPane(dialogPanel);
-        JPanel selectionPanel = new JPanel(null);
-        dialogPanel.add(selectionPanel, BorderLayout.CENTER);
-        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
-        dialogPanel.add(buttonPanel, BorderLayout.PAGE_END);
-
-
-        addDialog.setModalityType(ModalityType.APPLICATION_MODAL);
-
-
-        //Create HolonObject selection Box
-        HolonObject[] holonObjects = control.getModel().getCanvas().getAllHolonObjectsRecursive().toArray(HolonObject[]::new);
-
-        DefaultComboBoxModel<HolonObject> comboBoxModel = new DefaultComboBoxModel<>(holonObjects);
-
-
-        JComboBox<HolonObject> holonObjectSelector = new JComboBox<>(comboBoxModel);
-        holonObjectSelector.setBounds(10, 30, 800, 30);
-
-        DefaultComboBoxModel<HolonElement> comboBoxModelElements = new DefaultComboBoxModel<>(holonObjects[0].elementsStream().toArray(HolonElement[]::new));
-        JComboBox<HolonElement> holonElementSelector = new JComboBox<>(comboBoxModelElements);
-        holonElementSelector.setBounds(10, 80, 800, 30);
-
-
-        holonObjectSelector.addItemListener(aListener -> {
-            if (aListener.getStateChange() == ItemEvent.SELECTED) {
-                DefaultComboBoxModel<HolonElement> newComboBoxModelElements = new DefaultComboBoxModel<>(((HolonObject) aListener.getItem()).elementsStream().toArray(HolonElement[]::new));
-                holonElementSelector.setModel(newComboBoxModelElements);
-            }
-        });
-
-        if (element == null) {
-            selectionPanel.add(holonObjectSelector);
-            selectionPanel.add(holonElementSelector);
-            JLabel selectObjectLabel = new JLabel("Select HolonObject:");
-            selectObjectLabel.setBounds(10, 10, 200, 20);
-            selectionPanel.add(selectObjectLabel);
-            JLabel selectElementLabel = new JLabel("Select HolonElement:");
-            selectElementLabel.setBounds(10, 60, 200, 20);
-            selectionPanel.add(selectElementLabel);
-        } else {
-            JLabel selectElementLabel = new JLabel("Selected: " + element);
-            selectElementLabel.setBounds(10, 60, 2000, 20);
-            selectionPanel.add(selectElementLabel);
-        }
-
-
-        JPanel flexAttributesBorderPanel = new JPanel(null);
-        flexAttributesBorderPanel.setBounds(10, 120, 800, 200);
-        flexAttributesBorderPanel.setBorder(BorderFactory.createTitledBorder("Flexibility Attributes"));
-        selectionPanel.add(flexAttributesBorderPanel);
-        JLabel flexNameLabel = new JLabel("Name:");
-        flexNameLabel.setBounds(10, 20, 50, 20);
-        flexAttributesBorderPanel.add(flexNameLabel);
-        JFormattedTextField nameTextField = new JFormattedTextField(intermediateFlex.name);
-        nameTextField.addPropertyChangeListener(changed -> intermediateFlex.name = nameTextField.getText());
-        nameTextField.setBounds(80, 15, 200, 30);
-        flexAttributesBorderPanel.add(nameTextField);
-        JLabel flexSpeedLabel = new JLabel("Speed:");
-        flexSpeedLabel.setBounds(10, 55, 50, 20);
-        flexAttributesBorderPanel.add(flexSpeedLabel);
-        //Integer formatter
-        NumberFormat format = NumberFormat.getIntegerInstance();
-        format.setGroupingUsed(false);
-        format.setParseIntegerOnly(true);
-        NumberFormatter integerFormatter = new NumberFormatter(format);
-        integerFormatter.setMinimum(0);
-        integerFormatter.setCommitsOnValidEdit(true);
-
-
-        JFormattedTextField speedTextField = new JFormattedTextField(integerFormatter);
-        speedTextField.setValue(intermediateFlex.speed);
-        speedTextField.setToolTipText("Only positive Integer.");
-        speedTextField.addPropertyChangeListener(actionEvent -> intermediateFlex.speed = Integer.parseInt(speedTextField.getValue().toString()));
-        speedTextField.setBounds(80, 50, 200, 30);
-        flexAttributesBorderPanel.add(speedTextField);
-        speedTextField.setEnabled(false);
-
-        JLabel flexDurationLabel = new JLabel("Duration:");
-        flexDurationLabel.setBounds(10, 90, 70, 20);
-        flexAttributesBorderPanel.add(flexDurationLabel);
-
-
-        NumberFormatter moreThenZeroIntegerFormatter = new NumberFormatter(format);
-        moreThenZeroIntegerFormatter.setMinimum(1);
-        moreThenZeroIntegerFormatter.setCommitsOnValidEdit(true);
-
-        JFormattedTextField durationTextField = new JFormattedTextField(moreThenZeroIntegerFormatter);
-        durationTextField.setValue(intermediateFlex.getDuration());
-        durationTextField.setToolTipText("Only positive Integer bigger then 0.");
-        durationTextField.addPropertyChangeListener(actionEvent -> intermediateFlex.setDuration(Integer.parseInt(durationTextField.getValue().toString())));
-        durationTextField.setBounds(80, 85, 200, 30);
-        flexAttributesBorderPanel.add(durationTextField);
-
-        JLabel flexCostsLabel = new JLabel("Costs:");
-        flexCostsLabel.setBounds(10, 125, 70, 20);
-        flexAttributesBorderPanel.add(flexCostsLabel);
-
-        //Double Format:
-        NumberFormat doubleFormat = NumberFormat.getNumberInstance(Locale.US);
-        doubleFormat.setMinimumFractionDigits(1);
-        doubleFormat.setMaximumFractionDigits(2);
-        doubleFormat.setRoundingMode(RoundingMode.HALF_UP);
-
-        //CostFormatter:
-        NumberFormatter costsFormatter = new NumberFormatter(doubleFormat);
-        costsFormatter.setMinimum(0.0);
-
-        JFormattedTextField costTextField = new JFormattedTextField(costsFormatter);
-        costTextField.setValue(intermediateFlex.cost);
-        costTextField.setToolTipText("Only non negative Double with DecimalSeparator Point('.').");
-        costTextField.addPropertyChangeListener(propertyChange -> intermediateFlex.cost = Float.parseFloat(costTextField.getValue().toString()));
-        costTextField.setBounds(80, 120, 200, 30);
-        flexAttributesBorderPanel.add(costTextField);
-
-
-        JLabel flexCooldownLabel = new JLabel("Cooldown:");
-        flexCooldownLabel.setBounds(310, 20, 70, 20);
-        flexAttributesBorderPanel.add(flexCooldownLabel);
-
-
-        JFormattedTextField cooldownTextField = new JFormattedTextField(moreThenZeroIntegerFormatter);
-        cooldownTextField.setValue(intermediateFlex.getCooldown());
-        cooldownTextField.setToolTipText("Only positive Integer.");
-        cooldownTextField.addPropertyChangeListener(actionEvent -> intermediateFlex.setCooldown(Integer.parseInt(cooldownTextField.getValue().toString())));
-        cooldownTextField.setBounds(380, 15, 200, 30);
-        flexAttributesBorderPanel.add(cooldownTextField);
-
-        JCheckBox offeredCheckBox = new JCheckBox("Offered");
-        offeredCheckBox.setSelected(this.offered);
-        offeredCheckBox.setBounds(310, 55, 200, 20);
-        flexAttributesBorderPanel.add(offeredCheckBox);
-
-        JCheckBox onConstrainCheckBox = new JCheckBox("On_Constrain");
-        onConstrainCheckBox.setSelected(this.onConstrain);
-        onConstrainCheckBox.setBounds(310, 80, 200, 20);
-        flexAttributesBorderPanel.add(onConstrainCheckBox);
-
-        JCheckBox offConstrainCheckBox = new JCheckBox("Off_Constrain");
-        offConstrainCheckBox.setSelected(this.offConstrain);
-        offConstrainCheckBox.setBounds(310, 105, 200, 20);
-        flexAttributesBorderPanel.add(offConstrainCheckBox);
-
-
-        //Both cant be true....
-        onConstrainCheckBox.addActionListener(clicked -> {
-            if (onConstrainCheckBox.isSelected()) offConstrainCheckBox.setSelected(false);
-        });
-        offConstrainCheckBox.addActionListener(clicked -> {
-            if (offConstrainCheckBox.isSelected()) onConstrainCheckBox.setSelected(false);
-        });
-
-        JButton createFlexButton = new JButton("Create");
-        createFlexButton.addActionListener(clicked -> {
-            HolonElement ele;
-            if (element == null) {
-                ele = (HolonElement) holonElementSelector.getSelectedItem();
-            } else {
-                ele = element;
-            }
-            Flexibility toCreateFlex = new Flexibility(ele);
-            toCreateFlex.name = intermediateFlex.name;
-            toCreateFlex.speed = intermediateFlex.speed;
-            toCreateFlex.setDuration(intermediateFlex.getDuration());
-            toCreateFlex.cost = intermediateFlex.cost;
-            toCreateFlex.setCooldown(intermediateFlex.getCooldown());
-            toCreateFlex.offered = offeredCheckBox.isSelected();
-            if (onConstrainCheckBox.isSelected()) toCreateFlex.constrainList.add(Constrain.createOnConstrain());
-            if (offConstrainCheckBox.isSelected()) toCreateFlex.constrainList.add(Constrain.createOffConstrain());
-
-            assert ele != null;
-            ele.flexList.add(toCreateFlex);
-            //save checkboxes
-            this.offered = offeredCheckBox.isSelected();
-            this.onConstrain = onConstrainCheckBox.isSelected();
-            this.offConstrain = offConstrainCheckBox.isSelected();
-
-
-            control.updateStateForCurrentIteration();
-            addDialog.dispose();
-        });
-        buttonPanel.add(createFlexButton);
-        JButton cancelButton = new JButton("Cancel");
-        cancelButton.addActionListener(clicked -> addDialog.dispose());
-        buttonPanel.add(cancelButton);
-
-
-        //last
-        addDialog.setLocationRelativeTo(this);
-        addDialog.setVisible(true);
+    JDialog addDialog = new JDialog();
+    addDialog.setTitle("Create Flexibility");
+    addDialog.setBounds(0, 0, 820, 400);
+    addDialog.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
+    JPanel dialogPanel = new JPanel(new BorderLayout());
+    addDialog.setContentPane(dialogPanel);
+    JPanel selectionPanel = new JPanel(null);
+    dialogPanel.add(selectionPanel, BorderLayout.CENTER);
+    JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+    dialogPanel.add(buttonPanel, BorderLayout.PAGE_END);
+
+    addDialog.setModalityType(ModalityType.APPLICATION_MODAL);
+
+    //Create HolonObject selection Box
+    HolonObject[] holonObjects = control.getModel().getCanvas().getAllHolonObjectsRecursive()
+        .toArray(HolonObject[]::new);
+
+    DefaultComboBoxModel<HolonObject> comboBoxModel = new DefaultComboBoxModel<>(holonObjects);
+
+    JComboBox<HolonObject> holonObjectSelector = new JComboBox<>(comboBoxModel);
+    holonObjectSelector.setBounds(10, 30, 800, 30);
+
+    DefaultComboBoxModel<HolonElement> comboBoxModelElements = new DefaultComboBoxModel<>(
+        holonObjects[0].elementsStream().toArray(HolonElement[]::new));
+    JComboBox<HolonElement> holonElementSelector = new JComboBox<>(comboBoxModelElements);
+    holonElementSelector.setBounds(10, 80, 800, 30);
+
+    holonObjectSelector.addItemListener(aListener -> {
+      if (aListener.getStateChange() == ItemEvent.SELECTED) {
+        DefaultComboBoxModel<HolonElement> newComboBoxModelElements = new DefaultComboBoxModel<>(
+            ((HolonObject) aListener.getItem()).elementsStream().toArray(HolonElement[]::new));
+        holonElementSelector.setModel(newComboBoxModelElements);
+      }
+    });
+
+    if (element == null) {
+      selectionPanel.add(holonObjectSelector);
+      selectionPanel.add(holonElementSelector);
+      JLabel selectObjectLabel = new JLabel("Select HolonObject:");
+      selectObjectLabel.setBounds(10, 10, 200, 20);
+      selectionPanel.add(selectObjectLabel);
+      JLabel selectElementLabel = new JLabel("Select HolonElement:");
+      selectElementLabel.setBounds(10, 60, 200, 20);
+      selectionPanel.add(selectElementLabel);
+    } else {
+      JLabel selectElementLabel = new JLabel("Selected: " + element);
+      selectElementLabel.setBounds(10, 60, 2000, 20);
+      selectionPanel.add(selectElementLabel);
     }
     }
 
 
+    JPanel flexAttributesBorderPanel = new JPanel(null);
+    flexAttributesBorderPanel.setBounds(10, 120, 800, 200);
+    flexAttributesBorderPanel.setBorder(BorderFactory.createTitledBorder("Flexibility Attributes"));
+    selectionPanel.add(flexAttributesBorderPanel);
+    JLabel flexNameLabel = new JLabel("Name:");
+    flexNameLabel.setBounds(10, 20, 50, 20);
+    flexAttributesBorderPanel.add(flexNameLabel);
+    JFormattedTextField nameTextField = new JFormattedTextField(intermediateFlex.name);
+    nameTextField.addPropertyChangeListener(
+        changed -> intermediateFlex.name = nameTextField.getText());
+    nameTextField.setBounds(80, 15, 200, 30);
+    flexAttributesBorderPanel.add(nameTextField);
+    JLabel flexSpeedLabel = new JLabel("Speed:");
+    flexSpeedLabel.setBounds(10, 55, 50, 20);
+    flexAttributesBorderPanel.add(flexSpeedLabel);
+    //Integer formatter
+    NumberFormat format = NumberFormat.getIntegerInstance();
+    format.setGroupingUsed(false);
+    format.setParseIntegerOnly(true);
+    NumberFormatter integerFormatter = new NumberFormatter(format);
+    integerFormatter.setMinimum(0);
+    integerFormatter.setCommitsOnValidEdit(true);
+
+    JFormattedTextField speedTextField = new JFormattedTextField(integerFormatter);
+    speedTextField.setValue(intermediateFlex.speed);
+    speedTextField.setToolTipText("Only positive Integer.");
+    speedTextField.addPropertyChangeListener(
+        actionEvent -> intermediateFlex.speed = Integer.parseInt(
+            speedTextField.getValue().toString()));
+    speedTextField.setBounds(80, 50, 200, 30);
+    flexAttributesBorderPanel.add(speedTextField);
+    speedTextField.setEnabled(false);
+
+    JLabel flexDurationLabel = new JLabel("Duration:");
+    flexDurationLabel.setBounds(10, 90, 70, 20);
+    flexAttributesBorderPanel.add(flexDurationLabel);
+
+    NumberFormatter moreThenZeroIntegerFormatter = new NumberFormatter(format);
+    moreThenZeroIntegerFormatter.setMinimum(1);
+    moreThenZeroIntegerFormatter.setCommitsOnValidEdit(true);
+
+    JFormattedTextField durationTextField = new JFormattedTextField(moreThenZeroIntegerFormatter);
+    durationTextField.setValue(intermediateFlex.getDuration());
+    durationTextField.setToolTipText("Only positive Integer bigger then 0.");
+    durationTextField.addPropertyChangeListener(actionEvent -> intermediateFlex.setDuration(
+        Integer.parseInt(durationTextField.getValue().toString())));
+    durationTextField.setBounds(80, 85, 200, 30);
+    flexAttributesBorderPanel.add(durationTextField);
+
+    JLabel flexCostsLabel = new JLabel("Costs:");
+    flexCostsLabel.setBounds(10, 125, 70, 20);
+    flexAttributesBorderPanel.add(flexCostsLabel);
+
+    //Double Format:
+    NumberFormat doubleFormat = NumberFormat.getNumberInstance(Locale.US);
+    doubleFormat.setMinimumFractionDigits(1);
+    doubleFormat.setMaximumFractionDigits(2);
+    doubleFormat.setRoundingMode(RoundingMode.HALF_UP);
+
+    //CostFormatter:
+    NumberFormatter costsFormatter = new NumberFormatter(doubleFormat);
+    costsFormatter.setMinimum(0.0);
+
+    JFormattedTextField costTextField = new JFormattedTextField(costsFormatter);
+    costTextField.setValue(intermediateFlex.cost);
+    costTextField.setToolTipText("Only non negative Double with DecimalSeparator Point('.').");
+    costTextField.addPropertyChangeListener(
+        propertyChange -> intermediateFlex.cost = Float.parseFloat(
+            costTextField.getValue().toString()));
+    costTextField.setBounds(80, 120, 200, 30);
+    flexAttributesBorderPanel.add(costTextField);
+
+    JLabel flexCooldownLabel = new JLabel("Cooldown:");
+    flexCooldownLabel.setBounds(310, 20, 70, 20);
+    flexAttributesBorderPanel.add(flexCooldownLabel);
+
+    JFormattedTextField cooldownTextField = new JFormattedTextField(moreThenZeroIntegerFormatter);
+    cooldownTextField.setValue(intermediateFlex.getCooldown());
+    cooldownTextField.setToolTipText("Only positive Integer.");
+    cooldownTextField.addPropertyChangeListener(actionEvent -> intermediateFlex.setCooldown(
+        Integer.parseInt(cooldownTextField.getValue().toString())));
+    cooldownTextField.setBounds(380, 15, 200, 30);
+    flexAttributesBorderPanel.add(cooldownTextField);
+
+    JCheckBox offeredCheckBox = new JCheckBox("Offered");
+    offeredCheckBox.setSelected(this.offered);
+    offeredCheckBox.setBounds(310, 55, 200, 20);
+    flexAttributesBorderPanel.add(offeredCheckBox);
+
+    JCheckBox onConstrainCheckBox = new JCheckBox("On_Constrain");
+    onConstrainCheckBox.setSelected(this.onConstrain);
+    onConstrainCheckBox.setBounds(310, 80, 200, 20);
+    flexAttributesBorderPanel.add(onConstrainCheckBox);
+
+    JCheckBox offConstrainCheckBox = new JCheckBox("Off_Constrain");
+    offConstrainCheckBox.setSelected(this.offConstrain);
+    offConstrainCheckBox.setBounds(310, 105, 200, 20);
+    flexAttributesBorderPanel.add(offConstrainCheckBox);
+
+    //Both cant be true....
+    onConstrainCheckBox.addActionListener(clicked -> {
+      if (onConstrainCheckBox.isSelected()) {
+        offConstrainCheckBox.setSelected(false);
+      }
+    });
+    offConstrainCheckBox.addActionListener(clicked -> {
+      if (offConstrainCheckBox.isSelected()) {
+        onConstrainCheckBox.setSelected(false);
+      }
+    });
+
+    JButton createFlexButton = new JButton("Create");
+    createFlexButton.addActionListener(clicked -> {
+      HolonElement ele;
+      if (element == null) {
+        ele = (HolonElement) holonElementSelector.getSelectedItem();
+      } else {
+        ele = element;
+      }
+      Flexibility toCreateFlex = new Flexibility(ele);
+      toCreateFlex.name = intermediateFlex.name;
+      toCreateFlex.speed = intermediateFlex.speed;
+      toCreateFlex.setDuration(intermediateFlex.getDuration());
+      toCreateFlex.cost = intermediateFlex.cost;
+      toCreateFlex.setCooldown(intermediateFlex.getCooldown());
+      toCreateFlex.offered = offeredCheckBox.isSelected();
+      if (onConstrainCheckBox.isSelected()) {
+        toCreateFlex.constrainList.add(Constrain.createOnConstrain());
+      }
+      if (offConstrainCheckBox.isSelected()) {
+        toCreateFlex.constrainList.add(Constrain.createOffConstrain());
+      }
+
+      assert ele != null;
+      ele.flexList.add(toCreateFlex);
+      //save checkboxes
+      this.offered = offeredCheckBox.isSelected();
+      this.onConstrain = onConstrainCheckBox.isSelected();
+      this.offConstrain = offConstrainCheckBox.isSelected();
+
+      control.updateStateForCurrentIteration();
+      addDialog.dispose();
+    });
+    buttonPanel.add(createFlexButton);
+    JButton cancelButton = new JButton("Cancel");
+    cancelButton.addActionListener(clicked -> addDialog.dispose());
+    buttonPanel.add(cancelButton);
+
+    //last
+    addDialog.setLocationRelativeTo(this);
+    addDialog.setVisible(true);
+  }
+
+
+  static class ElementInfo {
+
+    HolonElement ele;
+
+    public ElementInfo(HolonElement ele) {
+      this.ele = ele;
+    }
 
 
-    static class ElementInfo {
-        HolonElement ele;
-
-        public ElementInfo(HolonElement ele) {
-            this.ele = ele;
-        }
-
-        @Override
-        public String toString() {
-            return ele.getName() + " Priority:" + ele.getPriority();
-        }
+    @Override
+    public String toString() {
+      return ele.getName() + " Priority:" + ele.getPriority();
     }
     }
+  }
 
 
 
 
 }
 }

+ 169 - 158
src/holeg/ui/view/window/Outliner.java

@@ -10,169 +10,180 @@ import holeg.ui.controller.Control;
 import holeg.ui.view.image.Import;
 import holeg.ui.view.image.Import;
 import holeg.utility.listener.WindowClosingListener;
 import holeg.utility.listener.WindowClosingListener;
 import holeg.utility.math.decimal.Format;
 import holeg.utility.math.decimal.Format;
-
-import javax.swing.*;
-import javax.swing.tree.DefaultMutableTreeNode;
-import javax.swing.tree.DefaultTreeCellRenderer;
-import java.awt.*;
+import java.awt.BorderLayout;
+import java.awt.Color;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
 import java.util.stream.Stream;
 import java.util.stream.Stream;
+import javax.swing.ImageIcon;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTabbedPane;
+import javax.swing.JTree;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeCellRenderer;
 
 
 public class Outliner extends JFrame {
 public class Outliner extends JFrame {
-	private static final Logger log = Logger.getLogger(Outliner.class.getName());
-	private final Control control;
-	JTabbedPane tabbedPane = new JTabbedPane();
-	JPanel hierarchyPanel = new JPanel(new BorderLayout());
-	JPanel holonPanel = new JPanel(new BorderLayout());
-	Runnable update = this::update;
-
-	private static final String ConsumptionFontHTMLBracket = "<font bgcolor='#"
-			+ Integer.toHexString(ColorPreference.Energy.Consumption.getRGB()).substring(2) + "'>";
-	private static final String ProductionFontHTMLBracket = "<font bgcolor='#"
-			+ Integer.toHexString(ColorPreference.Energy.Production.getRGB()).substring(2) + "'>";
-	private static final String FontClosingBracket = "</font> ";
-
-	private static final String ProducerNodeText = getColoredHtmlText(ColorPreference.HolonObject.Producer, "Producer");
-	private static final String OverSuppliedNodeText = getColoredHtmlText(ColorPreference.HolonObject.OverSupplied, "Over supplied");
-	private static final String SuppliedNodeText = getColoredHtmlText(ColorPreference.HolonObject.Supplied, "Supplied");
-	private static final String PartiallySuppliedNodeText = getColoredHtmlText(ColorPreference.HolonObject.PartiallySupplied, "Partially supplied");
-	private static final String NotSuppliedNodeText = getColoredHtmlText(ColorPreference.HolonObject.NotSupplied, "Not supplied");
-	private static final String NoEnergyNodeText = getColoredHtmlText(ColorPreference.HolonObject.NoEnergy, "No energy");
-
-	private static String getColoredHtmlText(Color color, String text){
-		return "<html><font bgcolor='#"
-				+ Integer.toHexString(color.getRGB()).substring(2) + "'>" +
-				text + FontClosingBracket;
-	}
-
-
-
-
-	public Outliner(JFrame parentFrame, Control control) {
-		setBounds(0, 0, 400, parentFrame.getHeight());
-		this.setIconImage(Import.loadImage(ImagePreference.Logo, 30, 30));
-		this.setTitle("Outliner");
-		setLocationRelativeTo(parentFrame);
-		this.setVisible(true);
-		this.control = control;
-		update();
-		this.getContentPane().add(tabbedPane);
-		this.addWindowListener((WindowClosingListener) e -> control.OnCanvasUpdate.removeListener(update));
-		control.OnCanvasUpdate.addListener(update);
-		tabbedPane.addTab("Hierarchy", hierarchyPanel);
-		tabbedPane.addTab("Holons", holonPanel);
-	}
-
-	public void update() {
-		hierarchyPanel.removeAll();
-		holonPanel.removeAll();
-		DefaultMutableTreeNode topListPanel = new DefaultMutableTreeNode();
-		DefaultMutableTreeNode objects = new DefaultMutableTreeNode("HolonObjects");
-		DefaultMutableTreeNode switches = new DefaultMutableTreeNode("Switches");
-		DefaultMutableTreeNode nodes = new DefaultMutableTreeNode("Nodes");
-		DefaultMutableTreeNode cables = new DefaultMutableTreeNode("Cable");
-		topListPanel.add(objects);
-		topListPanel.add(switches);
-		topListPanel.add(nodes);
-		topListPanel.add(cables);
-		DefaultMutableTreeNode topHolonNode = createHolonNode();
-		DefaultMutableTreeNode topHierarchyNode = createHierarchyNode();
-
-		JTree hierarchyTree = new JTree(topHierarchyNode);
-		signIconsForTree(hierarchyTree);
-		hierarchyTree.setRootVisible(false);
-		for (int i = 0; i < hierarchyTree.getRowCount(); i++) {
-			hierarchyTree.expandRow(i);
-		}
-		hierarchyPanel.add(new JScrollPane(hierarchyTree));
-
-		JTree holonTree = new JTree(topHolonNode);
-		signIconsForTree(holonTree);
-		holonTree.setRootVisible(false);
-		for (int i = 0; i < holonTree.getRowCount(); i++) {
-			holonTree.expandRow(i);
-		}
-		holonPanel.add(new JScrollPane(holonTree));
-
-		holonPanel.revalidate();
-		hierarchyPanel.repaint();
-	}
-
-	private DefaultMutableTreeNode createHolonNode() {
-		DefaultMutableTreeNode topHolonNode = new DefaultMutableTreeNode();
-		for (Holon holon : control.getModel().holons) {
-			DefaultMutableTreeNode holonNode = new DefaultMutableTreeNode("Holon");
-			DefaultMutableTreeNode producer = new DefaultMutableTreeNode(ProducerNodeText);
-			DefaultMutableTreeNode overSupplied = new DefaultMutableTreeNode(OverSuppliedNodeText);
-			DefaultMutableTreeNode supplied = new DefaultMutableTreeNode(SuppliedNodeText);
-			DefaultMutableTreeNode partiallySupplied = new DefaultMutableTreeNode(PartiallySuppliedNodeText);
-			DefaultMutableTreeNode notSupplied = new DefaultMutableTreeNode(NotSuppliedNodeText);
-			DefaultMutableTreeNode noEnergy = new DefaultMutableTreeNode(NoEnergyNodeText);
-
-			for(HolonObject hObject : holon.holonObjects){
-				DefaultMutableTreeNode holonObjectNode = createColoredTreeNodeFromHolonObject(hObject);
-				switch(hObject.getState()){
-					case PRODUCER -> producer.add(holonObjectNode);
-					case OVER_SUPPLIED -> overSupplied.add(holonObjectNode);
-					case SUPPLIED -> supplied.add(holonObjectNode);
-					case PARTIALLY_SUPPLIED -> partiallySupplied.add(holonObjectNode);
-					case NOT_SUPPLIED -> notSupplied.add(holonObjectNode);
-					case NO_ENERGY -> noEnergy.add(holonObjectNode);
-				}
-			}
-			Stream.of(producer, overSupplied, supplied, partiallySupplied, notSupplied, noEnergy)
-					.filter(node -> !node.isLeaf()).forEach(holonNode::add);
-			topHolonNode.add(holonNode);
-		}
-		return topHolonNode;
-	}
-	private DefaultMutableTreeNode createHierarchyNode() {
-		DefaultMutableTreeNode hierarchyNode = new DefaultMutableTreeNode();
-		hierarchyNode.add(getNodeFromGroupNode(control.getModel().getCanvas()));
-		DefaultMutableTreeNode edgeNode = new DefaultMutableTreeNode("Edges");
-		control.getModel().getEdgesOnCanvas().forEach(edge -> {
-			edgeNode.add(new DefaultMutableTreeNode(edge.toString()));
-		});
-		hierarchyNode.add(edgeNode);
-		return hierarchyNode;
-	}
-	private DefaultMutableTreeNode getNodeFromGroupNode(GroupNode groupNode){
-		DefaultMutableTreeNode node = new DefaultMutableTreeNode(groupNode.getName());
-		groupNode.getHolonObjects().forEach(obj -> node.add(canvasObjectToNode(obj)));
-		groupNode.getSwitches().forEach(obj -> node.add(canvasObjectToNode(obj)));
-		groupNode.getNodes().forEach(obj -> node.add(canvasObjectToNode(obj)));
-		groupNode.getGroupNodes().forEach(obj -> node.add(getNodeFromGroupNode(obj)));
-		return node;
-	}
-
-	private DefaultMutableTreeNode canvasObjectToNode(AbstractCanvasObject obj) {
-		return new DefaultMutableTreeNode(obj.getName() + " [" + obj.getId()+"]");
-	}
-
-
-
-
-
-	private void signIconsForTree(JTree t) {
-		ImageIcon ClosedIcon = new ImageIcon(Import.loadImage(ImagePreference.Button.Outliner.Closed, 9, 9));
-		ImageIcon OpenIcon = new ImageIcon(Import.loadImage(ImagePreference.Button.Outliner.Open, 9, 9));
-		ImageIcon LeafIcon = new ImageIcon(Import.loadImage(ImagePreference.Button.Outliner.Leaf, 9, 9));
-		DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
-		renderer.setClosedIcon(ClosedIcon);
-		renderer.setOpenIcon(OpenIcon);
-		renderer.setLeafIcon(LeafIcon);
-		t.setCellRenderer(renderer);
-	}
-
-
-	private DefaultMutableTreeNode createColoredTreeNodeFromHolonObject(HolonObject obj){
-		float energy = obj.getActualEnergy();
-		String context = "<html>" + obj.getName() + "&nbsp;&nbsp;&nbsp;&nbsp;"
-				+ (obj.isConsumer()? ConsumptionFontHTMLBracket : ProductionFontHTMLBracket ) + Format.doubleTwoPlaces(energy) + FontClosingBracket
-				+ "</html>";
-		return new DefaultMutableTreeNode(context);
-	}
 
 
+  private static final Logger log = Logger.getLogger(Outliner.class.getName());
+  private static final String ConsumptionFontHTMLBracket = "<font bgcolor='#"
+      + Integer.toHexString(ColorPreference.Energy.Consumption.getRGB()).substring(2) + "'>";
+  private static final String ProductionFontHTMLBracket = "<font bgcolor='#"
+      + Integer.toHexString(ColorPreference.Energy.Production.getRGB()).substring(2) + "'>";
+  private static final String FontClosingBracket = "</font> ";
+  private static final String ProducerNodeText = getColoredHtmlText(
+      ColorPreference.HolonObject.Producer, "Producer");
+  private static final String OverSuppliedNodeText = getColoredHtmlText(
+      ColorPreference.HolonObject.OverSupplied, "Over supplied");
+  private static final String SuppliedNodeText = getColoredHtmlText(
+      ColorPreference.HolonObject.Supplied, "Supplied");
+  private static final String PartiallySuppliedNodeText = getColoredHtmlText(
+      ColorPreference.HolonObject.PartiallySupplied, "Partially supplied");
+  private static final String NotSuppliedNodeText = getColoredHtmlText(
+      ColorPreference.HolonObject.NotSupplied, "Not supplied");
+  private static final String NoEnergyNodeText = getColoredHtmlText(
+      ColorPreference.HolonObject.NoEnergy, "No energy");
+  private final Control control;
+  JTabbedPane tabbedPane = new JTabbedPane();
+  JPanel hierarchyPanel = new JPanel(new BorderLayout());
+  JPanel holonPanel = new JPanel(new BorderLayout());
+  Runnable update = this::update;
+
+  public Outliner(JFrame parentFrame, Control control) {
+    setBounds(0, 0, 400, parentFrame.getHeight());
+    this.setIconImage(Import.loadImage(ImagePreference.Logo, 30, 30));
+    this.setTitle("Outliner");
+    setLocationRelativeTo(parentFrame);
+    this.setVisible(true);
+    this.control = control;
+    update();
+    this.getContentPane().add(tabbedPane);
+    this.addWindowListener(
+        (WindowClosingListener) e -> control.OnCanvasUpdate.removeListener(update));
+    control.OnCanvasUpdate.addListener(update);
+    tabbedPane.addTab("Hierarchy", hierarchyPanel);
+    tabbedPane.addTab("Holons", holonPanel);
+  }
+
+  private static String getColoredHtmlText(Color color, String text) {
+    return "<html><font bgcolor='#"
+        + Integer.toHexString(color.getRGB()).substring(2) + "'>" +
+        text + FontClosingBracket;
+  }
+
+  public void update() {
+    hierarchyPanel.removeAll();
+    holonPanel.removeAll();
+    DefaultMutableTreeNode topListPanel = new DefaultMutableTreeNode();
+    DefaultMutableTreeNode objects = new DefaultMutableTreeNode("HolonObjects");
+    DefaultMutableTreeNode switches = new DefaultMutableTreeNode("Switches");
+    DefaultMutableTreeNode nodes = new DefaultMutableTreeNode("Nodes");
+    DefaultMutableTreeNode cables = new DefaultMutableTreeNode("Cable");
+    topListPanel.add(objects);
+    topListPanel.add(switches);
+    topListPanel.add(nodes);
+    topListPanel.add(cables);
+    DefaultMutableTreeNode topHolonNode = createHolonNode();
+    DefaultMutableTreeNode topHierarchyNode = createHierarchyNode();
+
+    JTree hierarchyTree = new JTree(topHierarchyNode);
+    signIconsForTree(hierarchyTree);
+    hierarchyTree.setRootVisible(false);
+    for (int i = 0; i < hierarchyTree.getRowCount(); i++) {
+      hierarchyTree.expandRow(i);
+    }
+    hierarchyPanel.add(new JScrollPane(hierarchyTree));
+
+    JTree holonTree = new JTree(topHolonNode);
+    signIconsForTree(holonTree);
+    holonTree.setRootVisible(false);
+    for (int i = 0; i < holonTree.getRowCount(); i++) {
+      holonTree.expandRow(i);
+    }
+    holonPanel.add(new JScrollPane(holonTree));
+
+    holonPanel.revalidate();
+    hierarchyPanel.repaint();
+  }
+
+  private DefaultMutableTreeNode createHolonNode() {
+    DefaultMutableTreeNode topHolonNode = new DefaultMutableTreeNode();
+    for (Holon holon : control.getModel().holons) {
+      DefaultMutableTreeNode holonNode = new DefaultMutableTreeNode("Holon");
+      DefaultMutableTreeNode producer = new DefaultMutableTreeNode(ProducerNodeText);
+      DefaultMutableTreeNode overSupplied = new DefaultMutableTreeNode(OverSuppliedNodeText);
+      DefaultMutableTreeNode supplied = new DefaultMutableTreeNode(SuppliedNodeText);
+      DefaultMutableTreeNode partiallySupplied = new DefaultMutableTreeNode(
+          PartiallySuppliedNodeText);
+      DefaultMutableTreeNode notSupplied = new DefaultMutableTreeNode(NotSuppliedNodeText);
+      DefaultMutableTreeNode noEnergy = new DefaultMutableTreeNode(NoEnergyNodeText);
+
+      for (HolonObject hObject : holon.holonObjects) {
+        DefaultMutableTreeNode holonObjectNode = createColoredTreeNodeFromHolonObject(hObject);
+        switch (hObject.getState()) {
+          case PRODUCER -> producer.add(holonObjectNode);
+          case OVER_SUPPLIED -> overSupplied.add(holonObjectNode);
+          case SUPPLIED -> supplied.add(holonObjectNode);
+          case PARTIALLY_SUPPLIED -> partiallySupplied.add(holonObjectNode);
+          case NOT_SUPPLIED -> notSupplied.add(holonObjectNode);
+          case NO_ENERGY -> noEnergy.add(holonObjectNode);
+        }
+      }
+      Stream.of(producer, overSupplied, supplied, partiallySupplied, notSupplied, noEnergy)
+          .filter(node -> !node.isLeaf()).forEach(holonNode::add);
+      topHolonNode.add(holonNode);
+    }
+    return topHolonNode;
+  }
+
+  private DefaultMutableTreeNode createHierarchyNode() {
+    DefaultMutableTreeNode hierarchyNode = new DefaultMutableTreeNode();
+    hierarchyNode.add(getNodeFromGroupNode(control.getModel().getCanvas()));
+    DefaultMutableTreeNode edgeNode = new DefaultMutableTreeNode("Edges");
+    control.getModel().getEdgesOnCanvas().forEach(edge -> {
+      edgeNode.add(new DefaultMutableTreeNode(edge.toString()));
+    });
+    hierarchyNode.add(edgeNode);
+    return hierarchyNode;
+  }
+
+  private DefaultMutableTreeNode getNodeFromGroupNode(GroupNode groupNode) {
+    DefaultMutableTreeNode node = new DefaultMutableTreeNode(groupNode.getName());
+    groupNode.getHolonObjects().forEach(obj -> node.add(canvasObjectToNode(obj)));
+    groupNode.getSwitches().forEach(obj -> node.add(canvasObjectToNode(obj)));
+    groupNode.getNodes().forEach(obj -> node.add(canvasObjectToNode(obj)));
+    groupNode.getGroupNodes().forEach(obj -> node.add(getNodeFromGroupNode(obj)));
+    return node;
+  }
+
+  private DefaultMutableTreeNode canvasObjectToNode(AbstractCanvasObject obj) {
+    return new DefaultMutableTreeNode(obj.getName() + " [" + obj.getId() + "]");
+  }
+
+
+  private void signIconsForTree(JTree t) {
+    ImageIcon ClosedIcon = new ImageIcon(
+        Import.loadImage(ImagePreference.Button.Outliner.Closed, 9, 9));
+    ImageIcon OpenIcon = new ImageIcon(
+        Import.loadImage(ImagePreference.Button.Outliner.Open, 9, 9));
+    ImageIcon LeafIcon = new ImageIcon(
+        Import.loadImage(ImagePreference.Button.Outliner.Leaf, 9, 9));
+    DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
+    renderer.setClosedIcon(ClosedIcon);
+    renderer.setOpenIcon(OpenIcon);
+    renderer.setLeafIcon(LeafIcon);
+    t.setCellRenderer(renderer);
+  }
+
+
+  private DefaultMutableTreeNode createColoredTreeNodeFromHolonObject(HolonObject obj) {
+    float energy = obj.getActualEnergy();
+    String context = "<html>" + obj.getName() + "&nbsp;&nbsp;&nbsp;&nbsp;"
+        + (obj.isConsumer() ? ConsumptionFontHTMLBracket : ProductionFontHTMLBracket)
+        + Format.doubleTwoPlaces(energy) + FontClosingBracket
+        + "</html>";
+    return new DefaultMutableTreeNode(context);
+  }
 
 
 
 
 }
 }

+ 12 - 11
src/holeg/utility/events/Action.java

@@ -5,17 +5,18 @@ import java.util.Set;
 import java.util.function.Consumer;
 import java.util.function.Consumer;
 
 
 public class Action<T> {
 public class Action<T> {
-    private final Set<Consumer<T>> listeners = new HashSet<Consumer<T>>();
 
 
-    public void addListener(Consumer<T> listener) {
-        listeners.add(listener);
-    }
+  private final Set<Consumer<T>> listeners = new HashSet<Consumer<T>>();
 
 
-    public void removeListener(Consumer<T> listener) {
-    	listeners.remove(listener);
-    }
-    
-    public void broadcast(T argument) {
-    	listeners.forEach(x -> x.accept(argument));
-    }
+  public void addListener(Consumer<T> listener) {
+    listeners.add(listener);
+  }
+
+  public void removeListener(Consumer<T> listener) {
+    listeners.remove(listener);
+  }
+
+  public void broadcast(T argument) {
+    listeners.forEach(x -> x.accept(argument));
+  }
 }
 }

+ 14 - 11
src/holeg/utility/events/Event.java

@@ -1,18 +1,21 @@
 package holeg.utility.events;
 package holeg.utility.events;
+
 import java.util.HashSet;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.Set;
 
 
 public class Event {
 public class Event {
-    private final Set<Runnable> listeners = new HashSet<Runnable>();
-    public void addListener(Runnable listener) {
-        listeners.add(listener);
-    }
 
 
-    public void broadcast() {
-        listeners.forEach(Runnable::run);
-    }
-    
-    public void removeListener(Runnable listener) {
-    	listeners.remove(listener);
-    }
+  private final Set<Runnable> listeners = new HashSet<Runnable>();
+
+  public void addListener(Runnable listener) {
+    listeners.add(listener);
+  }
+
+  public void broadcast() {
+    listeners.forEach(Runnable::run);
+  }
+
+  public void removeListener(Runnable listener) {
+    listeners.remove(listener);
+  }
 }
 }

+ 8 - 7
src/holeg/utility/listener/LostFocusListener.java

@@ -5,12 +5,13 @@ import java.awt.event.FocusListener;
 
 
 @FunctionalInterface
 @FunctionalInterface
 public interface LostFocusListener extends FocusListener {
 public interface LostFocusListener extends FocusListener {
-	void update(FocusEvent e);
-	
-	default void focusGained(FocusEvent e) {
-	}
 
 
-	default void focusLost(FocusEvent e) {
-		update(e);
-	}
+  void update(FocusEvent e);
+
+  default void focusGained(FocusEvent e) {
+  }
+
+  default void focusLost(FocusEvent e) {
+    update(e);
+  }
 }
 }

+ 16 - 8
src/holeg/utility/listener/ResizeListener.java

@@ -4,12 +4,20 @@ import java.awt.event.ComponentEvent;
 import java.awt.event.ComponentListener;
 import java.awt.event.ComponentListener;
 
 
 @FunctionalInterface
 @FunctionalInterface
-public interface ResizeListener extends ComponentListener{
-	void update(ComponentEvent e); 
-	default void componentResized(ComponentEvent e) {
-		update(e);
-	}
-	default void componentMoved(ComponentEvent e) {}
-	default void componentHidden(ComponentEvent e) {}
-	default void componentShown(ComponentEvent e) {}
+public interface ResizeListener extends ComponentListener {
+
+  void update(ComponentEvent e);
+
+  default void componentResized(ComponentEvent e) {
+    update(e);
+  }
+
+  default void componentMoved(ComponentEvent e) {
+  }
+
+  default void componentHidden(ComponentEvent e) {
+  }
+
+  default void componentShown(ComponentEvent e) {
+  }
 }
 }

+ 17 - 14
src/holeg/utility/listener/SimpleDocumentListener.java

@@ -5,20 +5,23 @@ import javax.swing.event.DocumentListener;
 
 
 @FunctionalInterface
 @FunctionalInterface
 public interface SimpleDocumentListener extends DocumentListener {
 public interface SimpleDocumentListener extends DocumentListener {
-    void update(DocumentEvent e);
-
-    @Override
-    default void insertUpdate(DocumentEvent e) {
-        update(e);
-    }
-    @Override
-    default void removeUpdate(DocumentEvent e) {
-        update(e);
-    }
-    @Override
-    default void changedUpdate(DocumentEvent e) {
-        update(e);
-    }
+
+  void update(DocumentEvent e);
+
+  @Override
+  default void insertUpdate(DocumentEvent e) {
+    update(e);
+  }
+
+  @Override
+  default void removeUpdate(DocumentEvent e) {
+    update(e);
+  }
+
+  @Override
+  default void changedUpdate(DocumentEvent e) {
+    update(e);
+  }
 }
 }
 
 
 
 

+ 34 - 25
src/holeg/utility/listener/WindowClosingListener.java

@@ -1,31 +1,40 @@
 package holeg.utility.listener;
 package holeg.utility.listener;
-import java.awt.event.WindowListener;
+
 import java.awt.event.WindowEvent;
 import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
 
 
 @FunctionalInterface
 @FunctionalInterface
 public interface WindowClosingListener extends WindowListener {
 public interface WindowClosingListener extends WindowListener {
-	void update(WindowEvent e);
-	@Override
-	default void windowOpened(WindowEvent e) {
-	}
-	@Override
-	default void windowClosing(WindowEvent e) {
-		update(e);
-	}
-	@Override
-	default void windowClosed(WindowEvent e) {
-	}
-	@Override
-	default void windowIconified(WindowEvent e) {
-	}
-	@Override
-	default void windowDeiconified(WindowEvent e) {
-	}
-	@Override
-	default void windowActivated(WindowEvent e) {
-	}
-	@Override
-	default void windowDeactivated(WindowEvent e) {
-	}
-	
+
+  void update(WindowEvent e);
+
+  @Override
+  default void windowOpened(WindowEvent e) {
+  }
+
+  @Override
+  default void windowClosing(WindowEvent e) {
+    update(e);
+  }
+
+  @Override
+  default void windowClosed(WindowEvent e) {
+  }
+
+  @Override
+  default void windowIconified(WindowEvent e) {
+  }
+
+  @Override
+  default void windowDeiconified(WindowEvent e) {
+  }
+
+  @Override
+  default void windowActivated(WindowEvent e) {
+  }
+
+  @Override
+  default void windowDeactivated(WindowEvent e) {
+  }
+
 }
 }

+ 41 - 32
src/holeg/utility/math/Maths.java

@@ -1,37 +1,46 @@
 package holeg.utility.math;
 package holeg.utility.math;
 
 
 public class Maths {
 public class Maths {
-	public final static double EPSILON = 1E-6;
-	
-	/**
-	 * Linear Interpolation from first to second via alpha amount.
-	 * @param first
-	 * @param second
-	 * @param alpha
-	 * @return
-	 */
-	public static double lerp(double first, double second, double alpha) {
-		return first * (1.0 - alpha) + second * alpha;
-	}
-	/**
-	 * Inverse Linear Interpolation from min to max to get the corresponding alpha from value.
-	 * @param min
-	 * @param max
-	 * @param value
-	 * @return
-	 */
-	public static double invLerp(double min, double max, double value) {
-		if (Math.abs(max - min) < EPSILON) return max;
-		else return (value - min) / (max - min);
-	}
 
 
-	public static int Clamp(int value, int min, int max){
-		return Math.max(min, Math.min(max, value));
-	}
-	public static float Clamp(float value, float min, float max){
-		return Math.max(min, Math.min(max, value));
-	}
-	public static double Clamp(double value, double min, double max){
-		return Math.max(min, Math.min(max, value));
-	}
+  public final static double EPSILON = 1E-6;
+
+  /**
+   * Linear Interpolation from first to second via alpha amount.
+   *
+   * @param first
+   * @param second
+   * @param alpha
+   * @return
+   */
+  public static double lerp(double first, double second, double alpha) {
+    return first * (1.0 - alpha) + second * alpha;
+  }
+
+  /**
+   * Inverse Linear Interpolation from min to max to get the corresponding alpha from value.
+   *
+   * @param min
+   * @param max
+   * @param value
+   * @return
+   */
+  public static double invLerp(double min, double max, double value) {
+    if (Math.abs(max - min) < EPSILON) {
+      return max;
+    } else {
+      return (value - min) / (max - min);
+    }
+  }
+
+  public static int Clamp(int value, int min, int max) {
+    return Math.max(min, Math.min(max, value));
+  }
+
+  public static float Clamp(float value, float min, float max) {
+    return Math.max(min, Math.min(max, value));
+  }
+
+  public static double Clamp(double value, double min, double max) {
+    return Math.max(min, Math.min(max, value));
+  }
 }
 }

+ 76 - 70
src/holeg/utility/math/Random.java

@@ -1,77 +1,83 @@
 package holeg.utility.math;
 package holeg.utility.math;
 
 
 
 
+public class Random {
 
 
 
 
+  private static java.util.Random random = new java.util.Random();
 
 
-public class Random {
-		
-		
-		private static java.util.Random random = new java.util.Random();
-	
-		/**
-		 * True or false
-		 * @return the random boolean.
-		 */
-		public static boolean nextBoolean(){
-			return random.nextBoolean();
-		}
-		/**
-		 * Between 0.0(inclusive) and 1.0 (exclusive)
-		 * @return the random double.
-		 */
-		public static double nextDouble() {
-			return random.nextDouble();
-		}
-		
-		public static float nextFloatInRange(float min, float max) {
-			return min + random.nextFloat() * Math.abs(max - min);
-		}
-		/**
-		 * Returns the next pseudorandom, Gaussian ("normally") distributed double value with mean
-		 * and standard deviation from this random number generator's sequence. 
-		 * @param mean
-		 * @param deviation
-		 * @return
-		 */
-		public static double nextGaussian(double mean, double deviation) {
-			return mean + random.nextGaussian() * deviation;
-		}
-		public static double nextDoubleInRange(double min, double max) {
-			return min + random.nextDouble() * Math.abs(max - min);
-		}
-		
-		/**
-		 * Random Int in Range [min;max[ with UniformDistirbution
-		 * @param min
-		 * @param max
-		 * @return
-		 */
-		public static int nextIntegerInRange(int min, int max) {
-			return min + random.nextInt(max - min);
-		}
-		/**
-		 * Random Int in Range [min;max[ with UniformDistirbution
-		 * @param min
-		 * @param max
-		 * @param valueBetween a value between min and max
-		 * @return
-		 */
-		public static int nextIntegerInRangeExcept(int min, int max,int valueBetween) {
-			int result = min;
-			if(max - min == 1) {
-				//return the other value
-				return (valueBetween == min)? max:min;
-			}
-			try {
-				result = min + random.nextInt((max - 1) - min);
-				if(result >= valueBetween) {
-					result++;
-				}
-			}catch(java.lang.IllegalArgumentException e){
-				System.err.println("min : " + min + " max : " + max + " valueBetween:" + valueBetween);
-				System.err.println("Except max should be more then min");
-			}
-			return result;
-		}
+  /**
+   * True or false
+   *
+   * @return the random boolean.
+   */
+  public static boolean nextBoolean() {
+    return random.nextBoolean();
+  }
+
+  /**
+   * Between 0.0(inclusive) and 1.0 (exclusive)
+   *
+   * @return the random double.
+   */
+  public static double nextDouble() {
+    return random.nextDouble();
+  }
+
+  public static float nextFloatInRange(float min, float max) {
+    return min + random.nextFloat() * Math.abs(max - min);
+  }
+
+  /**
+   * Returns the next pseudorandom, Gaussian ("normally") distributed double value with mean and
+   * standard deviation from this random number generator's sequence.
+   *
+   * @param mean
+   * @param deviation
+   * @return
+   */
+  public static double nextGaussian(double mean, double deviation) {
+    return mean + random.nextGaussian() * deviation;
+  }
+
+  public static double nextDoubleInRange(double min, double max) {
+    return min + random.nextDouble() * Math.abs(max - min);
+  }
+
+  /**
+   * Random Int in Range [min;max[ with UniformDistirbution
+   *
+   * @param min
+   * @param max
+   * @return
+   */
+  public static int nextIntegerInRange(int min, int max) {
+    return min + random.nextInt(max - min);
+  }
+
+  /**
+   * Random Int in Range [min;max[ with UniformDistirbution
+   *
+   * @param min
+   * @param max
+   * @param valueBetween a value between min and max
+   * @return
+   */
+  public static int nextIntegerInRangeExcept(int min, int max, int valueBetween) {
+    int result = min;
+    if (max - min == 1) {
+      //return the other value
+      return (valueBetween == min) ? max : min;
+    }
+    try {
+      result = min + random.nextInt((max - 1) - min);
+      if (result >= valueBetween) {
+        result++;
+      }
+    } catch (java.lang.IllegalArgumentException e) {
+      System.err.println("min : " + min + " max : " + max + " valueBetween:" + valueBetween);
+      System.err.println("Except max should be more then min");
+    }
+    return result;
+  }
 }
 }

+ 26 - 25
src/holeg/utility/math/decimal/Format.java

@@ -6,29 +6,30 @@ import java.text.NumberFormat;
 import java.util.Locale;
 import java.util.Locale;
 
 
 public class Format {
 public class Format {
-	
-	private static DecimalFormat formatter;
-	private static DecimalFormat twoFormatter;
-	
-	static {
-		NumberFormat nf = NumberFormat.getNumberInstance(Locale.US);
-		formatter = (DecimalFormat) nf;
-		formatter.applyPattern("#.###########");
-		formatter.setRoundingMode(RoundingMode.UP);
-		
-		twoFormatter = (DecimalFormat) nf;
-		twoFormatter.applyPattern("#.##");
-		twoFormatter.setRoundingMode(RoundingMode.UP);
-	}
-	public static String doubleFixedPlaces(int places, double value) {
-		return String.format(Locale.US, "%." +  places  + "f", value);
-	}
-	
-	public static String doubleTwoPlaces(double value) {
-		return twoFormatter.format(value);
-	}
-	
-	public static String doubleAllPlaces(double value) {
-		return formatter.format(value);
-	}
+
+  private static DecimalFormat formatter;
+  private static DecimalFormat twoFormatter;
+
+  static {
+    NumberFormat nf = NumberFormat.getNumberInstance(Locale.US);
+    formatter = (DecimalFormat) nf;
+    formatter.applyPattern("#.###########");
+    formatter.setRoundingMode(RoundingMode.UP);
+
+    twoFormatter = (DecimalFormat) nf;
+    twoFormatter.applyPattern("#.##");
+    twoFormatter.setRoundingMode(RoundingMode.UP);
+  }
+
+  public static String doubleFixedPlaces(int places, double value) {
+    return String.format(Locale.US, "%." + places + "f", value);
+  }
+
+  public static String doubleTwoPlaces(double value) {
+    return twoFormatter.format(value);
+  }
+
+  public static String doubleAllPlaces(double value) {
+    return formatter.format(value);
+  }
 }
 }

+ 56 - 40
src/holeg/utility/math/decimal/Sampler.java

@@ -2,46 +2,62 @@ package holeg.utility.math.decimal;
 
 
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
+
 //To sample floats and get basic statistical values;
 //To sample floats and get basic statistical values;
 public class Sampler {
 public class Sampler {
-	public class SampleInfo{
-		public String parameterName;
-		public int sampleSize = 0;
-		public float min = Float.MAX_VALUE;
-		public float max = Float.MIN_VALUE;
-		private float sum = 0;
-		public float getAvg() {
-			if(sampleSize > 0)
-				return sum / (float)sampleSize;
-			return 0;
-		}
-		public void addSample(float sample) {
-			if(sample < min) min = sample;
-			if(sample > max) max = sample;
-			sum += sample;
-			sampleSize++;
-		}
-		public String toString() {
-			return "[" + parameterName + " in Range(" + min + ", " + max + ") with a Average of " + getAvg() + " from "+ sampleSize + " Smaples]"; 
-		}
-	}
-	public HashMap<String, SampleInfo> logMap = new HashMap<String, SampleInfo>();
-	public void addSample(String parameterName, float sample) {
-		//Puts the sample in the right LogInfo container or create a new container if not exist jet
-		if(logMap.containsKey(parameterName)) {
-			SampleInfo info = logMap.get(parameterName);
-			info.addSample(sample);
-		}else {
-			SampleInfo info = new SampleInfo();
-			info.parameterName = parameterName;
-			info.addSample(sample);
-			logMap.put(parameterName, info);
-		}
-	}
-	public String toString() {
-		return logMap.values().stream().map(Object::toString).collect(Collectors.joining("\n"));
-	}
-	public void clear() {
-		logMap.clear();
-	}
+
+  public HashMap<String, SampleInfo> logMap = new HashMap<String, SampleInfo>();
+
+  public void addSample(String parameterName, float sample) {
+    //Puts the sample in the right LogInfo container or create a new container if not exist jet
+    if (logMap.containsKey(parameterName)) {
+      SampleInfo info = logMap.get(parameterName);
+      info.addSample(sample);
+    } else {
+      SampleInfo info = new SampleInfo();
+      info.parameterName = parameterName;
+      info.addSample(sample);
+      logMap.put(parameterName, info);
+    }
+  }
+
+  public String toString() {
+    return logMap.values().stream().map(Object::toString).collect(Collectors.joining("\n"));
+  }
+
+  public void clear() {
+    logMap.clear();
+  }
+
+  public class SampleInfo {
+
+    public String parameterName;
+    public int sampleSize = 0;
+    public float min = Float.MAX_VALUE;
+    public float max = Float.MIN_VALUE;
+    private float sum = 0;
+
+    public float getAvg() {
+      if (sampleSize > 0) {
+        return sum / (float) sampleSize;
+      }
+      return 0;
+    }
+
+    public void addSample(float sample) {
+      if (sample < min) {
+        min = sample;
+      }
+      if (sample > max) {
+        max = sample;
+      }
+      sum += sample;
+      sampleSize++;
+    }
+
+    public String toString() {
+      return "[" + parameterName + " in Range(" + min + ", " + max + ") with a Average of "
+          + getAvg() + " from " + sampleSize + " Smaples]";
+    }
+  }
 }
 }

Some files were not shown because too many files changed in this diff