Axel Nordh il y a 4 ans
Parent
commit
90fa617a41

+ 21 - 0
OddsJavaFx/.classpath

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
+		<attributes>
+			<attribute name="module" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="lib" path="C:/Users/Axel/.m2/repository/com/google/guava/guava/30.0-jre/guava-30.0-jre.jar" sourcepath="C:/Users/Axel/.m2/repository/com/google/guava/guava/30.0-jre/guava-30.0-jre-sources.jar">
+		<attributes>
+			<attribute name="maven.pomderived" value="true"/>
+			<attribute name="maven.groupId" value="com.google.guava"/>
+			<attribute name="maven.artifactId" value="guava"/>
+			<attribute name="maven.version" value="30.0-jre"/>
+			<attribute name="maven.scope" value="compile"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/JavaFX"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/Odds"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>

+ 23 - 0
OddsJavaFx/.project

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>OddsJavaFx</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.xtext.ui.shared.xtextBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.xtext.ui.shared.xtextNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

+ 15 - 0
OddsJavaFx/.settings/org.eclipse.jdt.core.prefs

@@ -0,0 +1,15 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=11
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=11

+ 5 - 0
OddsJavaFx/bin/.gitignore

@@ -0,0 +1,5 @@
+/application/
+/controllers/
+/data/
+/fxml/
+/objects/

+ 8 - 0
OddsJavaFx/build.fxbuild

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="ASCII"?>
+<anttasks:AntTask xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:anttasks="http://org.eclipse.fx.ide.jdt/1.0" buildDirectory="${project}/build">
+  <deploy>
+    <application name="OddsJavaFx"/>
+    <info/>
+  </deploy>
+  <signjar/>
+</anttasks:AntTask>

+ 49 - 0
OddsJavaFx/src/application/Main.java

@@ -0,0 +1,49 @@
+package application;
+
+import java.io.IOException;
+
+import javafx.application.Application;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.Scene;
+import javafx.scene.layout.StackPane;
+import javafx.stage.Stage;
+
+
+public class Main extends Application {
+
+	private Stage primaryStage;
+	private StackPane rootLayout;
+
+	@Override
+	public void start(Stage primaryStage) {
+		try {
+			this.primaryStage = primaryStage;
+			this.primaryStage.setTitle("New Odds");
+
+			initRootLayout();
+		} catch(final Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	public void initRootLayout() {
+		try {
+			// Load root layout from fxml file.
+			final FXMLLoader loader = new FXMLLoader();
+			loader.setLocation(Main.class.getResource("../fxml/OddsFxBuilder.fxml"));
+			rootLayout = (StackPane) loader.load();
+
+			// Show the scene containing the root layout.
+			final Scene scene = new Scene(rootLayout);
+			primaryStage.setScene(scene);
+			primaryStage.show();
+		} catch (final IOException e) {
+			e.printStackTrace();
+		}
+	}
+
+	public static void main(String[] args) {
+		launch(args);
+	}
+
+}

+ 1 - 0
OddsJavaFx/src/application/application.css

@@ -0,0 +1 @@
+/* JavaFX CSS - Leave this comment until you have at least create one rule which uses -fx-Property */

+ 249 - 0
OddsJavaFx/src/controllers/MainController.java

@@ -0,0 +1,249 @@
+package controllers;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.net.URL;
+import java.time.LocalDate;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ResourceBundle;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+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.Button;
+import javafx.scene.control.ChoiceBox;
+import javafx.scene.control.ComboBox;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.Pane;
+import objects.SoccerMatch;
+import parser.OddsPortal;
+
+public class MainController implements Initializable {
+
+	@FXML private MatchTabController matchTabController;
+	@FXML private StatisticsTabController statTabController;
+	@FXML private MatchStatTabController matchStatTabController;
+
+	ObservableList<String> sports = FXCollections.observableArrayList();
+	ObservableList<String> countries = FXCollections.observableArrayList();
+	ObservableList<String> leagues = FXCollections.observableArrayList();
+	ObservableList<String> homeTeams = FXCollections.observableArrayList();
+	ObservableList<String> awayTeams = FXCollections.observableArrayList();
+
+	@FXML private ComboBox<String> sportSelector;
+	@FXML private ComboBox<String> countrySelector;
+	@FXML private ComboBox<String> leagueSelector;
+	@FXML private ChoiceBox<String> homeTeamSelector;
+	@FXML private ChoiceBox<String> awayTeamSelector;
+	@FXML private Button resetFilterButton;
+	@FXML private Button getLeagueInfoButton;
+	@FXML private Button getMoreLeagueInfo;
+	@FXML private Button updateStatsTableButton;
+	@FXML private Button showMatchStatsButton;
+	@FXML private TextField avgLeagueHomeScoreTxt;
+	@FXML private TextField avgLeagueAwayScoreTxt;
+	@FXML private TextField league0Goals;
+	@FXML private TextField league1Goal;
+	@FXML private TextField league1Goals;
+	@FXML private TextField league2Goals;
+	@FXML private TextField league3Goals;
+	@FXML private TextField league4Goals;
+	@FXML private TextField league5Goals;
+	@FXML private TextField league6Goals;
+
+	@FXML private Pane glass;
+
+	private ArrayList<SimpleEntry<Integer, String>> sportsList = Lists.newArrayList();
+	private final ArrayList<SimpleEntry<Integer, String>> countriesList = Lists.newArrayList();
+	private ArrayList<SimpleEntry<Integer, String>> leaguesList = Lists.newArrayList();
+
+	@SuppressWarnings("unchecked")
+	@Override
+	public void initialize(URL arg0, ResourceBundle arg1) {
+		sportsList = GuiMysql.getInstance().getSports();
+		sports.add("Sport");
+		for (final SimpleEntry<Integer, String>  entry : sportsList) {
+			if (entry.getValue().equals("soccer")) { // Använder just nu bara Soccer
+				sports.add(entry.getValue());
+			}
+		}
+
+		matchTabController.getTable().getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection) -> {
+			if (newSelection != null) {
+				showMatchStatsButton.setDisable(false);
+				final Object selectedItem = matchTabController.getTable().getSelectionModel().getSelectedItem();
+				System.out.println(selectedItem.toString());
+			} else {
+				showMatchStatsButton.setDisable(true);
+			}
+		});
+
+		sportSelector.setItems(sports);
+		countrySelector.setItems(countries);
+		leagueSelector.setItems(leagues);
+	}
+
+	@FXML
+	private void SportSelected(ActionEvent event) throws IOException {
+		if (sportSelector.getValue() != null && !sportSelector.getValue().equals("Sport")) {
+			countrySelector.setDisable(false);
+			final int sportId = sportsList.stream().filter(p -> p.getValue().equals(sportSelector.getValue())).findFirst().get().getKey();
+			final ArrayList<SoccerMatch> upcomingMatches = GuiMysql.getInstance().getTodaysMatches("SoccerResults", sportId);
+
+			matchTabController.setMatches(upcomingMatches, matchStatTabController);
+			countriesList.clear();
+			for (final SoccerMatch soccerMatch : upcomingMatches) {
+				homeTeams.add(soccerMatch.getHomeTeam().getTeamName());
+				awayTeams.add(soccerMatch.getAwayTeam().getTeamName());
+
+				if (countriesList.stream().noneMatch(p -> p != null && p.getValue().equals(soccerMatch.getHomeTeam().getCountryName()))) {
+					countriesList.add(new SimpleEntry<>(soccerMatch.getHomeTeam().getCountryId(), soccerMatch.getHomeTeam().getCountryName()));
+				}
+			}
+
+			countriesList.sort((c1, c2) -> c1.getValue().compareTo(c2.getValue()));
+			countriesList.forEach(c -> countries.add(c.getValue()));
+
+			homeTeamSelector.setItems(homeTeams);
+			awayTeamSelector.setItems(awayTeams);
+		}
+	}
+
+	@FXML
+	private void CountrySelected(ActionEvent event) {
+		if (countrySelector.getValue() != null && !countrySelector.getValue().equals("Country")) {
+			leagueSelector.setDisable(false);
+			final int countryId = getCountryIdFromSelector();
+			final int sportId = sportsList.stream().filter(p -> p.getValue().equals(sportSelector.getValue())).findFirst().get().getKey();
+			matchTabController.filterCountryMatches(countrySelector.getValue());
+
+			leaguesList = GuiMysql.getInstance().getLeagues(sportId, countryId);
+			final List<String> leaguesInTable = Lists.newArrayList();
+			matchTabController.getTableMatches().forEach(tr -> leaguesInTable.add((String) tr.get("league")));
+			final HashSet<String> newHashSet = Sets.newHashSet(leaguesInTable);
+
+			leagues.clear();
+			leagues.add("League");
+			leagues.addAll(newHashSet);
+		}
+	}
+
+	//	private Integer getSportIdFromSelector() {
+	//		return sportsList.stream().filter(p -> p.getValue().equals(sportSelector.getValue())).findFirst().get().getKey();
+	//	}
+
+	private Integer getCountryIdFromSelector() {
+		return countriesList.stream().filter(p -> p.getValue().equals(countrySelector.getValue())).findFirst().get().getKey();
+	}
+
+	private Integer getLeagueIdFromSelector() {
+		return leaguesList.stream().filter(p -> p.getValue().equals(leagueSelector.getValue())).findFirst().get().getKey();
+	}
+
+	@FXML
+	private void LeagueSelected(ActionEvent event) {
+
+		if (leagueSelector.getValue() != null && !leagueSelector.getValue().equals("League")) {
+			homeTeamSelector.setDisable(false);
+			awayTeamSelector.setDisable(false);
+			showMatchStatsButton.setDisable(false);
+			if (GuiMysql.getInstance().getParsingStarted(getCountryIdFromSelector(), getLeagueIdFromSelector())) {
+				getLeagueInfoButton.setDisable(true);
+				getMoreLeagueInfo.setDisable(false);
+			} else {
+				getLeagueInfoButton.setDisable(false);
+				getMoreLeagueInfo.setDisable(true);
+			}
+			matchTabController.filterLeagueMatches(leagueSelector.getValue());
+			updateStatsTableButton.setDisable(false);
+			final ArrayList<Float> leagueAvareges = GuiMysql.getInstance().getLeagueAvarages(getLeagueIdFromSelector(), getCountryIdFromSelector());
+
+			avgLeagueHomeScoreTxt.setText(leagueAvareges.get(0).toString());
+			avgLeagueAwayScoreTxt.setText(leagueAvareges.get(1).toString());
+		} else {
+			getMoreLeagueInfo.setDisable(true);
+			getLeagueInfoButton.setDisable(true);
+			updateStatsTableButton.setDisable(true);
+			showMatchStatsButton.setDisable(true);
+		}
+	}
+
+	@FXML
+	private void ResetFilter() {
+		sportSelector.setValue("Sport");
+		countrySelector.setValue("Country");
+		leagueSelector.setValue("League");
+		leagueSelector.setDisable(true);
+		countrySelector.setDisable(true);
+		matchTabController.resetFilter();
+	}
+
+	@FXML void getLeagueInfo() {
+		final String country = countrySelector.getValue().trim();
+		final String league = leagueSelector.getValue().trim();
+		glass.setDisable(false);
+		glass.setVisible(true);
+		glass.setOpacity(0.8);
+		final OddsPortal op = new OddsPortal();
+		op.getHistoricMatches(sportSelector.getValue().trim(), country, league, String.valueOf(LocalDate.now().getYear()));
+		glass.setOpacity(0.0);
+		glass.setVisible(false);
+		glass.setDisable(true);
+	}
+
+	@FXML
+	private void UpdateStatsTable() {
+		statTabController.setOverUnderTable(getLeagueIdFromSelector());
+	}
+
+	@FXML
+	private void getMoreLeagueInfo() {
+		final String lastParsedYear = GuiMysql.getInstance().getLastParsedYear(leagueSelector.getValue().trim(), getCountryIdFromSelector());
+		final String nextParseYear;
+		if (lastParsedYear.contains("-")) {
+			final String[] years = lastParsedYear.split("-");
+			int firstYear = Integer.valueOf(years[0]);
+			int lastYear = Integer.valueOf(years[1]);
+			firstYear--;
+			lastYear--;
+			nextParseYear = firstYear + "-" + lastYear;
+		} else if (lastParsedYear.length() == 4) {
+			Integer val = Integer.valueOf(lastParsedYear);
+			val--;
+			nextParseYear = String.valueOf(val);
+		} else {
+			System.out.println("Fail to get More league info for " + lastParsedYear);
+			return;
+		}
+
+		final String country = countrySelector.getValue().trim();
+		final String league = leagueSelector.getValue().trim();
+
+
+		final OddsPortal op = new OddsPortal();
+		op.getHistoricMatches("soccer", country, league, nextParseYear);
+	}
+
+	@FXML
+	private void setMatchStatInfo() {
+		final HashMap<?, ?> selectedItem = (HashMap<?, ?>) matchTabController.getTable().getSelectionModel().getSelectedItem();
+		final String season = GuiMysql.getInstance().getLastSeason(getCountryIdFromSelector(), getLeagueIdFromSelector());
+		matchStatTabController.setLeagueStandingsTable(getLeagueIdFromSelector(), season, getCountryIdFromSelector());
+		matchStatTabController.updateTab((String)selectedItem.get("homeTeam"), (String)selectedItem.get("awayTeam"),
+				((BigDecimal)selectedItem.get("goalDiff")).floatValue(),
+				((Float) selectedItem.get("avgScoreHome")),
+				((Float)selectedItem.get("avgConcededHome")),
+				((Float)selectedItem.get("avgScoreAway")),
+				((Float)selectedItem.get("avgConcededAway")));
+	}
+}

