Axel Nordh %!s(int64=2) %!d(string=hai) anos
pai
achega
10b6ea3f6f

+ 18 - 5
OddsJavaFx/pom.xml

@@ -48,11 +48,6 @@
         </resources>
     </build>
     <dependencies>
-        <dependency>
-            <groupId>Odds</groupId>
-            <artifactId>Odds</artifactId>
-            <version>Odds-0.0.1-SNAPSHOT</version>
-        </dependency>
         <dependency>
             <groupId>net.sourceforge.htmlunit</groupId>
             <artifactId>htmlunit</artifactId>
@@ -88,5 +83,23 @@
             <artifactId>guava</artifactId>
             <version>31.1-jre</version>
         </dependency>
+        <dependency>
+            <groupId>Odds</groupId>
+            <artifactId>Odds</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.seleniumhq.selenium</groupId>
+            <artifactId>selenium-java</artifactId>
+            <version>4.12.1</version>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/io.github.bonigarcia/webdrivermanager -->
+        <dependency>
+            <groupId>io.github.bonigarcia</groupId>
+            <artifactId>webdrivermanager</artifactId>
+            <version>5.5.3</version>
+        </dependency>
+
     </dependencies>
 </project>

+ 39 - 47
OddsJavaFx/src/controllers/AnalysisTestController.java

