commit 710124faff71463553fa57286419af60c8088340
Author: Ondřej Váně <onry.vane@gmail.com>
Date:   Thu Jul 29 17:55:18 2021 +0200

    #2 Implement check of used vs. set parameters
    
    - added functionality that checks if the thresholds have changed
    - if the thresholds have changed, the user is informed
    - added button for recalculation values

diff --git a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/controller/AppController.java b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/controller/AppController.java
index 946b861..94d5789 100644
--- a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/controller/AppController.java
+++ b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/controller/AppController.java
@@ -4,6 +4,7 @@ package cz.zcu.fav.kiv.antipatterndetectionapp.controller;
 import cz.zcu.fav.kiv.antipatterndetectionapp.detecting.AntiPatternManager;
 import cz.zcu.fav.kiv.antipatterndetectionapp.model.AntiPattern;
 import cz.zcu.fav.kiv.antipatterndetectionapp.model.Query;
+import cz.zcu.fav.kiv.antipatterndetectionapp.model.QueryResult;
 import cz.zcu.fav.kiv.antipatterndetectionapp.service.AntiPatternService;
 import cz.zcu.fav.kiv.antipatterndetectionapp.service.ProjectService;
 import org.slf4j.Logger;
@@ -14,6 +15,8 @@ import org.springframework.ui.Model;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.servlet.mvc.support.RedirectAttributes;
 
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
 import java.util.List;
 
 @Controller
@@ -74,8 +77,47 @@ public class AppController {
             return "index";
         }
 
-        model.addAttribute("queryResults", antiPatternManager.analyze(selectedProjects, selectedAntiPatterns));
+        List<QueryResult> results = antiPatternManager.analyze(selectedProjects, selectedAntiPatterns);
+        antiPatternService.saveAnalyzedProjects(selectedProjects, selectedAntiPatterns);
+        antiPatternService.saveResults(results);
+        antiPatternService.setConfigurationChanged(false);
 
+        model.addAttribute("queryResults", results);
+        model.addAttribute("recalculationTime", DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalTime.now()));
+
+        return "result";
+    }
+
+
+    @GetMapping("/analyze")
+    public String analyzeGet(Model model) {
+        if (antiPatternService.isConfigurationChanged()) {
+            model.addAttribute("isConfigurationChanged", true);
+        }
+        antiPatternService.setConfigurationChanged(false);
+
+        model.addAttribute("queryResults", antiPatternService.getResults());
+        model.addAttribute("recalculationTime", DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalTime.now()));
+
+        return "result";
+    }
+
+    @GetMapping("/recalculate")
+    public String recalculateGet(Model model) {
+        return analyzeGet(model);
+    }
+
+    @PostMapping("/recalculate")
+    public String resultRecalculate(Model model) {
+
+        List<QueryResult> results = antiPatternManager.analyze(antiPatternService.getAnalyzedProjects(),
+                antiPatternService.getAnalyzedAntiPatterns());
+
+        antiPatternService.saveResults(results);
+        antiPatternService.setConfigurationChanged(false);
+
+        model.addAttribute("queryResults", results);
+        model.addAttribute("recalculationTime", DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalTime.now()));
         return "result";
     }
 
diff --git a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/detecting/AntiPatternManager.java b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/detecting/AntiPatternManager.java
index 25f5e2f..6703733 100644
--- a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/detecting/AntiPatternManager.java
+++ b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/detecting/AntiPatternManager.java
@@ -1,7 +1,6 @@
 package cz.zcu.fav.kiv.antipatterndetectionapp.detecting;
 
 
-import cz.zcu.fav.kiv.antipatterndetectionapp.model.Query;
 import cz.zcu.fav.kiv.antipatterndetectionapp.model.QueryResult;
 
 import java.util.List;