+ 64 - 0
OddsJavaFx/src/controllers/MatchResultTabController.java

@@ -0,0 +1,64 @@
+package controllers;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.fxml.Initializable;
+import javafx.scene.control.TableColumn;
+import javafx.scene.control.TableView;
+import javafx.scene.control.cell.MapValueFactory;
+import objects.SoccerMatch;
+
+@SuppressWarnings("rawtypes")
+public class MatchResultTabController implements Initializable {
+
+	@FXML TableColumn<Map, String> homeTeamColumn = new TableColumn<>("Home Team");
+	@FXML TableColumn<Map, String> awayTeamColumn = new TableColumn<>("Away Team");
+	@FXML TableColumn<Map, Float> goalsHomeColumn = new TableColumn<>("Goals home");
+	@FXML TableColumn<Map, Float> goalsAwayColumn = new TableColumn<>("Goals away");
+	@FXML TableColumn<Map, String> countryColumn = new TableColumn<>("Country");
+	@FXML TableColumn<Map, String> leagueColumn = new TableColumn<>("League");
+
+	@FXML private TableView<Map<String, Object>> matchResultTable;
+
+	private ObservableList<Map<String, Object>> matches;
+
+	public MatchResultTabController() {
+	}
+
+	@Override
+	public void initialize(URL arg0, ResourceBundle arg1) {
+		homeTeamColumn.setCellValueFactory(new MapValueFactory<>("homeTeam"));
+		awayTeamColumn.setCellValueFactory(new MapValueFactory<>("awayTeam"));
+		goalsHomeColumn.setCellValueFactory(new MapValueFactory<>("goalsHome"));
+		goalsAwayColumn.setCellValueFactory(new MapValueFactory<>("goalsAway"));
+		countryColumn.setCellValueFactory(new MapValueFactory<>("country"));
+		leagueColumn.setCellValueFactory(new MapValueFactory<>("league"));
+
+		matches = FXCollections.<Map<String, Object>>observableArrayList();
+
+	}
+
+	public void setMatches(ArrayList<SoccerMatch> upcomingMatches) {
+
+		for (final SoccerMatch soccerMatch : upcomingMatches) {
+			final Map<String, Object> match = new HashMap<>();
+			match.put("homeTeam", soccerMatch.getHomeTeam().getTeamName());
+			match.put("awayTeam", soccerMatch.getAwayTeam().getTeamName());
+
+			match.put("country", soccerMatch.getHomeTeam().getCountryName());
+			match.put("league", soccerMatch.getHomeTeam().getTeamLeague());
+
+			matches.add(match);
+		}
+
+		matchResultTable.getItems().addAll(matches);
+
+	}
+}

+ 73 - 0
OddsJavaFx/src/controllers/MatchStatTabController.java

@@ -0,0 +1,73 @@
+package controllers;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+import com.google.common.collect.Maps;
+
+import data.GuiMysql;
+import javafx.fxml.FXML;
+import javafx.fxml.Initializable;
+import javafx.scene.control.TableColumn;
+import javafx.scene.control.TableView;
+import javafx.scene.control.cell.MapValueFactory;
+import objects.TeamStanding;
+
+@SuppressWarnings("rawtypes")
+public class MatchStatTabController implements Initializable {
+
+	@FXML TableView<Map<String, Object>> matchStatTable;
+
+	@FXML TableColumn<Map, String> team = new TableColumn<>("team");
+	@FXML TableColumn<Map, Integer> gamesPlayed = new TableColumn<>("gamesPlayed");
+	@FXML TableColumn<Map, Integer> win = new TableColumn<>("win");
+	@FXML TableColumn<Map, Integer> draw = new TableColumn<>("draw");
+	@FXML TableColumn<Map, Integer> loss = new TableColumn<>("loss");
+	@FXML TableColumn<Map, Integer> points = new TableColumn<>("points");
+	@FXML TableColumn<Map, Float> goalsScored = new TableColumn<>("goalsScored");
+	@FXML TableColumn<Map, Float> goalsConceded = new TableColumn<>("goalsConceded");
+	@FXML TableColumn<Map, Float> diff = new TableColumn<>("diff");
+
+	public MatchStatTabController() {
+	}
+
+	@Override
+	public void initialize(URL arg0, ResourceBundle arg1) {
+		team.setCellValueFactory(new MapValueFactory<>("team"));
+		gamesPlayed.setCellValueFactory(new MapValueFactory<>("gamesPlayed"));
+		win.setCellValueFactory(new MapValueFactory<>("win"));
+		draw.setCellValueFactory(new MapValueFactory<>("draw"));
+		loss.setCellValueFactory(new MapValueFactory<>("loss"));
+		points.setCellValueFactory(new MapValueFactory<>("points"));
+		goalsScored.setCellValueFactory(new MapValueFactory<>("goalsScored"));
+		goalsConceded.setCellValueFactory(new MapValueFactory<>("goalsConceded"));
+		diff.setCellValueFactory(new MapValueFactory<>("diff"));
+	}
+
+
+
+	public void updateTab(String homeTeam, String awayTeam, Float goalDiff, Float homeScore, Float homeConcede, Float awayScore, Float awayConceded) {
+
+	}
+
+	public void setLeagueStandingsTable(int leagueId, String season, int countryId) {
+		final ArrayList<TeamStanding> res = GuiMysql.getInstance().getLeagueTable(leagueId, season, countryId);
+		matchStatTable.getItems().clear();
+		for (final TeamStanding ts : res) {
+			final Map<String, Object> line = Maps.newHashMap();
+			final int gamesPlayed = ts.getWins() + ts.getDraws() + ts.getLosses();
+			line.put("team", ts.getTeamName());
+			line.put("gamesPlayed", gamesPlayed);
+			line.put("win", ts.getWins());
+			line.put("draw", ts.getDraws());
+			line.put("loss", ts.getLosses());
+			line.put("points", ts.getPoints());
+			line.put("goalsScored", ts.getGoalsScored() / gamesPlayed);
+			line.put("goalsConceded", ts.getGoalsConceded() / gamesPlayed);
+
+			matchStatTable.getItems().add(line);
+		}
+	}
+}

+ 195 - 0
OddsJavaFx/src/controllers/MatchTabController.java