@@ -146,6 +146,7 @@ public class AnalysisTestController implements Initializable {
                 return new TableCell<SoccerMatch, Void>() {
 
                     private final Button btn = new Button("Submit");
+
                     {
                         btn.setOnAction((ActionEvent event) -> {
                             SoccerMatch data = getTableView().getItems().get(getIndex());
@@ -218,19 +219,19 @@ public class AnalysisTestController implements Initializable {
         ObservableList<SoccerMatch> currentMatches = FXCollections.<SoccerMatch>observableArrayList();
 
         for (SoccerMatch soccerMatch : matches) {
-
-            int analyzeValue = getAnalyzeValue(soccerMatch);
-            soccerMatch.setAnalysisValue(analyzeValue);
             if (currentBetAmount > 0) {
                 soccerMatch.setBetAmount(currentBetAmount);
             }
-
             currentMatches.add(soccerMatch);
         }
-
         gameViewTable.getItems().addAll(currentMatches);
     }
 
+    private void SetAnalyzisValue(SoccerMatch soccerMatch) {
+        int analyzeValue = getAnalyzeValue(soccerMatch);
+        soccerMatch.setAnalysisValue(analyzeValue);
+    }
+
     private void addToBets(SoccerMatch data) {
         if (data.getAnalysisValueInt() > 0) {
             setNewBet(data, true);
@@ -246,7 +247,7 @@ public class AnalysisTestController implements Initializable {
                 && (b.getBet().equals("1") && b.getHomeScore() > b.getAwayScore())
                 || (b.getBet().equals("2") && b.getHomeScore() < b.getAwayScore())) { // Win
             b.setStatus(Bet.Status.DONE);
-            Float win = (b.getBetOdds() * b.getBetAmount());
+            float win = (b.getBetOdds() * b.getBetAmount());
             updateBank(win);
 
         } else if (b.getHomeScore() >= 0 && b.getAwayScore() >= 0) { // Loss
@@ -259,19 +260,15 @@ public class AnalysisTestController implements Initializable {
 
     @FXML
     private void CheckBetsAction() {
-
         activeBetsTable.getItems().stream().filter(p -> p.getStatus() == Bet.Status.OPEN).forEach(this::checkBet);
-
         activeBetsTable.refresh();
-
         updateBetAmount();
-
     }
 
     private void checkValidBetAmount() {
         try {
-            float bankValue = Float.parseFloat(bankTextField.getText());
-            float betPercent = Float.parseFloat(bettingPercentTextField.getText());
+            float bankValue = Float.parseFloat(bankTextField.getText().replace(",", "."));
+            float betPercent = Float.parseFloat(bettingPercentTextField.getText().replace(",", "."));
 
             final float betAmount = Float.parseFloat(FLOAT_FORMATTER.format(bankValue * (betPercent / 100f)));
             currentBetAmount = betAmount;
@@ -326,10 +323,8 @@ public class AnalysisTestController implements Initializable {
 
     private float getBank() {
         float bank = 0;
-        try {
-            bank = Float.parseFloat(bankTextField.getText());
-        } catch (NumberFormatException e) {
-
+        if (!bankTextField.getText().isEmpty()) {
+            bank = Float.parseFloat(bankTextField.getText().replace(",", "."));
         }
 
         return bank;
@@ -338,7 +333,8 @@ public class AnalysisTestController implements Initializable {
     @FXML
     private void GetMatchesAction() {
         List<SoccerMatch> matches = GuiMysql.getInstance().getMatches(1, date.getValue().toString(), "ASC", true);
-
+        matches.forEach(m -> SetAnalyzisValue(m));
+        matches = matches.stream().filter(m -> !m.getAnalysisValue().equals("No Bet")).toList();
         addMatchesToTable(matches);
     }
 
@@ -346,12 +342,14 @@ public class AnalysisTestController implements Initializable {
         float odds = 0f;
         float currentDebt = 0f;
         float result = currentBetAmount;
-        if (((newValue.getAnalysisValueInt() > 0 && newValue.getOdds1() > MIN_COVER_ODDS
-                && newValue.getOdds1() < MAX_COVER_ODDS) ||
-                (newValue.getAnalysisValueInt() < 0 && newValue.getOdds2() > MIN_COVER_ODDS
-                        && newValue.getOdds2() < MAX_COVER_ODDS))
-                &&
-                activeBetsTable.getItems().stream().filter(p -> p.getStatus() == Bet.Status.LOST).count() > 0) {
+
+        boolean isHomeBet = newValue.getAnalysisValueInt() > 0 && newValue.getOdds1() > MIN_COVER_ODDS
+                && newValue.getOdds1() < MAX_COVER_ODDS;
+        boolean isAwayBet = newValue.getAnalysisValueInt() < 0 && newValue.getOdds2() > MIN_COVER_ODDS
+                && newValue.getOdds2() < MAX_COVER_ODDS;
+
+        if ((isHomeBet || isAwayBet) &&
+                activeBetsTable.getItems().stream().anyMatch(p -> p.getStatus() == Bet.Status.LOST)) {
             Bet bet = activeBetsTable.getItems().stream().filter(p -> p.getStatus() == Bet.Status.LOST).findFirst()
                     .get();
 
@@ -362,7 +360,6 @@ public class AnalysisTestController implements Initializable {
                 currentDebt += tempBet.getBetAmount();
                 betCoverNumber++;
             }
-
             bet.setBetCoveredNumber(betCoverNumber);
 
             if (betCoverNumber > 3 && newValue.getAnalysisValueInt() < 10 && newValue.getAnalysisValueInt() > -10) {
@@ -414,27 +411,27 @@ public class AnalysisTestController implements Initializable {
     }
 
     private void setNewBet(SoccerMatch data, boolean isHomeBet) {
-        int betId = GuiMysql.getInstance()
-                .addAnalysisBet(new Bet(-1, data, isHomeBet ? "1" : "2", data.getBetAmount(),
-                        isHomeBet ? data.getOdds1() : data.getOdds2()));
+        float odds = isHomeBet ? data.getOdds1() : data.getOdds2();
+        Bet bet = new Bet(-1, data, isHomeBet ? "1" : "2", data.getBetAmount(), odds);
 
-        Bet bet = GuiMysql.getInstance().getAnalysisBet(betId);
-
-        if (data.getPreviousBet() != null) {
-            data.getPreviousBet().setStatus(Status.COVERED); // TODO Kommer att förstöra om odds är utanför cover radious
+        boolean shouldCover = data.getPreviousBet() != null && odds > MIN_COVER_ODDS && odds < MAX_COVER_ODDS;
+        if (shouldCover) {
+            int betId = GuiMysql.getInstance().addAnalysisBet(bet);
+            data.getPreviousBet().setStatus(Status.COVERED);
             bet.setCoveredBetId(data.getPreviousBet().getId());
-            GuiMysql.getInstance().setBetCovered(bet.getId(), bet.getCoveredBetId());
+            GuiMysql.getInstance().setBetCovered(betId, bet.getCoveredBetId());
+
             try {
                 activeBetsTable.getItems().set(activeBetsTable.getItems().indexOf(data.getPreviousBet()),
                         data.getPreviousBet());
             } catch (IndexOutOfBoundsException e) {
-                data.setPreviousBet(null); // TODO, ingen bra lösning kanske.. Men enkel att göra :)
+                System.out.printf("Failed to update bet between %s - %s to covered %n",
+                        data.getPreviousBet().getHomeTeamName(), data.getPreviousBet().getAwayTeamName());
             } finally {
-                if (data.getPreviousBet() != null) {
-                    GuiMysql.getInstance().updateBetStatus(data.getPreviousBet().getId(), Status.COVERED);
-                }
+                GuiMysql.getInstance().updateBetStatus(data.getPreviousBet().getId(), Status.COVERED);
             }
-
+        } else {
+            GuiMysql.getInstance().addAnalysisBet(bet);
         }
         activeBetsTable.getItems().add(bet);
         updateBank(-bet.getBetAmount());
@@ -442,23 +439,18 @@ public class AnalysisTestController implements Initializable {
 
     private void updateBank(float value) {
         float bank;
-        try {
-            bank = Float.parseFloat(bankTextField.getText());
+        if (!bankTextField.getText().isEmpty()) {
+            bank = Float.parseFloat(bankTextField.getText().replace(",", "."));
             bank += value;
-
             bankTextField.setText(String.valueOf(bank));
-        } catch (NumberFormatException e) {
-
         }
     }
 
     private void updateBetAmount() {
-        try {
+        if (!bettingPercentTextField.getText().isEmpty()) {
             float betLevel = Float.parseFloat(bettingPercentTextField.getText());
-            currentBetAmount = Float.parseFloat(FLOAT_FORMATTER.format(getBank() * (betLevel / 100f)));
-
-        } catch (NumberFormatException e) {
-
+            currentBetAmount = Float.parseFloat(FLOAT_FORMATTER.format(
+                    getBank() * (betLevel / 100f)).replace(",","."));
         }
     }
 

+ 158 - 0
OddsJavaFx/src/controllers/StryktipsetController.java

@@ -0,0 +1,158 @@
+package controllers;
+
+import data.GuiMysql;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.event.ActionEvent;
+import javafx.fxml.FXML;
+import javafx.fxml.Initializable;
+import javafx.scene.control.*;
+import javafx.scene.control.cell.PropertyValueFactory;
+import javafx.util.Callback;
+import objects.League;
+import objects.SoccerMatch;
+import objects.SoccerMatchAnalysis;
+import parser.Svenskaspel;
+
+import java.math.RoundingMode;
+import java.net.URL;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.*;
+
+@SuppressWarnings("rawtypes")
+public class StryktipsetController implements Initializable {
+
+    private static final DecimalFormat FLOAT_FORMATTER = new DecimalFormat("0.00");
+    TableColumn<SoccerMatchAnalysis, String> homeTeamNameColumn = new TableColumn<>("Home Team");
+    TableColumn<SoccerMatchAnalysis, String> awayTeamNameColumn = new TableColumn<>("Away Team");
+    TableColumn<SoccerMatchAnalysis, String> leagueNameColumn = new TableColumn<>("Country");
+
+    TableColumn<SoccerMatchAnalysis, String> countryNameColumn = new TableColumn<>("League");
+
+    TableColumn<SoccerMatchAnalysis, Integer> scoringDiffLastGamesColumn = new TableColumn<>("Scoring Diff");
+    TableColumn<SoccerMatchAnalysis, Integer> scoringTotalColumn = new TableColumn<>("Scoring Total");
+    TableColumn<SoccerMatchAnalysis, Integer> winCountColumn = new TableColumn<>("Win Count");
+    TableColumn<SoccerMatchAnalysis, Integer> winLossRatioColumn = new TableColumn<>("Win/loss Ratio");
+    TableColumn<SoccerMatchAnalysis, Void> bet1Column = new TableColumn<>("1");
+    TableColumn<SoccerMatchAnalysis, Void> betXColumn = new TableColumn<>("X");
+    TableColumn<SoccerMatchAnalysis, Void> bet2Column = new TableColumn<>("2");
+
+    @FXML
+    TableView<SoccerMatchAnalysis> gameViewTable;
+    @FXML
+    Button getMatchesButton;
+    @FXML
+    DatePicker date;
+
+    Map<String, League> leagueInfoMap = new HashMap<>();
+
+    @Override
+    public void initialize(URL location, ResourceBundle resources) {
+        FLOAT_FORMATTER.setRoundingMode(RoundingMode.UP);
+        DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.ENGLISH);
+        dfs.setDecimalSeparator('.');
+        dfs.setGroupingSeparator(',');
+        FLOAT_FORMATTER.setDecimalFormatSymbols(dfs);
+
+        date.valueProperty().addListener((observable, oldValue, newValue) -> {
+            if (oldValue != newValue) {
+                gameViewTable.getItems().clear();
+            }
+        });
+
+        homeTeamNameColumn.setCellValueFactory(new PropertyValueFactory<>("homeTeamName"));
+        awayTeamNameColumn.setCellValueFactory(new PropertyValueFactory<>("awayTeamName"));
+        leagueNameColumn.setCellValueFactory(new PropertyValueFactory<>("leagueName"));
+        countryNameColumn.setCellValueFactory(new PropertyValueFactory<>("countryName"));
+        scoringDiffLastGamesColumn.setCellValueFactory(new PropertyValueFactory<>("scoringDiffValue"));
+        scoringTotalColumn.setCellValueFactory(new PropertyValueFactory<>("scoringTotal"));
+        winCountColumn.setCellValueFactory(new PropertyValueFactory<>("winCount"));
+        winLossRatioColumn.setCellValueFactory(new PropertyValueFactory<>("winLossRatio"));
+
+        Callback<TableColumn<SoccerMatchAnalysis, Void>, TableCell<SoccerMatchAnalysis, Void>> cellFactory = new Callback<TableColumn<SoccerMatchAnalysis, Void>, TableCell<SoccerMatchAnalysis, Void>>() {
+            @Override
+            public TableCell<SoccerMatchAnalysis, Void> call(final TableColumn<SoccerMatchAnalysis, Void> param) {
+                return new TableCell<SoccerMatchAnalysis, Void>() {
+
+                    private final CheckBox checkbox = new CheckBox();
+
+                    {
+                        checkbox.setOnAction((ActionEvent event) -> {
+                            SoccerMatch data = getTableView().getItems().get(getIndex());
+
+                            addToBets(data);
+                        });
+                    }
+
+                    @Override
+                    public void updateItem(Void item, boolean empty) {
+                        super.updateItem(item, empty);
+                        if (empty) {
+                            setGraphic(null);
+                        } else {
+                            setGraphic(checkbox);
+                        }
+                    }
+
+                };
+            }
+        };
+
+        bet1Column.setCellFactory(cellFactory);
+        betXColumn.setCellFactory(cellFactory);
+        bet2Column.setCellFactory(cellFactory);
+
+        gameViewTable.getColumns().addAll(homeTeamNameColumn, awayTeamNameColumn, countryNameColumn, leagueNameColumn,
+                scoringDiffLastGamesColumn, scoringTotalColumn, winCountColumn, winLossRatioColumn,
+                bet1Column, betXColumn, bet2Column);
+        gameViewTable.setEditable(true);
+    }
+
+    private void addToBets(SoccerMatch data) {
+        // TODO
+    }
+
+    private void addMatchesToTable(List<SoccerMatchAnalysis> matches) {
+        ObservableList<SoccerMatchAnalysis> currentMatches = FXCollections.<SoccerMatchAnalysis>observableArrayList();
+
+        currentMatches.addAll(matches);
+
+        gameViewTable.getItems().addAll(currentMatches);
+    }
+
+    @FXML
+    private void GetMatchesAction() {
+        List<SoccerMatchAnalysis> matches = GuiMysql.getInstance().getMatchesForStryktipset(date.getValue().toString());
+
+        if (matches.isEmpty()) {
+            Svenskaspel parser = new parser.Svenskaspel();
+            matches = parser.GetStryktipsetSelenium(date.getValue().toString());
+        }
+
+        for (SoccerMatchAnalysis match : matches) {
+            League info = getLeagueInfo(match, match.getHomeTeam().getTeamLeague());
+            match.setLeagueName(match.getHomeTeam().getTeamLeague());
+            match.setCountryName(match.getHomeTeam().getCountryName());
+            match.setScoringDiffValue(match.getScoringDiffLastGames(info.getScoringDiffLastGame()));
+            match.setScoringTotal(match.scoringTotal(info.getScoringTotal(), true) - match.scoringTotal(info.getScoringTotal(), false));
+            match.setWinCount(match.winLossRatio(info.getWinLossRatio(), true) - match.winLossRatio(info.getWinLossRatio(), false));
+            match.setWinLossRatio(
+                    match.winLossRationHomeAndAway(true, info.getWinLossRatioHomeAndAway()) -
+                            match.winLossRationHomeAndAway(false, info.getWinLossRatioHomeAndAway())
+            );
+        }
+
+        addMatchesToTable(matches);
+    }
+
+    private League getLeagueInfo(SoccerMatch match, String leagueName) {
+        League info = leagueInfoMap.get(leagueName);
+        if (info == null) {
+            info = GuiMysql.getInstance().getLeagueInfo(match.getHomeTeam().getTeamLeagueId());
+            leagueInfoMap.put(leagueName, info);
+        }
+        return info;
+    }
+
+}

+ 144 - 21
OddsJavaFx/src/data/GuiMysql.java

@@ -10,28 +10,16 @@ import java.sql.Statement;
 import java.text.DecimalFormat;
 import java.text.SimpleDateFormat;
 import java.time.LocalDateTime;
-import java.util.AbstractMap;
+import java.util.*;
 import java.util.AbstractMap.SimpleEntry;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
 
+import objects.*;
 import org.eclipse.jetty.util.log.Log;
 
 import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
 
 import mysql.Mysql;
-import objects.BetDTO;
-import objects.Constants;
-import objects.League;
-import objects.OverUnder;
-import objects.SoccerMatch;
-import objects.Team;
-import objects.TeamResults;
-import objects.TeamStanding;
 import objects.bets.Bet;
 import objects.bets.Bet.Status;
 
@@ -646,8 +634,8 @@ public class GuiMysql extends Mysql {
     }
 
     public List<SoccerMatch> getMatches(int sportId, Integer countryId, Integer leagueId, String date, String order,
-            boolean exactDate,
-            boolean onlyPrio) {
+                                        boolean exactDate,
+                                        boolean onlyPrio) {
         final ArrayList<SoccerMatch> matches = Lists.newArrayList();
         final String dateSql;
         final String orderSql = " ORDER BY gameDate " + order;
@@ -769,8 +757,8 @@ public class GuiMysql extends Mysql {
     }
 
     public Map<String, String> getPreviousMatches(int numberOfMatches, String homeTeamName, String awayTeamName,
-            String date, int countryId,
-            int leagueId) {
+                                                  String date, int countryId,
+                                                  int leagueId) {
         Map<String, String> result = new HashMap<>();
 
         String homeTeamSql = "SELECT * FROM SoccerResults sr INNER JOIN Team t ON sr.homeTeamId = t.id WHERE t.name = ? AND sr.leagueId = ? AND DATE(gameDate) < ? ORDER BY gameDate DESC limit ?";
@@ -778,9 +766,9 @@ public class GuiMysql extends Mysql {
         String combinedSql = "SELECT * FROM SoccerResults sr INNER JOIN Team homeTeam ON homeTeamId = homeTeam.id INNER JOIN Team awayTeam ON sr.awayTeamId = awayTeam.id WHERE homeTeam.name = ? AND awayTeam.name = ? AND sr.leagueId = ? AND DATE(gameDate) < ? ORDER BY gameDate DESC LIMIT ?";
         String combinedReverseSql = "SELECT * FROM SoccerResults sr INNER JOIN Team homeTeam ON homeTeamId = homeTeam.id INNER JOIN Team awayTeam ON sr.awayTeamId = awayTeam.id WHERE homeTeam.name = ? AND awayTeam.name = ? AND sr.leagueId = ? AND DATE(gameDate) < ? ORDER BY gameDate DESC LIMIT ?";
         try (PreparedStatement homeTeamStat = conn.prepareStatement(homeTeamSql);
-                PreparedStatement awayTeamStat = conn.prepareStatement(awayTeamSql);
-                PreparedStatement combinedStat = conn.prepareStatement(combinedSql);
-                PreparedStatement combinedReversedStat = conn.prepareStatement(combinedReverseSql);) {
+             PreparedStatement awayTeamStat = conn.prepareStatement(awayTeamSql);
+             PreparedStatement combinedStat = conn.prepareStatement(combinedSql);
+             PreparedStatement combinedReversedStat = conn.prepareStatement(combinedReverseSql);) {
 
             homeTeamStat.setString(1, homeTeamName);
             homeTeamStat.setInt(2, leagueId);
@@ -1313,4 +1301,139 @@ public class GuiMysql extends Mysql {
         }
         return returnValue;
     }
+
+    public List<SoccerMatchAnalysis> getMatchesForStryktipset(String date) {
+        List<SoccerMatchAnalysis> result = new ArrayList<>();
+
+
+        return result;
+    }
+
+    public SoccerMatch getMatch(String date, String homeTeamName, String awayTeamName) {
+        SoccerMatch match = new SoccerMatch();
+        String sql = "SELECT * FROM SoccerResults sr " +
+                "JOIN Team ht ON ht.id = sr.homeTeamId " +
+                "JOIN Team awt ON awt.id = sr.awayTeamId " +
+                "WHERE DATE(sr.gameDate) = ? AND (ht.name LIKE ? OR awt.name LIKE ?)";
+        try (PreparedStatement stat = conn.prepareStatement(sql)) {
+            stat.setString(1, date);
+            stat.setString(2, homeTeamName);
+            stat.setString(3, awayTeamName);
+
+            ResultSet rs = stat.executeQuery();
+
+            while (rs.next()) {
+                match = new SoccerMatch(rs.getInt("id"), getTeam(rs.getInt("homeTeamId")),
+                        getTeam(rs.getInt("awayTeamId")), rs.getFloat("odds1"),
+                        rs.getFloat("oddsX"), rs.getFloat("odds2"),
+                        rs.getInt("homeScore"), rs.getInt("awayScore"),
+                        LocalDateTime.parse(rs.getString("gameDate")), rs.getString("season"));
+            }
+        } catch (SQLException e) {
+            e.printStackTrace();
+        }
+
+        return match;
+    }
+
+    public List<SoccerMatchCalcBestValue> getMatchesForCalcBestValues(Integer countryId, Integer leagueId, String date) {
+
+        final ArrayList<SoccerMatchCalcBestValue> matches = Lists.newArrayList();
+
+        String homeTeamSelect = "(SELECT count(case when homeScore > awayScore then 1 end) " +
+                "FROM (SELECT * FROM SoccerResults WHERE homeTeamId = res.homeTeamId AND " +
+                "HomeScore >= 0 AND awayScore >= 0 AND DATE(gameDate) < res.gameDate ORDER BY gameDate DESC LIMIT %s) as t) as homeWins%s," +
+                "(SELECT count(case when awayScore > homeScore then 1 end) " +
+                "FROM (SELECT * FROM SoccerResults WHERE homeTeamId = res.homeTeamId AND " +
+                "HomeScore >= 0 AND awayScore >= 0 AND DATE(gameDate) < res.gameDate ORDER BY gameDate DESC LIMIT %s) as t) as homeDraws%s," +
+                "(SELECT count(case when homeScore = awayScore then 1 end) " +
+                "FROM (SELECT * FROM SoccerResults WHERE homeTeamId = res.homeTeamId AND " +
+                "HomeScore >= 0 AND awayScore >= 0 AND DATE(gameDate)  < res.gameDate ORDER BY gameDate DESC LIMIT %s) as t) as homeLosses%s";
+
+        String awayTeamSelect = "(SELECT count(case when homeScore > awayScore then 1 end) " +
+                "FROM (SELECT * FROM SoccerResults WHERE homeTeamId = res.homeTeamId AND " +
+                "HomeScore >= 0 AND awayScore >= 0 AND DATE(gameDate) < res.gameDate ORDER BY gameDate DESC LIMIT %s) as t) as awayWins%s," +
+                "(SELECT count(case when awayScore > homeScore then 1 end) " +
+                "FROM (SELECT * FROM SoccerResults WHERE homeTeamId = res.homeTeamId AND " +
+                "HomeScore >= 0 AND awayScore >= 0 AND DATE(gameDate) < res.gameDate ORDER BY gameDate DESC LIMIT %s) as t) as awayDraws%s," +
+                "(SELECT count(case when homeScore = awayScore then 1 end) " +
+                "FROM (SELECT * FROM SoccerResults WHERE homeTeamId = res.homeTeamId AND " +
+                "HomeScore >= 0 AND awayScore >= 0 AND DATE(gameDate)  < res.gameDate ORDER BY gameDate DESC LIMIT %s) as t) as awayLosses%s";
+
+        StringJoiner homeTeamSqlJoiner = new StringJoiner(", ");
+        StringJoiner awayTeamSqlJoiner = new StringJoiner(", ");
+
+        for (int i = 1; i <= 20; i++) {
+            homeTeamSqlJoiner.add(String.format(homeTeamSelect, i, i, i, i, i, i));
+            awayTeamSqlJoiner.add(String.format(awayTeamSelect, i, i, i, i, i, i));
+        }
+
+        final String sql = "SELECT res.*, c.name as countryName, l.name as leagueName, "
+                + "hTeam.name as homeTeamName, aTeam.name as awayTeamName, "
+                + homeTeamSqlJoiner + "," + awayTeamSqlJoiner + " "
+                + "FROM SoccerResults as res "
+                + "INNER Join Team as hTeam ON res.homeTeamId = hTeam.id AND res.leagueId = hTeam.leagueId "
+                + "INNER Join Team as aTeam ON res.awayTeamId = aTeam.id AND res.leagueId = hTeam.leagueId "
+                + "INNER JOIN League l ON res.leagueId = l.id "
+                + "INNER JOIN Country c ON res.countryId = c.id "
+                + "WHERE " + "DATE(gameDate) <= '" + date + "' " + "AND res.leagueId = ? AND res.countryId = ? "
+                + "ORDER BY gameDate ASC";
+        try (PreparedStatement stat = conn.prepareStatement(sql)) {
+            stat.setInt(1, leagueId);
+            stat.setInt(2, countryId);
+
+            final ResultSet rs = stat.executeQuery();
+            while (rs.next()) {
+                final SoccerMatchCalcBestValue sm = new SoccerMatchCalcBestValue();
+                final Team homeTeam = new Team();
+                final Team awayTeam = new Team();
+
+                homeTeam.setTeamId(rs.getInt(Constants.HOME_TEAM_ID));
+                awayTeam.setTeamId(rs.getInt(Constants.AWAY_TEAM_ID));
+                homeTeam.setTeamName(rs.getString(Constants.HOME_TEAM_NAME));
+                awayTeam.setTeamName(rs.getString(Constants.AWAY_TEAM_NAME));
+                homeTeam.setTeamLeagueId(rs.getInt(Constants.LEAGUE_ID));
+                awayTeam.setTeamLeagueId(rs.getInt(Constants.LEAGUE_ID));
+                homeTeam.setTeamLeague(rs.getString(LEAGUE_NAME));
+                awayTeam.setTeamLeague(rs.getString(LEAGUE_NAME));
+                homeTeam.setCountryId(rs.getInt(Constants.COUNTRY_ID));
+                awayTeam.setCountryId(rs.getInt(Constants.COUNTRY_ID));
+                homeTeam.setCountryName(rs.getString(COUNTRY_NAME));
+                awayTeam.setCountryName(rs.getString(COUNTRY_NAME));
+
+                sm.setLeagueName(rs.getString(LEAGUE_NAME));
+                sm.setCountryName(rs.getString(COUNTRY_NAME));
+                sm.setAwayScore(rs.getInt(Constants.AWAY_SCORE));
+                sm.setHomeScore(rs.getInt(Constants.HOME_SCORE));
+                sm.setHomeTeam(homeTeam);
+                sm.setAwayTeam(awayTeam);
+                sm.setMatchId(rs.getInt(Constants.ID));
+                sm.setOdds1(rs.getFloat(Constants.ODDS_1));
+                sm.setOddsX(rs.getFloat(Constants.ODDS_X));
+                sm.setOdds2(rs.getFloat(Constants.ODDS_2));
+                sm.setGameDate(LocalDateTime.parse(rs.getString(Constants.GAME_DATE)));
+                sm.setSeason(rs.getString(Constants.SEASON));
+
+                sm.setHomeTeamName(homeTeam.getTeamName());
+                sm.setAwayTeamName(awayTeam.getTeamName());
+
+                for (int i = 1; i <= 20; i++) {
+                    sm.setHomeWins(i, rs.getInt("homeWins" + i));
+                    sm.setHomeDraws(i, rs.getInt("homeDraws" + i));
+                    sm.setHomeLosses(i, rs.getInt("homeLosses" + i));
+
+                    sm.setAwayWins(i, rs.getInt("awayWins" + i));
+                    sm.setAwayDraws(i, rs.getInt("awayDraws" + i));
+                    sm.setAwayLosses(i, rs.getInt("awayLosses" + i));
+                }
+
+                matches.add(sm);
+            }
+
+        } catch (final SQLException e) {
+            e.printStackTrace();
+        }
+
+        return matches;
+    }
 }

+ 5 - 0
OddsJavaFx/src/fxml/OddsFxBuilder.fxml

@@ -124,6 +124,11 @@
                      <fx:include fx:id="analyzeTesting" source="AnalysisTesting.fxml" />
                   </content>
                 </Tab>
+                  <Tab text="Stryktipset">
+                      <content>
+                          <fx:include fx:id="stryktipset" source="Stryktipset.fxml" />
+                      </content>
+                  </Tab>
               </tabs>
             </TabPane>
          </center>

+ 33 - 0
OddsJavaFx/src/fxml/Stryktipset.fxml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.scene.control.Button?>
+<?import javafx.scene.control.DatePicker?>
+<?import javafx.scene.control.SplitPane?>
+<?import javafx.scene.control.TableView?>
+<?import javafx.scene.layout.AnchorPane?>
+<?import javafx.scene.layout.FlowPane?>
+<?import javafx.scene.layout.VBox?>
+
+<AnchorPane xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controllers.StryktipsetController">
+   <children>
+      <VBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
+         <children>
+            <FlowPane alignment="CENTER_LEFT" prefHeight="30.0">
+               <children>
+                  <DatePicker fx:id="date" />
+                  <Button fx:id="getMatchesButton" mnemonicParsing="false" onAction="#GetMatchesAction" text="Get Matches" />
+               </children>
+            </FlowPane>
+            <SplitPane orientation="VERTICAL">
+              <items>
+                <AnchorPane>
+                     <children>
+                        <TableView fx:id="gameViewTable" editable="true" />
+                     </children>
+                  </AnchorPane>
+              </items>
+            </SplitPane>
+         </children>
+      </VBox>
+   </children>
+</AnchorPane>

+ 17 - 2
OddsJavaFx/src/objects/SoccerMatch.java

@@ -48,9 +48,24 @@ public class SoccerMatch {
     public SoccerMatch() {
     }
 
+    public void setMatchData(SoccerMatch match) {
+        this.matchId = match.getMatchId();
+        this.homeTeam = match.getHomeTeam();
+        this.awayTeam = match.getAwayTeam();
+        this.odds1 = match.getOdds1();
+        this.oddsX = match.getOddsX();
+        this.odds2 = match.getOdds2();
+        this.homeScore = match.getHomeScore();
+        this.awayScore = match.getAwayScore();
+        this.gameDate = match.getGameDate();
+        this.season = match.getSeason();
+        this.homeTeamName = homeTeam.getTeamName();
+        this.awayTeamName = awayTeam.getTeamName();
+    }
+
     public SoccerMatch(int id, Team homeTeam, Team awayTeam, float odds1, float oddsX, float odds2, int homeScore,
-            int awayScore,
-            LocalDateTime gameDate, String season) {
+                       int awayScore,
+                       LocalDateTime gameDate, String season) {
         this.matchId = id;
         this.homeTeam = homeTeam;
         this.awayTeam = awayTeam;

+ 102 - 78
OddsJavaFx/src/objects/SoccerMatchAnalysis.java

@@ -10,95 +10,133 @@ import java.util.Optional;
 
 import data.GuiMysql;
 
-public class SoccerMatchAnalysis {
+public class SoccerMatchAnalysis extends SoccerMatch {
 
-    SoccerMatch match;
     GuiMysql database;
     private List<TeamStanding> leagueTable;
     private LocalDate leagueTableUpdated;
+    private int scoringDiffValue;
+    private int scoringTotal;
+    private int winCount;
+    private int winLossRatio;
 
     public SoccerMatchAnalysis(SoccerMatch match) {
-        this.match = match;
+        setMatchData(match);
         database = GuiMysql.getInstance();
     }
 
+    public int getWinLossRatio() {
+        return winLossRatio;
+    }
+
+    public void setWinLossRatio(int winLossRatio) {
+        this.winLossRatio = winLossRatio;
+    }
+
+    public int getWinCount() {
+        return winCount;
+    }
+
+    public void setWinCount(int winCount) {
+        this.winCount = winCount;
+    }
+
+    public int getScoringTotal() {
+        return scoringTotal;
+    }
+
+    public void setScoringTotal(int scoringTotal) {
+        this.scoringTotal = scoringTotal;
+    }
+
+    public int getScoringDiffValue() {
+        return scoringDiffValue;
+    }
+
+    public void setScoringDiffValue(int scoringDiffValue) {
+        this.scoringDiffValue = scoringDiffValue;
+    }
+
     /**
      * Antalet mål som hemma laget gjort de senaste "gamesLookback" matcherna -
      * antalet mål för bortalaget under samma period
-     * 
+     *
      * @param gamesLookback - hur många matcher bakåt i tiden som ska kontrolleras
      * @return Float med skillnaden i mål mellan lagen hemma/borta
      */
     public int getScoringDiffLastGames(int gamesLookback) {
         int result = 0;
 
-        String sql = "SELECT * FROM "
-                + "(SELECT * FROM SoccerResults WHERE homeTeamId = ? AND leagueId = ? AND DATE(gameDate) < ? ORDER BY gameDate DESC LIMIT ?) ht "
-                + "UNION DISTINCT "
-                + "(SELECT * FROM SoccerResults WHERE awayTeamId = ? AND leagueId = ? AND DATE(gameDate) < ? ORDER BY gameDate DESC LIMIT ?);";
+        String sql = "SELECT * FROM " +
+                "(SELECT * FROM SoccerResults WHERE homeTeamId = ? AND leagueId = ? AND DATE" +
+                "(gameDate) < ? ORDER BY gameDate DESC LIMIT ?) ht " +
+                "UNION " +
+                "(SELECT * FROM SoccerResults WHERE " +
+                "awayTeamId = ? AND leagueId = ? AND DATE(gameDate) < ? " +
+                "ORDER BY gameDate DESC " +
+                "LIMIT ?);";
 
         int homeRes = 0;
         int awayRes = 0;
         try (PreparedStatement stat = database.getDbConnection().prepareStatement(sql)) {
-            stat.setInt(1, match.getHomeTeam().getTeamId());
-            stat.setInt(2, match.getHomeTeam().getTeamLeagueId());
-            stat.setString(3, match.getGameDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
+            stat.setInt(1, getHomeTeam().getTeamId());
+            stat.setInt(2, getHomeTeam().getTeamLeagueId());
+            stat.setString(3, getGameDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
             stat.setInt(4, gamesLookback);
 
-            stat.setInt(5, match.getAwayTeam().getTeamId());
-            stat.setInt(6, match.getAwayTeam().getTeamLeagueId());
-            stat.setString(7, match.getGameDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
+            stat.setInt(5, getAwayTeam().getTeamId());
+            stat.setInt(6, getAwayTeam().getTeamLeagueId());
+            stat.setString(7, getGameDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
             stat.setInt(8, gamesLookback);
 
             ResultSet rs = stat.executeQuery();
 
             while (rs.next()) {
-                if (match.getHomeTeam().getTeamId() == rs.getInt("homeTeamId")) {
+                if (getHomeTeam().getTeamId() == rs.getInt("homeTeamId")) {
                     homeRes += rs.getInt("homeScore");
                 }
-                if (match.getAwayTeam().getTeamId() == rs.getInt("awayTeamId")) {
+                if (getAwayTeam().getTeamId() == rs.getInt("awayTeamId")) {
                     awayRes += rs.getInt("awayScore");
                 }
             }
         } catch (SQLException e) {
             e.printStackTrace();
         }
-
-        return homeRes - awayRes;
+        scoringDiffValue = homeRes - awayRes;
+        return scoringDiffValue;
     }
 
     /**
-     * 
      * Plocka fram antalet mål som ett specifikt lag gjort under de senaste
      * <gamesLookback> matcherna
-     * 
+     *
      * @param gamesLookback - hur många matcher bakåt i tiden som ska kontrolleras
      * @param homeTeam      - är det hemma laget som ska kontrolleras i matchen
      * @return antalet mål som är gjorda av bestämt lag.
      */
     public int scoringTotal(int gamesLookback, boolean homeTeam) {
         int result = 0;
-        String sql = "SELECT * FROM "
-                + "(SELECT * FROM SoccerResults WHERE homeTeamId = ? AND leagueId = ? AND DATE(gameDate) < ? ORDER BY gameDate DESC LIMIT ?) ht "
-                + "UNION DISTINCT "
-                + "(SELECT * FROM SoccerResults WHERE awayTeamId = ? AND leagueId = ? AND DATE(gameDate) < ? ORDER BY gameDate DESC LIMIT ?)";
+        String sql = "SELECT * FROM " + "(SELECT * FROM SoccerResults WHERE homeTeamId = ? AND leagueId = ? AND DATE" +
+                "(gameDate) < ? ORDER BY gameDate DESC LIMIT ?) ht " + "UNION DISTINCT " + "(SELECT * FROM " +
+                "SoccerResults WHERE awayTeamId = ? AND leagueId = ? AND DATE(gameDate) < ? ORDER BY gameDate DESC " +
+                "LIMIT ?)";
 
         try (PreparedStatement stat = database.getDbConnection().prepareStatement(sql)) {
             final Team team;
             if (homeTeam) {
-                team = match.getHomeTeam();
+                team = getHomeTeam();
             } else {
-                team = match.getAwayTeam();
+                team = getAwayTeam();
             }
 
             stat.setInt(1, team.getTeamId());
             stat.setInt(2, team.getTeamLeagueId());
-            stat.setString(3, match.getGameDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
+            stat.setString(3, getGameDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
             stat.setInt(4, gamesLookback);
 
             stat.setInt(5, team.getTeamId());
             stat.setInt(6, team.getTeamLeagueId());
-            stat.setString(7, match.getGameDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
+            stat.setString(7, getGameDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
             stat.setInt(8, gamesLookback);
 
             ResultSet rs = stat.executeQuery();
@@ -119,17 +157,15 @@ public class SoccerMatchAnalysis {
 
     /**
      * Hämta tabell positionen för hemma eller borta laget
-     * 
+     *
      * @param homeTeam - är det hemma laget som ska kontrolleras för matchen?
      * @return position för specifierat lag
      */
     public int getTablePosition(boolean homeTeam) {
         int result = 0;
         updateLeagueTable();
-        Optional<TeamStanding> standingOptional = leagueTable.stream()
-                .filter(p -> p.getTeamName()
-                        .equals(homeTeam ? match.getHomeTeam().getTeamName() : match.getAwayTeam().getTeamName()))
-                .findFirst();
+        Optional<TeamStanding> standingOptional = leagueTable.stream().filter(p -> p.getTeamName().equals(homeTeam ?
+                getHomeTeam().getTeamName() : getAwayTeam().getTeamName())).findFirst();
 
         if (standingOptional.isPresent()) {
             TeamStanding standing = standingOptional.get();
@@ -139,30 +175,26 @@ public class SoccerMatchAnalysis {
     }
 
     private void updateLeagueTable() {
-        if (!leagueTableUpdated.isEqual(match.getGameDate().toLocalDate())) {
-            leagueTable = database.getLeagueTable(match.getHomeTeam().getTeamLeagueId(), match.getSeason(),
-                    match.getHomeTeam().getCountryId(),
-                    match.getGameDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
+        if (!leagueTableUpdated.isEqual(getGameDate().toLocalDate())) {
+            leagueTable = database.getLeagueTable(getHomeTeam().getTeamLeagueId(), getSeason(),
+                    getHomeTeam().getCountryId(), getGameDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
 
-            leagueTableUpdated = match.getGameDate().toLocalDate();
+            leagueTableUpdated = getGameDate().toLocalDate();
         }
     }
 
     /**
-     * 
      * @return Integer - hur många platser det är mellan hemma och borta laget
      */
     public int diffInStanding() {
         int result = 0;
         updateLeagueTable();
 
-        Optional<TeamStanding> homeTeamStandingOptional = leagueTable.stream()
-                .filter(p -> p.getTeamName().equals(match.getHomeTeam().getTeamName()))
-                .findFirst();
+        Optional<TeamStanding> homeTeamStandingOptional =
+                leagueTable.stream().filter(p -> p.getTeamName().equals(getHomeTeam().getTeamName())).findFirst();
 
-        Optional<TeamStanding> awayTeamStandingOptional = leagueTable.stream()
-                .filter(p -> p.getTeamName().equals(match.getAwayTeam().getTeamName()))
-                .findFirst();
+        Optional<TeamStanding> awayTeamStandingOptional =
+                leagueTable.stream().filter(p -> p.getTeamName().equals(getAwayTeam().getTeamName())).findFirst();
 
         if (homeTeamStandingOptional.isPresent() && awayTeamStandingOptional.isPresent()) {
             TeamStanding homeStanding = homeTeamStandingOptional.get();
@@ -174,9 +206,8 @@ public class SoccerMatchAnalysis {
     }
 
     /**
-     * 
      * Vinst förlust ratio för om man är enbart hemma eller bortalag.
-     * 
+     *
      * @param gamesLookback
      * @param homeTeam
      * @return Integer där vinst ger +1 lika ger 0 och förlust get -1
@@ -184,16 +215,16 @@ public class SoccerMatchAnalysis {
     public int winLossRatio(int gamesLookback, boolean homeTeam) {
         int result = 0;
 
-        Team team = homeTeam ? match.getHomeTeam() : match.getAwayTeam();
+        Team team = homeTeam ? getHomeTeam() : getAwayTeam();
 
         String teamSql = homeTeam ? "homeTeamId = ? " : "awayTeamId = ? ";
-        String sql = "SELECT * FROM SoccerResults WHERE " + teamSql
-                + "AND leagueId = ? AND DATE(gameDate) < ? ORDER BY gameDate DESC LIMIT ?";
+        String sql = "SELECT * FROM SoccerResults WHERE " + teamSql + "AND leagueId = ? AND DATE(gameDate) < ? ORDER " +
+                "BY gameDate DESC LIMIT ?";
 
         try (PreparedStatement stat = database.getDbConnection().prepareStatement(sql)) {
             stat.setInt(1, team.getTeamId());
             stat.setInt(2, team.getTeamLeagueId());
-            stat.setString(3, match.getGameDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
+            stat.setString(3, getGameDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
             stat.setInt(4, gamesLookback);
 
             ResultSet rs = stat.executeQuery();
@@ -225,22 +256,20 @@ public class SoccerMatchAnalysis {
     public int winLossRationHomeAndAway(boolean homeTeam, int gamesLookback) {
         int result = 0;
 
-        String sql = "SELECT * FROM "
-                + "(SELECT * FROM SoccerResults WHERE homeTeamId = ? AND leagueId = ? AND DATE(gameDate) < ? ORDER BY gameDate DESC LIMIT ?) a "
-                + "UNION DISTINCT "
-                + "(SELECT * FROM SoccerResults WHERE awayTeamId = ? AND leagueId = ? AND DATE(gameDate) < ? ORDER BY gameDate DESC LIMIT ?) "
-                + "ORDER BY gameDate DESC "
-                + "LIMIT ?";
-        Team team = homeTeam ? match.getHomeTeam() : match.getAwayTeam();
+        String sql = "SELECT * FROM " + "(SELECT * FROM SoccerResults WHERE homeTeamId = ? AND leagueId = ? AND DATE" +
+                "(gameDate) < ? ORDER BY gameDate DESC LIMIT ?) a " + "UNION DISTINCT " + "(SELECT * FROM " +
+                "SoccerResults WHERE awayTeamId = ? AND leagueId = ? AND DATE(gameDate) < ? ORDER BY gameDate DESC " +
+                "LIMIT ?) " + "ORDER BY gameDate DESC " + "LIMIT ?";
+        Team team = homeTeam ? getHomeTeam() : getAwayTeam();
         try (PreparedStatement stat = database.getDbConnection().prepareStatement(sql)) {
             stat.setInt(1, team.getTeamId());
             stat.setInt(2, team.getTeamLeagueId());
-            stat.setString(3, match.getGameDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
+            stat.setString(3, getGameDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
             stat.setInt(4, gamesLookback);
 
             stat.setInt(5, team.getTeamId());
             stat.setInt(6, team.getTeamLeagueId());
-            stat.setString(7, match.getGameDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
+            stat.setString(7, getGameDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
             stat.setInt(8, gamesLookback);
 
             stat.setInt(9, gamesLookback);
@@ -250,8 +279,8 @@ public class SoccerMatchAnalysis {
             while (rs.next()) {
                 if (rs.getInt("homeTeamId") == team.getTeamId() && rs.getInt("homeScore") > rs.getInt("awayScore")) {
                     result++;
-                } else if (rs.getInt("awayTeamId") == team.getTeamId()
-                        && rs.getInt("awayScore") > rs.getInt("homeScore")) {
+                } else if (rs.getInt("awayTeamId") == team.getTeamId() && rs.getInt("awayScore") > rs.getInt(
+                        "homeScore")) {
                     result++;
                 } else {
                     result--;
@@ -266,23 +295,21 @@ public class SoccerMatchAnalysis {
 
     public int goalsScoredHomeAndAway(boolean homeTeam, int gameLookback) {
         int result = 0;
-        Team team = homeTeam ? match.getHomeTeam() : match.getAwayTeam();
+        Team team = homeTeam ? getHomeTeam() : getAwayTeam();
 
-        String sql = "SELECT * FROM "
-                + "(SELECT * FROM SoccerResults WHERE homeTeamId = ? AND leagueId = ? AND DATE(gameDate) < ? ORDER BY gameDate DESC LIMIT ?) a "
-                + "UNION ALL "
-                + "(SELECT * FROM SoccerResults WHERE awayTeamId = ? AND leagueId = ? AND DATE(gameDate) < ? ORDER BY gameDate DESC LIMIT ?) "
-                + "ORDER BY gameDate DESC "
-                + "LIMIT ?";
+        String sql = "SELECT * FROM " + "(SELECT * FROM SoccerResults WHERE homeTeamId = ? AND leagueId = ? AND DATE" +
+                "(gameDate) < ? ORDER BY gameDate DESC LIMIT ?) a " + "UNION ALL " + "(SELECT * FROM SoccerResults " +
+                "WHERE awayTeamId = ? AND leagueId = ? AND DATE(gameDate) < ? ORDER BY gameDate DESC LIMIT ?) " +
+                "ORDER BY gameDate DESC " + "LIMIT ?";
 
         try (PreparedStatement stat = database.getDbConnection().prepareStatement(sql)) {
             stat.setInt(1, team.getTeamId());
             stat.setInt(2, team.getTeamLeagueId());
-            stat.setString(3, match.getGameDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
+            stat.setString(3, getGameDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
             stat.setInt(4, gameLookback);
             stat.setInt(5, team.getTeamId());
             stat.setInt(6, team.getTeamLeagueId());
-            stat.setString(7, match.getGameDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
+            stat.setString(7, getGameDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
             stat.setInt(8, gameLookback);
             stat.setInt(9, gameLookback);
 
@@ -304,17 +331,15 @@ public class SoccerMatchAnalysis {
 
     public int goalsScoredHomeOrAway(boolean homeTeam, int gameLookback) {
         int result = 0;
-        Team team = homeTeam ? match.getHomeTeam() : match.getAwayTeam();
+        Team team = homeTeam ? getHomeTeam() : getAwayTeam();
         String homeOrAway = homeTeam ? "home" : "away";
-        String sql = "SELECT SUM(" + homeOrAway
-                + "Score) FROM SoccerResults WHERE " + homeOrAway
-                + "TeamId = ? AND leagueId = ? AND DATE(gameDate) < ? ORDER BY gameDate DESC LIMIT ? "
-                + "ORDER BY gameDate DESC";
+        String sql = "SELECT SUM(" + homeOrAway + "Score) FROM SoccerResults WHERE " + homeOrAway + "TeamId = ? AND " +
+                "leagueId = ? AND DATE(gameDate) < ? ORDER BY gameDate DESC LIMIT ? " + "ORDER BY gameDate DESC";
 
         try (PreparedStatement stat = database.getDbConnection().prepareStatement(sql)) {
             stat.setInt(1, team.getTeamId());
             stat.setInt(2, team.getTeamLeagueId());
-            stat.setString(3, match.getGameDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
+            stat.setString(3, getGameDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
             stat.setInt(4, gameLookback);
 
             ResultSet rs = stat.executeQuery();
@@ -327,5 +352,4 @@ public class SoccerMatchAnalysis {
         }
         return result;
     }
-
 }

+ 55 - 0
OddsJavaFx/src/objects/SoccerMatchCalcBestValue.java

@@ -0,0 +1,55 @@
+package objects;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class SoccerMatchCalcBestValue extends SoccerMatch {
+
+    private Map<Integer, Integer> homeWins = new HashMap<Integer, Integer>();
+    private Map<Integer, Integer> homeDraws = new HashMap<Integer, Integer>();
+    private Map<Integer, Integer> homeLosses = new HashMap<Integer, Integer>();
+    private Map<Integer, Integer> awayWins = new HashMap<Integer, Integer>();
+    private Map<Integer, Integer> awayDraws = new HashMap<Integer, Integer>();
+    private Map<Integer, Integer> awayLosses = new HashMap<Integer, Integer>();
+
+    public void setHomeWins(int lookback, int value) {
+        homeWins.put(lookback, value);
+    }
+    public void setHomeDraws(int lookback, int value) {
+        homeDraws.put(lookback, value);
+    }
+    public void setHomeLosses(int lookback, int value) {
+        homeLosses.put(lookback, value);
+    }
+
+    public int getHomeWins(int lookback) {
+        return homeWins.getOrDefault(lookback, -1);
+    }
+    public int getHomeDraws(int lookback) {
+        return homeDraws.getOrDefault(lookback, -1);
+    }
+    public int getHomeLosses(int lookback) {
+        return homeLosses.getOrDefault(lookback, -1);
+    }
+
+    public void setAwayWins(int lookback, int value) {
+        awayWins.put(lookback, value);
+    }
+    public void setAwayDraws(int lookback, int value) {
+        awayDraws.put(lookback, value);
+    }
+    public void setAwayLosses(int lookback, int value) {
+        awayLosses.put(lookback, value);
+    }
+
+    public int getAwayWins(int lookback) {
+        return awayWins.getOrDefault(lookback, -1);
+    }
+    public int getAwayDraws(int lookback) {
+        return awayDraws.getOrDefault(lookback, -1);
+    }
+    public int getAwayLosses(int lookback) {
+        return awayLosses.getOrDefault(lookback, -1);
+    }
+
+}

+ 1 - 1
OddsJavaFx/src/parser/OddsPortal.java

@@ -235,7 +235,7 @@ public class OddsPortal implements ParserJoinedFunctions {
                             awayScore, overtime, odds1, oddsX, odds2, countryId, season, leagueId, sportId));
                 }
             }
-        } catch (FailingHttpStatusCodeException | IOException | SQLException e) {
+        } catch (FailingHttpStatusCodeException | IOException e) {
             e.printStackTrace();
         }
     }

+ 124 - 0
OddsJavaFx/src/parser/Svenskaspel.java

@@ -0,0 +1,124 @@
+package parser;
+
+import data.GuiMysql;
+import io.github.bonigarcia.wdm.WebDriverManager;
+import objects.SoccerMatch;
+import objects.SoccerMatchAnalysis;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.chrome.ChromeDriver;
+import org.openqa.selenium.chrome.ChromeOptions;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class Svenskaspel {
+
+    String matchesXPATH = "//div[@class = 'pg_coupon_static__event_container']";
+    String date;
+
+    public List<SoccerMatchAnalysis> GetStryktipsetSelenium(String date) {
+        this.date = date;
+        String url = "https://spela.svenskaspel.se/stryktipset/resultat/" + date + "/statistik";
+
+        //RemoteWebDriver seleniumDriver = getSeleniumDriver();
+        //seleniumDriver.get(url);
+
+        WebDriverManager.chromedriver().setup();
+        ChromeDriver driver = new ChromeDriver(getChromeOptions());
+        driver.get(url);
+
+        CloseCookiePopup(driver);
+
+        try {
+            Thread.sleep(3000);
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+
+        List<SoccerMatchAnalysis> matches = FindMatches(driver);
+
+        driver.close();
+        driver.quit();
+        return matches;
+    }
+
+    private List<SoccerMatchAnalysis> FindMatches(WebDriver driver) {
+        List<SoccerMatch> soccerMatches = new ArrayList<>();
+        List<SoccerMatchAnalysis> matchAnalyses = new ArrayList<>();
+
+        List<WebElement> matches = driver.findElements(By.xpath(matchesXPATH));
+        for (WebElement match : matches) {
+            List<String> teamNames = GetNames(match);
+            soccerMatches.add(GuiMysql.getInstance().getMatch(date,
+                    teamNames.get(0).trim().replace(" ", "%"),
+                    teamNames.get(1).trim().replace(" ", "%")));
+        }
+
+        for (SoccerMatch match : soccerMatches) {
+            try {
+                matchAnalyses.add(new SoccerMatchAnalysis(match));
+            } catch (NullPointerException e) {
+                System.out.println("Failed to get team info between " + match.getHomeTeamName() + "-" + match.getAwayTeamName());
+            }
+        }
+
+        return matchAnalyses;
+    }
+
+    private List<String> GetNames(WebElement match) {
+        List<String> result = new ArrayList<>();
+
+        WebElement hometeamWebElement = match.findElement(By.xpath("./a/div[2]/span[1]"));
+        WebElement awayteamWebElement = match.findElement(By.xpath("./a/div[2]/span[3]"));
+
+        if (hometeamWebElement.findElements(By.xpath("./abbr")).size() == 1) {
+            String teamName = hometeamWebElement.findElement(By.xpath("./abbr")).getAttribute("title");
+            result.add(teamName);
+        } else {
+            result.add(hometeamWebElement.findElement(By.xpath("./span")).getText());
+        }
+
+        if (awayteamWebElement.findElements(By.xpath("./abbr")).size() == 1) {
+            String teamName = awayteamWebElement.findElement(By.xpath("./abbr")).getAttribute("title");
+            result.add(teamName);
+        } else {
+            result.add(awayteamWebElement.findElement(By.xpath("./span")).getText());
+        }
+
+        return result;
+    }
+
+    private void CloseCookiePopup(WebDriver driver) {
+        WebElement acceptButton = driver.findElement(By.xpath("//button[contains(@class,'primary')]"));
+        acceptButton.click();
+    }
+
+    private ChromeOptions getChromeOptions() {
+        ChromeOptions options = new ChromeOptions();
+        // Fixing 255 Error crashes
+        options.addArguments("--no-sandbox");
+        options.addArguments("--disable-dev-shm-usage");
+
+        // Options to trick bot detection
+        // Removing webdriver property
+        options.addArguments("--disable-blink-features=AutomationControlled");
+        options.setExperimentalOption("excludeSwitches", Collections.singletonList("enable-automation"));
+        options.setExperimentalOption("useAutomationExtension", null);
+
+        // Changing the user agent / browser fingerprint
+        options.addArguments("window-size=1920,1080");
+        options.addArguments(
+                "user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36");
+
+        // Other
+        options.addArguments("disable-infobars");
+
+        return options;
+    }
+}

+ 22 - 9
OddsJavaFx/src/tests/LastResultsTest.java

@@ -7,6 +7,7 @@ import java.util.List;
 
 import data.GuiMysql;
 import objects.SoccerMatch;
+import objects.SoccerMatchCalcBestValue;
 import objects.TeamResults;
 
 public class LastResultsTest extends TestClass {
@@ -105,8 +106,12 @@ public class LastResultsTest extends TestClass {
 		int bestLookBack = 1;
 		float bestBankResult = 1000f;
 
-		final List<SoccerMatch> matches = GuiMysql.getInstance().getMatches(sportId, countryId, leagueId,
+		/* final List<SoccerMatch> matches = GuiMysql.getInstance().getMatches(sportId, countryId, leagueId,
 				LocalDate.now().atStartOfDay().format(DateTimeFormatter.ISO_DATE), "ASC", false, false);
+*/
+		final List<SoccerMatchCalcBestValue> matches = GuiMysql.getInstance().getMatchesForCalcBestValues(countryId, leagueId,
+				LocalDate.now().atStartOfDay().format(DateTimeFormatter.ISO_DATE));
+
 
 		final LocalDateTime currentDate = matches.get(0).getGameDate();
 		LocalDate localDate = currentDate.toLocalDate();
@@ -118,20 +123,27 @@ public class LastResultsTest extends TestClass {
 				int wins = 0;
 				final float betMarginDecimal = 1 + (betMargin / (float) 100);
 				bank = startingBank;
-				for (final SoccerMatch soccerMatch : matches) {
+				for (final SoccerMatchCalcBestValue soccerMatch : matches) {
 					if (soccerMatch.getHomeScore() < 0 || soccerMatch.getAwayScore() < 0) {
 						continue;
 					}
 
-					final TeamResults homeTeamResults = GuiMysql.getInstance().getTeamResultsTest(soccerMatch.getHomeTeam().getTeamId(), lookBack,
+/*					final TeamResults homeTeamResults = GuiMysql.getInstance().getTeamResultsTest(soccerMatch.getHomeTeam().getTeamId(), lookBack,
 							true, soccerMatch.getGameDate().format(DateTimeFormatter.ISO_DATE));
 					final TeamResults awayTeamResults = GuiMysql.getInstance().getTeamResultsTest(soccerMatch.getAwayTeam().getTeamId(), lookBack,
 							false, soccerMatch.getGameDate().format(DateTimeFormatter.ISO_DATE));
-
-					final float homeWinPercent = (homeTeamResults.getWins() + awayTeamResults.getLosses())
-							/ Float.valueOf(homeTeamResults.getCount() + awayTeamResults.getCount()) * 100;
-					final float awayWinPercent = (homeTeamResults.getLosses() + awayTeamResults.getWins())
+*/
+					final float homeWinPercent = (soccerMatch.getHomeWins(lookBack) + soccerMatch.getAwayLosses(lookBack))
+							/ Float.valueOf(lookBack * 2) * 100;
+					/*final float awayWinPercent = (homeTeamResults.getLosses() + awayTeamResults.getWins())
 							/ Float.valueOf(homeTeamResults.getCount() + awayTeamResults.getCount()) * 100;
+					 */
+					final float awayWinPercent = (soccerMatch.getHomeLosses(lookBack) + soccerMatch.getAwayWins(lookBack))
+							/ Float.valueOf(lookBack * 2) * 100;
+
+					if (homeWinPercent < 0 ||awayWinPercent < 0) {
+						continue;
+					}
 
 					final float homeOdds = 100 / homeWinPercent;
 					final float awayOdds = 100 / awayWinPercent;
@@ -165,11 +177,12 @@ public class LastResultsTest extends TestClass {
 					bestBetMargin = betMargin;
 					bestLookBack = lookBack;
 					bestBankResult = bank;
-				} else {
+				}
+				/*else {
 					System.out.println("NOT BEST bank " + bank + " with lookback " + lookBack + " and betMargin " + betMargin + " Bet on "
 							+ betOnGameCount + " of " + matches.size() + "(" + betOnGameCount / (float) matches.size() + ") wins " + wins + "("
 							+ wins / Float.valueOf(betOnGameCount) + ")" + " Win / game " + (bank - startingBank) / Float.valueOf(wins) + " kr");
-				}
+				}*/
 			}
 		}
 	}

+ 2 - 2
OddsJavaFx/src/tests/RelevanceTest.java

@@ -224,9 +224,9 @@ public class RelevanceTest extends TestClass {
         for (SoccerMatch soccerMatch : matches) {
             SoccerMatchAnalysis analysis = new SoccerMatchAnalysis(soccerMatch);
             int homeWinsCount = analysis.winLossRationHomeAndAway(true, gamesLookback);
-            int awayWindCount = analysis.winLossRationHomeAndAway(false, gamesLookback);
+            int awayWinsCount = analysis.winLossRationHomeAndAway(false, gamesLookback);
 
-            int diff = homeWinsCount - awayWindCount;
+            int diff = homeWinsCount - awayWinsCount;
 
             checkBetResults(soccerMatch, diff);
         }