diff --git a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/model/CacheablesValues.java b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/model/CacheablesValues.java
new file mode 100644
index 0000000..89a31da
--- /dev/null
+++ b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/model/CacheablesValues.java
@@ -0,0 +1,46 @@
+package cz.zcu.fav.kiv.antipatterndetectionapp.model;
+
+import java.util.List;
+
+public class CacheablesValues {
+
+    // these values ​​store information about currently processed projects and anti-patterns
+    private String[] analyzedProjects;
+    private String[] analyzedAntiPatterns;
+
+    // this value indicate if configuration values have changed
+    private boolean configurationChanged = false;
+    private List<QueryResult> results;
+
+    public String[] getAnalyzedProjects() {
+        return analyzedProjects;
+    }
+
+    public void setAnalyzedProjects(String[] analyzedProjects) {
+        this.analyzedProjects = analyzedProjects;
+    }
+
+    public String[] getAnalyzedAntiPatterns() {
+        return analyzedAntiPatterns;
+    }
+
+    public void setAnalyzedAntiPatterns(String[] analyzedAntiPatterns) {
+        this.analyzedAntiPatterns = analyzedAntiPatterns;
+    }
+
+    public boolean isConfigurationChanged() {
+        return configurationChanged;
+    }
+
+    public void setConfigurationChanged(boolean configurationChanged) {
+        this.configurationChanged = configurationChanged;
+    }
+
+    public List<QueryResult> getResults() {
+        return results;
+    }
+
+    public void setResults(List<QueryResult> results) {
+        this.results = results;
+    }
+}
diff --git a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/service/AntiPatternService.java b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/service/AntiPatternService.java
index 8cd16e0..301ed8e 100644
--- a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/service/AntiPatternService.java
+++ b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/service/AntiPatternService.java
@@ -2,6 +2,7 @@ package cz.zcu.fav.kiv.antipatterndetectionapp.service;
 
 import cz.zcu.fav.kiv.antipatterndetectionapp.detecting.detectors.AntiPatternDetector;
 import cz.zcu.fav.kiv.antipatterndetectionapp.model.AntiPattern;
+import cz.zcu.fav.kiv.antipatterndetectionapp.model.QueryResult;
 
 import java.util.List;
 
@@ -18,4 +19,19 @@ public interface AntiPatternService {
     List<AntiPatternDetector> getAllAntiPatternsForGivenIds(Long[] ids);
 
     boolean saveNewConfiguration(String[] configNames, String[] configValues);
+
+    void saveAnalyzedProjects(String[] selectedProjects, String[] selectedAntiPatterns);
+
+    String[] getAnalyzedProjects();
+
+    String[] getAnalyzedAntiPatterns();
+
+    boolean isConfigurationChanged();
+
+    void setConfigurationChanged(boolean configurationChanged);
+
+    void saveResults(List<QueryResult> results);
+
+    List<QueryResult> getResults();
+
 }
diff --git a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/service/AntiPatternServiceImpl.java b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/service/AntiPatternServiceImpl.java
index 29dd4ac..ae7e795 100644
--- a/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/service/AntiPatternServiceImpl.java
+++ b/src/main/java/cz/zcu/fav/kiv/antipatterndetectionapp/service/AntiPatternServiceImpl.java
@@ -2,6 +2,8 @@ package cz.zcu.fav.kiv.antipatterndetectionapp.service;
 
 import cz.zcu.fav.kiv.antipatterndetectionapp.detecting.detectors.AntiPatternDetector;
 import cz.zcu.fav.kiv.antipatterndetectionapp.model.AntiPattern;