@@ -0,0 +1,195 @@
+package controllers;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import com.google.common.collect.Lists;
+
+import data.GuiMysql;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.fxml.Initializable;
+import javafx.scene.control.TableColumn;
+import javafx.scene.control.TableView;
+import javafx.scene.control.cell.MapValueFactory;
+import objects.SoccerMatch;
+import objects.TeamResults;
+
+@SuppressWarnings("rawtypes")
+public class MatchTabController implements Initializable {
+
+	@FXML TableColumn<Map, String> gameDateColumn = new TableColumn<>("Gamedate");
+	@FXML TableColumn<Map, String> homeTeamColumn = new TableColumn<>("Home Team");
+	@FXML TableColumn<Map, String> awayTeamColumn = new TableColumn<>("Away Team");
+	@FXML TableColumn<Map, Float> odds1Column = new TableColumn<>("odds 1");
+	@FXML TableColumn<Map, Float> oddsXColumn = new TableColumn<>("odds X");
+	@FXML TableColumn<Map, Float> odds2Column = new TableColumn<>("odds 2");
+	@FXML TableColumn<Map, Float> goalsHomeColumn = new TableColumn<>("Goals home");
+	@FXML TableColumn<Map, Float> goalsAwayColumn = new TableColumn<>("Goals away");
+	@FXML TableColumn<Map, Float> goalDiff = new TableColumn<>("Difference");
+	@FXML TableColumn<Map, Float> avgScoreHomeColumn = new TableColumn<>("Avg score home");
+	@FXML TableColumn<Map, Float> avgConcededHomeColumn = new TableColumn<>("Avg conceded home");
+	@FXML TableColumn<Map, Float> avgScoreAwayColumn = new TableColumn<>("Avg score away");
+	@FXML TableColumn<Map, Float> avgConcededAwayColumn = new TableColumn<>("Avg conceded away");
+	@FXML TableColumn<Map, String> countryColumn = new TableColumn<>("Country");
+	@FXML TableColumn<Map, String> leagueColumn = new TableColumn<>("League");
+
+	@FXML TableColumn<Map, String> homeWinColumn = new TableColumn<>("homeWin");
+	@FXML TableColumn<Map, String> drawColumn = new TableColumn<>("draw");
+	@FXML TableColumn<Map, String> awayWinColumn = new TableColumn<>("awayWin");
+
+	@FXML private TableView<Map<String, Object>> matchTable;
+
+	private ObservableList<Map<String, Object>> matches;
+	private ObservableList<Map<String, Object>> originalMatches;
+	private ObservableList<Map<String, Object>> coutryFilteredMatches;
+
+	public MatchTabController() {
+	}
+
+	@Override
+	public void initialize(URL arg0, ResourceBundle arg1) {
+		gameDateColumn.setCellValueFactory(new MapValueFactory<>("gameDate"));
+		homeTeamColumn.setCellValueFactory(new MapValueFactory<>("homeTeam"));
+		awayTeamColumn.setCellValueFactory(new MapValueFactory<>("awayTeam"));
+		odds1Column.setCellValueFactory(new MapValueFactory<>("odds1"));
+		oddsXColumn.setCellValueFactory(new MapValueFactory<>("oddsX"));
+		odds2Column.setCellValueFactory(new MapValueFactory<>("odds2"));
+		goalsHomeColumn.setCellValueFactory(new MapValueFactory<>("goalsHome"));
+		goalsAwayColumn.setCellValueFactory(new MapValueFactory<>("goalsAway"));
+		goalDiff.setCellValueFactory(new MapValueFactory<>("goalDiff"));
+		avgScoreHomeColumn.setCellValueFactory(new MapValueFactory<>("avgScoreHome"));
+		avgConcededHomeColumn.setCellValueFactory(new MapValueFactory<>("avgConcededHome"));
+		avgScoreAwayColumn.setCellValueFactory(new MapValueFactory<>("avgScoreAway"));
+		avgConcededAwayColumn.setCellValueFactory(new MapValueFactory<>("avgConcededAway"));
+		countryColumn.setCellValueFactory(new MapValueFactory<>("country"));
+		leagueColumn.setCellValueFactory(new MapValueFactory<>("league"));
+
+		homeWinColumn.setCellValueFactory(new MapValueFactory<>("homeWin"));
+		drawColumn.setCellValueFactory(new MapValueFactory<>("draw"));
+		awayWinColumn.setCellValueFactory(new MapValueFactory<>("awayWin"));
+
+		matches = FXCollections.<Map<String, Object>>observableArrayList();
+
+	}
+
+	public void setMatches(ArrayList<SoccerMatch> upcomingMatches, MatchStatTabController matchStatController) {
+		matches = FXCollections.<Map<String, Object>>observableArrayList();
+		for (final SoccerMatch soccerMatch : upcomingMatches) {
+
+
+			final Map<String, Object> match = new HashMap<>();
+			match.put("homeTeam", soccerMatch.getHomeTeam().getTeamName());
+			match.put("awayTeam", soccerMatch.getAwayTeam().getTeamName());
+			match.put("odds1", soccerMatch.getOdds1());
+			match.put("oddsX", soccerMatch.getOddsX());
+			match.put("odds2", soccerMatch.getOdds2());
+
+			final ArrayList<Float> avgHomeTeamGoals = calculateAvgHomeScore(soccerMatch.getHomeTeam().getTeamId());
+			final ArrayList<Float> avgAwayTeamGoals = calculateAvgAwayScore(soccerMatch.getAwayTeam().getTeamId());
+
+			match.put("gameDate", soccerMatch.getGameDate().toString());
+			match.put("avgScoreHome", avgHomeTeamGoals.get(0));
+			match.put("avgConcededHome", avgHomeTeamGoals.get(1));
+			match.put("avgScoreAway", avgAwayTeamGoals.get(0));
+			match.put("avgConcededAway", avgAwayTeamGoals.get(1));
+			match.put("goalsHome",
+					GuiMysql.getInstance().round(new BigDecimal(avgHomeTeamGoals.get(0) + avgAwayTeamGoals.get(1)),
+							GuiMysql.getInstance().getIncrement(), RoundingMode.HALF_UP));
+			match.put("goalsAway",
+					GuiMysql.getInstance().round(new BigDecimal(avgAwayTeamGoals.get(0) + avgHomeTeamGoals.get(1)),
+							GuiMysql.getInstance().getIncrement(), RoundingMode.HALF_UP));
+			match.put("goalDiff",
+					GuiMysql.getInstance()
+					.round(new BigDecimal((avgHomeTeamGoals.get(0) + avgAwayTeamGoals.get(1))
+							- (avgAwayTeamGoals.get(0) + avgHomeTeamGoals.get(1))),
+							GuiMysql.getInstance().getIncrement(), RoundingMode.HALF_UP));
+			match.put("country", soccerMatch.getHomeTeam().getCountryName());
+			match.put("league", soccerMatch.getHomeTeam().getTeamLeague());
+
+
+			final int lookBack = 15;
+			final TeamResults homeTeamResults = GuiMysql.getInstance().getTeamResults(soccerMatch.getHomeTeam().getTeamId(), lookBack, true);
+			final TeamResults awayTeamResults = GuiMysql.getInstance().getTeamResults(soccerMatch.getAwayTeam().getTeamId(), lookBack, true);
+
+			match.put("homeWin", (homeTeamResults.getWins() + awayTeamResults.getLosses()) / Float.valueOf(homeTeamResults.getCount() + awayTeamResults.getCount()) * 100f + "(" + (homeTeamResults.getCount() + awayTeamResults.getCount()) + ")");
+			match.put("draw", (homeTeamResults.getDraws() + awayTeamResults.getDraws()) / Float.valueOf(homeTeamResults.getCount() + awayTeamResults.getCount()) * 100f);
+			match.put("awayWin", (homeTeamResults.getLosses() + awayTeamResults.getWins()) / Float.valueOf(homeTeamResults.getCount() + awayTeamResults.getCount()) * 100f);
+
+			matches.add(match);
+		}
+
+		originalMatches = matches;
+		matchTable.getItems().addAll(matches);
+
+	}
+
+	public void filterLeagueMatches(String filterByName) {
+		final Collection<Map<String, Object>> filteredMatches = coutryFilteredMatches.stream()
+				.filter(p -> p.get("league").equals(filterByName))
+				.collect(Collectors.toCollection(FXCollections::observableArrayList));
+		matchTable.getItems().clear();
+		matchTable.getItems().addAll(filteredMatches);
+	}
+
+	public void filterCountryMatches(String filterByName) {
+		final Collection<Map<String, Object>> filteredMatches = originalMatches.stream()
+				.filter(p -> p.get("country").equals(filterByName))
+				.collect(Collectors.toCollection(FXCollections::observableArrayList));
+		matchTable.getItems().clear();
+		matchTable.getItems().addAll(filteredMatches);
+		coutryFilteredMatches = matchTable.getItems();
+	}
+
+	public void resetFilter() {
+		// matches = originalMatches;
+		matchTable.getItems().clear();
+		// if (matches != null) {
+		// matchTable.getItems().addAll(matches);
+		// }
+		matches = matchTable.getItems();
+	}
+
+	private ArrayList<Float> calculateAvgHomeScore(int teamId) {
+		return GuiMysql.getInstance().getAvgHomeScore(teamId);
+	}
+
+	private ArrayList<Float> calculateAvgAwayScore(int teamId) {
+		return GuiMysql.getInstance().getAvgAwayScore(teamId);
+	}
+
+	public Collection<Map<String, Object>> getTableMatches() {
+		return matchTable.getItems();
+	}
+
+	public ArrayList<String> getLeaguesFromSelection(String value) {
+		final ArrayList<String> leagues = Lists.newArrayList();
+		coutryFilteredMatches.forEach(f -> {
+			if (!leagues.contains(f.get("league"))) {
+				leagues.add((String) f.get("league"));
+			}
+		});
+		return leagues;
+	}
+
+	public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
+
+		final Map<Object, Boolean> seen = new ConcurrentHashMap<>();
+		return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
+	}
+
+	public TableView getTable() {
+		return matchTable;
+	}
+}

+ 114 - 0
OddsJavaFx/src/controllers/StatisticsTabController.java

