From 7ddfe9739b0a1870c8c8b6a7bee95ffdc2d959b3 Mon Sep 17 00:00:00 2001
From: Eilert Tunheim <emtunhei@stud.ntnu.no>
Date: Fri, 1 Apr 2022 16:01:58 +0200
Subject: [PATCH] Added check for lower or uppercase input given by the user
 and changed input from textfields to dropdown menues

---
 .../java/com/application/DB/Constants.java    |   5 +-
 src/main/java/com/application/DB/DB.java      |  47 ++--
 .../com/application/GUI/InputPopUpWindow.java | 203 ++++++++++++------
 .../GUI/LineChartFunctionality.java           |  27 +--
 .../com.application/CSS/styleSheet.css        |   2 +-
 .../application/GUI/InputPopUpWindow.class    | Bin 5139 -> 5798 bytes
 6 files changed, 175 insertions(+), 109 deletions(-)

diff --git a/src/main/java/com/application/DB/Constants.java b/src/main/java/com/application/DB/Constants.java
index 69d7d92..b2f5926 100644
--- a/src/main/java/com/application/DB/Constants.java
+++ b/src/main/java/com/application/DB/Constants.java
@@ -20,14 +20,13 @@ public final class Constants {
 
     // User inputs
     public static String TREE_SPECIES = "";
-    public static  String WIDTH_DIMENTION = "";
-    public static  String HEIGHT_DIMENTION = "";
+    public static  String DIMENSIONS = "";
     public static  String SAWSET = "";
     public static  String MOISTURE_GOAL = "";
 
     // Number of wanted drying periods
 
-    public static int NUMBER_OF_PERIODS = 2;
+    public static int NUMBER_OF_PERIODS = 1;
 
     // Database ID/name
     public static final String PROJECT_ID = "sf-drying-optimization";
diff --git a/src/main/java/com/application/DB/DB.java b/src/main/java/com/application/DB/DB.java
index 7e976b1..670782d 100644
--- a/src/main/java/com/application/DB/DB.java
+++ b/src/main/java/com/application/DB/DB.java
@@ -127,32 +127,30 @@ public class DB {
 
     public static Map<Integer, Map<String, Number>> setInputParameters() throws Exception {
 
-        String extraInputParameter = "";
-        String treeSpecies = "AND " +NAME_PARAMATERS+ " LIKE "+'"'+"%"+ TREE_SPECIES +"%"+'"'+" ";
-        String width = "AND " +NAME_PARAMATERS+ " LIKE "+'"'+"%"+ WIDTH_DIMENTION +"%"+'"'+" ";
-        String height = "AND " +NAME_PARAMATERS+ " LIKE "+'"'+"%"+ HEIGHT_DIMENTION +"%"+'"'+" ";
-        String widthXHeight = "AND " +NAME_PARAMATERS+ " LIKE "+'"'+"%"+ WIDTH_DIMENTION+"x"+HEIGHT_DIMENTION +"%"+'"'+" ";
-        String sawset = "AND " +NAME_PARAMATERS+ " LIKE "+'"'+"%"+ SAWSET +"%"+'"'+" ";
-        String moistureGoal = "AND " +NAME_PARAMATERS+ " LIKE "+'"'+"%"+ MOISTURE_GOAL+'%' +"%"+'"'+" ";
+        // If location is Valasen, then the database stores furu as fura, swedish.
+        if(LOCATION_ID == 124 && TREE_SPECIES.equalsIgnoreCase("Furu")) {
+            TREE_SPECIES = "Fura";
+        }
 
         System.out.printf("Tree species: \t%s\n",TREE_SPECIES);
-        System.out.printf("Width: \t\t\t%s\n",WIDTH_DIMENTION);
-        System.out.printf("Height: \t\t%s\n",HEIGHT_DIMENTION);
+        System.out.printf("Width: \t\t\t%s\n",DIMENSIONS);
         System.out.printf("Sawset: \t\t%s\n",SAWSET);
         System.out.printf("Moisture: \t\t%s\n",MOISTURE_GOAL);
 
+        String extraInputParameter = "";
+        String treeSpecies = "AND LOWER(" +NAME_PARAMATERS+ ") LIKE LOWER("+'"'+"%"+ TREE_SPECIES +"%"+'"'+") ";
+        String dimensions = "AND LOWER(" +NAME_PARAMATERS+ ") LIKE LOWER("+'"'+"%"+ DIMENSIONS +"%"+'"'+") ";
+        String sawset = "AND LOWER(" +NAME_PARAMATERS+ ") LIKE LOWER("+'"'+"%"+ SAWSET +"%"+'"'+") ";
+        String moistureGoal = "AND LOWER(" +NAME_PARAMATERS+ ") LIKE LOWER("+'"'+"%"+ MOISTURE_GOAL +"%"+'"'+") ";
+
+
+
         // Input parameters
         if(!TREE_SPECIES.isEmpty()){
             extraInputParameter += treeSpecies;
         }
-        if(!WIDTH_DIMENTION.isEmpty() && !HEIGHT_DIMENTION.isEmpty()){
-            extraInputParameter += widthXHeight;
-        }
-        else if(!WIDTH_DIMENTION.isEmpty()){
-            extraInputParameter += width;
-        }
-        else if(!HEIGHT_DIMENTION.isEmpty()){
-            extraInputParameter += height;
+        if(!DIMENSIONS.isEmpty()){
+            extraInputParameter += dimensions;
         }
         if(!SAWSET.isEmpty()){
             extraInputParameter += sawset;
@@ -163,7 +161,7 @@ public class DB {
 
 
 
-        Map<String, String> results = new HashMap<>();
+        Map<String, String> results;
         while(true){
             System.out.printf("\nExtra parameters:\n %s\n\n",extraInputParameter);
             // Retrieves the dates
@@ -171,21 +169,15 @@ public class DB {
 
             // Checks if any dates where found, if not parameters are removed until dates are found
             if(results.size()<NUMBER_OF_PERIODS){
-                if(extraInputParameter.contains(width)) {
-                    extraInputParameter = extraInputParameter.replace(width,"");
-                    System.out.println("Width is removed");
-                } else if(extraInputParameter.contains(sawset)) {
+                if(extraInputParameter.contains(sawset)) {
                     extraInputParameter = extraInputParameter.replace(sawset,"");
                     System.out.println("Sawset is removed");
                 } else if(extraInputParameter.contains(treeSpecies)) {
                     extraInputParameter = extraInputParameter.replace(treeSpecies,"");
                     System.out.println("Tree species is removed");
-                } else if(extraInputParameter.contains(height)) {
-                    extraInputParameter = extraInputParameter.replace(height,"");
+                } else if(extraInputParameter.contains(dimensions)) {
+                    extraInputParameter = extraInputParameter.replace(dimensions,"");
                     System.out.println("Height is removed");
-                } else if(extraInputParameter.contains(widthXHeight)) {
-                    extraInputParameter = extraInputParameter.replace(widthXHeight,"");
-                    System.out.println("widthXHeight is removed");
                 } else if(extraInputParameter.contains(moistureGoal)) {
                     extraInputParameter = extraInputParameter.replace(moistureGoal,"");
                     System.out.println("Moisture goal is removed");
@@ -329,6 +321,7 @@ public class DB {
                         "AND "+START_DRYING_NAME+" BETWEEN \"1990-01-01 00:00:00\" AND \"" + TODAYS_DATE + "\" " +
                         "AND "+STOP_DRYING_NAME+" BETWEEN \"1990-01-01 00:00:00\" AND \"" + TODAYS_DATE + "\" " +
                                 extraInputParameter +
+                        "AND LOWER(" +NAME_PARAMATERS+ ") NOT LIKE LOWER("+'"'+"%"+ "test" +"%"+'"'+") " +
                         "Group by "+ START_DRYING_NAME + " " +
                         "Order by "+ START_DRYING_NAME + " ASC " +
                         "LIMIT " + LIMIT;
diff --git a/src/main/java/com/application/GUI/InputPopUpWindow.java b/src/main/java/com/application/GUI/InputPopUpWindow.java
index d69a71d..0595c67 100644
--- a/src/main/java/com/application/GUI/InputPopUpWindow.java
+++ b/src/main/java/com/application/GUI/InputPopUpWindow.java
@@ -1,16 +1,19 @@
 package com.application.GUI;
 
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
 import javafx.geometry.Pos;
 import javafx.scene.*;
 import javafx.scene.control.*;
 import javafx.scene.layout.*;
 import javafx.stage.*;
-import org.checkerframework.checker.units.qual.K;
 
 import java.util.Map;
+import java.util.concurrent.*;
 
 import static com.application.DB.Constants.*;
 import static com.application.DB.DB.setInputParameters;
+import static com.application.GUI.LineChartFunctionality.loadMultipleSeries;
 import static com.application.GUI.LineChartFunctionality.loadSingleSeries;
 
 
@@ -22,8 +25,13 @@ import static com.application.GUI.LineChartFunctionality.loadSingleSeries;
  */
 public class InputPopUpWindow {
 
-    public static void display()
-    {
+    private static final Integer SLEEP_MILLS = 3000;
+    private static final Integer RUN_SLEEP_MILLS = 1000;
+    private static int afterSeconds = SLEEP_MILLS / RUN_SLEEP_MILLS;
+
+
+
+    public static void display() {
         Stage window = new Stage();
 
         window.initModality(Modality.APPLICATION_MODAL);
@@ -37,38 +45,60 @@ public class InputPopUpWindow {
         // Tree species
         Label treeSpeciesInputLabel = new Label("Tree Species");
         treeSpeciesInputLabel.setId("inputLabel");
-        TextField treeSpeciesInputText = new TextField();
-        treeSpeciesInputText.setId("inputLabelText");
-        treeSpeciesInputText.setPromptText("Bjørk");
-        treeSpeciesInputText.getText();
-
-        // Width
-        Label widthInputLabel = new Label("Width");
-        widthInputLabel.setId("inputLabel");
-        TextField widthInputText = new TextField();
-        widthInputText.setId("inputLabelText");
-        widthInputText.setPromptText("47");
-
-        // Height
-        Label heightInputLabel = new Label("Height");
-        heightInputLabel.setId("inputLabel");
-        TextField heightInputText = new TextField();
-        heightInputText.setId("inputLabelText");
-        heightInputText.setPromptText("200");
+        ObservableList<String> treeSpecies = FXCollections.observableArrayList(
+                 "Furu",
+                        "Gran"
+        );
+        ComboBox<String> treeSpeciesList = new ComboBox<String>(treeSpecies);
+        treeSpeciesList.setPromptText("Select Tree Species");
+        treeSpeciesList.setId("inputDropDownBox");
+        treeSpeciesList.setEditable(true);
+
+        // Dimensions
+        Label dimensionsInputLabel = new Label("Dimensions");
+        dimensionsInputLabel.setId("inputLabel");
+        ObservableList<String> dimensions = FXCollections.observableArrayList(
+                        "47x150",
+                        "47x200",
+                        "50x150",
+                        "50x200"
+                );
+        ComboBox<String> dimensionsList = new ComboBox<String>(dimensions);
+        dimensionsList.setPromptText("Select Dimensions");
+        dimensionsList.setId("inputDropDownBox");
+        dimensionsList.setEditable(true);
+
+
 
         // Sawset
         Label sawsetInputLabel = new Label("Sawset");
         sawsetInputLabel.setId("inputLabel");
-        TextField sawsetInputText = new TextField();
-        sawsetInputText.setId("inputLabelText");
-        sawsetInputText.setPromptText("4x");
+        ObservableList<String> sawset = FXCollections.observableArrayList(
+                     "1ex",
+                            "2ex",
+                            "3ex",
+                            "4ex"
+        );
+        ComboBox<String> sawsetList = new ComboBox<String>(sawset);
+        sawsetList.setPromptText("Select Dimensions");
+        sawsetList.setId("inputDropDownBox");
+        sawsetList.setEditable(true);
 
         // Moisture
         Label moistureGoalInputLabel = new Label("Moisture Goal");
         moistureGoalInputLabel.setId("inputLabel");
-        TextField moistureGoalInputText = new TextField();
-        moistureGoalInputText.setId("inputLabelText");
-        moistureGoalInputText.setPromptText("12%");
+        ObservableList<String> moistureGoal = FXCollections.observableArrayList(
+                 "10%",
+                        "12%",
+                        "14%",
+                        "16%",
+                        "18%",
+                        "20%"
+        );
+        ComboBox<String> moistureList = new ComboBox<String>(moistureGoal);
+        moistureList.setPromptText("Select Dimensions");
+        moistureList.setId("inputDropDownBox");
+        moistureList.setEditable(true);;
 
 
         // Bottom - start button
@@ -76,16 +106,89 @@ public class InputPopUpWindow {
         startButton.setId("inputButtonStart");
 
         startButton.setOnAction(e -> {
-            TREE_SPECIES = treeSpeciesInputText.getText();
-            WIDTH_DIMENTION = widthInputText.getText();
-            HEIGHT_DIMENTION = heightInputText.getText();
-            SAWSET = sawsetInputText.getText();
-            MOISTURE_GOAL = moistureGoalInputText.getText();
+                    // Retrieves the user inputs
+                    TREE_SPECIES = treeSpeciesList.getValue();
+                    DIMENSIONS = dimensionsList.getValue();
+                    SAWSET = sawsetList.getValue();
+                    MOISTURE_GOAL = moistureList.getValue();
+
+                    // If the input is null, sets the corresponding value to be empty
+                    if(treeSpeciesList.getValue() == null){TREE_SPECIES = "";}
+                    if(dimensionsList.getValue() == null){DIMENSIONS = "";}
+                    if(sawsetList.getValue() == null){SAWSET = "";}
+                    if(moistureList.getValue() == null){MOISTURE_GOAL = "";}
+
+
+
+                    window.close();
+
+
+                    try {
+                        loadSingleSeries(setInputParameters());
+                        //loadMultipleSeries(setInputParameters());
+                        //loadSingleSeries();
+                        //loadMultipleSeries();
+                    } catch (Exception ex) {
+                        ex.printStackTrace();
+                    }
+                }
+
+                );
+
+            /*
+            try{
+                Thread thread = new Thread(new Runnable() {
+
+                    @Override
+                    public void run() {
+                        try {
+                            // Henter her data fra databasen
+                            loadSingleSeries(setInputParameters());
+                            //loadSingleSeries();
+                            //loadMultipleSeries();
+                        } catch (Exception ex) {
+                            ex.printStackTrace();
+                        }
+                    }
+                });
+                thread.start();
+            } catch (Exception ex) {
+                ex.printStackTrace();
+            }
+                }
+                );
+
+             */
+
+/*
+                    // Fungerende ny thread!!@@@@@
+                    try{
+                        Thread thread = new Thread(new Runnable() {
+
+                            @Override
+                            public void run() {
+                                try {
+                                    // Henter her data fra databasen
+                                    loadSingleSeries(setInputParameters());
+                                    //loadSingleSeries();
+                                    //loadMultipleSeries();
+                                } catch (Exception ex) {
+                                    ex.printStackTrace();
+                                }
+                            }
+                        });
+                        thread.start();
+                    } catch (Exception ex) {
+                        ex.printStackTrace();
+                    }
+                }
 
-            window.close();
+                );
 
+ */
 
-            class KwhThread implements Runnable {
+/*
+            class KwhThread implements Runnable  {
 
                 Map<Integer, Map<String, Number>> dataVariable;
                 private volatile boolean finished;
@@ -104,8 +207,6 @@ public class InputPopUpWindow {
                     }
                 }
 
-
-
                 public Map<Integer, Map<String, Number>> getDataVariable() throws InterruptedException {
 
                     synchronized (this){
@@ -129,37 +230,17 @@ public class InputPopUpWindow {
             }
 
 
+ */
 
+/*
 
 
-            /*
-            // Fungerende ny thread!!@@@@@
-            try{
-                Thread thread = new Thread(new Runnable() {
-
-                    @Override
-                    public void run() {
-                        try {
-                            loadSingleSeries(setInputParameters());
-                            //loadSingleSeries();
-                            //loadMultipleSeries();
-                        } catch (Exception ex) {
-                            ex.printStackTrace();
-                        }
-                    }
-                });
-                thread.start();
-                //thread.join();
-            } catch (Exception ex) {
-                ex.printStackTrace();
-            }
+ */
 
-             */
-        });
 
         VBox layout = new VBox(10);
-        layout.getChildren().addAll(inputLabel, treeSpeciesInputLabel, treeSpeciesInputText, widthInputLabel, widthInputText, heightInputLabel, heightInputText,
-                sawsetInputLabel, sawsetInputText, moistureGoalInputLabel, moistureGoalInputText, startButton);
+        layout.getChildren().addAll(inputLabel, treeSpeciesInputLabel, treeSpeciesList, dimensionsInputLabel, dimensionsList,
+                sawsetInputLabel, sawsetList, moistureGoalInputLabel, moistureList, startButton);
         layout.setAlignment(Pos.CENTER);
 
         Scene scene = new Scene(layout, 600, 500);
diff --git a/src/main/java/com/application/GUI/LineChartFunctionality.java b/src/main/java/com/application/GUI/LineChartFunctionality.java
index f856137..2aa9836 100644
--- a/src/main/java/com/application/GUI/LineChartFunctionality.java
+++ b/src/main/java/com/application/GUI/LineChartFunctionality.java
@@ -15,10 +15,10 @@ public class LineChartFunctionality {
     private static NumberAxis yAxis;
 
 
-    public LineChartFunctionality(){
+    public LineChartFunctionality() {
         xAxis = new CategoryAxis();
         yAxis = new NumberAxis();
-        lineChart = new LineChart<>(xAxis,yAxis);
+        lineChart = new LineChart<>(xAxis, yAxis);
         xAxis.setLabel("Date");
         xAxis.setAnimated(false);
         yAxis.setLabel("Kwh");
@@ -34,11 +34,11 @@ public class LineChartFunctionality {
         return lineChart;
     }
 
-    public static void updateLineChart(XYChart.Series<String, Number> series){
+    public static void updateLineChart(XYChart.Series<String, Number> series) {
         lineChart.getData().add(series);
     }
 
-    public static void clearLineChart(){
+    public static void clearLineChart() {
         lineChart.getData().clear();
     }
 
@@ -75,17 +75,17 @@ public class LineChartFunctionality {
         return getLineChart();
     }
 
-    public static void loadMultipleSeries() throws Exception {
+    public static LineChart<String, Number> loadMultipleSeries(Map<Integer, Map<String, Number>> userInput) throws Exception {
 
-        Map<Integer, Map<String, Number>> kWh = DB.setInputParameters();
+        //Map<Integer, Map<String, Number>> kWh = DB.setInputParameters();
         //System.out.println(kWh.size());
 
-        for (Map.Entry<Integer, Map<String, Number>> entryKwh : kWh.entrySet()) {
+        for (Map.Entry<Integer, Map<String, Number>> entryKwh : userInput.entrySet()) {
             Map data = entryKwh.getValue();
             //System.out.println(data.size());
 
             XYChart.Series<String, Number> newSeries = new XYChart.Series<String, Number>();
-            for (Object entryData : data.entrySet()){
+            for (Object entryData : data.entrySet()) {
                 //System.out.println("data: \t"+entryData);
                 String entryString = entryData.toString();
                 String[] arr = entryString.split("=");
@@ -96,18 +96,11 @@ public class LineChartFunctionality {
 
 
                 // Connect the data to a series
-                newSeries.getData().add(new XYChart.Data<String, Number>(date,kwhValue));
+                newSeries.getData().add(new XYChart.Data<String, Number>(date, kwhValue));
 
             }
             updateLineChart(newSeries);
         }
-
-
-/*
-        for (Map.Entry<Integer, Map> entryKwh : kWh.entrySet()) {
-            System.out.printf("Index: \t%s\t\t\tkWh: \t%s\n",entryKwh.getKey(),entryKwh.getValue());
-        }
- */
+        return getLineChart();
     }
-
 }
diff --git a/src/main/resources/com.application/CSS/styleSheet.css b/src/main/resources/com.application/CSS/styleSheet.css
index 9669a07..dcd1a78 100644
--- a/src/main/resources/com.application/CSS/styleSheet.css
+++ b/src/main/resources/com.application/CSS/styleSheet.css
@@ -93,7 +93,7 @@
     -fx-font-family: Arial;
 }
 
-#inputLabelText {
+#inputDropDownBox {
     -fx-pref-height: 17;
     -fx-translate-x: 5;
     -fx-max-height: infinity;
diff --git a/target/classes/com/application/GUI/InputPopUpWindow.class b/target/classes/com/application/GUI/InputPopUpWindow.class
index 5c8bdbb587857b0435a8caf341dc7a0ab82de3d6..9ea2513d2c3ca6d86f03a8c1eccdbd16db02f761 100644
GIT binary patch
delta 3483
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
VGX_b9-Oy5Z4+As9UWR=P`vE`wGl2jA

delta 2836
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
T$uJjM_{?KqW|+^gfMFp3GAfn4

-- 
GitLab