+import cz.zcu.fav.kiv.antipatterndetectionapp.model.CacheablesValues;
+import cz.zcu.fav.kiv.antipatterndetectionapp.model.QueryResult;
 import cz.zcu.fav.kiv.antipatterndetectionapp.repository.AntiPatternRepository;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -17,6 +19,9 @@ public class AntiPatternServiceImpl implements AntiPatternService {
     @Autowired
     private AntiPatternRepository antiPatternRepository;
 
+    // class that stores cached values
+    private CacheablesValues cacheablesValues = new CacheablesValues();
+
     @Override
     public List<AntiPatternDetector> getAllAntiPatterns() {
         return antiPatternRepository.getAllAntiPatterns();
@@ -66,6 +71,7 @@ public class AntiPatternServiceImpl implements AntiPatternService {
                     if (antiPatternDetector.getAntiPatternModel().getConfigurations().get(configNames[i]).getValue().getClass() == Integer.class) {
                         try {
                             antiPatternDetector.getAntiPatternModel().getConfigurations().get(configNames[i]).setValue((Integer.parseInt(configValues[i])));
+                            setConfigurationChanged(true);
                         } catch (NumberFormatException e) {
                             return false;
                         }
@@ -73,12 +79,14 @@ public class AntiPatternServiceImpl implements AntiPatternService {
                     } else if (antiPatternDetector.getAntiPatternModel().getConfigurations().get(configNames[i]).getValue().getClass() == Float.class) {
                         try {
                             antiPatternDetector.getAntiPatternModel().getConfigurations().get(configNames[i]).setValue((Float.parseFloat(configValues[i])));
+                            setConfigurationChanged(true);
                         } catch (NumberFormatException e) {
                             return false;
                         }
                     } else if (antiPatternDetector.getAntiPatternModel().getConfigurations().get(configNames[i]).getValue().getClass() == Double.class) {
                         try {
                             antiPatternDetector.getAntiPatternModel().getConfigurations().get(configNames[i]).setValue((Double.parseDouble(configValues[i])));
+                            setConfigurationChanged(true);
                         } catch (NumberFormatException e) {
                             return false;
                         }
@@ -88,4 +96,40 @@ public class AntiPatternServiceImpl implements AntiPatternService {
         }
         return true;
     }
+
+    @Override
+    public void saveAnalyzedProjects(String[] selectedProjects, String[] selectedAntiPatterns) {
+        this.cacheablesValues.setAnalyzedProjects(selectedProjects);
+        this.cacheablesValues.setAnalyzedAntiPatterns(selectedAntiPatterns);
+    }
+
+    @Override
+    public String[] getAnalyzedProjects() {
+        return this.cacheablesValues.getAnalyzedProjects();
+    }
+
+    @Override
+    public String[] getAnalyzedAntiPatterns() {
+        return this.cacheablesValues.getAnalyzedAntiPatterns();
+    }
+
+    @Override
+    public void setConfigurationChanged(boolean configurationChanged) {
+        this.cacheablesValues.setConfigurationChanged(configurationChanged);
+    }
+
+    @Override
+    public boolean isConfigurationChanged() {
+        return this.cacheablesValues.isConfigurationChanged();
+    }
+
+    @Override
+    public void saveResults(List<QueryResult> results) {
+        this.cacheablesValues.setResults(results);
+    }
+
+    @Override
+    public List<QueryResult> getResults() {
+        return this.cacheablesValues.getResults();
+    }
 }
diff --git a/src/main/webapp/WEB-INF/templates/result.html b/src/main/webapp/WEB-INF/templates/result.html
index bdb1b41..d91b4f1 100644
--- a/src/main/webapp/WEB-INF/templates/result.html
+++ b/src/main/webapp/WEB-INF/templates/result.html
@@ -21,6 +21,10 @@
         .icon-style {
             border-radius: 30px;
         }
+
+        input, button, submit {
+            border: none;
+        }
     </style>
 
 </head>
@@ -31,6 +35,20 @@
 
 <!-- Result table container -->
 <div class="container">
+    <!-- Container for show success message -->
+    <div class="container">
+        <div th:if="${isConfigurationChanged}" class="alert alert-warning" role="alert">
+            Configuration values have changed! Would you like to
+            <form action="#" th:action="@{/recalculate}" method="post" style="display: inline-block">
+                <button type="submit"
+                        style="display: inline-block;background-color: #FEF3CD; color: #167AF6; text-decoration: underline;">
+                    recalculate
+                </button>
+            </form>
+            the results?
+        </div>
+    </div>
+    <!-- ./Container for show success message -->
     <h1>Results</h1>
     <table class="table table-bordered table-hover">
         <!-- Result table header -->
@@ -91,6 +109,7 @@
         </tbody>
         <!-- ./Result table content -->
     </table>
+    <p><small th:text="@{Last recalculated at &#160;} + ${ recalculationTime}"></small></p>
 
     <!-- Table legend -->
     <h6>Legend:</h6>
@@ -114,13 +133,34 @@
 </div>
 <!-- ./Result table container -->
 
-<!-- Script to popover -->
+<!-- Scripts -->
 <script>
+    // script to popover
     $(document).ready(function () {
         $('[data-toggle="popover"]').popover();
     });
+
+    // this code handling back browser button to result page
+    window.onload = function () {
+        if (typeof history.pushState === "function") {
+            history.pushState("jibberish", null, null);
+            window.onpopstate = function () {
+                history.pushState('newjibberish', null, null);
+            };
+        } else {
+            var ignoreHashChange = true;
+            window.onhashchange = function () {
+                if (!ignoreHashChange) {
+                    ignoreHashChange = true;
+                    window.location.hash = Math.random();
+                } else {
+                    ignoreHashChange = false;
+                }
+            };
+        }
+    }
 </script>
-<!-- ./Script to popover -->
+<!-- ./Scripts -->
 
 </body>
 </html>