@@ -0,0 +1,114 @@
+package controllers;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+import data.GuiMysql;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.fxml.Initializable;
+import javafx.scene.control.TableColumn;
+import javafx.scene.control.TableView;
+import javafx.scene.control.cell.MapValueFactory;
+import objects.OverUnder;
+
+@SuppressWarnings("rawtypes")
+public class StatisticsTabController implements Initializable {
+
+	@FXML private TableView<Map<String, Object>> statsTable;
+
+	@FXML TableColumn<Map, Float> diffColumn = new TableColumn<>("Diff");
+	@FXML TableColumn<Map, String> u05 = new TableColumn<>("Under 0.5");
+	@FXML TableColumn<Map, String> o05 = new TableColumn<>("Over 0.5");
+	@FXML TableColumn<Map, String> u15 = new TableColumn<>("Under 1.5");
+	@FXML TableColumn<Map, String> o15 = new TableColumn<>("Over 1.5");
+	@FXML TableColumn<Map, String> u25 = new TableColumn<>("Under 2.5");
+	@FXML TableColumn<Map, String> o25 = new TableColumn<>("Over 2.5");
+	@FXML TableColumn<Map, String> u35 = new TableColumn<>("Under 3.5");
+	@FXML TableColumn<Map, String> o35 = new TableColumn<>("Over 3.5");
+	@FXML TableColumn<Map, String> u45 = new TableColumn<>("Under 4.5");
+	@FXML TableColumn<Map, String> o45 = new TableColumn<>("Over 4.5");
+	@FXML TableColumn<Map, String> u55 = new TableColumn<>("Under 5.5");
+	@FXML TableColumn<Map, String> o55 = new TableColumn<>("Over 5.5");
+	@FXML TableColumn<Map, String> u65 = new TableColumn<>("Under 6.5");
+	@FXML TableColumn<Map, String> o65 = new TableColumn<>("Over 6.5");
+
+	private ObservableList<Map<String, Object>> statLines;
+
+	public StatisticsTabController() {
+	}
+
+	@Override
+	public void initialize(URL arg0, ResourceBundle arg1) {
+		diffColumn.setCellValueFactory(new MapValueFactory<>("diff"));
+		u05.setCellValueFactory(new MapValueFactory<>("u05"));
+		o05.setCellValueFactory(new MapValueFactory<>("o05"));
+		u15.setCellValueFactory(new MapValueFactory<>("u15"));
+		o15.setCellValueFactory(new MapValueFactory<>("o15"));
+		u25.setCellValueFactory(new MapValueFactory<>("u25"));
+		o25.setCellValueFactory(new MapValueFactory<>("o25"));
+		u35.setCellValueFactory(new MapValueFactory<>("u35"));
+		o35.setCellValueFactory(new MapValueFactory<>("o35"));
+		u45.setCellValueFactory(new MapValueFactory<>("u45"));
+		o45.setCellValueFactory(new MapValueFactory<>("o45"));
+		u55.setCellValueFactory(new MapValueFactory<>("u55"));
+		o55.setCellValueFactory(new MapValueFactory<>("o55"));
+		u65.setCellValueFactory(new MapValueFactory<>("u65"));
+		o65.setCellValueFactory(new MapValueFactory<>("o65"));
+
+		statLines = FXCollections.<Map<String, Object>>observableArrayList();
+
+	}
+
+	public void setOverUnderTable(int leagueId) {
+		final ArrayList<OverUnder> statsOverUnder = GuiMysql.getInstance().getStatsOverUnder(leagueId);
+
+		statLines.clear();
+		for (final OverUnder ou : statsOverUnder) {
+			final Map<String, Object> line = new HashMap<>();
+			if (statLines.stream().noneMatch(p -> p.get("diff") == ou.getKey())) {
+				line.put("diff", ou.getKey());
+				line.put("u05", ou.getGoals().get(0) + " (" + ou.calcMinOdds(ou.getGoals().get(0)) + ")");
+				line.put("o05", getOverStat(ou, 1) + " (" + ou.calcMinOdds(getOverStat(ou, 1)) + ")");
+				line.put("u15", getUnderStat(ou, 2) + " (" + ou.calcMinOdds(getUnderStat(ou, 2)) + ")");
+				line.put("o15", getOverStat(ou, 2) + " (" + ou.calcMinOdds(getOverStat(ou, 2)) + ")");
+				line.put("u25", getUnderStat(ou, 3) + " (" + ou.calcMinOdds(getUnderStat(ou, 3)) + ")");
+				line.put("o25", getOverStat(ou, 3) + " (" + ou.calcMinOdds(getOverStat(ou, 3)) + ")");
+				line.put("u35", getUnderStat(ou, 4) + " (" + ou.calcMinOdds(getUnderStat(ou, 4)) + ")");
+				line.put("o35", getOverStat(ou, 4) + " (" + ou.calcMinOdds(getOverStat(ou, 4)) + ")");
+				line.put("u45", getUnderStat(ou, 5) + " (" + ou.calcMinOdds(getUnderStat(ou, 5)) + ")");
+				line.put("o45", getOverStat(ou, 5) + " (" + ou.calcMinOdds(getOverStat(ou, 5)) + ")");
+				line.put("u55", getUnderStat(ou, 6) + " (" + ou.calcMinOdds(getUnderStat(ou, 6)) + ")");
+				line.put("o55", getOverStat(ou, 6) + " (" + ou.calcMinOdds(getOverStat(ou, 6)) + ")");
+				line.put("u65", getUnderStat(ou, 7) + " (" + ou.calcMinOdds(getUnderStat(ou, 7)) + ")");
+				line.put("o65", getOverStat(ou, 7) + " (" + ou.calcMinOdds(getOverStat(ou, 7)) + ")");
+
+				statLines.add(line);
+			}
+		}
+		statsTable.getItems().clear();
+		statsTable.getItems().addAll(statLines);
+	}
+
+	private int getUnderStat(OverUnder ou, float atMostXGoals) {
+		final ArrayList<Integer> goals = ou.getGoals();
+		int sum = 0;
+		for (int i = 0; i < (goals.size() < atMostXGoals?goals.size():atMostXGoals); i++) {
+			sum += goals.get(i);
+		}
+		return sum;
+	}
+
+	private int getOverStat(OverUnder ou, int atLeastXGoals) {
+		final ArrayList<Integer> goals = ou.getGoals();
+		int sum = 0;
+		for (int i = atLeastXGoals; i < goals.size(); i++) {
+			sum += goals.get(i);
+		}
+		return sum;
+	}
+}

+ 411 - 0
OddsJavaFx/src/data/GuiMysql.java

@@ -0,0 +1,411 @@
+package data;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.text.DecimalFormat;
+import java.time.LocalDateTime;
+import java.util.AbstractMap;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.ArrayList;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+
+import mysql.Mysql;
+import objects.OverUnder;
+import objects.SoccerMatch;
+import objects.Team;
+import objects.TeamResults;
+import objects.TeamStanding;
+
+public class GuiMysql extends Mysql {
+
+	private static final BigDecimal INCREMENT = new BigDecimal(0.2);
+	private static final GuiMysql instance = new GuiMysql();
+	private final Connection conn;
+
+
+	private GuiMysql() {
+		super();
+		conn = this.getConnection();
+	}
+
+	public static GuiMysql getInstance() {
+		return instance;
+	}
+
+	public ArrayList<SimpleEntry<Integer, String>> getSports() {
+
+		final ArrayList<AbstractMap.SimpleEntry<Integer, String>> sports = Lists.newArrayList();
+		try {
+			final String sql = "SELECT id, name FROM Sport";
+			PreparedStatement stmt;
+			stmt = conn.prepareStatement(sql);
+
+			final ResultSet rs = stmt.executeQuery();
+
+			while (rs.next()) {
+				final SimpleEntry<Integer, String> entry = new SimpleEntry<>(rs.getInt("id"), rs.getString("name"));
+				sports.add(entry);
+			}
+		} catch (final SQLException e) {
+			e.printStackTrace();
+		}
+
+		return sports;
+	}
+
+	public ArrayList<SimpleEntry<Integer, String>> getCountries() {
+
+		final ArrayList<AbstractMap.SimpleEntry<Integer, String>> countries = Lists.newArrayList();
+		try {
+			final String sql = "SELECT id, name FROM Country";
+			final PreparedStatement stmt = conn.prepareStatement(sql);
+
+			final ResultSet rs = stmt.executeQuery();
+
+			while (rs.next()) {
+				final SimpleEntry<Integer, String> entry = new SimpleEntry<>(rs.getInt("id"), rs.getString("name"));
+				countries.add(entry);
+			}
+		} catch (final SQLException e) {
+			e.printStackTrace();
+		}
+		return countries;
+	}
+
+	public ArrayList<SimpleEntry<Integer, String>> getLeagues(int sportId, int countryId) {
+
+		final ArrayList<AbstractMap.SimpleEntry<Integer, String>> leagues = Lists.newArrayList();
+		try {
+			final String sql = "SELECT id, name FROM League WHERE sportId = ? AND countryId = ? ORDER BY name ASC";
+			final PreparedStatement stmt = conn.prepareStatement(sql);
+			stmt.setInt(1, sportId);
+			stmt.setInt(2, countryId);
+
+			final ResultSet rs = stmt.executeQuery();
+
+			while (rs.next()) {
+				final SimpleEntry<Integer, String> entry = new SimpleEntry<>(rs.getInt("id"), rs.getString("name"));
+				leagues.add(entry);
+			}
+		} catch (final SQLException e) {
+			e.printStackTrace();
+		}
+		return leagues;
+	}
+
+	public ArrayList<SoccerMatch> getTodaysMatches(String sportResultTable, int sportId) {
+		final ArrayList<SoccerMatch> matches = Lists.newArrayList();
+		final String sql = "SELECT res.id, homeTeam, awayTeam, homeScore, awayScore, overtime, odds1, oddsX, odds2, gameDate, season, res.leagueId, res.countryId, " +
+				"hTeam.name as homeTeamName, aTeam.name as awayTeamName, " +
+				"league.name as leagueName, " +
+				"country.name as countryName " +
+				"FROM " + sportResultTable + " as res " +
+				"Join Team as hTeam ON res.homeTeam = hTeam.id " +
+				"Join Team as aTeam ON res.awayTeam = aTeam.id " +
+				"Join League as league ON res.leagueId = league.id " +
+				"Join Country as country ON res.countryId = country.id " +
+				"where homeScore = -1 AND DATE(gameDate) = DATE(now()) AND league.name NOT LIKE '%cup%' AND league.name NOT LIKE '%group%'";
+
+		try {
+			final PreparedStatement stmt = conn.prepareStatement(sql);
+
+			final ResultSet rs = stmt.executeQuery();
+			while (rs.next()) {
+				final SoccerMatch sm = new SoccerMatch();
+				final Team homeTeam = new Team();
+				final Team awayTeam = new Team();
+
+				homeTeam.setTeamId(rs.getInt("homeTeam"));
+				awayTeam.setTeamId(rs.getInt("awayTeam"));
+				homeTeam.setTeamName(rs.getString("homeTeamName"));
+				awayTeam.setTeamName(rs.getString("awayTeamName"));
+				homeTeam.setTeamLeagueId(rs.getInt("leagueId"));
+				awayTeam.setTeamLeagueId(rs.getInt("leagueId"));
+				homeTeam.setTeamLeague(rs.getString("leagueName"));
+				awayTeam.setTeamLeague(rs.getString("leagueName"));
+				homeTeam.setCountryId(rs.getInt("countryId"));
+				awayTeam.setCountryId(rs.getInt("countryId"));
+				homeTeam.setCountryName(rs.getString("countryName"));
+				awayTeam.setCountryName(rs.getString("countryName"));
+
+				sm.setAwayScore(rs.getInt("awayScore"));
+				sm.setHomeScore(rs.getInt("homeScore"));
+				sm.setHomeTeam(homeTeam);
+				sm.setAwayTeam(awayTeam);
+				sm.setMatchId(rs.getInt("id"));
+				sm.setOdds1(rs.getFloat("odds1"));
+				sm.setOddsX(rs.getFloat("oddsX"));
+				sm.setOdds2(rs.getFloat("odds2"));
+				sm.setGameDate(LocalDateTime.parse(rs.getString("gameDate")));
+
+				matches.add(sm);
+			}
+
+		} catch (final SQLException e) {
+			e.printStackTrace();
+		}
+
+		return matches;
+	}
+
+	public ArrayList<Float> getAvgHomeScore(int teamId) {
+		final ArrayList<Float> returnValue = Lists.newArrayList();
+		final String sql = "SELECT AVG(homeScore) as avgScored, AVG(awayScore) as avgConceded FROM SoccerResults WHERE homeScore != -1 && homeTeam = ?";
+		try {
+			final PreparedStatement stmt = conn.prepareStatement(sql);
+			stmt.setInt(1, teamId);
+
+			final ResultSet rs = stmt.executeQuery();
+
+			while (rs.next()) {
+				returnValue.add(rs.getFloat("avgScored"));
+				returnValue.add(rs.getFloat("avgConceded"));
+			}
+
+		} catch (final SQLException e) {
+			e.printStackTrace();
+		}
+
+		return returnValue;
+	}
+
+	public ArrayList<Float> getAvgAwayScore(int teamId) {
+		final ArrayList<Float> returnValue = Lists.newArrayList();
+		final String sql = "SELECT AVG(homeScore) as avgConceded, AVG(awayScore) as avgScored FROM SoccerResults WHERE awayScore != -1 && awayTeam = ?";
+		try {
+			final PreparedStatement stmt = conn.prepareStatement(sql);
+			stmt.setInt(1, teamId);
+
+			final ResultSet rs = stmt.executeQuery();
+
+			while (rs.next()) {
+				returnValue.add(rs.getFloat("avgScored"));
+				returnValue.add(rs.getFloat("avgConceded"));
+			}
+
+		} catch (final SQLException e) {
+			e.printStackTrace();
+		}
+
+		return returnValue;
+	}
+
+	public ArrayList<Float> getLeagueAvarages(int leagueId, int countryId) {
+		final ArrayList<Float> returnValue = Lists.newArrayList();
+		final String sql = "SELECT AVG(homeScore) avgHomeScore, AVG(awayScore) as avgAwayScore"
+				+ " FROM SoccerResults WHERE leagueId = ? AND countryId = ?";
+
+		final String goalsSql = "SELECT (homeScore + awayScore) as totalGoals, count(*) as count FROM SoccerResults  WHERE leagueId = ? AND countryId = ? AND season = ? GROUP BY totalGoals ORDER BY totalGoals asc";
+		try {
+			final PreparedStatement stmt = conn.prepareStatement(sql);
+			stmt.setInt(1, leagueId);
+			stmt.setInt(2, countryId);
+
+			final ResultSet rs = stmt.executeQuery();
+			while (rs.next()) {
+				returnValue.add(rs.getFloat("avgHomeScore"));
+				returnValue.add(rs.getFloat("avgAwayScore"));
+			}
+
+			final PreparedStatement goalStmt = conn.prepareStatement(goalsSql);
+			goalStmt.setInt(1, leagueId);
+			goalStmt.setInt(2, countryId);
+			goalStmt.setString(3, getLastSeason(countryId, leagueId));
+
+			final ResultSet goalRs = goalStmt.executeQuery();
+			while (goalRs.next()) {
+
+			}
+
+		} catch (final SQLException e) {
+			e.printStackTrace();
+		}
+
+		return returnValue;
+	}
+
+	public ArrayList<OverUnder> getStatsOverUnder(int leagueId) {
+
+		final DecimalFormat df = new DecimalFormat("##.##");
+		df.setRoundingMode(RoundingMode.HALF_DOWN);
+		final ArrayList<OverUnder> result = Lists.newArrayList();
+
+		final String sql = "SELECT ((sHome.avgScored + sAway.avgConceded) - (sAway.avgScored + sHome.avgConceded)) as diff, (homeScore + awayScore) as numGoals "
+				+ "FROM SoccerResults "
+				+ "INNER JOIN (SELECT homeTeam, AVG(homeScore) as avgScored, AVG(awayScore) as avgConceded FROM SoccerResults WHERE homeScore != -1 && homeTeam = SoccerResults.homeTeam GROUP BY homeTeam) as sHome ON SoccerResults.homeTeam = sHome.homeTeam "
+				+ "INNER JOIN (SELECT awayTeam, AVG(homeScore) as avgConceded, AVG(awayScore) as avgScored FROM SoccerResults WHERE awayScore != -1 && awayTeam = SoccerResults.awayTeam GROUP BY awayTeam) as sAway ON SoccerResults.awayTeam = sAway.awayTeam "
+				+ "WHERE homeScore != -1 AND awayScore != -1 AND leagueId = ? "
+				+ "ORDER BY diff ASC";
+		try {
+			final PreparedStatement stmt = conn.prepareStatement(sql);
+			stmt.setInt(1, leagueId);
+			final ResultSet rs = stmt.executeQuery();
+
+			while (rs.next()) {
+				final float diff = rs.getFloat("diff");
+				final int numGoals = rs.getInt("numGoals");
+				//				final Float formatted = Float.valueOf(df.format(diff));
+				//				final Float formatted = BigDecimal.valueOf(diff).setScale(1, BigDecimal.ROUND_HALF_DOWN).floatValue();
+				final Float formatted = round(new BigDecimal(diff), INCREMENT, RoundingMode.HALF_UP).floatValue();
+
+				final OverUnder entry = result.stream().filter(ou -> ou.getKey().compareTo(formatted) == 0).findFirst().orElse(new OverUnder(formatted));
+				entry.addGoalStat(numGoals);
+				result.add(entry);
+			}
+		} catch (final SQLException e) {
+			e.printStackTrace();
+		}
+		return result;
+	}
+
+	public BigDecimal round(BigDecimal value, BigDecimal increment,
+			RoundingMode roundingMode) {
+		if (increment.signum() == 0) {
+			// 0 increment does not make much sense, but prevent division by 0
+			return value;
+		} else {
+			final BigDecimal divided = value.divide(increment, 0, roundingMode);
+			final BigDecimal result = divided.multiply(increment);
+			return result.setScale(2, RoundingMode.HALF_UP);
+		}
+	}
+
+	public BigDecimal getIncrement() {
+		return INCREMENT;
+	}
+
+	public ArrayList<TeamStanding> getLeagueTable(int leagueId, String season, int countryId) {
+		final ArrayList<TeamStanding> result = Lists.newArrayList();
+
+		final String sql = "SELECT teamName.name as teamName, count(*) played, count(case when homeScore > awayScore then 1 end) wins, "
+				+ "count(case when awayScore> homeScore then 1 end) lost, "
+				+ "count(case when homeScore = awayScore then 1 end) draws, "
+				+ "sum(homeScore) homeScore, "
+				+ "sum(awayScore) awayScore, "
+				+ "sum(homeScore) - sum(awayScore) goal_diff, "
+				+ "sum(case when homeScore > awayScore then 3 else 0 end  + case "
+				+ "WHEN homeScore = awayScore then 1 else 0 end) score, "
+				+ "season FROM "
+				+ "(select hometeam team, homeScore, awayScore, season, leagueId as league, countryId as country FROM SoccerResults "
+				+ "union all SELECT awayteam, awayScore, homeScore, season, leagueId as league, countryId as country FROM SoccerResults) a "
+				+ "INNER JOIN Team teamName ON team = teamName.id "
+				+ "WHERE season = ? "
+				+ "AND league = ? "
+				+ "AND country = ? "
+				+ "AND homeScore != -1 "
+				+ "AND awayScore != -1 "
+				+ "group by team "
+				+ "order by score desc, goal_diff desc";
+		try {
+			final PreparedStatement stmt = conn.prepareStatement(sql);
+
+			stmt.setString(1, season);
+			stmt.setInt(2, leagueId);
+			stmt.setInt(3, countryId);
+
+			final String tempSql = sql.replaceAll("\\?", "%s");
+			System.out.println(String.format(tempSql, season, leagueId, countryId));
+
+			final ResultSet rs = stmt.executeQuery();
+			while (rs.next()) {
+				final TeamStanding ts = new TeamStanding(rs.getString("teamName"), rs.getInt("wins"), rs.getInt("lost"), rs.getInt("draws"),
+						rs.getInt("score"), rs.getFloat("homeScore"), rs.getFloat("awayScore"), rs.getFloat("goal_diff"));
+				result.add(ts);
+			}
+
+		} catch (final SQLException e) {
+			e.printStackTrace();
+			System.out.println("Sql vid fel: " + sql);
+		}
+
+		return result;
+	}
+
+	public boolean getParsingStarted(int countryId, int leagueId) {
+		boolean returnValue = false;
+		final String sql = "SELECT parsedYear FROM League WHERE id = ? AND countryId = ?";
+		try {
+			final PreparedStatement stmt = conn.prepareStatement(sql);
+			stmt.setInt(1, leagueId);
+			stmt.setInt(2, countryId);
+
+			final ResultSet rs = stmt.executeQuery();
+			while (rs.next()) {
+				final String parsedYear = rs.getString("parsedYear");
+				if (!Strings.isNullOrEmpty(parsedYear)) {
+					returnValue = true;
+				}
+			}
+		} catch (final SQLException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+
+		return returnValue;
+	}
+
+	public String getLastSeason(Integer countryId, Integer leagueId) {
+		String season = "";
+		final String sql = "SELECT season FROM SoccerResults WHERE leagueId = ? AND countryId = ? ORDER BY season DESC limit 1";
+		try {
+			final PreparedStatement stmt = conn.prepareStatement(sql);
+			stmt.setInt(1, leagueId);
+			stmt.setInt(2, countryId);
+
+			final ResultSet rs = stmt.executeQuery();
+			while (rs.next()) {
+				season = rs.getString("season");
+			}
+		} catch (final SQLException e) {
+			e.printStackTrace();
+		}
+
+		return season;
+	}
+
+	public TeamResults getTeamResults(int teamId, int numResults, boolean isHomeTeam) {
+		final String sql;
+		final TeamResults tr = new TeamResults();
+		if (isHomeTeam) {
+			sql = "SELECT count(case when homeScore > awayScore then 1 end) wins, " +
+					"count(case when awayScore > homeScore then 1 end) lost, " +
+					"count(case when homeScore = awayScore then 1 end) draws " +
+					"FROM SoccerResults WHERE homeTeam = ? AND " +
+					"HomeScore >= 0 AND awayScore >= 0 LIMIT ?";
+		} else {
+			sql = "SELECT count(case when homeScore < awayScore then 1 end) wins, " +
+					"count(case when awayScore < homeScore then 1 end) lost, " +
+					"count(case when homeScore = awayScore then 1 end) draws " +
+					"FROM SoccerResults WHERE awayTeam = ? AND " +
+					"HomeScore >= 0 AND awayScore >= 0 LIMIT ?";
+		}
+
+		try {
+			final PreparedStatement stat = conn.prepareStatement(sql);
+			stat.setInt(1, teamId);
+			stat.setInt(2, numResults);
+			final ResultSet rs = stat.executeQuery();
+
+			while (rs.next()) {
+				final int draws = rs.getInt("draws");
+				final int wins = rs.getInt("wins");
+				final int lost = rs.getInt("lost");
+				tr.setDraws(draws);
+				tr.setWins(wins);
+				tr.setLosses(lost);
+				tr.setCount(wins+draws+lost);
+			}
+		} catch (final SQLException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+
+		return tr;
+	}
+}

+ 21 - 0
OddsJavaFx/src/fxml/MatchResultTabBuilder.fxml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.scene.control.TableColumn?>
+<?import javafx.scene.control.TableView?>
+<?import javafx.scene.layout.AnchorPane?>
+
+<AnchorPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/11.0.1" fx:controller="controllers.MatchResultTabController">
+	<children>
+	   <TableView fx:id="matchResultTable" layoutX="110.0" layoutY="93.0" prefHeight="546.0" prefWidth="893.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
+	     <columns>
+	       <TableColumn fx:id="homeTeamColumn" prefWidth="75.0" text="Home team" />
+	       <TableColumn fx:id="awayTeamColumn" prefWidth="75.0" text="Away team" />
+	       <TableColumn fx:id="goalsHomeColumn" prefWidth="75.0" text="Goals home" />
+	       <TableColumn fx:id="goalsAwayColumn" prefWidth="75.0" text="Goals away" />
+	       <TableColumn fx:id="countryColumn" prefWidth="75.0" text="Country" />
+	       <TableColumn fx:id="leagueColumn" prefWidth="75.0" text="League" />
+	     </columns>
+	   </TableView>
+	</children>
+</AnchorPane>
+

+ 27 - 0
OddsJavaFx/src/fxml/MatchStatTabBuilder.fxml

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.scene.control.TableColumn?>
+<?import javafx.scene.control.TableView?>
+<?import javafx.scene.layout.AnchorPane?>
+<?import javafx.scene.layout.BorderPane?>
+
+<AnchorPane xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controllers.MatchStatTabController">
+   <children>
+      <BorderPane layoutX="110.0" layoutY="93.0" prefHeight="546.0" prefWidth="893.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
+         <center>
+            <TableView fx:id="matchStatTable" prefHeight="546.0" prefWidth="479.0" BorderPane.alignment="CENTER">
+              <columns>
+                <TableColumn fx:id="team" prefWidth="100.0" text="Team" />
+                <TableColumn fx:id="gamesPlayed" prefWidth="87.0" text="Games played" />
+                <TableColumn fx:id="win" prefWidth="63.0" text="Win" />
+                <TableColumn fx:id="draw" prefWidth="75.0" text="Draw" />
+                <TableColumn fx:id="loss" prefWidth="75.0" text="Loss" />
+                <TableColumn fx:id="points" prefWidth="75.0" text="Points" />
+                <TableColumn fx:id="goalsScored" prefWidth="85.0" text="Goals scored" />
+                <TableColumn fx:id="goalsConceded" prefWidth="101.0" text="Goals conceded" />
+                <TableColumn fx:id="diff" prefWidth="39.0" text="Difference" />
+              </columns>
+            </TableView>
+         </center></BorderPane>
+   </children>
+</AnchorPane>

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

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.scene.control.TableColumn?>
+<?import javafx.scene.control.TableView?>
+<?import javafx.scene.layout.AnchorPane?>
+
+<AnchorPane xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controllers.MatchTabController">
+	<children>
+	   <TableView fx:id="matchTable" layoutX="110.0" layoutY="93.0" prefHeight="546.0" prefWidth="893.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
+	     <columns>
+	       <TableColumn fx:id="gameDateColumn" editable="false" prefWidth="75.0" text="Game date" />
+	       <TableColumn fx:id="homeTeamColumn" editable="false" prefWidth="75.0" text="Home team" />
+	       <TableColumn fx:id="awayTeamColumn" prefWidth="75.0" text="Away team" />
+	       <TableColumn fx:id="odds1Column" prefWidth="75.0" text="Odds 1" />
+	       <TableColumn fx:id="oddsXColumn" prefWidth="75.0" text="Odds X" />
+	       <TableColumn fx:id="odds2Column" prefWidth="75.0" text="Odds 2" />
+	       <TableColumn fx:id="goalsHomeColumn" prefWidth="75.0" text="Goals home" />
+	       <TableColumn fx:id="goalsAwayColumn" prefWidth="75.0" text="Goals away" />
+	       <TableColumn fx:id="goalDiff" prefWidth="75.0" text="Difference" />
+	       <TableColumn fx:id="avgScoreHomeColumn" prefWidth="75.0" text="Avg score home" />
+	       <TableColumn fx:id="avgConcededHomeColumn" prefWidth="75.0" text="Avg conceded home" />
+	       <TableColumn fx:id="avgScoreAwayColumn" prefWidth="75.0" text="Avg score away" />
+	       <TableColumn fx:id="avgConcededAwayColumn" prefWidth="75.0" text="Avg conceded away" />
+	       <TableColumn fx:id="countryColumn" prefWidth="75.0" text="Country" />
+	       <TableColumn fx:id="leagueColumn" prefWidth="75.0" text="League" />
+	       
+	       <TableColumn fx:id="homeWinColumn" prefWidth="75.0" text="Home Win" />
+	       <TableColumn fx:id="drawColumn" prefWidth="75.0" text="Draw" />
+	       <TableColumn fx:id="awayWinColumn" prefWidth="75.0" text="Away win" />
+	     </columns>
+	   </TableView>
+	</children>
+</AnchorPane>

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

@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.scene.control.Button?>
+<?import javafx.scene.control.ChoiceBox?>
+<?import javafx.scene.control.ComboBox?>
+<?import javafx.scene.control.SplitPane?>
+<?import javafx.scene.control.Tab?>
+<?import javafx.scene.control.TabPane?>
+<?import javafx.scene.control.TextField?>
+<?import javafx.scene.effect.Light.Distant?>
+<?import javafx.scene.effect.Lighting?>
+<?import javafx.scene.effect.Shadow?>
+<?import javafx.scene.layout.BorderPane?>
+<?import javafx.scene.layout.FlowPane?>
+<?import javafx.scene.layout.Pane?>
+<?import javafx.scene.layout.StackPane?>
+<?import javafx.scene.text.Font?>
+
+<StackPane prefHeight="800.0" prefWidth="1600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controllers.MainController">
+   <children>
+      <BorderPane prefHeight="600.0" prefWidth="1200.0">
+         <top>
+            <FlowPane BorderPane.alignment="CENTER">
+               <children>
+                  <ComboBox id="SportComboBox" fx:id="sportSelector" onAction="#SportSelected" prefHeight="25.0" prefWidth="200.0" promptText="Sport" />
+                  <ComboBox id="CountryComboBox" fx:id="countrySelector" disable="true" onAction="#CountrySelected" prefHeight="25.0" prefWidth="200.0" promptText="Country" />
+                  <ComboBox id="LeagueComboBox" fx:id="leagueSelector" disable="true" onAction="#LeagueSelected" prefHeight="25.0" prefWidth="200.0" promptText="League" />
+                  <Button fx:id="resetFilterButton" mnemonicParsing="false" onAction="#ResetFilter" text="Reset Filter" />
+                  <Button fx:id="getLeagueInfoButton" disable="true" mnemonicParsing="false" onAction="#getLeagueInfo" text="Get League Info" />
+                  <Button fx:id="getMoreLeagueInfo" disable="true" mnemonicParsing="false" onAction="#getMoreLeagueInfo" text="Get more league info" />
+                  <Button fx:id="updateStatsTableButton" disable="true" mnemonicParsing="false" onAction="#UpdateStatsTable" text="Update Statistics" />
+                  <Button fx:id="showMatchStatsButton" disable="true" mnemonicParsing="false" onAction="#setMatchStatInfo" text="Show match stats" />
+               </children>
+            </FlowPane>
+         </top>
+         <left>
+            <SplitPane dividerPositions="0.38190954773869346" prefHeight="575.0" prefWidth="300.0" BorderPane.alignment="CENTER">
+              <items>
+                  <FlowPane prefHeight="573.0">
+                     <children>
+                        <TextField alignment="CENTER" editable="false" prefHeight="25.0" text="Home team" />
+                        <TextField alignment="CENTER" editable="false" prefHeight="25.0" text="Away team" />
+                        <TextField editable="false" prefHeight="25.0" prefWidth="100.0" text="League avarages">
+                           <font>
+                              <Font name="System Bold" size="12.0" />
+                           </font>
+                        </TextField>
+                        <TextField editable="false" text="Home score" />
+                        <TextField editable="false" text="Away score" />
+                        <TextField editable="false" prefHeight="25.0" prefWidth="149.0" text="Season Scoring">
+                           <font>
+                              <Font name="System Bold" size="12.0" />
+                           </font>
+                        </TextField>
+                        <TextField editable="false" text="0 Goals" />
+                        <TextField editable="false" text="1 Goal" />
+                        <TextField editable="false" text="2 Goals" />
+                        <TextField editable="false" text="3 Goals" />
+                        <TextField editable="false" text="4 Goals" />
+                        <TextField editable="false" text="5 Goals" />
+                        <TextField editable="false" text="6+ Goals" />
+                     </children>
+                  </FlowPane>
+                  <FlowPane prefHeight="573.0" prefWidth="149.0">
+                     <children>
+                        <ChoiceBox id="HomeTeamSelector" fx:id="homeTeamSelector" disable="true" prefHeight="25.0" prefWidth="100.0" />
+                        <ChoiceBox id="AwayTeamSelector" fx:id="awayTeamSelector" disable="true" prefHeight="25.0" prefWidth="100.0" />
+                        <TextField editable="false" prefHeight="25.0" prefWidth="100.0" text="League avarages">
+                           <font>
+                              <Font name="System Bold" size="12.0" />
+                           </font>
+                        </TextField>
+                        <TextField fx:id="avgLeagueHomeScoreTxt" editable="false" />
+                        <TextField fx:id="avgLeagueAwayScoreTxt" editable="false" />
+                        <TextField editable="false" />
+                        <TextField fx:id="league0Goals" editable="false" />
+                        <TextField fx:id="league1Goal" editable="false" />
+                        <TextField fx:id="league2Goals" editable="false" />
+                        <TextField fx:id="league3Goals" editable="false" />
+                        <TextField fx:id="league4Goals" editable="false" />
+                        <TextField fx:id="league5Goals" editable="false" />
+                        <TextField fx:id="league6Goals" editable="false" />
+                     </children>
+                  </FlowPane>
+              </items>
+            </SplitPane>
+         </left>
+         <center>
+            <TabPane prefHeight="200.0" prefWidth="200.0" tabClosingPolicy="UNAVAILABLE" BorderPane.alignment="CENTER">
+              <tabs>
+                <Tab text="Predictions">
+                  <content>
+                    <fx:include fx:id="matchTab" source="MatchTabBuilder.fxml" />
+                  </content>
+                </Tab>
+                <Tab text="To Be Resolved">
+                  <content>
+                    <fx:include fx:id="resultsTab" source="MatchResultTabBuilder.fxml" />
+                  </content>
+                </Tab>
+                <Tab text="Statistic Tests">
+                  <content>
+                    <fx:include fx:id="statTab" source="StatisticsTabBuilder.fxml" />
+                  </content>
+                </Tab>
+                <Tab text="Match Statistics">
+                	<content>
+ 						<fx:include fx:id="matchStatTab" source="MatchStatTabBuilder.fxml" />               	
+                	</content>
+                </Tab>
+              </tabs>
+            </TabPane>
+         </center>
+      </BorderPane>
+      <Pane fx:id="glass" disable="true" opacity="0.0" prefHeight="600.0" prefWidth="1200.0" style="-fx-background-color: #000111;" visible="false">
+         <children>
+            <TextField alignment="CENTER" editable="false" layoutX="198.0" layoutY="231.0" style="-fx-background-color: #000FFF; -fx-text-fill: #FFFFFF;" text="WAIT">
+               <font>
+                  <Font size="65.0" />
+               </font>
+               <effect>
+                  <Lighting>
+                     <bumpInput>
+                        <Shadow />
+                     </bumpInput>
+                     <light>
+                        <Light.Distant />
+                     </light>
+                  </Lighting>
+               </effect>
+            </TextField>
+         </children>
+      </Pane>
+   </children>
+</StackPane>

+ 34 - 0
OddsJavaFx/src/fxml/StatisticsTabBuilder.fxml

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.scene.control.TableColumn?>
+<?import javafx.scene.control.TableView?>
+<?import javafx.scene.layout.AnchorPane?>
+<?import javafx.scene.layout.BorderPane?>
+
+<AnchorPane prefHeight="411.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controllers.StatisticsTabController">
+   <children>
+      <BorderPane prefHeight="411.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
+         <center>
+            <TableView fx:id="statsTable" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
+              <columns>
+                <TableColumn fx:id="diffColumn" prefWidth="75.0" text="Difference" />
+                  <TableColumn fx:id="u05" prefWidth="75.0" text="Under 0.5 mål" />
+                  <TableColumn fx:id="o05" prefWidth="75.0" text="Över 0.5 mål" />
+                  <TableColumn fx:id="u15" prefWidth="75.0" text="Under 1.5 mål" />
+                  <TableColumn fx:id="o15" prefWidth="75.0" text="Över 1.5 mål" />
+                  <TableColumn fx:id="u25" prefWidth="75.0" text="Under 2.5 mål" />
+                  <TableColumn fx:id="o25" prefWidth="75.0" text="Över 2.5 mål" />
+                  <TableColumn fx:id="u35" prefWidth="75.0" text="Under 3.5 mål" />
+                  <TableColumn fx:id="o35" prefWidth="75.0" text="Över 3.5 mål" />
+                  <TableColumn fx:id="u45" prefWidth="75.0" text="Under 4.5 mål" />
+                  <TableColumn fx:id="o45" prefWidth="75.0" text="Över 4.5 mål" />
+                  <TableColumn fx:id="u55" prefWidth="75.0" text="Under 5.5 mål" />
+                  <TableColumn fx:id="o55" prefWidth="75.0" text="Över 5.5 mål" />
+                  <TableColumn fx:id="u65" prefWidth="75.0" text="Under 6.5 mål" />
+                  <TableColumn fx:id="o65" prefWidth="75.0" text="Över 6.5 mål" />
+              </columns>
+            </TableView>
+         </center>
+      </BorderPane>
+   </children>
+</AnchorPane>

+ 43 - 0
OddsJavaFx/src/objects/ActionButtonTableCell.java

@@ -0,0 +1,43 @@
+package objects;
+
+import java.util.function.Function;
+
+import javafx.event.ActionEvent;
+import javafx.scene.control.Button;
+import javafx.scene.control.TableCell;
+import javafx.scene.control.TableColumn;
+import javafx.util.Callback;
+
+public class ActionButtonTableCell<S> extends TableCell<S, Button> {
+
+	private final Button actionButton;
+
+	public ActionButtonTableCell(String label, Function< S, S> function) {
+		this.getStyleClass().add("action-button-table-cell");
+
+		this.actionButton = new Button(label);
+		this.actionButton.setOnAction((ActionEvent e) -> {
+			function.apply(getCurrentItem());
+		});
+		this.actionButton.setMaxWidth(Double.MAX_VALUE);
+	}
+
+	public S getCurrentItem() {
+		return getTableView().getItems().get(getIndex());
+	}
+
+	public static <S> Callback<TableColumn<S, Button>, TableCell<S, Button>> forTableColumn(String label, Function< S, S> function) {
+		return param -> new ActionButtonTableCell<>(label, function);
+	}
+
+	@Override
+	public void updateItem(Button item, boolean empty) {
+		super.updateItem(item, empty);
+
+		if (empty) {
+			setGraphic(null);
+		} else {
+			setGraphic(actionButton);
+		}
+	}
+}

+ 163 - 0
OddsJavaFx/src/objects/MatchData.java

@@ -0,0 +1,163 @@
+package objects;
+
+import java.math.BigDecimal;
+
+public class MatchData {
+	private String gameDateColumn;
+	private String homeTeamColumn;
+	private String awayTeamColumn;
+	private Float odds1Column;
+	private Float oddsXColumn;
+	private Float odds2Column;
+	private BigDecimal goalsHomeColumn;
+	private BigDecimal goalsAwayColumn;
+	private BigDecimal goalDiff;
+	private Float avgScoreHomeColumn;
+	private Float avgConcededHomeColumn;
+	private Float avgScoreAwayColumn;
+	private Float avgConcededAwayColumn;
+	private String countryColumn;
+	private String leagueColumn;
+
+	public MatchData(String gameDateColumn, String homeTeamColumn, String awayTeamColumn, Float odds1Column,
+			Float oddsXColumn, Float odds2Column, BigDecimal goalsHomeColumn, BigDecimal goalsAwayColumn, BigDecimal goalDiff,
+			Float avgScoreHomeColumn, Float avgConcededHomeColumn, Float avgScoreAwayColumn,
+			Float avgConcededAwayColumn, String countryColumn, String leagueColumn) {
+		super();
+		this.gameDateColumn = gameDateColumn;
+		this.homeTeamColumn = homeTeamColumn;
+		this.awayTeamColumn = awayTeamColumn;
+		this.odds1Column = odds1Column;
+		this.oddsXColumn = oddsXColumn;
+		this.odds2Column = odds2Column;
+		this.goalsHomeColumn = goalsHomeColumn;
+		this.goalsAwayColumn = goalsAwayColumn;
+		this.goalDiff = goalDiff;
+		this.avgScoreHomeColumn = avgScoreHomeColumn;
+		this.avgConcededHomeColumn = avgConcededHomeColumn;
+		this.avgScoreAwayColumn = avgScoreAwayColumn;
+		this.avgConcededAwayColumn = avgConcededAwayColumn;
+		this.countryColumn = countryColumn;
+		this.leagueColumn = leagueColumn;
+	}
+
+	public String getGameDateColumn() {
+		return gameDateColumn;
+	}
+
+	public String getHomeTeamColumn() {
+		return homeTeamColumn;
+	}
+
+	public String getAwayTeamColumn() {
+		return awayTeamColumn;
+	}
+
+	public Float getOdds1Column() {
+		return odds1Column;
+	}
+
+	public Float getOddsXColumn() {
+		return oddsXColumn;
+	}
+
+	public Float getOdds2Column() {
+		return odds2Column;
+	}
+
+	public BigDecimal getGoalsHomeColumn() {
+		return goalsHomeColumn;
+	}
+
+	public BigDecimal getGoalsAwayColumn() {
+		return goalsAwayColumn;
+	}
+
+	public BigDecimal getGoalDiff() {
+		return goalDiff;
+	}
+
+	public Float getAvgScoreHomeColumn() {
+		return avgScoreHomeColumn;
+	}
+
+	public Float getAvgConcededHomeColumn() {
+		return avgConcededHomeColumn;
+	}
+
+	public Float getAvgScoreAwayColumn() {
+		return avgScoreAwayColumn;
+	}
+
+	public Float getAvgConcededAwayColumn() {
+		return avgConcededAwayColumn;
+	}
+
+	public String getCountryColumn() {
+		return countryColumn;
+	}
+
+	public String getLeagueColumn() {
+		return leagueColumn;
+	}
+
+	public void setGameDateColumn(String gameDateColumn) {
+		this.gameDateColumn = gameDateColumn;
+	}
+
+	public void setHomeTeamColumn(String homeTeamColumn) {
+		this.homeTeamColumn = homeTeamColumn;
+	}
+
+	public void setAwayTeamColumn(String awayTeamColumn) {
+		this.awayTeamColumn = awayTeamColumn;
+	}
+
+	public void setOdds1Column(Float odds1Column) {
+		this.odds1Column = odds1Column;
+	}
+
+	public void setOddsXColumn(Float oddsXColumn) {
+		this.oddsXColumn = oddsXColumn;
+	}
+
+	public void setOdds2Column(Float odds2Column) {
+		this.odds2Column = odds2Column;
+	}
+
+	public void setGoalsHomeColumn(BigDecimal goalsHomeColumn) {
+		this.goalsHomeColumn = goalsHomeColumn;
+	}
+
+	public void setGoalsAwayColumn(BigDecimal goalsAwayColumn) {
+		this.goalsAwayColumn = goalsAwayColumn;
+	}
+
+	public void setGoalDiff(BigDecimal goalDiff) {
+		this.goalDiff = goalDiff;
+	}
+
+	public void setAvgScoreHomeColumn(Float avgScoreHomeColumn) {
+		this.avgScoreHomeColumn = avgScoreHomeColumn;
+	}
+
+	public void setAvgConcededHomeColumn(Float avgConcededHomeColumn) {
+		this.avgConcededHomeColumn = avgConcededHomeColumn;
+	}
+
+	public void setAvgScoreAwayColumn(Float avgScoreAwayColumn) {
+		this.avgScoreAwayColumn = avgScoreAwayColumn;
+	}
+
+	public void setAvgConcededAwayColumn(Float avgConcededAwayColumn) {
+		this.avgConcededAwayColumn = avgConcededAwayColumn;
+	}
+
+	public void setCountryColumn(String countryColumn) {
+		this.countryColumn = countryColumn;
+	}
+
+	public void setLeagueColumn(String leagueColumn) {
+		this.leagueColumn = leagueColumn;
+	}
+}

+ 68 - 0
OddsJavaFx/src/objects/OverUnder.java

@@ -0,0 +1,68 @@
+package objects;
+
+import java.util.ArrayList;
+
+import com.google.common.collect.Lists;
+
+public class OverUnder {
+
+	private Float key;
+	private final ArrayList<Integer> goals;
+	private int total;
+
+	public OverUnder() {
+		goals = Lists.newArrayList(0,0,0,0,0,0,0,0,0,0);
+	}
+
+	public OverUnder(Float key) {
+		this.key = key;
+		goals = Lists.newArrayList(0,0,0,0,0,0,0,0,0,0);
+	}
+
+	public void addGoalStat(int numGoals) {
+		if (numGoals > 9) {
+			Integer val = goals.get(9);
+			val++;
+			goals.set(9, val);
+		} else {
+			Integer val = goals.get(numGoals);
+			val++;
+			goals.set(numGoals, val);
+		}
+
+		updateTotal();
+	}
+
+	private void updateTotal() {
+		total = 0;
+		goals.forEach(g -> total += g);
+	}
+
+	public Float getKey() {
+		return key;
+	}
+
+	public void setKey(Float key) {
+		this.key = key;
+	}
+
+	public ArrayList<Integer> getGoals() {
+		return goals;
+	}
+
+	public int getTotal() {
+		return total;
+	}
+
+	public void setTotal(int total) {
+		this.total = total;
+	}
+
+	public float calcMinOdds(int numGoals) {
+		if (numGoals == 0) {
+			return 1F;
+		}
+		return 1 / (1 / (goals.stream().mapToInt(Integer::intValue).sum()/Float.valueOf(numGoals)));
+
+	}
+}

+ 109 - 0
OddsJavaFx/src/objects/SoccerMatch.java

@@ -0,0 +1,109 @@
+package objects;
+
+import java.time.LocalDateTime;
+
+public class SoccerMatch {
+
+	private Team homeTeam;
+	private Team awayTeam;
+
+	private int matchId;
+	private int homeScore;
+	private int awayScore;
+
+	private float odds1;
+	private float oddsX;
+	private float odds2;
+
+	private LocalDateTime gameDate;
+
+	public Team getHomeTeam() {
+		return homeTeam;
+	}
+
+
+	public Team getAwayTeam() {
+		return awayTeam;
+	}
+
+
+	public int getMatchId() {
+		return matchId;
+	}
+
+
+	public int getHomeScore() {
+		return homeScore;
+	}
+
+
+	public int getAwayScore() {
+		return awayScore;
+	}
+
+
+	public float getOdds1() {
+		return odds1;
+	}
+
+
+	public float getOddsX() {
+		return oddsX;
+	}
+
+
+	public float getOdds2() {
+		return odds2;
+	}
+
+
+	public void setHomeTeam(Team homeTeam) {
+		this.homeTeam = homeTeam;
+	}
+
+
+	public void setAwayTeam(Team awayTeam) {
+		this.awayTeam = awayTeam;
+	}
+
+
+	public void setMatchId(int matchId) {
+		this.matchId = matchId;
+	}
+
+
+	public void setHomeScore(int homeScore) {
+		this.homeScore = homeScore;
+	}
+
+
+	public void setAwayScore(int awayScore) {
+		this.awayScore = awayScore;
+	}
+
+
+	public void setOdds1(float odds1) {
+		this.odds1 = odds1;
+	}
+
+
+	public void setOddsX(float oddsX) {
+		this.oddsX = oddsX;
+	}
+
+
+	public void setOdds2(float odds2) {
+		this.odds2 = odds2;
+	}
+
+
+	public LocalDateTime getGameDate() {
+		return gameDate;
+	}
+
+
+	public void setGameDate(LocalDateTime gameDate) {
+		this.gameDate = gameDate;
+	}
+
+}

+ 49 - 0
OddsJavaFx/src/objects/Team.java

@@ -0,0 +1,49 @@
+package objects;
+
+public class Team {
+
+	private int teamId;
+	private String teamName;
+	private int countryId;
+	private String countryName;
+	private int teamLeagueId;
+	private String teamLeague;
+
+	public int getTeamId() {
+		return teamId;
+	}
+	public String getTeamName() {
+		return teamName;
+	}
+	public int getCountryId() {
+		return countryId;
+	}
+	public String getCountryName() {
+		return countryName;
+	}
+	public int getTeamLeagueId() {
+		return teamLeagueId;
+	}
+	public String getTeamLeague() {
+		return teamLeague;
+	}
+	public void setTeamId(int teamId) {
+		this.teamId = teamId;
+	}
+	public void setTeamName(String teamName) {
+		this.teamName = teamName;
+	}
+	public void setCountryId(int countryId) {
+		this.countryId = countryId;
+	}
+	public void setCountryName(String countryName) {
+		this.countryName = countryName;
+	}
+	public void setTeamLeagueId(int teamLeagueId) {
+		this.teamLeagueId = teamLeagueId;
+	}
+	public void setTeamLeague(String teamLeague) {
+		this.teamLeague = teamLeague;
+	}
+
+}

+ 37 - 0
OddsJavaFx/src/objects/TeamResults.java

@@ -0,0 +1,37 @@
+package objects;
+
+public class TeamResults {
+
+	int wins;
+	int draws;
+	int losses;
+
+	int count;
+
+
+
+	public int getWins() {
+		return wins;
+	}
+	public int getDraws() {
+		return draws;
+	}
+	public int getLosses() {
+		return losses;
+	}
+	public void setWins(int wins) {
+		this.wins = wins;
+	}
+	public void setDraws(int draws) {
+		this.draws = draws;
+	}
+	public void setLosses(int losses) {
+		this.losses = losses;
+	}
+	public int getCount() {
+		return count;
+	}
+	public void setCount(int count) {
+		this.count = count;
+	}
+}

+ 83 - 0
OddsJavaFx/src/objects/TeamStanding.java

@@ -0,0 +1,83 @@
+package objects;
+
+public class TeamStanding {
+
+	private int wins;
+	private int losses;
+	private int draws;
+	private int points;
+	private String teamName;
+	private float goalsScored;
+	private float goalsConceded;
+	private float goalDiff;
+
+	public TeamStanding(String teamName, int wins, int losses, int draws, int points, float goalsScored, float goalsConceded, float goalDiff) {
+		super();
+		this.wins = wins;
+		this.losses = losses;
+		this.draws = draws;
+		this.points = points;
+		this.teamName = teamName;
+		this.goalsScored = goalsScored;
+		this.goalsConceded = goalsConceded;
+		this.goalDiff = goalDiff;
+	}
+
+	public int getWins() {
+		return wins;
+	}
+	public int getLosses() {
+		return losses;
+	}
+	public int getDraws() {
+		return draws;
+	}
+	public int getPoints() {
+		return points;
+	}
+	public void setWins(int wins) {
+		this.wins = wins;
+	}
+	public void setLosses(int losses) {
+		this.losses = losses;
+	}
+	public void setDraws(int draws) {
+		this.draws = draws;
+	}
+	public void setPoints(int points) {
+		this.points = points;
+	}
+
+	public String getTeamName() {
+		return teamName;
+	}
+
+	public void setTeamName(String teamName) {
+		this.teamName = teamName;
+	}
+
+	public float getGoalsScored() {
+		return goalsScored;
+	}
+
+	public float getGoalsConceded() {
+		return goalsConceded;
+	}
+
+	public float getGoalDiff() {
+		return goalDiff;
+	}
+
+	public void setGoalsScored(float goalsScored) {
+		this.goalsScored = goalsScored;
+	}
+
+	public void setGoalsConceded(float goalsConceded) {
+		this.goalsConceded = goalsConceded;
+	}
+
+	public void setGoalDiff(float goalDiff) {
+		this.goalDiff = goalDiff;
+	}
+
+}