Browse Source

Selenium OddsPortal runner done

Axel Nordh 3 năm trước cách đây
mục cha
commit
172e790f7e
41 tập tin đã thay đổi với 3880 bổ sung2243 xóa
  1. 2 1
      Odds/.gitignore
  2. 81 0
      Odds/BWin.csv
  3. 66 0
      Odds/BetHard.csv
  4. 28 0
      Odds/BetSafe.csv
  5. 71 33
      Odds/Expekt.csv
  6. 127 42
      Odds/NordicBet.csv
  7. BIN
      Odds/chromedriver.exe
  8. 20 19
      Odds/src/Main.java
  9. 99 48
      Odds/src/main/ArbChecker.java
  10. 261 193
      Odds/src/mysql/Mysql.java
  11. 72 17
      Odds/src/object/ArbResults.java
  12. 24 0
      Odds/src/object/Odds.java
  13. 119 50
      Odds/src/object/ResultDTO.java
  14. 101 0
      Odds/src/parser/BWinParser.java
  15. 136 0
      Odds/src/parser/BetHard.java
  16. 59 24
      Odds/src/parser/BetSafeParser.java
  17. 45 3
      Odds/src/parser/ExpektParser.java
  18. 46 21
      Odds/src/parser/NordicBetParser.java
  19. 268 158
      Odds/src/parser/OddsPortal.java
  20. 27 1
      Odds/src/parser/ParserBase.java
  21. 8 0
      Odds/src/parser/Todo/BetssonParser.java
  22. 9 0
      Odds/src/parser/Todo/ComeOnParser.java
  23. 8 0
      Odds/src/parser/Todo/MrGreenParser.java
  24. 8 0
      Odds/src/parser/Todo/SnabbareParser.java
  25. 1 0
      Odds/src/parser/Todo/SpeedyBetParser_KanskeBesvärlig.java
  26. 7 0
      Odds/src/parser/Todo/UnibetParser.java
  27. 191 162
      OddsJavaFx/src/controllers/AnalysisTestController.java
  28. 150 139
      OddsJavaFx/src/controllers/TestsController.java
  29. 731 684
      OddsJavaFx/src/data/GuiMysql.java
  30. 1 1
      OddsJavaFx/src/fxml/AnalysisTesting.fxml
  31. 1 0
      OddsJavaFx/src/fxml/Testing.fxml
  32. 88 47
      OddsJavaFx/src/objects/League.java
  33. 99 80
      OddsJavaFx/src/objects/bets/Bet.java
  34. 302 304
      OddsJavaFx/src/parser/OddsPortal.java
  35. 294 0
      OddsJavaFx/src/tests/AnalysisBettDrawTester.java
  36. 2 2
      OddsJavaFx/src/tests/AnalysisBettTester.java
  37. 29 27
      OddsJavaFx/src/tests/HomeDrawAwayTest.java
  38. 112 98
      OddsJavaFx/src/tests/LeagueTablePositionTest.java
  39. 27 33
      OddsJavaFx/src/tests/PrioCountriesAll.java
  40. 158 54
      OddsJavaFx/src/tests/RelevanceTest.java
  41. 2 2
      OddsJavaFx/src/tests/TestClass.java

+ 2 - 1
Odds/.gitignore

@@ -1,4 +1,5 @@
 /bin/
 /target/
 /.settings/
-.classpath
+.classpath
+/.apt_generated/

+ 81 - 0
Odds/BWin.csv

@@ -0,0 +1,81 @@
+Gillingham FC,Dagenham & Redbridge FC,2.4,3.2,2.85,2.05,1.68
+CD Feirense,CD Santa Clara,2.85,3.0,2.55,2.3,1.55
+GD Chaves,FC Porto,7.5,4.75,1.39,1.63,2.1
+Burgos CF,SD Eibar,3.0,2.7,2.5,0.0,0.0
+CD Lugo,Sporting Gijon,3.0,2.87,2.37,2.4,1.49
+UD Ibiza,Racing Santander,2.4,2.8,3.0,0.0,0.0
+Levante UD,SD Ponferradina,1.36,4.4,7.75,1.78,1.9
+Malaga CF,Granada CF,3.6,2.95,2.1,2.37,1.51
+Parma Calcio,Benevento Calcio,1.85,3.4,4.2,2.05,1.66
+Cittadella,SSC Bari,2.45,2.85,3.2,2.4,1.49
+Cosenza,Brescia Calcio,3.25,3.1,2.2,2.15,1.62
+Perugia Calcio,SPAL,2.0,3.2,3.75,2.15,1.62
+Reggina 1914,Frosinone Calcio,2.5,3.0,2.95,2.1,1.63
+Modena FC,Venezia FC,2.3,3.2,3.1,1.9,1.77
+Genoa CFC,FC Sudtirol,1.46,4.2,6.75,1.93,1.75
+SC Pisa,Ascoli Calcio 1898 FC,1.98,3.25,3.8,2.15,1.62
+US Palermo,Como 1907,2.3,3.25,3.0,1.95,1.73
+NK Olimpija Ljubljana,NS Mura,1.83,3.6,3.6,1.65,2.1
+AD Ceuta,San Sebastian Reyes,3.2,2.9,2.15,0.0,0.0
+CD Atletico Baleares,SD Logrones,1.88,2.95,4.0,0.0,0.0
+UD Cornella,Real Murcia CF,3.6,2.85,2.0,0.0,0.0
+CD Alcoyano,Athletic Bilbao B,1.8,3.0,4.2,2.4,1.5
+CE Sabadell FC,Real Union de Irun,1.78,3.0,4.33,0.0,0.0
+CA Osasuna B,Gimnastic de Tarragona,2.0,2.95,3.5,2.35,1.52
+Enppi Club,Haras El Hodood,1.98,2.75,3.9,0.0,0.0
+Smouha SC,Aswan FC,1.93,2.85,3.9,0.0,0.0
+Future FC,Al-Ittihad Al-Sakandary,1.73,3.2,4.4,2.1,1.65
+Ceramica Cleopatra,Ismaily SC,2.25,2.8,3.1,0.0,0.0
+ATK Mohun Bagan,Jamshedpur,1.68,3.7,4.4,1.71,2.0
+VfL WolfsburgD,AS RomaD,1.34,4.6,6.75,1.6,2.2
+Real MadridD,ChelseaD,3.7,3.2,1.85,1.88,1.8
+SKN St. PöltenD,Slavia PragD,2.1,3.3,2.85,1.72,1.98
+Red Bull Bragantino SPWomen,SC Corinthians SPWomen,7.25,4.2,1.37,1.55,2.25
+Al ShababOMA,Salalah SC,1.35,4.5,7.0,1.93,1.77
+Falkirk FC,Dundee FC,3.8,3.5,1.73,1.68,2.05
+Attard FC,St Andrews FC,3.1,3.4,1.98,1.63,2.1
+Fgura United FC,Vittoriosa Stars,1.31,4.5,8.0,0.0,0.0
+Naxxar Lions FC,Melita FC,1.6,3.75,4.4,1.63,2.1
+Lija Athletic,San Gwann FC,2.2,3.3,2.7,1.6,2.2
+Al-Salmiya,Al SahelKUW,1.49,4.1,5.0,1.58,2.2
+Al-ArabiKUW,Al-Qadisiya,2.35,3.25,2.55,1.8,1.88
+ADO Den HaagWomen,FeyenoordD,1.62,3.8,4.2,1.62,2.15
+FC Gagra,FC Spaeri,2.1,3.25,2.9,1.87,1.82
+Aizawl FC,Neroca FC,1.78,3.4,3.8,1.95,1.75
+Trau FC,Punjab FC,2.9,3.2,2.1,1.93,1.75
+FC Ashdod,Maccabi Bnei Reina,1.77,3.3,3.9,1.95,1.73
+Hapoel Be`er Sheva FC,Hapoel Tel Aviv FC,1.6,3.6,4.6,1.82,1.87
+Maccabi Haifa FC,Bnei Sakhnin FC,1.25,5.0,9.25,1.63,2.1
+PSS Sleman,Madura United,3.4,3.1,1.93,2.1,1.62
+Kroatien,Brasilien,8.25,5.0,1.36,1.73,2.0
+Nederländerna,Argentina,3.4,3.1,2.25,2.35,1.53
+FC Famalicao,CD Tondela,1.82,3.4,4.33,2.05,1.68
+Cangzhou Mighty Lions,Wuhan FC,2.25,3.4,2.75,1.8,1.88
+Shanghai Shenhua FC,Dalian Professional FC,2.55,3.4,2.45,1.83,1.85
+Shenzhen FC,Changchun Yatai FC,4.1,3.8,1.7,1.71,2.0
+Wuhan Three Towns FC,Shandong Taishan FC,1.87,3.6,3.5,1.8,1.88
+Brisbane Roar FC,Adelaide United FC,2.5,3.4,2.65,1.65,2.1
+Sepsi OSK,FC Voluntari,1.53,3.8,5.75,2.05,1.66
+Crawley Town,Hartlepool United FC,2.0,3.5,3.5,1.88,1.8
+FC Villefranche-Beaujolais,LB Chateauroux,2.37,3.0,2.75,2.05,1.66
+US Avranches,AS Nancy,3.2,3.1,2.05,2.0,1.7
+Le Puy Foot 43 Auvergne,USL Dunkerque,3.0,3.1,2.1,2.05,1.66
+Stade Briochin,Le Mans FC,3.0,3.2,2.1,1.95,1.73
+Sedan Ardennes,Stade Olympique Choletais,1.98,3.1,3.4,2.0,1.68
+Red Star FC,FC de Versailles 78,1.87,3.25,3.6,1.95,1.75
+Paris 13 Atletico,FC Bastia Borgo,1.95,3.25,3.3,2.1,1.65
+Hyderabad FC,SC East Bengal,1.5,4.1,5.5,1.71,2.0
+Samsunspor,Yeni Malatyaspor,1.38,4.6,6.75,1.63,2.1
+K.V. R.S. Waasland Beveren,RSC Anderlecht Futures,1.52,4.1,4.75,0.0,0.0
+Jong KRC Genk,Club NXTU23,2.1,3.6,2.7,0.0,0.0
+SC Weiche Flensburg 08,Hannover 96 II,2.05,3.7,2.7,0.0,0.0
+Eintracht Norderstedt,SV DROCHTERSEN / ASSEL,2.0,3.5,2.9,1.58,2.2
+Chemnitzer FC,Hertha BSC II,1.52,4.0,4.75,1.65,2.1
+VSG Altglienicke,VfB Germania Halberstadt,1.29,5.25,7.0,0.0,0.0
+FC-Astoria Walldorf,TSG 1899 Hoffenheim IIU23,3.25,3.4,1.9,1.62,2.1
+Arbroath FC,Dunfermline Athletic FC,2.1,3.3,2.9,1.78,1.9
+Alloa Athletic FC,Queen of The South FC,2.1,3.4,2.87,1.66,2.05
+RANS Nusantara FC,Tira-Persikabo,2.7,3.25,2.2,1.65,2.1
+PSIS Semarang,Borneo FC Samarinda,2.95,3.3,2.05,1.83,1.85
+CSD Municipal,Antigua GFC,1.58,3.4,5.25,2.2,1.6
+CD Walter Ferretti,Diriangen FC Diriamba,3.25,3.3,1.95,1.82,1.85

+ 66 - 0
Odds/BetHard.csv

@@ -0,0 +1,66 @@
+Rio Ave,Sporting Lisbon,7.25,5.25,1.35,0.0,0.0
+Managua,Real Esteli,2.7,2.85,2.4,0.0,0.0
+Gillingham,Dagenham & Redbridge,2.5,3.25,2.95,0.0,0.0
+Parma,Benevento,1.83,3.45,4.15,0.0,0.0
+Cittadella AS,Bari,2.4,2.9,3.2,0.0,0.0
+Nuova Cosenza,Brescia,3.4,3.1,2.2,0.0,0.0
+Genoa,Sudtirol Alto Adige,1.5,3.95,6.5,0.0,0.0
+Modena,Venezia,2.35,3.05,3.15,0.0,0.0
+Perugia,Spal,2.05,3.15,3.8,0.0,0.0
+Reggina,Frosinone,2.5,2.95,3.0,0.0,0.0
+Pisa,Ascoli,2.1,3.2,3.65,0.0,0.0
+Palermo,Como,2.2,3.2,3.3,0.0,0.0
+Burgos CF,Eibar,3.1,2.8,2.55,0.0,0.0
+CD Lugo,Sporting Gijon,3.2,2.95,2.4,0.0,0.0
+Ibiza Eivissa,Racing Santander,2.4,2.9,3.25,0.0,0.0
+Levante,Ponferradina,1.41,4.55,6.75,0.0,0.0
+Malaga,Granada CF,3.1,3.0,2.4,0.0,0.0
+Feirense,CD Santa Clara,2.9,3.1,2.5,0.0,0.0
+Chaves,Porto,7.5,4.85,1.35,0.0,0.0
+Smouha SC,Aswan,1.95,2.8,4.35,0.0,0.0
+Future FC,Al-Ittihad Al-Sakandary,1.8,3.0,4.75,0.0,0.0
+Ceramica Cleopatra,El Ismaily,2.45,2.8,3.0,0.0,0.0
+Deportivo Pereira,Indepen Medellin,2.2,3.0,3.15,0.0,0.0
+Olimpija Ljubljana,NS Mura,1.9,3.25,3.6,0.0,0.0
+Wolfsburg [W],AS Roma [W],1.28,4.8,7.5,0.0,0.0
+Real Madrid [W],Chelsea [W],3.3,3.05,2.05,0.0,0.0
+St Polten [W],Slavia Prague [W],2.05,3.35,3.05,0.0,0.0
+Al Manama,Bahrain SC,1.58,3.35,5.25,0.0,0.0
+East Riffa,Al Ahli [BRN],2.75,3.2,2.25,0.0,0.0
+CS Mioveni,Uta Arad,3.9,3.0,1.9,0.0,0.0
+Otelul Galati,FC Buzau,2.4,2.95,2.8,0.0,0.0
+Botosani,FCSB,1.95,3.4,3.3,0.0,0.0
+Shanghai Jiading Huilong,Nantong Zhiyun,1.5,4.6,4.3,0.0,0.0
+Zibo Cuju,Kunshan FC,10.25,6.0,1.17,0.0,0.0
+Sichuan Jiuniu,Suzhou Dongwu,1.95,3.25,3.35,0.0,0.0
+Aizawl FC,NEROCA,1.66,3.55,4.25,0.0,0.0
+Trau FC,RoundGlass Punjab,2.9,3.25,2.15,0.0,0.0
+PSS Sleman,Madura United,3.0,3.15,2.15,0.0,0.0
+PSM Makassar,Persita Tangerang,2.0,3.2,3.25,0.0,0.0
+Bali United Pusam FC,Bhayangkara FC,1.86,3.2,3.7,0.0,0.0
+Falkirk,Dundee FC,3.75,3.5,1.76,0.0,0.0
+ATK Mohun Bagan,Jamshedpur FC,1.71,3.35,4.05,0.0,0.0
+FC Ashdod,Maccabi Bnei Raina,1.8,3.2,3.75,0.0,0.0
+Hapoel Beer Sheva,Hapoel Tel Aviv,1.55,3.65,4.6,0.0,0.0
+Maccabi Haifa,Bnei Sakhnin,1.21,5.5,8.5,0.0,0.0
+Hapoel Nir Ramat HaSharon,Maccabi Kabilio Jaffa FC,2.6,2.95,2.45,0.0,0.0
+Hapoel Petah Tikva,Hapoel Afula,2.15,2.8,3.25,0.0,0.0
+Hapoel Nof Hagalil,Bnei Yehuda,2.65,2.95,2.45,0.0,0.0
+Racing Club Abidjan,Sporting Gagnoa,2.4,2.65,3.0,0.0,0.0
+Den Haag [W],Feyenoord [W],1.51,4.3,4.15,0.0,0.0
+Sur Club,Al Ittihad [OMA],2.05,2.8,3.55,0.0,0.0
+Al-Msnaa,AL Nahda [OMA],6.0,2.95,1.58,0.0,0.0
+Bani Yas,Masfut,1.17,6.0,8.5,0.0,0.0
+Al Ain [UAE],Dibba Al Fujairah,1.16,6.0,9.5,0.0,0.0
+Al-Arabi [UAE],Ajman,6.0,4.2,1.35,0.0,0.0
+Al Urooba [UAE],Khorfakkan FC,5.75,4.4,1.36,0.0,0.0
+Shirak Gjumri,FC Noah,1.9,3.35,3.2,0.0,0.0
+Ararat Yerevan,BKMA Yerevan,1.57,3.3,4.75,0.0,0.0
+Ethiopia Bunna,Hadia Hosaina,3.1,3.0,2.1,0.0,0.0
+Wolkite Ketema,Ethiopian Medhin,2.8,2.9,2.25,0.0,0.0
+CSD Comunicaciones,Coban Imperial,1.34,3.65,7.0,0.0,0.0
+Fgura United,Vittoriosa Stars,1.29,4.6,6.75,0.0,0.0
+Attard FC,St. Andrews,3.1,3.35,1.9,0.0,0.0
+Naxxar Lions,Melita,1.54,3.75,4.4,0.0,0.0
+Lija Athletic,San Gwann,2.15,3.45,2.55,0.0,0.0
+AS Kigali,APR FC,2.7,2.6,2.6,0.0,0.0

+ 28 - 0
Odds/BetSafe.csv

@@ -0,0 +1,28 @@
+Atletico Baleares,Logroñés,1.95,3.0,4.33,-1.0,-1.0
+Ceuta,SS de los Reyes,3.3,3.0,2.25,-1.0,-1.0
+Parma,Benevento,1.87,3.4,4.2,2.1,1.7
+Burgos,Eibar,3.0,2.8,2.65,-1.0,-1.0
+Cittadella,Bari,2.5,2.9,3.1,-1.0,-1.0
+Nuova Cosenza,Brescia,3.2,3.1,2.3,2.15,1.65
+Genoa,Sudtirol,1.45,4.2,7.0,1.95,1.8
+Modena,Venezia,2.4,3.1,3.0,2.0,1.75
+Perugia,Spal,2.05,3.2,3.75,2.15,1.65
+Reggina,Frosinone,2.5,3.0,2.95,2.1,1.68
+UD Cornella,UCAM Murcia,3.75,3.0,2.1,-1.0,-1.0
+Lugo,Sporting de Gijón,3.1,2.95,2.45,-1.0,-1.0
+Alcoyano,Athletic B,1.83,3.2,4.5,-1.0,-1.0
+Pisa,Ascoli,2.05,3.2,3.75,2.2,1.62
+Levante,Ponferradina,1.36,4.75,8.0,1.8,1.95
+UD Ibiza-Eivissa,Racing B,2.45,2.95,3.1,-1.0,-1.0
+KS Vllaznia,PSG,29.0,13.0,-1.0,-1.0,-1.0
+VfL Wolfsburg,AS Roma W,1.33,4.75,7.5,1.6,2.2
+Sabadell,Real Union,1.85,3.2,4.5,-1.0,-1.0
+Osasuna B,Gimnàstic,2.05,3.1,3.75,2.4,1.53
+Kroatien,Brasilien,9.6,5.1,1.36,1.8,2.09
+Nederländerna,Argentina,3.6,3.15,2.28,2.48,1.57
+Crawley Town,Hartlepool,2.05,3.5,3.5,1.95,1.85
+Gillingham,Dag & Redbridge,2.55,3.2,2.8,2.1,1.72
+Palermo,Como,2.4,3.2,2.95,2.0,1.75
+Malaga,Granada,3.75,3.1,2.1,2.4,1.53
+Real Madrid,Chelsea LFC,3.75,3.4,1.83,1.9,1.8
+St. Polten,SK Slavia Praha,2.1,3.5,2.95,1.68,2.05

+ 71 - 33
Odds/Expekt.csv

@@ -1,33 +1,71 @@
-FC Oleksandriya,Rukh Vynnyky,1.04,9.5,46.0
-Johor Darul Takzim,Borussia Dortmund,801.0,301.0,-1.0
-Sydkorea,Ghana,2.7,3.15,2.95
-Brasilien,Schweiz,1.47,4.5,8.0
-Portugal,Uruguay,2.08,3.35,4.3
-Châteauroux,Le Mans,2.15,3.4,2.85
-UD Ibiza,FC Andorra,3.05,2.9,2.48
-Qarabağ,Zira IK,1.11,6.4,12.5
-Aris Limassol,Pafos FC,2.55,3.0,2.48
-Olympiakos Nicosia,Nea Salamis Famagusta,2.63,2.95,2.48
-Punjab,Aizawl FC,1.68,3.7,4.1
-Csikszereda Miercurea Ciuc,CSC Șelimbăr,1.34,4.1,8.0
-Ayr United,Pollok,1.18,6.5,12.0
-Altinordu,Manisa Büyükşehir Belediyespor,3.15,3.15,2.1
-Wakiso Giants FC,Express FC,1.85,3.0,4.2
-Ecuador,Senegal,2.45,3.25,3.25
-Nederländerna,Qatar,1.21,7.0,17.0
-Iran,USA,4.1,3.55,2.0
-Wales,England,8.5,4.75,1.43
-ASO Chlef,MC EL Bayadh,1.98,2.9,4.1
-Belouizdad,CS Constantine,1.55,3.6,5.8
-MC Alger,Paradou Ac,1.5,3.5,7.5
-NC Magra,USM Alger,4.1,2.85,2.02
-RC Arbaâ,USM Khenchela,2.18,2.65,3.85
-US Biskra,JS Kabylie,2.38,2.6,3.5
-ES Sétif,MC Oran,1.5,3.65,6.5
-JS Saoura,AB Chelghoum Laid,1.11,6.75,20.0
-Kenkre,Neroca FC,3.65,3.05,1.95
-Chindia Târgovişte,Universitatea Craiova,4.1,3.15,1.95
-ND Gorica,Tabor Sezana,2.08,3.2,3.0
-Maribor,NK Bravo,1.7,3.4,4.0
-SV Türkgücü-Ataspor München,SV Heimstetten,1.47,4.25,5.1
-BSG Chemie Leipzig,BFC Dynamo,2.05,3.5,3.0
+PSM Makassar,Persita Tangerang,1.5,3.7,5.5,-1.0,-1.0
+Gillingham,Dag & Red,2.5,3.25,2.85,2.05,1.73
+Burgos,Eibar,3.05,2.7,2.6,-1.0,-1.0
+Lugo,Sporting Gijón,3.1,2.9,2.4,-1.0,-1.0
+Levante,Ponferradina,1.36,4.5,8.0,1.79,1.94
+UD Ibiza,Racing Santander,2.5,2.85,3.05,-1.0,-1.0
+Málaga,Granada,3.85,3.0,2.04,2.48,1.49
+Parma,Benevento,1.85,3.4,4.2,2.07,1.72
+Cittadella,Bari,2.5,2.85,3.1,2.43,1.53
+Cosenza,Brescia,3.5,3.0,2.2,2.2,1.63
+Genoa,Südtirol,1.42,4.1,7.5,1.95,1.81
+Modena,Venezia,2.35,3.0,3.1,1.98,1.78
+Perugia,Spal,2.05,3.1,3.8,2.25,1.61
+Reggina,Frosinone,2.5,2.95,3.0,2.2,1.63
+Pisa,Ascoli,2.05,3.15,3.75,2.18,1.64
+Palermo,Como,2.4,3.0,3.1,1.98,1.78
+KS Vllaznia (d),Paris SG (d),35.0,17.0,1.01,-1.0,-1.0
+VfL Wolfsburg (d),Roma (d),1.3,5.1,8.5,1.53,2.4
+Real Madrid (d),Chelsea (d),3.75,3.4,1.93,1.83,1.93
+St.Pölten-Spratzern (d),Slavia Praha (d),2.05,3.65,3.15,1.79,1.94
+ENPPI Club,Haras El Hodood,1.9,2.9,4.0,-1.0,-1.0
+Smouha SC,Aswan FC,1.93,2.8,4.5,-1.0,-1.0
+Future FC,Al-Ittihad Alexandria,1.73,3.05,5.2,2.1,1.65
+Ceramica Cleopatra,Ismaily,2.3,2.8,3.3,-1.0,-1.0
+TRAU FC,Punjab,3.25,3.05,2.1,1.97,1.78
+Mohun Bagan,Jamshedpur FC,1.75,3.7,4.3,1.7,2.1
+Bali United,Bhayangkara,1.6,3.3,4.7,2.02,1.72
+Hapoel Nof HaGalil F.C.,Bnei Yehuda Tel Aviv,2.8,3.15,2.3,2.2,1.63
+ADO Den Haag (d),Feyenoord (d),1.75,4.35,3.8,1.64,2.12
+Feirense,Santa Clara,3.0,3.0,2.45,2.43,1.53
+Chaves,Porto,6.85,4.7,1.4,1.66,2.15
+FC Botoşani,FCSB,1.8,3.8,3.8,1.65,2.25
+Mioveni,AFC UTA Arad,4.3,3.15,1.9,2.55,1.52
+Oţelul Galaţi,FC Buzău,2.45,3.1,2.9,2.4,1.54
+Falkirk,Dundee FC,4.0,3.5,1.75,1.67,2.14
+Olimpija Ljubljana,NŠ Mura,1.82,3.65,3.3,1.65,2.15
+Aston Villa,Brighton,2.8,3.35,2.4,1.72,2.06
+Reims,Sochaux,1.9,3.6,3.2,1.72,2.02
+Arsenal,Lyon,2.23,3.65,2.8,1.64,2.18
+Getafe,Chivas Guadalajara,2.0,3.9,3.15,1.73,2.02
+Elche,Leeds,2.9,4.1,2.06,1.87,1.87
+Kroatien,Brasilien,10.0,5.1,1.37,1.8,2.04
+Nederländerna,Argentina,3.65,3.15,2.32,2.38,1.6
+Crawley Town,Hartlepool United,2.0,3.6,3.4,1.91,1.81
+Avranches,Nancy,3.0,3.35,2.08,1.95,1.84
+Bourg-Péronnas,Orleans,1.85,3.5,3.55,1.95,1.84
+Le Puy Football 43 Auvergne,Dunkerque,3.15,3.25,2.04,2.1,1.73
+Red Star FC,Versailles 78,1.76,3.6,3.8,1.89,1.9
+Sedan,Cholet,1.92,3.45,3.3,1.9,1.89
+Stade Briochin,Le Mans,2.85,3.5,2.12,1.84,1.96
+Villefranche,Châteauroux,2.16,3.35,2.88,1.98,1.82
+Gobelins,Bastia-Borgo,2.0,3.25,3.3,2.15,1.7
+Brisbane Roar,Adelaide United,2.43,3.75,2.6,1.67,2.2
+Doxa Katokopias,AEK Larnaca,4.9,3.45,1.57,1.84,1.81
+Pafos FC,Apoel Nicosia,2.35,2.65,3.1,2.33,1.49
+Hyderabad FC,Quess East Bengal Club,1.5,4.25,6.0,1.71,2.07
+RANS Nusantara FC,PS Tira,2.7,3.3,2.2,1.65,2.14
+PSIS Semarang,Pusamania Borneo,2.95,3.4,2.05,1.86,1.86
+Coleraine,Crusaders Belfast,2.75,3.35,2.2,1.75,2.02
+Famalicão,CD de Tondela,1.78,3.35,4.7,2.28,1.58
+ACS Sepsi OSK Sfântul Gheorghe,SC FC Voluntari SA,1.53,3.85,6.0,2.04,1.75
+Alloa Athletic,Queen of the South,2.1,3.4,3.0,1.67,2.14
+Arbroath,Dunfermline Athletic,2.15,3.25,3.1,1.81,1.94
+Samsunspor,Yeni Malatyaspor,1.4,4.0,6.1,1.64,2.14
+1. FFC Frankfurt (d),1. FFC Turbine Potsdam (d),1.17,6.4,8.0,-1.0,-1.0
+ETSV Weiche Flensburg,Hannover 96 II,2.1,3.35,3.0,-1.0,-1.0
+Eintracht Norderstedt,SV Drochtersen/Assel,2.05,3.15,3.25,1.65,2.16
+Chemnitzer FC,Hertha Berlin II,1.58,3.8,4.7,1.63,2.2
+VSG Altglienicke,Germania Halberstadt,1.28,5.5,6.75,-1.0,-1.0
+Astoria Walldorf,Hoffenheim II,3.05,3.6,1.95,1.57,2.33
+KCCA,Express FC,1.6,3.6,4.75,1.91,1.81

+ 127 - 42
Odds/NordicBet.csv

@@ -1,42 +1,127 @@
-Johor Darul Ta zim,Borussia Dortmund,51.0,51.0,-1.0
-PAOK,FC Ashdod,1.85,4.0,4.33
-Real Betis (Perapanamera),Lazio (Rodja),1.01,20.0,25.0
-West Ham (Taz),Real Sociedad (Jekos),8.55,3.63,1.45
-Sydkorea,Ghana,2.7,3.15,2.85
-Ierapetra,Proodeftiki,1.7,4.0,4.2
-Kifisia,Kallithea,2.35,2.9,3.2
-Brasilien,Schweiz,1.48,4.4,7.3
-Altinordu,Manisa FK,3.25,3.4,2.2
-Portugal,Uruguay,2.0,3.3,4.2
-ArzignanoChiampo,L.R. Vicenza Virtus,3.4,3.2,2.1
-Ayr United,Pollok,1.15,7.0,15.0
-Hitchin Town,Redditch Utd,2.75,3.4,2.25
-Kings Langley,Nuneaton,2.95,3.3,2.2
-Shandong Luneng,Cangzhou Mighty Lions,1.22,6.5,10.0
-Tianjin Teda,Guangzhou R F,1.6,4.0,5.0
-Hebei China Fortune Football Club,Dalian Aerbin FC,67.0,13.0,1.02
-Shanghai SIPG,Henan Construction,1.75,3.6,4.5
-Wuhan Three Towns,Changchun Yatai,1.28,5.5,9.0
-Zhejiang Professional,Beijing Guoan,2.55,3.5,2.55
-Shenzhen XiangXue,Wuhan Zall,1.68,4.0,4.5
-Pordenone,Pro Patria,1.8,3.3,4.5
-Foggia,Messina,1.7,3.5,4.75
-Tunisien,Frankrike,6.8,4.1,1.55
-Australien,Danmark,7.0,4.2,1.52
-Catanzaro,Giugliano,1.38,4.5,7.5
-Feralpisalo,Juventus-U23,2.2,3.1,3.3
-Lecco,Renate,2.25,3.2,3.1
-Mantova,Albinoleffe,2.4,2.95,3.1
-Pergolettese,Novara,2.7,3.1,2.6
-Piacenza,Triestina,2.7,3.1,2.6
-Virtus Verona,Pro Sesto,2.55,3.0,2.8
-Latina,Monopoli,2.35,3.0,3.1
-Taranto,Crotone,4.2,3.5,1.8
-Polen,Argentina,7.7,4.35,1.47
-Saudiarabien,Mexiko,4.95,4.05,1.68
-Sangiuliano City,Padova,2.55,3.0,2.8
-Avellino,Juve Stabia,2.2,3.1,3.3
-Potenza,Audace Cerignola,2.6,3.0,2.75
-Turris,Fidelis Andria,2.15,3.2,3.3
-Francavilla,Pescara,3.75,3.5,1.87
-Sporting CP,Farense,1.15,7.0,17.0
+Manchester City (ECF_slezaintima),Tottenham Hotspur (ECF_white_boy1927),27.0,15.0,1.01,-1.0,-1.0
+Chelsea (ECF_Upcake22),Manchester United (ECF_Rus_1995_LAN),7.65,1.15,12.0,-1.0,-1.0
+Girona FC,Standard de Liege,2.0,3.75,3.3,1.57,2.35
+Adana Demirspor,FK Liepaja,1.18,6.4,12.0,-1.0,-1.0
+Atletico Baleares,Logroñés,1.95,3.0,4.33,-1.0,-1.0
+Ceuta,SS de los Reyes,3.3,3.0,2.25,-1.0,-1.0
+Viveiro CF,Alondras CF,2.6,3.0,2.65,2.35,1.53
+RC Celta de Vigo III (Gran Pena FC),Club Rapido de Bouzas,2.35,3.0,2.95,2.25,1.57
+Racing Club Villalbes,CD Barco,1.95,3.3,3.6,1.95,1.78
+CD Rota,Coria CF,3.2,2.95,2.25,2.35,1.52
+AD Cartaya,CD Gerena,4.33,3.2,1.8,2.2,1.6
+Conil CF,Córdoba B,3.5,3.2,2.0,2.1,1.66
+UD Ciudad de Torredonjimeno,Atletico Porcuna CF,1.9,3.25,3.75,2.05,1.68
+UD Almeria B,CF Motril,1.57,3.75,5.0,1.72,2.0
+Silva SD,CSD Arzúa,2.05,3.25,3.3,2.1,1.66
+Parma,Benevento,1.87,3.4,4.2,2.1,1.7
+Sivaspor,Saarbrucken,1.65,3.7,4.75,1.52,2.4
+1. FC Tatran Presov,MFK Dukla Banska Bystrica,4.2,4.0,1.68,1.57,2.3
+Burgos,Eibar,3.0,2.8,2.65,-1.0,-1.0
+Fortuna Sittard,Livingston,1.8,4.0,3.75,-1.0,-1.0
+Aston Villa FC,Brighton and Hove Albion FC,2.8,3.5,2.4,1.72,2.1
+Cremonese,Salsomaggiore,1.05,10.0,34.0,-1.0,-1.0
+ATK Mohun Bagan,Jamshedpur FC,1.7,3.75,4.5,1.75,2.0
+Cittadella,Bari,2.5,2.9,3.1,-1.0,-1.0
+Nuova Cosenza,Brescia,3.2,3.1,2.3,2.15,1.65
+Genoa,Sudtirol,1.45,4.2,7.0,1.95,1.8
+Modena,Venezia,2.4,3.1,3.0,2.0,1.75
+Perugia,Spal,2.05,3.2,3.75,2.15,1.65
+Reggina,Frosinone,2.5,3.0,2.95,2.1,1.68
+AS Lamia,NFC Volos,2.7,3.5,2.35,2.05,1.72
+UD Cornella,UCAM Murcia,3.75,3.0,2.1,-1.0,-1.0
+Stade de Reims,FC Sochaux Montbeliard,2.05,3.6,3.3,1.75,2.05
+Casalarreina CF,SD Oyonesa,3.5,3.3,1.95,1.95,1.78
+Lugo,Sporting de Gijón,3.1,2.95,2.45,-1.0,-1.0
+Arsenal,Olympique Lyonnais,2.45,3.6,2.7,1.7,2.15
+CD Choco,Arosa SC,3.5,3.1,2.05,2.05,1.68
+UD Somozas,UD Paiosaco,1.53,3.75,5.5,1.9,1.8
+UD Ourense,Deportivo La Coruna II,2.6,3.2,2.5,1.95,1.78
+Atletico Arteixo,Estradense,2.65,3.25,2.4,2.2,1.6
+NK Olimpija Ljubljana,NÅ  Mura,1.9,3.6,3.6,1.68,2.1
+Feirense,Santa Clara,2.85,3.0,2.6,2.4,1.53
+Alcoyano,Athletic B,1.83,3.2,4.5,-1.0,-1.0
+Pisa,Ascoli,2.05,3.2,3.75,2.2,1.62
+Levante,Ponferradina,1.36,4.75,8.0,1.8,1.95
+UD Ibiza-Eivissa,Racing B,2.45,2.95,3.1,-1.0,-1.0
+Sabadell,Real Union,1.85,3.2,4.5,-1.0,-1.0
+Osasuna B,Gimnàstic,2.05,3.1,3.75,2.4,1.53
+Chaves,Porto,7.0,4.75,1.4,1.63,2.2
+Gillingham,Dag & Redbridge,2.55,3.2,2.8,2.1,1.72
+Elche CF,Leeds United,3.0,3.75,2.15,1.87,1.87
+Palermo,Como,2.4,3.2,2.95,2.0,1.75
+Malaga,Granada,3.75,3.1,2.1,2.45,1.52
+Keciörengücü,Adanaspor,1.78,3.75,4.33,1.75,2.1
+Tuzlaspor,Çaykur Rizespor,3.5,3.5,2.05,1.9,1.9
+Guangzhou,Guangzhou R F,2.6,3.5,2.5,2.0,1.75
+Zhejiang Professional,Meizhou Hakka,1.68,3.75,4.75,1.8,1.95
+Chengdu Rongcheng,Shanghai SIPG,2.95,3.4,2.3,1.95,1.8
+Kifisia,Ierapetra,1.28,4.85,10.0,1.9,1.82
+Blackburn,Preston,2.18,3.25,3.45,2.25,1.65
+AŠK Bravo,NK Koper,2.85,3.2,2.4,2.05,1.72
+FC Goa,Odisha FC,2.1,3.6,3.1,1.62,2.2
+Granada B,UCAM Murcia,3.3,3.1,2.2,2.15,1.65
+Rotherham,Bristol City,2.92,3.3,2.4,2.01,1.8
+Ipswich,Peterborough,1.55,4.2,5.5,1.87,1.9
+Shrewsbury,Bolton,3.1,3.3,2.3,2.15,1.7
+Irodotos,Kallithea,8.5,4.35,1.35,1.86,1.86
+Carlisle,Barrow,2.35,3.2,3.1,2.2,1.66
+Crewe,Leyton Orient,3.75,3.4,2.0,2.3,1.6
+Harrogate Town,Northampton,3.0,3.3,2.35,2.1,1.72
+Denizlispor,Altay,3.1,3.4,2.25,2.0,1.8
+Alessandria,Montevarchi,2.4,3.0,3.0,2.45,1.52
+Reggiana,Olbia,1.44,4.33,6.5,1.8,1.95
+San Donato Tavarnelle,Imolese,2.2,3.0,3.4,2.45,1.52
+Vis Pesaro,Cesena,4.0,3.2,1.95,2.4,1.53
+Reading,Coventry,2.5,3.25,2.85,2.14,1.71
+Burton Albion,Derby,3.1,3.4,2.25,1.95,1.83
+Forest Green,Cheltenham,2.45,3.3,2.9,2.05,1.75
+Rochdale,Stockport,4.0,3.5,1.9,2.1,1.72
+NorthEast United,Chennaiyin FC,3.6,3.5,1.95,1.83,1.9
+Banbury United,Curzon Ashton,1.95,3.6,3.5,1.8,1.95
+Buxton,Peterborough Sports,2.4,3.3,2.75,2.0,1.75
+Chester,Alfreton Town,1.83,3.6,4.0,1.95,1.8
+Chorley,Telford,1.7,3.75,4.5,1.75,2.0
+Farsley Celtic,Leamington,2.0,3.4,3.5,2.0,1.75
+Gloucester City,Darlington,2.65,3.6,2.35,1.8,1.95
+Kettering,AFC Fylde,3.6,3.6,1.9,1.83,1.9
+Kidderminster,Blyth Spartans,1.6,4.0,5.0,1.85,1.9
+Kings Lynn,Bradford PA,1.33,4.75,8.5,1.8,1.95
+Scarborough Athletic,Brackley,3.5,3.4,2.0,2.0,1.75
+Southport,Boston Utd,2.4,3.5,2.65,1.8,1.95
+Spennymoor Town FC,Hereford,2.25,3.3,3.0,1.87,1.87
+Blackpool,Birmingham,2.75,3.3,2.55,2.04,1.77
+Middlesbrough,Luton,1.8,3.65,4.4,2.03,1.78
+Millwall,Wigan,1.88,3.45,4.25,2.22,1.66
+Sheffield Utd,Huddersfield,1.48,4.4,6.4,1.76,2.07
+Stoke,Cardiff,2.08,3.45,3.55,2.07,1.76
+Swansea,Norwich,2.4,3.45,2.85,1.9,1.9
+Accrington,Portsmouth,3.25,3.5,2.15,1.9,1.9
+Bristol Rovers,Port Vale,2.5,3.3,2.8,1.95,1.83
+Cambridge,Plymouth,3.2,3.5,2.15,1.83,1.95
+Exeter,Sheffield Wed,3.75,3.6,1.95,2.0,1.83
+Lincoln,Wycombe,2.9,3.3,2.45,2.05,1.75
+Milton Keynes,Fleetwood,2.2,3.3,3.3,2.1,1.72
+Morecambe,Charlton,3.75,3.6,1.95,2.0,1.83
+Oxford Utd,Barnsley,2.3,3.4,3.0,2.0,1.8
+Grimsby,Tranmere,2.3,3.2,3.2,2.3,1.62
+Newport County,Doncaster,2.05,3.4,3.6,2.15,1.7
+Salford City FC,Walsall,2.45,3.25,2.9,2.25,1.63
+Stevenage,Mansfield,2.05,3.4,3.6,2.05,1.75
+Sutton United,Colchester,1.95,3.4,4.0,2.15,1.7
+Swindon,AFC Wimbledon,1.95,3.6,3.75,1.95,1.85
+Marocko,Portugal,5.35,3.8,1.7,2.18,1.69
+Cádiz CF B,Betis B,2.35,2.95,3.2,-1.0,-1.0
+Burgos Promesas,Palencia,3.4,3.25,2.1,2.15,1.65
+UD Mutilvera,Alfaro,2.1,3.1,3.6,2.2,1.62
+Racing Rioja,Tudelano,2.7,3.0,2.65,-1.0,-1.0
+Real Sociedad B,CF La Nucía,2.05,3.1,3.75,2.4,1.53
+Göztepe,Manisa FK,2.3,3.4,3.0,1.87,1.9
+Celta B,Cultural Leonesa,2.1,3.1,3.6,2.1,1.68
+AD San Juan,Logrones Promesas,2.15,3.2,3.3,2.2,1.62
+Lucchese,Carrarese,2.3,3.0,3.2,-1.0,-1.0
+Pontedera,Fermana,1.95,3.2,4.0,-1.0,-1.0
+Rimini,Ancona,2.5,3.0,2.9,-1.0,-1.0
+Siena,Fiorenzuola,2.1,3.1,3.6,-1.0,-1.0
+Sassari Torres,Gubbio,3.4,3.1,2.15,2.45,1.52
+Guijuelo,Bergantinos,1.95,3.3,3.75,2.15,1.65
+CD Eldense,Amorebieta,1.75,3.5,4.5,2.35,1.55

BIN
Odds/chromedriver.exe


+ 20 - 19
Odds/src/Main.java

@@ -10,30 +10,13 @@ public class Main {
     public static void main(String[] args) {
 
         // testExpektParser();
-//        updateFromOddsportal();
+        updateFromOddsportal();
 
-        testArbMatches();
+//        testArbMatches();
 //        op.getHistoricMatches("soccer", "japan", "j2-league", "2020");
         // callingRScript();
     }
 
-    private static void testArbMatches() {
-        new ArbChecker();
-    }
-
-    private static void updateFromOddsportal() {
-        final OddsPortal op = new OddsPortal();
-        System.out.println("Getting Yesterdays matches");
-        op.getYesterdaysMatches();
-        System.out.println("Getting Todays Matches");
-        op.getTodaysMatches();
-        System.out.println("Getting tomorrows matches");
-        op.getTomorrowsMatches();
-
-        System.out.println("Getting next matches");
-        op.getNextDaysMatches();
-    }
-
     private static void callingRScript() throws IOException {
         System.out.println(System.getProperty("user.dir"));
         final String rPath = System.getProperty("user.dir") + "\\src\\RScript\\scorePrediction.R";
@@ -57,4 +40,22 @@ public class Main {
         }
     }
 
+    private static void testArbMatches() {
+        new ArbChecker();
+    }
+
+    private static void updateFromOddsportal() {
+        final OddsPortal op = new OddsPortal();
+        System.out.println("Getting Yesterdays matches");
+        op.getYesterdaysMatches();
+        System.out.println("Getting Todays Matches");
+        op.getTodaysMatches();
+        System.out.println("Getting tomorrows matches");
+        op.getTomorrowsMatches();
+
+        System.out.println("Getting next matches");
+        op.getNextDaysMatches();
+
+    }
+
 }

+ 99 - 48
Odds/src/main/ArbChecker.java

@@ -12,6 +12,8 @@ import java.util.Arrays;
 import java.util.List;
 
 import object.ArbResults;
+import parser.BWinParser;
+import parser.BetHard;
 import parser.BetSafeParser;
 import parser.ExpektParser;
 import parser.NordicBetParser;
@@ -21,84 +23,133 @@ public class ArbChecker {
     private List<ArbResults> nordicBetMatches = new ArrayList<>();
     private List<ArbResults> expektResults = new ArrayList<>();
     private List<ArbResults> betSafeResults = new ArrayList<>();
+    private List<ArbResults> betHardResults = new ArrayList<>();
+    private List<ArbResults> bWinResults = new ArrayList<>();
 
     public ArbChecker() {
-    //    NordicBetParser nbp = new NordicBetParser();
-    //    nordicBetMatches.addAll(nbp.parseSoccerMatches().stream().map(m -> new ArbResults(m, "NordicBet")).toList());
-    //    printResultsToArrayFile(nordicBetMatches, "NordicBet.csv");
+        NordicBetParser nbp = new NordicBetParser();
+        nordicBetMatches.addAll(nbp.parseSoccerMatches().stream().map(m -> new ArbResults(m, "NordicBet")).toList());
+        printResultsToArrayFile(nordicBetMatches, "NordicBet.csv");
 
-    //    ExpektParser ep = new ExpektParser();
-    //    expektResults.addAll(ep.seleniumParseSoccerMatches().stream().map(m -> new ArbResults(m, "Expekt")).toList());
-    //    printResultsToArrayFile(expektResults, "Expekt.csv");
+        ExpektParser ep = new ExpektParser();
+        expektResults.addAll(ep.seleniumParseSoccerMatches().stream().map(m -> new ArbResults(m, "Expekt")).toList());
+        printResultsToArrayFile(expektResults, "Expekt.csv");
 
-    // BetSafeParser bsp = new BetSafeParser();
-    // betSafeResults.addAll(bsp.seleniumPaseSoccerMatches().stream().map(m -> new ArbResults(m, "BetSafe")).toList());
-    // printResultsToArrayFile(betSafeResults, "BetSafe.csv");
+        BetSafeParser bsp = new BetSafeParser();
+        betSafeResults.addAll(bsp.seleniumPaseSoccerMatches().stream().map(m -> new ArbResults(m, "BetSafe")).toList());
+        printResultsToArrayFile(betSafeResults, "BetSafe.csv");
+
+        BetHard bh = new BetHard();
+        betHardResults.addAll(bh.seleniumParseMatches().stream().map(m -> new ArbResults(m, "BetHard")).toList());
+        printResultsToArrayFile(betHardResults, "BetHard.csv");
+
+        BWinParser bwin = new BWinParser();
+        bWinResults
+                .addAll(bwin.parseSoccerMatches().stream().map(m -> new ArbResults(m, BWinParser.BOOKIE)).toList());
+        printResultsToArrayFile(bWinResults, BWinParser.BOOKIE + ".csv");
 
         getResultsFromFile("NordicBet.csv", nordicBetMatches, "NordicBet");
         getResultsFromFile("Expekt.csv", expektResults, "Expekt");
-        getResultsFromFile("BetSafe.csv", expektResults, "BetSafe");
+        getResultsFromFile("BetSafe.csv", betSafeResults, "BetSafe");
+        getResultsFromFile("BetHard.csv", betHardResults, "BetHard");
+        getResultsFromFile(BWinParser.BOOKIE + ".csv", bWinResults, BWinParser.BOOKIE);
 
         List<SimpleEntry<String, List<ArbResults>>> resultLists = new ArrayList<>();
         SimpleEntry<String, List<ArbResults>> entryNordicBet = new SimpleEntry<>("NordicBet", this.nordicBetMatches);
         SimpleEntry<String, List<ArbResults>> betSafe = new SimpleEntry<>("BetSafe", this.betSafeResults);
+        SimpleEntry<String, List<ArbResults>> betHard = new SimpleEntry<>("BetHard", this.betHardResults);
+        SimpleEntry<String, List<ArbResults>> expekt = new SimpleEntry<>("Expekt", this.expektResults);
+        SimpleEntry<String, List<ArbResults>> bwinEntries = new SimpleEntry<>(BWinParser.BOOKIE, this.bWinResults);
 
+        resultLists.add(expekt);
         resultLists.add(entryNordicBet);
         resultLists.add(betSafe);
-        checkForArbs(new SimpleEntry<>("Expekt", expektResults), resultLists);
+        resultLists.add(betHard);
+        resultLists.add(bwinEntries);
+        checkForArbs(resultLists);
+
     }
 
-    private void checkForArbs(SimpleEntry<String, List<ArbResults>> mainList,
-            List<SimpleEntry<String, List<ArbResults>>> resultLists) {
-        for (ArbResults match : mainList.getValue()) {
-            String replaceParentecesRegEx = "\\(.*\\)| [A-Za-z]{2} |Club|club";
-            List<String> homeTeamParts = Arrays
-                    .asList(match.getHomeTeam().replaceAll(replaceParentecesRegEx, "").trim().split(" "));
-            List<String> awayTeamParts = Arrays
-                    .asList(match.getAwayTeam().replaceAll(replaceParentecesRegEx, "").trim().split(" "));
-
-            for (SimpleEntry<String, List<ArbResults>> list : resultLists) {
-                List<ArbResults> homeTeamFound = list.getValue().stream()
-                        .filter(p -> Arrays.asList(p.getHomeTeam().replaceAll(replaceParentecesRegEx, "")
-                                .trim().split(" ")).stream().anyMatch(homeTeamParts::contains))
+    private void checkForArbs(List<SimpleEntry<String, List<ArbResults>>> resultLists) {
+        ArrayList<ArbResults> addedMatches = new ArrayList<>();
+
+        String replaceParentecesRegEx = "\\(.*\\)| [A-Za-z]{2} |Club|club|II|FC|NK|AL|Al";
+
+        for (SimpleEntry<String, List<ArbResults>> list : resultLists) {
+            for (ArbResults match : list.getValue()) {
+
+                List<String> homeTeamParts = Arrays
+                        .asList(match.getHomeTeam().replaceAll(replaceParentecesRegEx, "").trim().split(" "));
+                List<String> awayTeamParts = Arrays
+                        .asList(match.getAwayTeam().replaceAll(replaceParentecesRegEx, "").trim().split(" "));
+
+                List<ArbResults> homeTeamFound = addedMatches.stream()
+                        .filter(p -> p.getHomeTeam().replaceAll(replaceParentecesRegEx, "")
+                                .trim().equals(match.getHomeTeam().replaceAll(replaceParentecesRegEx, "")
+                                        .trim()))
                         .toList();
 
-                List<ArbResults> awayTeamFound = list.getValue().stream()
-                        .filter(p -> Arrays.asList(p.getAwayTeam().replaceAll(replaceParentecesRegEx, "")
-                                .trim().split(" ")).stream().anyMatch(awayTeamParts::contains))
+                List<ArbResults> awayTeamFound = addedMatches.stream()
+                        .filter(p -> p.getAwayTeam().replaceAll(replaceParentecesRegEx, "")
+                                .trim().equals(match.getAwayTeam().replaceAll(replaceParentecesRegEx, "")
+                                        .trim()))
                         .toList();
 
                 if (homeTeamFound.isEmpty() || awayTeamFound.isEmpty()) {
-//                    System.out.println(match.getHomeTeam() + "-" + match.getAwayTeam() + " Not found in list");
-                    continue;
+                    addedMatches.add(new ArbResults(match.getHomeTeam(), match.getAwayTeam(), match.getOdds1(),
+                            match.getOddsX(), match.getOdds2(), list.getKey()));
+                } else if (homeTeamFound.size() == 1) {
+                    homeTeamFound.get(0).addOdds1(list.getKey(), match.getOdds1());
+                    homeTeamFound.get(0).addOddsX(list.getKey(), match.getOddsX());
+                    homeTeamFound.get(0).addOdds2(list.getKey(), match.getOdds2());
+
+                    homeTeamFound.get(0).addOver25Odds(list.getKey(), match.getOver25());
+                    homeTeamFound.get(0).addUnder25Odds(list.getKey(), match.getUnder25());
+                } else if (awayTeamFound.size() == 1) {
+                    awayTeamFound.get(0).addOdds1(list.getKey(), match.getOdds1());
+                    awayTeamFound.get(0).addOddsX(list.getKey(), match.getOddsX());
+                    awayTeamFound.get(0).addOdds2(list.getKey(), match.getOdds2());
+
+                    awayTeamFound.get(0).addOver25Odds(list.getKey(), match.getOver25());
+                    awayTeamFound.get(0).addUnder25Odds(list.getKey(), match.getUnder25());
+                } else if (homeTeamFound.size() > 1) {
+                    for (ArbResults htf : homeTeamFound) {
+                        System.out.println("Multiple found home " + htf);
+                    }
+                } else if (awayTeamFound.size() > 1) {
+                    for (ArbResults atf : awayTeamFound) {
+                        System.out.println("Multiple found away " + atf);
+                    }
                 }
+            }
+        }
 
-                if (homeTeamFound.size() == 1) {
-                    match.addOdds1(list.getKey(), homeTeamFound.get(0).getOdds1());
-                    match.addOddsX(list.getKey(), homeTeamFound.get(0).getOddsX());
-                    match.addOdds2(list.getKey(), homeTeamFound.get(0).getOdds2());
-                    System.out.println(
-                            "Found match mainlist " + match.toStringWithExtra() + " arb value "
-                                    + calculateArbValue3Part(match));
-                } else if (awayTeamFound.size() == 1) {
-                    match.addOdds1(list.getKey(), awayTeamFound.get(0).getOdds1());
-                    match.addOddsX(list.getKey(), awayTeamFound.get(0).getOddsX());
-                    match.addOdds2(list.getKey(), awayTeamFound.get(0).getOdds2());
-                    System.out.println(
-                            "Found match mainlist " + match.toStringWithExtra() + " arb value "
-                                    + calculateArbValue3Part(match));
+        List<ArbResults> GOGOList = new ArrayList<>();
+        for (ArbResults match : addedMatches) {
+            if (match.multipleOddsExist()) {
+                if (calculateArbValue3Part(match) < 1.0f
+                        || match.getArbValueOverUnder() > 0f && match.getArbValueOverUnder() < 1.0f) {
+                    GOGOList.add(match);
+                } else {
+                    System.out.println("Result " + match.toStringWithExtra() + " arb value "
+                            + calculateArbValue3Part(match) + " OverUnderVal " + match.getArbValueOverUnder());
                 }
             }
         }
+        for (ArbResults match : GOGOList) {
+            System.out.println("GOGOGOGOGOGO Result " + match.toStringWithExtra() + " arb value "
+                    + calculateArbValue3Part(match) + " Over Under arb value" + match.getArbValueOverUnder());
+        }
     }
 
     private float calculateArbValue3Part(ArbResults res) {
-        return (1 / res.getMaxOdds1().getOdds()) + (1 / res.getMaxOddsX().getOdds()) + (1 / res.getMaxOdds2().getOdds());
+        return (1 / res.getMaxOdds1().getOdds()) + (1 / res.getMaxOddsX().getOdds())
+                + (1 / res.getMaxOdds2().getOdds());
     }
 
     private void printResultsToArrayFile(List<ArbResults> results, String fileName) {
         try (BufferedWriter bw = new BufferedWriter(
-            new FileWriter(System.getProperty("user.dir") + File.separator + fileName))) {
+                new FileWriter(System.getProperty("user.dir") + File.separator + fileName))) {
             StringBuilder sb = new StringBuilder();
 
             for (ArbResults r : results) {
@@ -108,7 +159,6 @@ public class ArbChecker {
 
             bw.write(sb.toString());
         } catch (IOException e) {
-            // TODO Auto-generated catch block
             e.printStackTrace();
         }
     }
@@ -122,10 +172,11 @@ public class ArbChecker {
                 String[] values = line.split(",");
                 resultsList.add(new ArbResults(values[0], values[1], Float.parseFloat(values[2]),
                         Float.parseFloat(values[3]),
-                        Float.parseFloat(values[4]), bookie));
+                        Float.parseFloat(values[4]),
+                        Float.parseFloat(values[5]),
+                        Float.parseFloat(values[6]), bookie));
             }
         } catch (IOException e) {
-            // TODO Auto-generated catch block
             e.printStackTrace();
         }
     }

+ 261 - 193
Odds/src/mysql/Mysql.java

@@ -9,6 +9,7 @@ import java.sql.Statement;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
+import java.util.List;
 
 import org.eclipse.jetty.util.log.Log;
 
@@ -37,65 +38,154 @@ public class Mysql {
         return instance;
     }
 
-    protected Connection getConnection() {
-        if (conn == null) {
-            try {
-                conn = DriverManager.getConnection(URL + DATABASE + TIMEZONE_FIX, USERNAME, PASSWORD);
-            } catch (final SQLException e) {
-                throw new RuntimeException(e.getMessage(), e);
-            }
+    public int addCountry(String name) throws SQLException {
+        name = name.replace(" ", "-");
+        name = name.replace("\\.", "");
+        final String sql = "INSERT INTO Country (name) VALUES (?) ON DUPLICATE KEY UPDATE name = ?";
+        try (PreparedStatement stat = conn.prepareStatement(sql)) {
+            stat.setString(1, name);
+            stat.setString(2, name);
+            stat.executeUpdate();
         }
-        return conn;
+
+        return getId("Country", name, -1, -1);
     }
 
-    public CurrentParsing getCurrentParsing() {
-        final CurrentParsing returnValue = new CurrentParsing();
-        final String sql = "SELECT * FROM parsing";
-        try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            final ResultSet rs = stat.executeQuery();
-            while (rs.next()) {
-                returnValue.setDone(rs.getBoolean("done"));
-                returnValue.setCurrentYear(rs.getInt("year"));
-                returnValue.setCurrentDate(rs.getDate("gameDate"));
-                returnValue.setLeague(rs.getString("league"));
-                returnValue.setPage(rs.getInt("page"));
+    public int addLeague(String leagueName, String country, String sport) {
+        int countryId = -1;
+        try {
+            leagueName = leagueName.trim();
+            leagueName = leagueName.replace(" ", "-");
+            leagueName = leagueName.replace("\\.", "");
+            final int sportId = addSport(sport);
+            countryId = addCountry(country);
+            final String sql = "INSERT INTO League (name, sportId, countryId) VALUES (?, ?, ?) "
+                    + "ON DUPLICATE KEY UPDATE name = ?";
+            try (PreparedStatement stat = conn.prepareStatement(sql)) {
+                stat.setString(1, leagueName);
+                stat.setInt(2, sportId);
+                stat.setInt(3, countryId);
+                stat.setString(4, leagueName);
+
+                stat.executeUpdate();
             }
-        } catch (final SQLException e) {
+        } catch (SQLException e) {
             e.printStackTrace();
         }
-        return returnValue;
+        return getId("League", leagueName, countryId, -1);
     }
 
-    public int addLeague(String leagueName, String country, String sport) throws SQLException {
-        leagueName = leagueName.trim();
-        leagueName = leagueName.replace(" ", "-");
-        leagueName = leagueName.replace("\\.", "");
-        final int sportId = addSport(sport);
-        final int countryId = addCountry(country);
-        final String sql = "INSERT INTO League (name, sportId, countryId) VALUES (?, ?, ?) "
-                + "ON DUPLICATE KEY UPDATE name = ?";
-        try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setString(1, leagueName);
-            stat.setInt(2, sportId);
-            stat.setInt(3, countryId);
-            stat.setString(4, leagueName);
+    public void addResult(ResultDTO result) {
+        if (result.getCountryId() < 0 || result.getLeagueId() < 0) {
+            System.out.println(String.format("Must supply countryId %s and leagueId %s", result.getCountryId(),
+                    result.getLeagueId()));
+            return;
+        }
+        try {
+            int homeTeamId = getOrInsertTeam(result.getHomeTeam(), result.getCountryId(), result.getLeagueId(),
+                    result.getSportId());
+
+            final int awayTeamId = getOrInsertTeam(result.getAwayTeam(), result.getCountryId(), result.getLeagueId(),
+                    result.getSportId());
+
+            final String selectSql = "SELECT id FROM SoccerResults WHERE homeTeamId = ? AND awayTeamId = ? AND DATE(gameDate) = DATE(?)";
+            final ResultSet rs;
+            int gameId = -1;
+            final String date = result.getGameDate().format(DateTimeFormatter.ISO_DATE);
+            try (PreparedStatement stat = conn.prepareStatement(selectSql)) {
+                stat.setInt(1, homeTeamId);
+                stat.setInt(2, awayTeamId);
+                stat.setString(3, date);
 
-            stat.executeUpdate();
+                rs = stat.executeQuery();
+                while (rs.next()) {
+                    gameId = rs.getInt("id");
+                }
+            }
+
+            if (gameId != -1) {
+                final String sql = "UPDATE " + result.getTableName()
+                        + " SET homeScore = ?, awayScore = ?, overtime = ?, odds1 = ?, oddsX = ?, odds2 = ? "
+                        + "WHERE homeTeamId = ? AND awayTeamId = ? AND DATE(gameDate) = ?";
+
+                try (PreparedStatement stat = conn.prepareStatement(sql)) {
+                    stat.setInt(1, result.getHomeScore());
+                    stat.setInt(2, result.getAwayScore());
+                    stat.setBoolean(3, result.isOvertime());
+                    stat.setFloat(4, result.getOdds1());
+                    stat.setFloat(5, result.getOddsX());
+                    stat.setFloat(6, result.getOdds2());
+                    stat.setInt(7, homeTeamId);
+                    stat.setInt(8, awayTeamId);
+                    stat.setString(9, date);
+
+                    stat.executeUpdate();
+                }
+
+            } else {
+                final String sql = "INSERT INTO " + result.getTableName()
+                        + " (homeTeamId, awayTeamId, homeScore, awayScore, overtime, odds1, oddsX, odds2, countryId, gameDate, season, leagueId) "
+                        + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE homeScore = ?, awayScore = ?, odds1 = ?, oddsX = ?, odds2 = ?";
+                try (PreparedStatement stat = conn.prepareStatement(sql)) {
+                    stat.setInt(1, homeTeamId);
+                    stat.setInt(2, awayTeamId);
+                    stat.setInt(3, result.getHomeScore());
+                    stat.setInt(4, result.getAwayScore());
+                    stat.setBoolean(5, result.isOvertime());
+                    stat.setFloat(6, result.getOdds1());
+                    stat.setFloat(7, result.getOddsX());
+                    stat.setFloat(8, result.getOdds2());
+                    stat.setInt(9, result.getCountryId());
+                    stat.setString(10, result.getGameDate().toString());
+                    stat.setString(11, result.getSeason());
+                    stat.setInt(12, result.getLeagueId());
+                    stat.setInt(13, result.getHomeScore());
+                    stat.setInt(14, result.getAwayScore());
+                    stat.setFloat(15, result.getOdds1());
+                    stat.setFloat(16, result.getOddsX());
+                    stat.setFloat(17, result.getOdds2());
+
+                    stat.execute();
+                }
+            }
+        } catch (SQLException e) {
+            e.printStackTrace();
         }
-        return getId("League", leagueName, countryId, -1);
     }
 
-    public int addCountry(String name) throws SQLException {
-        name = name.replace(" ", "-");
-        name = name.replace("\\.", "");
-        final String sql = "INSERT INTO Country (name) VALUES (?) ON DUPLICATE KEY UPDATE name = ?";
+    public void addResults(List<ResultDTO> resultsToInsert) {
+
+        final String sql = "INSERT INTO SoccerResults (homeTeamId, awayTeamId, homeScore, awayScore, overtime, odds1, oddsX, odds2, countryId, gameDate, season, leagueId) "
+                + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE homeScore = ?, awayScore = ?, odds1 = ?, oddsX = ?, odds2 = ?";
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setString(1, name);
-            stat.setString(2, name);
-            stat.executeUpdate();
-        }
 
-        return getId("Country", name, -1, -1);
+            for (ResultDTO resultDTO : resultsToInsert) {
+
+                stat.setInt(1, resultDTO.getHomeTeamId());
+                stat.setInt(2, resultDTO.getAwayTeamId());
+                stat.setInt(3, resultDTO.getHomeScore());
+                stat.setInt(4, resultDTO.getAwayScore());
+                stat.setBoolean(5, resultDTO.isOvertime());
+                stat.setFloat(6, resultDTO.getOdds1());
+                stat.setFloat(7, resultDTO.getOddsX());
+                stat.setFloat(8, resultDTO.getOdds2());
+                stat.setInt(9, resultDTO.getCountryId());
+                stat.setString(10, resultDTO.getGameDate().toString());
+                stat.setString(11, resultDTO.getSeason());
+                stat.setInt(12, resultDTO.getLeagueId());
+                stat.setInt(13, resultDTO.getHomeScore());
+                stat.setInt(14, resultDTO.getAwayScore());
+                stat.setFloat(15, resultDTO.getOdds1());
+                stat.setFloat(16, resultDTO.getOddsX());
+                stat.setFloat(17, resultDTO.getOdds2());
+
+                stat.addBatch();
+            }
+
+            stat.executeBatch();
+        } catch (SQLException e) {
+            e.printStackTrace();
+        }
     }
 
     public int addSport(String sport) throws SQLException {
@@ -110,43 +200,13 @@ public class Mysql {
         return getId("Sport", sport, -1, -1);
     }
 
-    private int getId(String table, String name, int countryId, int leagueId) throws SQLException {
-        String sql = "SELECT id FROM " + table + " WHERE name = ?";
-        int id = -1;
-        if (countryId > -1) {
-            sql += " AND countryId = ?";
-        }
-        if (leagueId > -1) {
-            sql += " AND leagueId = ?";
-        }
-        try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setString(1, name.trim());
-            if (countryId > -1 && leagueId > -1) {
-                stat.setInt(2, countryId);
-                stat.setInt(3, leagueId);
-            } else if (countryId > -1) {
-                stat.setInt(2, countryId);
-            } else if (leagueId > -1) {
-                stat.setInt(2, leagueId);
-            }
-            final ResultSet insertRs = stat.executeQuery();
-            if (insertRs.next()) {
-                id = insertRs.getInt("id");
-            }
-        }
-        return id;
-    }
-
-    public int getLeagueId(int sportId, int countryId, String leagueName) {
-        final String sql = "SELECT id FROM League WHERE name = ? AND countryId = ? AND sportId = ?";
+    public int getCountryId(String country) {
+        final String sql = "SELECT id from Country WHERE name = ?";
         int id = -1;
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setString(1, leagueName.trim());
-            stat.setInt(2, countryId);
-            stat.setInt(3, sportId);
+            stat.setString(1, country.trim());
 
             final ResultSet rs = stat.executeQuery();
-
             while (rs.next()) {
                 id = rs.getInt("id");
             }
@@ -156,114 +216,113 @@ public class Mysql {
         return id;
     }
 
-    public int getSportId(String sportName) {
-        final String sql = "SELECT id from Sport WHERE name = ?";
-        int id = 0;
+    public CurrentParsing getCurrentParsing() {
+        final CurrentParsing returnValue = new CurrentParsing();
+        final String sql = "SELECT * FROM parsing";
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setString(1, sportName.trim());
-
             final ResultSet rs = stat.executeQuery();
             while (rs.next()) {
-                id = rs.getInt("id");
+                returnValue.setDone(rs.getBoolean("done"));
+                returnValue.setCurrentYear(rs.getInt("year"));
+                returnValue.setCurrentDate(rs.getDate("gameDate"));
+                returnValue.setLeague(rs.getString("league"));
+                returnValue.setPage(rs.getInt("page"));
             }
         } catch (final SQLException e) {
             e.printStackTrace();
         }
-        return id;
+        return returnValue;
     }
 
-    public int getCountryId(String country) throws SQLException {
-        final String sql = "SELECT id from Country WHERE name = ?";
-        int id = -1;
+    public Connection getDbConnection() {
+        if (conn == null) {
+            conn = getConnection();
+        }
+        return conn;
+    }
+
+    public String getLastParsedYear(String leagueName, int countryId) {
+        String returnValue = "";
+
+        final String sql = "SELECT parsedYear FROM League WHERE name = ? AND countryId = ?";
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setString(1, country.trim());
+            stat.setString(1, leagueName);
+            stat.setInt(2, countryId);
 
             final ResultSet rs = stat.executeQuery();
+
             while (rs.next()) {
-                id = rs.getInt("id");
+                returnValue = rs.getString("parsedYear");
             }
+        } catch (final SQLException e) {
+            e.printStackTrace();
         }
-        return id;
+
+        return returnValue;
     }
 
-    public void addResult(ResultDTO result) throws SQLException {
-//		String tableName, LocalDateTime gameDate, String homeTeam, String awayTeam, int homeScore,
-//			int awayScore, boolean overtime, float odds1, float oddsX, float odds2, int countryId, String season,
-//			int leagueId, int sportId) throws SQLException {
+    public String getLastSeason(int leagueId, int countryId) {
+        String result = "";
+        String sql = "SELECT season FROM SoccerResults WHERE leagueId = ? AND countryId = ? ORDER BY gameDate DESC limit 1";
+
+        try (PreparedStatement stat = getConnection().prepareStatement(sql)) {
+            stat.setInt(1, leagueId);
+            stat.setInt(2, countryId);
+
+            ResultSet rs = stat.executeQuery();
 
-        if (result.getCountryId() < 0 || result.getLeagueId() < 0) {
-            System.out.println(String.format("Must supply countryId %s and leagueId %s", result.getCountryId(),
-                    result.getLeagueId()));
-            return;
-        }
-        final int homeTeamId = getOrInsertTeam(result.getHomeTeam(), result.getCountryId(), result.getLeagueId(),
-                result.getSportId());
-        final int awayTeamId = getOrInsertTeam(result.getAwayTeam(), result.getCountryId(), result.getLeagueId(),
-                result.getSportId());
-
-        final String selectSql = "SELECT id FROM SoccerResults WHERE homeTeamId = ? AND awayTeamId = ? AND DATE(gameDate) = DATE(?)";
-        final ResultSet rs;
-        int gameId = -1;
-        final String date = result.getGameDate().format(DateTimeFormatter.ISO_DATE);
-        try (PreparedStatement stat = conn.prepareStatement(selectSql)) {
-            stat.setInt(1, homeTeamId);
-            stat.setInt(2, awayTeamId);
-            stat.setString(3, date);
-
-            rs = stat.executeQuery();
             while (rs.next()) {
-                gameId = rs.getInt("id");
+                result = rs.getString("season");
             }
+        } catch (SQLException e) {
+            e.printStackTrace();
         }
 
-        if (gameId != -1) {
-            final String sql = "UPDATE " + result.getTableName()
-                    + " SET homeScore = ?, awayScore = ?, overtime = ?, odds1 = ?, oddsX = ?, odds2 = ? "
-                    + "WHERE homeTeamId = ? AND awayTeamId = ? AND DATE(gameDate) = ?";
+        return result;
+    }
 
-            try (PreparedStatement stat = conn.prepareStatement(sql)) {
-                stat.setInt(1, result.getHomeScore());
-                stat.setInt(2, result.getAwayScore());
-                stat.setBoolean(3, result.isOvertime());
-                stat.setFloat(4, result.getOdds1());
-                stat.setFloat(5, result.getOddsX());
-                stat.setFloat(6, result.getOdds2());
-                stat.setInt(7, homeTeamId);
-                stat.setInt(8, awayTeamId);
-                stat.setString(9, date);
+    public String getLastSeason(String leagueName, int countryId) {
+        String sql = "SELECT season FROM SoccerResults WHERE leagueId = (SELECT id FROM League WHERE name = ? AND countryId = ?) ORDER BY gameDate DESC limit 1";
+        String result = null;
+        try (PreparedStatement stat = conn.prepareStatement(sql)) {
+            stat.setString(1, leagueName);
+            stat.setInt(2, countryId);
 
-                stat.executeUpdate();
+            ResultSet rs = stat.executeQuery();
+
+            while (rs.next()) {
+                result = rs.getString("season");
             }
+        } catch (SQLException e) {
+            e.printStackTrace();
+        }
 
-        } else {
-            final String sql = "INSERT INTO " + result.getTableName()
-                    + " (homeTeamId, awayTeamId, homeScore, awayScore, overtime, odds1, oddsX, odds2, countryId, gameDate, season, leagueId) "
-                    + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE homeScore = ?, awayScore = ?, odds1 = ?, oddsX = ?, odds2 = ?";
-            try (PreparedStatement stat = conn.prepareStatement(sql)) {
-                stat.setInt(1, homeTeamId);
-                stat.setInt(2, awayTeamId);
-                stat.setInt(3, result.getHomeScore());
-                stat.setInt(4, result.getAwayScore());
-                stat.setBoolean(5, result.isOvertime());
-                stat.setFloat(6, result.getOdds1());
-                stat.setFloat(7, result.getOddsX());
-                stat.setFloat(8, result.getOdds2());
-                stat.setInt(9, result.getCountryId());
-                stat.setString(10, result.getGameDate().toString());
-                stat.setString(11, result.getSeason());
-                stat.setInt(12, result.getLeagueId());
-                stat.setInt(13, result.getHomeScore());
-                stat.setInt(14, result.getAwayScore());
-                stat.setFloat(15, result.getOdds1());
-                stat.setFloat(16, result.getOddsX());
-                stat.setFloat(17, result.getOdds2());
-
-                stat.execute();
+        if (Strings.isNullOrEmpty(result)) {
+            result = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy"));
+        }
+        return result;
+    }
+
+    public int getLeagueId(int sportId, int countryId, String leagueName) {
+        final String sql = "SELECT id FROM League WHERE name = ? AND countryId = ? AND sportId = ?";
+        int id = -1;
+        try (PreparedStatement stat = conn.prepareStatement(sql)) {
+            stat.setString(1, leagueName.trim());
+            stat.setInt(2, countryId);
+            stat.setInt(3, sportId);
+
+            final ResultSet rs = stat.executeQuery();
+
+            while (rs.next()) {
+                id = rs.getInt("id");
             }
+        } catch (SQLException e) {
+            e.printStackTrace();
         }
+        return id;
     }
 
-    private int getOrInsertTeam(String teamName, int countryId, int leagueId, int sportId) throws SQLException {
+    public int getOrInsertTeam(String teamName, int countryId, int leagueId, int sportId) {
         teamName = teamName.replace('\u00A0', ' ').trim();
         int teamId;
         if (leagueId > 0) {
@@ -281,6 +340,8 @@ public class Mysql {
                     final ResultSet generatedKeys = stat.getGeneratedKeys();
                     generatedKeys.next();
                     teamId = generatedKeys.getInt(1);
+                } catch (SQLException e) {
+                    e.printStackTrace();
                 }
             }
         } else {
@@ -291,6 +352,22 @@ public class Mysql {
         return teamId;
     }
 
+    public int getSportId(String sportName) {
+        final String sql = "SELECT id from Sport WHERE name = ?";
+        int id = 0;
+        try (PreparedStatement stat = conn.prepareStatement(sql)) {
+            stat.setString(1, sportName.trim());
+
+            final ResultSet rs = stat.executeQuery();
+            while (rs.next()) {
+                id = rs.getInt("id");
+            }
+        } catch (final SQLException e) {
+            e.printStackTrace();
+        }
+        return id;
+    }
+
     public void setParsingForLeague(int leagueId, int sportId, int countryId, LocalDateTime gameDate,
             int currentParsePage, String parsedYear) {
         final String sql = "UPDATE League SET parsedYear = ?, parsedPage = ?, lastParsedGameDate = ? WHERE sportId = ? AND countryId = ? AND id = ?";
@@ -311,52 +388,43 @@ public class Mysql {
         }
     }
 
-    public String getLastParsedYear(String leagueName, int countryId) {
-        String returnValue = "";
-
-        final String sql = "SELECT parsedYear FROM League WHERE name = ? AND countryId = ?";
-        try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setString(1, leagueName);
-            stat.setInt(2, countryId);
-
-            final ResultSet rs = stat.executeQuery();
-
-            while (rs.next()) {
-                returnValue = rs.getString("parsedYear");
-            }
-        } catch (final SQLException e) {
-            e.printStackTrace();
-        }
-
-        return returnValue;
-    }
-
-    public Connection getDbConnection() {
+    protected Connection getConnection() {
         if (conn == null) {
-            conn = getConnection();
+            try {
+                conn = DriverManager.getConnection(URL + DATABASE + TIMEZONE_FIX, USERNAME, PASSWORD);
+            } catch (final SQLException e) {
+                throw new RuntimeException(e.getMessage(), e);
+            }
         }
         return conn;
     }
 
-    public String getLastSeason(String leagueName, int countryId) {
-        String sql = "SELECT season FROM SoccerResults WHERE leagueId = (SELECT id FROM League WHERE name = ? AND countryId = ?) ORDER BY gameDate DESC limit 1";
-        String result = null;
+    private int getId(String table, String name, int countryId, int leagueId) {
+        String sql = "SELECT id FROM " + table + " WHERE name = ?";
+        int id = -1;
+        if (countryId > -1) {
+            sql += " AND countryId = ?";
+        }
+        if (leagueId > -1) {
+            sql += " AND leagueId = ?";
+        }
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setString(1, leagueName);
-            stat.setInt(2, countryId);
-
-            ResultSet rs = stat.executeQuery();
-
-            while (rs.next()) {
-                result = rs.getString("season");
+            stat.setString(1, name.trim());
+            if (countryId > -1 && leagueId > -1) {
+                stat.setInt(2, countryId);
+                stat.setInt(3, leagueId);
+            } else if (countryId > -1) {
+                stat.setInt(2, countryId);
+            } else if (leagueId > -1) {
+                stat.setInt(2, leagueId);
+            }
+            final ResultSet insertRs = stat.executeQuery();
+            if (insertRs.next()) {
+                id = insertRs.getInt("id");
             }
         } catch (SQLException e) {
             e.printStackTrace();
         }
-
-        if (Strings.isNullOrEmpty(result)) {
-            result = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy"));
-        }
-        return result;
+        return id;
     }
 }

+ 72 - 17
Odds/src/object/ArbResults.java

@@ -11,6 +11,12 @@ public class ArbResults extends ResultDTO {
     List<Odds> oddsXList = new ArrayList<>();
     List<Odds> odds2List = new ArrayList<>();
 
+    List<Odds> over25List = new ArrayList<>();
+    List<Odds> under25List = new ArrayList<>();
+
+    Odds over25;
+    Odds under25;
+
     String bookie;
 
     public ArbResults(String homeTeamName, String awayTeamName, float odds1, float oddsX, float odds2, String bookie) {
@@ -23,7 +29,22 @@ public class ArbResults extends ResultDTO {
     }
 
     public ArbResults(ResultDTO m, String bookie) {
-        this(m.homeTeam, m.awayTeam, m.odds1, m.oddsX, m.odds2, bookie);
+        this(m.homeTeam, m.awayTeam, m.odds1, m.oddsX, m.odds2, m.getOddsOver25goals(), m.getOddsUnder25goals(),
+                bookie);
+    }
+
+    public ArbResults(String homeTeamName, String awayTeamName, float odds1, float oddsX, float odds2,
+            float over25, float under25, String bookie) {
+        this(homeTeamName, awayTeamName, odds1, oddsX, odds2, bookie);
+        this.over25 = new Odds(bookie, over25);
+        this.under25 = new Odds(bookie, under25);
+
+        over25List.add(this.over25);
+        under25List.add(this.under25);
+
+        this.oddsOver25goals = over25;
+        this.oddsUnder25goals = under25;
+
     }
 
     public void addOdds1(String bookie, float value) {
@@ -42,21 +63,27 @@ public class ArbResults extends ResultDTO {
         Float val = Collections.max(odds1List.stream().map(m -> m.odds).toList());
         Optional<Odds> o = odds1List.stream().filter(p -> p.odds == val).findFirst();
 
-        return o.isPresent()?o.get():null;
+        return o.isPresent() ? o.get() : null;
     }
 
     public Odds getMaxOddsX() {
         Float val = Collections.max(oddsXList.stream().map(m -> m.odds).toList());
         Optional<Odds> o = oddsXList.stream().filter(p -> p.odds == val).findFirst();
 
-        return o.isPresent()?o.get():null;
+        return o.isPresent() ? o.get() : null;
     }
 
     public Odds getMaxOdds2() {
         Float val = Collections.max(odds2List.stream().map(m -> m.odds).toList());
         Optional<Odds> o = odds2List.stream().filter(p -> p.odds == val).findFirst();
 
-        return o.isPresent()?o.get():null;
+        return o.isPresent() ? o.get() : null;
+    }
+
+    public boolean multipleOddsExist() {
+        return ((odds1List.size() > 1 || oddsXList.size() > 1 || odds2List.size() > 1)
+                && (!getMaxOdds1().bookie.equals(getMaxOdds2().bookie)
+                        || !getMaxOdds1().bookie.equals(getMaxOddsX().bookie)));
     }
 
     public String toStringWithExtra() {
@@ -65,22 +92,50 @@ public class ArbResults extends ResultDTO {
         return string;
     }
 
-    public class Odds {
-        String bookie;
-        float odds;
+    public float getOver25() {
+        return this.oddsOver25goals;
+    }
+
+    public float getUnder25() {
+        return this.oddsUnder25goals;
+    }
+
+    public void setOver25(Odds over25) {
+        this.over25 = over25;
+    }
 
-        public Odds(String bookie, float odds) {
-            this.bookie = bookie;
-            this.odds = odds;
-        }
+    public void setUnder25(Odds under25) {
+        this.under25 = under25;
+    }
 
-        public float getOdds() {return odds;}
+    public void addOver25Odds(String bookie, float odds) {
+        this.over25List.add(new Odds(bookie, odds));
+    }
 
-        public String getBookie() {return bookie;}
+    public void addUnder25Odds(String bookie, float odds) {
+        this.under25List.add(new Odds(bookie, odds));
+    }
 
-        @Override
-        public String toString() {
-            return "(" + bookie + ") " + odds;
-        }
+    public Odds getMaxOver25() {
+        Float val = Collections.max(over25List.stream().map(m -> m.odds).toList());
+        Optional<Odds> o = over25List.stream().filter(p -> p.odds == val).findFirst();
+
+        return o.isPresent() ? o.get() : null;
     }
+
+    public Odds getMaxUnder25() {
+        Float val = Collections.max(under25List.stream().map(m -> m.odds).toList());
+        Optional<Odds> o = under25List.stream().filter(p -> p.odds == val).findFirst();
+
+        return o.isPresent() ? o.get() : null;
+    }
+
+    public float getArbValueOverUnder() {
+
+        Odds maxOver25 = getMaxOver25();
+        Odds maxUnder25 = getMaxUnder25();
+
+        return (1 / maxOver25.odds) + (1 / maxUnder25.odds);
+    }
+
 }

+ 24 - 0
Odds/src/object/Odds.java

@@ -0,0 +1,24 @@
+package object;
+
+public class Odds {
+    String bookie;
+    float odds;
+
+    public Odds(String bookie, float odds) {
+        this.bookie = bookie;
+        this.odds = odds;
+    }
+
+    public float getOdds() {
+        return odds;
+    }
+
+    public String getBookie() {
+        return bookie;
+    }
+
+    @Override
+    public String toString() {
+        return "(" + bookie + ") " + odds;
+    }
+}

+ 119 - 50
Odds/src/object/ResultDTO.java

@@ -14,13 +14,42 @@ public class ResultDTO {
     float odds1;
     float oddsX;
     float odds2;
+    float oddsOver25goals;
+    float oddsUnder25goals;
     int countryId;
     String season;
     int leagueId;
     int sportId;
+    private int homeTeamId;
+    private int awayTeamId;
 
     public ResultDTO() {
-    };
+    }
+
+    public ResultDTO(String tableName) {
+        super();
+        this.tableName = tableName;
+    }
+
+    public ResultDTO(String tableName, LocalDateTime gameDate, int homeTeamId, int awayTeamId, int homeScore,
+            int awayScore, boolean overtime, float odds1, float oddsX, float odds2, int countryId, String season,
+            int leagueId, int sportId) {
+        super();
+        this.tableName = tableName;
+        this.gameDate = gameDate;
+        this.homeTeamId = homeTeamId;
+        this.awayTeamId = awayTeamId;
+        this.homeScore = homeScore;
+        this.awayScore = awayScore;
+        this.overtime = overtime;
+        this.odds1 = odds1;
+        this.oddsX = oddsX;
+        this.odds2 = odds2;
+        this.countryId = countryId;
+        this.season = season;
+        this.leagueId = leagueId;
+        this.sportId = sportId;
+    }
 
     public ResultDTO(String tableName, LocalDateTime gameDate, String homeTeam, String awayTeam, int homeScore,
             int awayScore, boolean overtime, float odds1, float oddsX, float odds2, int countryId, String season,
@@ -50,120 +79,160 @@ public class ResultDTO {
         this.odds2 = odds2;
     }
 
-    public String getTableName() {
-        return tableName;
+    public ResultDTO(String homeTeamName, String awayTeamName, float odds1, float oddsX, float odds2,
+            float oddsOver25, float oddsUnder25) {
+        this(homeTeamName, awayTeamName, odds1, oddsX, odds2);
+        this.oddsOver25goals = oddsOver25;
+        this.oddsUnder25goals = oddsUnder25;
     }
 
-    public void setTableName(String tableName) {
-        this.tableName = tableName;
+    public int getAwayScore() {
+        return awayScore;
+    }
+
+    public String getAwayTeam() {
+        return awayTeam;
+    }
+
+    public int getAwayTeamId() {
+        return awayTeamId;
+    }
+
+    public int getCountryId() {
+        return countryId;
     }
 
     public LocalDateTime getGameDate() {
         return gameDate;
     }
 
-    public void setGameDate(LocalDateTime gameDate) {
-        this.gameDate = gameDate;
+    public int getHomeScore() {
+        return homeScore;
     }
 
     public String getHomeTeam() {
         return homeTeam;
     }
 
-    public void setHomeTeam(String homeTeam) {
-        this.homeTeam = homeTeam;
+    public int getHomeTeamId() {
+        return homeTeamId;
     }
 
-    public String getAwayTeam() {
-        return awayTeam;
+    public int getLeagueId() {
+        return leagueId;
     }
 
-    public void setAwayTeam(String awayTeam) {
-        this.awayTeam = awayTeam;
+    public float getOdds1() {
+        return odds1;
     }
 
-    public int getHomeScore() {
-        return homeScore;
+    public float getOdds2() {
+        return odds2;
     }
 
-    public void setHomeScore(int homeScore) {
-        this.homeScore = homeScore;
+    public float getOddsOver25goals() {
+        return oddsOver25goals;
     }
 
-    public int getAwayScore() {
-        return awayScore;
+    public float getOddsUnder25goals() {
+        return oddsUnder25goals;
     }
 
-    public void setAwayScore(int awayScore) {
-        this.awayScore = awayScore;
+    public float getOddsX() {
+        return oddsX;
+    }
+
+    public String getSeason() {
+        return season;
+    }
+
+    public int getSportId() {
+        return sportId;
+    }
+
+    public String getTableName() {
+        return tableName;
     }
 
     public boolean isOvertime() {
         return overtime;
     }
 
-    public void setOvertime(boolean overtime) {
-        this.overtime = overtime;
+    public void setAwayScore(int awayScore) {
+        this.awayScore = awayScore;
     }
 
-    public float getOdds1() {
-        return odds1;
+    public void setAwayTeam(String awayTeam) {
+        this.awayTeam = awayTeam;
     }
 
-    public void setOdds1(float odds1) {
-        this.odds1 = odds1;
+    public void setAwayTeamId(int awayTeamId) {
+        this.awayTeamId = awayTeamId;
     }
 
-    public float getOddsX() {
-        return oddsX;
+    public void setCountryId(int countryId) {
+        this.countryId = countryId;
     }
 
-    public void setOddsX(float oddsX) {
-        this.oddsX = oddsX;
+    public void setGameDate(LocalDateTime gameDate) {
+        this.gameDate = gameDate;
     }
 
-    public float getOdds2() {
-        return odds2;
+    public void setHomeScore(int homeScore) {
+        this.homeScore = homeScore;
     }
 
-    public void setOdds2(float odds2) {
-        this.odds2 = odds2;
+    public void setHomeTeam(String homeTeam) {
+        this.homeTeam = homeTeam;
     }
 
-    public int getCountryId() {
-        return countryId;
+    public void setHomeTeamId(int homeTeamId) {
+        this.homeTeamId = homeTeamId;
     }
 
-    public void setCountryId(int countryId) {
-        this.countryId = countryId;
+    public void setLeagueId(int leagueId) {
+        this.leagueId = leagueId;
     }
 
-    public String getSeason() {
-        return season;
+    public void setOdds1(float odds1) {
+        this.odds1 = odds1;
     }
 
-    public void setSeason(String season) {
-        this.season = season;
+    public void setOdds2(float odds2) {
+        this.odds2 = odds2;
     }
 
-    public int getLeagueId() {
-        return leagueId;
+    public void setOddsOver25goals(float oddsOver25goals) {
+        this.oddsOver25goals = oddsOver25goals;
     }
 
-    public void setLeagueId(int leagueId) {
-        this.leagueId = leagueId;
+    public void setOddsUnder25goals(float oddsUnder25goals) {
+        this.oddsUnder25goals = oddsUnder25goals;
     }
 
-    public int getSportId() {
-        return sportId;
+    public void setOddsX(float oddsX) {
+        this.oddsX = oddsX;
+    }
+
+    public void setOvertime(boolean overtime) {
+        this.overtime = overtime;
+    }
+
+    public void setSeason(String season) {
+        this.season = season;
     }
 
     public void setSportId(int sportId) {
         this.sportId = sportId;
     }
 
+    public void setTableName(String tableName) {
+        this.tableName = tableName;
+    }
+
     @Override
     public String toString() {
-        return homeTeam + "," + awayTeam + "," + odds1 + "," + oddsX + "," + odds2;
+        return homeTeam + "," + awayTeam + "," + odds1 + "," + oddsX + "," + odds2 + "," + oddsOver25goals + ","
+                + oddsUnder25goals;
     }
 }

+ 101 - 0
Odds/src/parser/BWinParser.java

@@ -0,0 +1,101 @@
+package parser;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.chrome.ChromeDriver;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+import object.ArbResults;
+import object.Odds;
+import object.ResultDTO;
+
+public class BWinParser extends ParserBase {
+
+    public static final String BOOKIE = "BWin";
+    String url = "https://sports.bwin.se/sv/sports/fotboll-4/idag";
+    String url2 = "https://sports.bwin.se/sv/sports/fotboll-4/imorgon";
+
+    public List<ResultDTO> parseSoccerMatches() {
+        List<ResultDTO> result = new ArrayList<>();
+
+        ChromeDriver driver = getSeleniumDriver();
+        WebDriverWait wait = getWaitDriver(driver);
+
+        parsePage(result, driver, wait, url);
+        parsePage(result, driver, wait, url2);
+
+        driver.close();
+        return result;
+    }
+
+    private void parsePage(List<ResultDTO> result, ChromeDriver driver, WebDriverWait wait, String url) {
+        driver.get(url);
+        wait.until(ExpectedConditions.numberOfElementsToBeMoreThan(By.xpath("//div[@class='calendar-event-info']"), 0));
+
+        List<WebElement> matchDivs = driver.findElements(By.xpath("//div[@class='calendar-event-info']"));
+
+        for (WebElement matchDiv : matchDivs) {
+            List<WebElement> participants = matchDiv.findElements(By.xpath(".//div[@class='participant']"));
+            if (participants.size() != 2) {
+                System.out.println("Not correct number of participants " + participants.size()
+                        + (participants.size() > 0 ? " first is " + participants.get(0).getText() : ""));
+                continue;
+            }
+            String homeTeam = participants.get(0).getText();
+            String awayTeam = participants.get(1).getText();
+
+            List<Odds> matchOdds = getMatchOdds(matchDiv);
+            List<Odds> overUnderOdds = getOverUnderOdds(matchDiv);
+
+            if (matchOdds.size() == 3 && overUnderOdds.size() == 2) {
+                result.add(new ArbResults(homeTeam, awayTeam, matchOdds.get(0).getOdds(), matchOdds.get(1).getOdds(),
+                        matchOdds.get(2).getOdds(),
+                        overUnderOdds.get(0).getOdds(), overUnderOdds.get(1).getOdds(), BOOKIE));
+                System.out.println("Added " + result.get(result.size() - 1) + " with 2.5 over under");
+            } else if (matchOdds.size() == 3 && overUnderOdds.size() != 2) {
+                result.add(new ArbResults(homeTeam, awayTeam, matchOdds.get(0).getOdds(), matchOdds.get(1).getOdds(),
+                        matchOdds.get(2).getOdds(), BOOKIE));
+                System.out.println("Added " + result.get(result.size() - 1) + " WITHOUT 2.5 over under");
+            } else {
+                System.out.println("Results not added for matchDiv " + matchDiv.toString());
+            }
+        }
+    }
+
+    private List<Odds> getMatchOdds(WebElement matchDiv) {
+        List<Odds> result = new ArrayList<>();
+        if (checkIfElementExists(matchDiv, ".//ms-option-group[1]")) {
+            WebElement oddsContainer = matchDiv.findElement(By.xpath(".//ms-option-group[1]"));
+
+            List<WebElement> odds = oddsContainer.findElements(By.xpath(".//ms-font-resizer"));
+
+            if (odds.size() == 3) {
+                result.add(new Odds(BOOKIE, formatFloat(odds.get(0).getText())));
+                result.add(new Odds(BOOKIE, formatFloat(odds.get(1).getText())));
+                result.add(new Odds(BOOKIE, formatFloat(odds.get(2).getText())));
+            }
+        }
+        return result;
+    }
+
+    private List<Odds> getOverUnderOdds(WebElement matchDiv) {
+        List<Odds> result = new ArrayList<>();
+        if (checkIfElementExists(matchDiv, ".//ms-option-group[2]")) {
+            WebElement oddsContainer = matchDiv.findElement(By.xpath(".//ms-option-group[2]"));
+
+            List<WebElement> odds = oddsContainer.findElements(By.xpath(".//ms-font-resizer"));
+
+            if (odds.size() == 3) {
+                if (formatFloat(odds.get(0).getText().replace(",", ".")) == 2.5f) {
+                    result.add(new Odds(BOOKIE, formatFloat(odds.get(1).getText())));
+                    result.add(new Odds(BOOKIE, formatFloat(odds.get(2).getText())));
+                }
+            }
+        }
+        return result;
+    }
+}

+ 136 - 0
Odds/src/parser/BetHard.java

@@ -0,0 +1,136 @@
+package parser;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.chrome.ChromeDriver;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+import object.ResultDTO;
+
+public class BetHard extends ParserBase {
+
+    private boolean tomorrowParsed;
+
+    public BetHard() {
+    }
+
+    public List<ResultDTO> seleniumParseMatches() {
+        List<ResultDTO> result = new ArrayList<>();
+
+        String url = "https://se-sports.bethard.com/sports/?langid=722&stoken=logout";
+        ChromeDriver driver = getSeleniumDriver();
+
+        WebDriverWait wait = getWaitDriver(driver);
+
+        driver.get(url);
+
+        wait.until(
+                ExpectedConditions.numberOfElementsToBeMoreThan(
+                        By.xpath("//div[contains(@class,'sports-list-item-text')]"),
+                        0));
+
+        WebElement fotballSideMenu = driver
+                .findElement(By.xpath("//div[@data-uat='sports-list-item-text-name' and text()='Fotboll']/.."));
+
+        wait.until(ExpectedConditions.elementToBeClickable(
+                By.xpath("//div[@data-uat='sports-list-item-text-name' and text()='Fotboll']/..")));
+
+        fotballSideMenu.click();
+
+        wait.until(ExpectedConditions.elementToBeClickable(
+                By.xpath("//span[@data-uat='tab-switch-btn-text' and text()='Daglig matchlista']/../..")));
+        WebElement dagligLista = driver
+                .findElement(By.xpath("//span[@data-uat='tab-switch-btn-text' and text()='Daglig matchlista']/../.."));
+
+        dagligLista.click();
+
+        wait.until(
+                ExpectedConditions.numberOfElementsToBeMoreThan(By.xpath("//div[@class='rj-instant-collapsible']"), 0));
+
+        parseMatches(driver, wait, result);
+
+        driver.close();
+        return result;
+    }
+
+    private void parseMatches(ChromeDriver driver, WebDriverWait wait, List<ResultDTO> result) {
+        List<WebElement> expandableDivs = driver
+                .findElements(By.xpath("//div[@class='rj-instant-collapsible']"));
+
+        List<WebElement> handledDiv = new ArrayList<>();
+        while (true) {
+            WebElement webElement = expandableDivs.get(0);
+            scrollElementIntoViewCenter(driver, webElement);
+            if (webElement.getAttribute("data-collapsed").equals(Boolean.TRUE.toString())) {
+                int matchDivsBefore = driver.findElements(By.xpath("//div[@class='rj-ev-list__ev-card__inner']"))
+                        .size();
+                webElement.click();
+                wait.until(ExpectedConditions.numberOfElementsToBeMoreThan(
+                        By.xpath("//div[@class='rj-ev-list__ev-card__inner']"), matchDivsBefore - 1));
+            }
+            List<WebElement> matchDiv = webElement
+                    .findElements(By.xpath(".//div[@class='rj-ev-list__ev-card__inner']"));
+            for (WebElement match : matchDiv) {
+                parseMatch(match, result);
+            }
+
+            handledDiv.add(webElement);
+            expandableDivs.remove(webElement);
+            expandableDivs = driver
+                    .findElements(By.xpath("//div[@class='rj-instant-collapsible']"));
+
+            expandableDivs.removeAll(handledDiv);
+
+            if (expandableDivs.size() <= 0) {
+                break;
+            }
+        }
+        if (!tomorrowParsed) {
+            tomorrowParsed = true;
+            try {
+                scrollToTopOfPage(driver);
+                Thread.sleep(200);
+                WebElement tomorrowHeader = driver.findElement(By.xpath("//div[text()='Imorgon']//../.."));
+
+                tomorrowHeader.click();
+                wait.until(
+                        ExpectedConditions.numberOfElementsToBeMoreThan(
+                                By.xpath("//div[@class='rj-instant-collapsible']"),
+                                0));
+                Thread.sleep(200);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+            parseMatches(driver, wait, result);
+        }
+    }
+
+    private void parseMatch(WebElement match, List<ResultDTO> result) {
+        WebElement participants = match.findElement(By.xpath(".//a/div[contains(@class,'name')]"));
+
+        WebElement homeTeamSpan = participants.findElement(By.xpath(".//div[1]/span"));
+        WebElement awayTeamSpan = participants.findElement(By.xpath(".//div[2]/span"));
+
+        String homeTeamName = homeTeamSpan.getText();
+        String awayTeamName = awayTeamSpan.getText();
+
+        if (!checkIfElementExists(match, ".//button[1]//div[2]/span") || // no odds for this game
+                !checkIfElementExists(match, ".//button[2]//div[2]/span") ||
+                !checkIfElementExists(match, ".//button[3]//div[2]/span")) {
+            return;
+        }
+        WebElement odds1Span = match.findElement(By.xpath(".//button[1]//div[2]/span"));
+        WebElement oddsXSpan = match.findElement(By.xpath(".//button[2]//div[2]/span"));
+        WebElement odds2Span = match.findElement(By.xpath(".//button[3]//div[2]/span"));
+
+        float odds1 = formatFloat(odds1Span.getText());
+        float oddsX = formatFloat(oddsXSpan.getText());
+        float odds2 = formatFloat(odds2Span.getText());
+
+        result.add(new ResultDTO(homeTeamName, awayTeamName, odds1, oddsX, odds2));
+    }
+}

+ 59 - 24
Odds/src/parser/BetSafeParser.java

@@ -21,7 +21,8 @@ public class BetSafeParser extends ParserBase {
 
     List<ResultDTO> result = new ArrayList<>();
 
-    public BetSafeParser() {}
+    public BetSafeParser() {
+    }
 
     public List<ResultDTO> seleniumPaseSoccerMatches() {
         String url = "https://www.betsafe.com/sv/odds/fotboll";
@@ -46,6 +47,8 @@ public class BetSafeParser extends ParserBase {
         // Behöver också kolla om det finns mer att ladda obg-show-more-less-button
         // ng-star-inserted
         // Kontrollera att det inte står "Show less" då den minimerar igen
+
+        List<WebElement> handledDivs = new ArrayList<>();
         for (WebElement element : expandableDivs) {
             try {
                 String xpath = ".//span[text()='Live']";
@@ -60,6 +63,7 @@ public class BetSafeParser extends ParserBase {
 
                 xpath = ".//span[text()='Kommande idag']";
                 if (checkIfElementExists(element, xpath)) {
+                    scrollElementIntoViewCenter(driver, element);
                     element.click();
                     wait.until(ExpectedConditions.numberOfElementsToBeMoreThan(By.xpath(
                             "//div[contains(@class,'obg-event-row-event-container')]"), matchDivs.size()));
@@ -71,7 +75,9 @@ public class BetSafeParser extends ParserBase {
                 }
 
                 xpath = ".//span[text()='Imorgon']";
+                Thread.sleep(200);
                 if (checkIfElementExists(element, xpath)) {
+                    scrollElementIntoViewCenter(driver, element);
                     element.click();
                     wait.until(ExpectedConditions.numberOfElementsToBeMoreThan(By.xpath(
                             "//div[contains(@class,'obg-event-row-event-container')]"), matchDivs.size()));
@@ -81,9 +87,16 @@ public class BetSafeParser extends ParserBase {
                     scrollElementIntoView(driver, element);
                 }
 
-            } catch (ElementNotFoundException e) {
+            } catch (ElementNotFoundException | InterruptedException e) {
                 // Empty by design, no more matches today
             }
+
+            List<WebElement> newDivs = matchDivs.stream().filter(p -> !handledDivs.contains(p)).toList();
+
+            for (WebElement match : newDivs) {
+                parseMatch(driver, match);
+                handledDivs.add(match);
+            }
         }
 
         expandAllMatches(driver, wait, matchDivs);
@@ -92,10 +105,13 @@ public class BetSafeParser extends ParserBase {
                 .findElements(By.xpath("//div[contains(@class,'obg-event-row-event-container')]"));
 
         js.executeScript("window.stop;");
-        for (WebElement match : matchDivs) {
+        List<WebElement> newDivs = matchDivs.stream().filter(p -> !handledDivs.contains(p)).toList();
+
+        for (WebElement match : newDivs) {
+            scrollElementIntoViewCenter(driver, match);
             parseMatch(driver, match);
         }
-        System.out.println("found " + matchDivs.size() + " matches");
+        System.out.println("found " + matchDivs.size() + " matches handled " + handledDivs.size());
 
         driver.close();
         return result;
@@ -103,20 +119,25 @@ public class BetSafeParser extends ParserBase {
 
     private void expandAllMatches(ChromeDriver driver, WebDriverWait wait, List<WebElement> matchDivs) {
         List<WebElement> buttons = driver
-        .findElements(By.xpath("//button[contains(@class,'obg-show-more-less-button')]"));
-        scrollElementIntoViewCenter(driver, buttons.get(0));
+                .findElements(By.xpath("//button[contains(@class,'obg-show-more-less-button')]"));
 
         for (WebElement button : buttons) {
             WebElement findElement = button.findElement(By.xpath(".//span"));
             while (!findElement.getText().contains("färre")) {
-                scrollElementIntoViewCenter(driver, buttons.get(0));
+                scrollElementIntoView(driver, findElement);
+                try {
+                    Thread.sleep(200);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+                scrollElementIntoViewCenter(driver, findElement);
                 button.click();
                 findElement = button.findElement(By.xpath(".//span"));
+                scrollElementIntoViewCenter(driver, findElement);
             }
-
         }
 
-        if (buttons.size() > 0) {
+        if (!buttons.isEmpty()) {
             wait.until(ExpectedConditions.numberOfElementsToBeMoreThan(By.xpath(
                     "//div[contains(@class,'obg-event-row-event-container')]"), matchDivs.size()));
         }
@@ -152,23 +173,37 @@ public class BetSafeParser extends ParserBase {
                 }
 
             }
-            result.add(new ResultDTO(homeTeamName, awayTeamName, odds1, oddsX, odds2));
+
+            float oddsOver25 = -1f;
+            float oddsUnder25 = -1f;
+
+            Optional<WebElement> numberOfGoalsContainer = oddsContainers.stream()
+                    .filter(p -> checkIfElementExists(p, ".//header/div/span")
+                            ? p.findElement(By.xpath(".//header/div/span"))
+                                    .getText().toLowerCase().trim().contains("antal mål")
+                            : Boolean.FALSE)
+                    .findFirst();
+
+            if (numberOfGoalsContainer.isPresent()) {
+                List<WebElement> overUnderElements = numberOfGoalsContainer.get()
+                        .findElements(By.xpath(".//section//span[contains(@class, 'obg-selection-content-label')]"));
+
+                for (WebElement element : overUnderElements) {
+                    WebElement oddsElement = element.findElement(By.xpath(".//..//..//span[@test-id='odds']"));
+                    if (element.getText().trim().equals("över 2.5")) {
+                        oddsOver25 = formatFloat(oddsElement.getText());
+                    } else if (element.getText().trim().equals("under 2.5")) {
+                        oddsUnder25 = formatFloat(oddsElement.getText());
+                    }
+                }
+            }
+
+            result.add(new ResultDTO(homeTeamName, awayTeamName, odds1, oddsX, odds2, oddsOver25, oddsUnder25));
             System.out.println(homeTeamName + "-" + awayTeamName + " odds (" + odds1 + "," + oddsX + "," + odds2 + ")");
         } catch (StaleElementReferenceException e) {
-            System.out.println("Stale element, refreshing");
-            driver.navigate().refresh();
-            parseMatch(driver, match);
+//            System.out.println("Stale element, refreshing");
+//            driver.navigate().refresh();
+//            parseMatch(driver, match);
         }
     }
-
-    private float formatFloat(String string) {
-        float result = -1f;
-        try {
-            result = Float.parseFloat(string);
-        } catch (NumberFormatException e) {
-            // Empty by design
-        }
-
-        return result;
-    }
 }

+ 45 - 3
Odds/src/parser/ExpektParser.java

@@ -71,8 +71,8 @@ public class ExpektParser extends ParserBase {
         scrollElementIntoViewCenter(driver, expandableDivs.get(0));
         for (WebElement element : expandableDivs) {
             if (!checkIfElementExists(element, ".//following-sibling::ul")) {
+                scrollElementIntoViewCenter(driver, element);
                 element.click();
-                scrollElementIntoView(driver, element);
             }
         }
 
@@ -121,7 +121,50 @@ public class ExpektParser extends ParserBase {
                 od++;
             }
 
-            result.add(new ResultDTO(homeTeamName, awayTeamName, odds1, oddsX, odds2));
+            float oddsOver25 = -1f;
+            float oddsUnder25 = -1f;
+
+            if (checkIfElementExists(element,
+                    ".//div[@class='KambiBC-list-view__column KambiBC-bet-offers-list__column KambiBC-bet-offers-list__column--num-2']")) {
+                WebElement overUnderContainer = element.findElement(By.xpath(
+                        ".//div[@class='KambiBC-list-view__column KambiBC-bet-offers-list__column KambiBC-bet-offers-list__column--num-2']"));
+
+                if (checkIfElementExists(overUnderContainer, ".//div//div//button[1]//div//div[1]//div[1]")) {
+
+                    WebElement overUnderText1 = overUnderContainer
+                            .findElement(By.xpath(".//div//div//button[1]//div//div[1]//div[1]")); // Över Under text
+                    WebElement overUnderText2 = overUnderContainer
+                            .findElement(By.xpath(".//div//div//button[2]//div//div[1]//div[1]")); // Över Under text
+
+                    WebElement overUnderSiffra1 = overUnderContainer
+                            .findElement(By.xpath(".//div//div//button[1]//div//div[1]//div[2]"));
+                    WebElement overUnderSiffra2 = overUnderContainer
+                            .findElement(By.xpath(".//div//div//button[2]//div//div[1]//div[2]"));
+
+                    WebElement overUnderOdds1 = overUnderContainer
+                            .findElement(By.xpath(".//div//div//button[1]//div//div[2]//div[2]"));
+                    WebElement overUnderOdds2 = overUnderContainer
+                            .findElement(By.xpath(".//div//div//button[2]//div//div[2]//div[2]"));
+
+                    if (overUnderText1.getText().toLowerCase().equals("över")
+                            && formatFloat(overUnderSiffra1.getText()) == 2.5) {
+                        oddsOver25 = formatFloat(overUnderOdds1.getText());
+                    } else if (overUnderText1.getText().toLowerCase().equals("under")
+                            && formatFloat(overUnderSiffra1.getText()) == 2.5) {
+                        oddsUnder25 = formatFloat(overUnderOdds1.getText());
+                    }
+
+                    if (overUnderText2.getText().toLowerCase().equals("över")
+                            && formatFloat(overUnderSiffra2.getText()) == 2.5) {
+                        oddsOver25 = formatFloat(overUnderOdds2.getText());
+                    } else if (overUnderText2.getText().toLowerCase().equals("under")
+                            && formatFloat(overUnderSiffra2.getText()) == 2.5) {
+                        oddsUnder25 = formatFloat(overUnderOdds2.getText());
+                    }
+                }
+            }
+
+            result.add(new ResultDTO(homeTeamName, awayTeamName, odds1, oddsX, odds2, oddsOver25, oddsUnder25));
             System.out.println(homeTeamName + "-" + awayTeamName + " (" + odds1 + "," + oddsX + "," + odds2 + ")");
         }
 
@@ -185,7 +228,6 @@ public class ExpektParser extends ParserBase {
 
             // System.out.println(webResponse.getContentAsString());
         } catch (FailingHttpStatusCodeException | IOException e) {
-            // TODO Auto-generated catch block
             e.printStackTrace();
         }
     }

+ 46 - 21
Odds/src/parser/NordicBetParser.java

@@ -50,6 +50,7 @@ public class NordicBetParser extends ParserBase {
                     element.click();
                     wait.until(ExpectedConditions.numberOfElementsToBeMoreThan(By.xpath(
                             "//div[contains(@class,'obg-event-row-event-container')]"), matchDivs.size()));
+                    Thread.sleep(200);
                     matchDivs = driver
                             .findElements(By.xpath("//div[contains(@class,'obg-event-row-event-container')]"));
                     scrollElementIntoView(driver, element);
@@ -60,7 +61,7 @@ public class NordicBetParser extends ParserBase {
                     element.click();
                     wait.until(ExpectedConditions.numberOfElementsToBeMoreThan(By.xpath(
                             "//div[contains(@class,'obg-event-row-event-container')]"), matchDivs.size()));
-
+                    Thread.sleep(200);
                     matchDivs = driver
                             .findElements(By.xpath("//div[contains(@class,'obg-event-row-event-container')]"));
                     scrollElementIntoView(driver, element);
@@ -72,13 +73,13 @@ public class NordicBetParser extends ParserBase {
                     element.click();
                     wait.until(ExpectedConditions.numberOfElementsToBeMoreThan(By.xpath(
                             "//div[contains(@class,'obg-event-row-event-container')]"), matchDivs.size()));
-
+                    Thread.sleep(200);
                     matchDivs = driver
                             .findElements(By.xpath("//div[contains(@class,'obg-event-row-event-container')]"));
                     scrollElementIntoView(driver, element);
                 }
 
-            } catch (ElementNotFoundException e) {
+            } catch (ElementNotFoundException | InterruptedException e) {
                 // Empty by design, no more matches today
             }
         }
@@ -90,6 +91,7 @@ public class NordicBetParser extends ParserBase {
 
         js.executeScript("window.stop;");
         for (WebElement match : matchDivs) {
+            scrollElementIntoViewCenter(driver, match);
             parseMatch(driver, match);
         }
         System.out.println("found " + matchDivs.size() + " matches");
@@ -106,6 +108,11 @@ public class NordicBetParser extends ParserBase {
             WebElement findElement = button.findElement(By.xpath(".//span"));
             while (!findElement.getText().contains("less")) {
                 button.click();
+                try {
+                    Thread.sleep(200);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
                 findElement = button.findElement(By.xpath(".//span"));
             }
 
@@ -130,9 +137,12 @@ public class NordicBetParser extends ParserBase {
             List<WebElement> oddsContainers = match.findElements(By.xpath(".//obg-event-row-market-container"));
 
             Optional<WebElement> matchOddsContainer = oddsContainers.stream()
-                    .filter(p -> p.findElement(By.xpath("//header/div/span"))
-                            .getText().equals("Matchresultat"))
+                    .filter(p -> checkIfElementExists(p, ".//header//div//span")
+                            ? p.findElement(By.xpath(".//header/div/span"))
+                                    .getText().equals("Matchresultat")
+                            : Boolean.FALSE)
                     .findFirst();
+
             float odds1 = -1f;
             float oddsX = -1f;
             float odds2 = -1f;
@@ -147,23 +157,38 @@ public class NordicBetParser extends ParserBase {
                 }
 
             }
-            parsedMatches.add(new ResultDTO(homeTeamName, awayTeamName, odds1, oddsX, odds2));
-            System.out.println(homeTeamName + "-" + awayTeamName + " odds (" + odds1 + "," + oddsX + "," + odds2 + ")");
-        } catch (StaleElementReferenceException e) {
-            System.out.println("Stale element, refreshing");
-            driver.navigate().refresh();
-            parseMatch(driver, match);
-        }
-    }
 
-    private float formatFloat(String string) {
-        float result = -1f;
-        try {
-            result = Float.parseFloat(string);
-        } catch (NumberFormatException e) {
-            // Empty by design
-        }
+            float oddsOver25 = -1f;
+            float oddsUnder25 = -1f;
+
+            Optional<WebElement> numberOfGoalsContainer = oddsContainers.stream()
+                    .filter(p -> checkIfElementExists(p, ".//header/div/span")
+                            ? p.findElement(By.xpath(".//header/div/span"))
+                                    .getText().toLowerCase().trim().contains("antal mål")
+                            : Boolean.FALSE)
+                    .findFirst();
+
+            if (numberOfGoalsContainer.isPresent()) {
+                List<WebElement> overUnderElements = numberOfGoalsContainer.get()
+                        .findElements(By.xpath(".//section//span[contains(@class, 'obg-selection-content-label')]"));
+
+                for (WebElement element : overUnderElements) {
+                    WebElement oddsElement = element.findElement(By.xpath(".//..//..//span[@test-id='odds']"));
+                    if (element.getText().trim().equals("över 2.5")) {
+                        oddsOver25 = formatFloat(oddsElement.getText());
+                    } else if (element.getText().trim().equals("under 2.5")) {
+                        oddsUnder25 = formatFloat(oddsElement.getText());
+                    }
+                }
+            }
 
-        return result;
+            parsedMatches.add(new ResultDTO(homeTeamName, awayTeamName, odds1, oddsX, odds2, oddsOver25, oddsUnder25));
+            System.out.println(homeTeamName + "-" + awayTeamName + " odds (" + odds1 + "," + oddsX + "," + odds2 + ")"
+                    + " overUnder: " + oddsOver25 + "/" + oddsUnder25);
+        } catch (StaleElementReferenceException e) {
+//            System.out.println("Stale element, refreshing");
+//            driver.navigate().refresh();
+//            parseMatch(driver, match);
+        }
     }
 }

+ 268 - 158
Odds/src/parser/OddsPortal.java

@@ -1,17 +1,19 @@
 package parser;
 
 import java.io.IOException;
-import java.sql.SQLException;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
-import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import org.eclipse.jetty.util.log.Log;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.chrome.ChromeDriver;
 
 import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
 import com.gargoylesoftware.htmlunit.WebClient;
@@ -27,8 +29,10 @@ import com.google.common.base.Strings;
 import mysql.Mysql;
 import object.ResultDTO;
 
-public class OddsPortal implements ParserJoinedFunctions {
+public class OddsPortal extends ParserBase implements ParserJoinedFunctions {
 
+    private static final String DIV_CONTAINS_CLASS_TABS_DIV_NOT_CLASS_DIV_1_DIV = "//div[contains(@class,'tabs')]/div[not(@class)]/div[1]/div";
+    private static final String SOCCER_RESULTS_TABLE_NAME = "SoccerResults";
     private static final String CLASS = "class";
     private static final String DATE_PATTERN = "yyyyMMdd";
     private LocalDateTime baseDate;
@@ -37,158 +41,11 @@ public class OddsPortal implements ParserJoinedFunctions {
     private int leagueId;
     private LocalDateTime gameDate;
 
-    public void getYesterdaysMatches() {
-        baseDate = LocalDateTime.now().plusDays(-1);
-        final String date = LocalDate.now().plusDays(-1).format(DateTimeFormatter.ofPattern(DATE_PATTERN));
-        getMatchesByDate(date);
-    }
-
-    public void getTodaysMatches() {
-        baseDate = LocalDateTime.now();
-        final String date = LocalDate.now().format(DateTimeFormatter.ofPattern(DATE_PATTERN));
-        getMatchesByDate(date);
-    }
-
-    public void getTomorrowsMatches() {
-        baseDate = LocalDateTime.now().plusDays(1);
-        final String dateTomorrow = LocalDate.now().plusDays(1).format(DateTimeFormatter.ofPattern(DATE_PATTERN));
-        getMatchesByDate(dateTomorrow);
-    }
-
-    public void getNextDaysMatches() {
-        baseDate = LocalDateTime.now().plusDays(2);
-        final String dateTomorrow = LocalDate.now().plusDays(2).format(DateTimeFormatter.ofPattern(DATE_PATTERN));
-        getMatchesByDate(dateTomorrow);
-    }
-
-    // https://stackoverflow.com/questions/14439991/skip-particular-javascript-execution-in-html-unit
-    // Skip url
-    private void getMatchesByDate(String date) {
-        final String soccerUrl = "https://oddsportal.com/matches/soccer/" + date;
-        // final String hockeyUrl = "https://oddsportal.com/matches/hockey/" + date;
-
-        try (final WebClient webClient = new WebClient()) {
-            webClient.getOptions().setUseInsecureSSL(true);
-            webClient.getOptions().setCssEnabled(false);
-            webClient.getOptions().setJavaScriptEnabled(true);
-            webClient.getOptions().setThrowExceptionOnScriptError(false);
-            webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
-            Logger.getLogger("com.gargoylesoftware").setLevel(Level.OFF);
-
-            webClient.waitForBackgroundJavaScript(3000);
-            parseSoccerMatches(soccerUrl, webClient, date);
-
-        } catch (Exception e) {
-            System.out.println("Webclient failed " + e.getMessage());
-            e.printStackTrace();
-        }
-    }
-
-    private void parseSoccerMatches(final String soccerUrl, final WebClient webClient, String date) {
-        try {
-            final HtmlPage soccerMatches = webClient.getPage(soccerUrl);
-            final HtmlTable matchesTable = soccerMatches.getFirstByXPath("//table[contains(@class, table-main)]");
-            final List<HtmlTableRow> rows = matchesTable.getRows();
-            String countryName = "";
-            String leagueName = "";
-            int i = 1;
-            for (final HtmlTableRow tr : rows) {
-                if (tr.getAttribute(CLASS).equals("dark center")) {
-                    final List<HtmlAnchor> countryLeague = tr.getByXPath(".//a");
-                    countryName = countryLeague.get(0).asNormalizedText().toLowerCase().trim();
-                    leagueName = countryLeague.get(1).asNormalizedText().toLowerCase().trim();
-                    leagueName = leagueName.replace(" ", "-");
-                    leagueName = leagueName.replace("\\.", "");
-                    countryName = countryName.replace(" ", "-");
-                    countryName = countryName.replace("\\.", "");
-                } else {
-                    final List<HtmlTableCell> cells = tr.getCells();
-                    final String[] time = cells.get(0).asNormalizedText().split(":");
-                    final String[] teams = cells.get(1).asNormalizedText().split(" - ");
-                    float odds1 = 0F;
-                    float oddsX = 0F;
-                    float odds2 = 0F;
-                    int homeScore = -1;
-                    int awayScore = -1;
-                    boolean overtime = false;
-
-                    boolean abandon = false;
-
-                    try {
-                        for (final HtmlTableCell tc : cells) {
-                            if (tc.getAttribute(CLASS).contains("live-score")) {
-                                abandon = true;
-                                break;
-                            }
-                            // Score
-                            if (tc.getAttribute(CLASS).contains("table-score")) {
-                                final String[] scoreValue = tc.asNormalizedText().split(":");
-                                homeScore = Integer.valueOf(scoreValue[0]);
-                                if (scoreValue[1].matches("\\D+")) {
-                                    overtime = true;
-                                }
-                                awayScore = Integer.valueOf(scoreValue[1].replaceAll("\\D+", ""));
-                            }
-                            if (tc.getAttribute(CLASS).contains("odds-nowrp")) {
-                                if (tc.asNormalizedText().matches("[+-][0-9][0-9][0-9]")) {
-                                    if (odds1 == 0F) {
-                                        odds1 = convertAmericanOddsToDecimal(Integer.valueOf(tc.asNormalizedText()));
-                                    } else if (oddsX == 0F) {
-                                        oddsX = convertAmericanOddsToDecimal(Integer.valueOf(tc.asNormalizedText()));
-                                    } else if (odds2 == 0F) {
-                                        odds2 = convertAmericanOddsToDecimal(Integer.valueOf(tc.asNormalizedText()));
-                                    }
-                                } else if (tc.asNormalizedText().matches("[0-9].[0-9]+")) {
-                                    if (odds1 == 0F) {
-                                        odds1 = Float.valueOf(tc.asNormalizedText());
-                                    } else if (oddsX == 0F) {
-                                        oddsX = Float.valueOf(tc.asNormalizedText());
-                                    } else if (odds2 == 0F) {
-                                        odds2 = Float.valueOf(tc.asNormalizedText());
-                                    }
-                                }
-                            }
-
-                        }
-                    } catch (final NumberFormatException e) {
-                        Log.getLog().info(String.format(
-                                "Failed to get the match between %s and %s at %s odds1 %s oddsX %s odds2 %s homeScore %s awayScore %s overtime %s",
-                                teams[0].trim(), teams[1].trim(),
-                                baseDate.withHour(Integer.valueOf(time[0])).withMinute(Integer.valueOf(time[1])),
-                                odds1, oddsX, odds2, homeScore, awayScore, (overtime ? "true" : "false")));
-                        continue;
-                    }
-
-                    if (abandon) {
-                        continue;
-                    }
-                    final Mysql mysql = Mysql.getInstance();
-                    final int leaguesId = mysql.addLeague(leagueName, countryName, "soccer");
-                    final int countrysId = mysql.getCountryId(countryName);
-                    final int sportsId = mysql.getSportId("soccer");
-
-                    String season = mysql.getLastSeason(leagueName, countryId); // TODO This don't work
-//					String season = String.valueOf(LocalDate.parse(date, DateTimeFormatter.ofPattern(DATE_PATTERN)).getYear());
-                    if (Strings.isNullOrEmpty(season)) {
-                        season = String.valueOf(LocalDateTime.now().getYear());
-                    }
-
-                    final LocalDateTime dt = baseDate.withHour(Integer.valueOf(time[0]))
-                            .withMinute(Integer.valueOf(time[1])).withSecond(0)
-                            .withNano(0);
-                    if (teams.length != 2) {
-                        System.out.println("Something wrong with teams " + Arrays.toString(teams));
-                    } else {
-                        mysql.addResult(new ResultDTO("SoccerResults", dt, teams[0].trim(), teams[1].trim(), homeScore,
-                                awayScore, overtime, odds1,
-                                oddsX, odds2, countrysId, season, leaguesId, sportsId));
-                    }
-                }
-            }
-        } catch (FailingHttpStatusCodeException | IOException | SQLException e) {
-            e.printStackTrace();
-        }
-    }
+    final int sportsId = Mysql.getInstance().getSportId("soccer");
+    private int currentLeagueId;
+    private int currentCountryId;
+    private List<ResultDTO> resultsToInsert = new ArrayList<>();
+    private String currentSeason;
 
     public void getHistoricMatches(String sport, String country, String league, String year) {
         final String url = "https://www.oddsportal.com/";
@@ -256,7 +113,7 @@ public class OddsPortal implements ParserJoinedFunctions {
                 }
                 // process new tournament table content
             }
-        } catch (FailingHttpStatusCodeException | IOException | SQLException e) {
+        } catch (FailingHttpStatusCodeException | IOException e) {
             e.printStackTrace();
         } catch (final ClassCastException cce) {
             Log.getLog().info("Class cast exception message: " + cce.getMessage() + " \ncause: " + cce.getCause());
@@ -267,9 +124,154 @@ public class OddsPortal implements ParserJoinedFunctions {
         Log.getLog().info("DONE with " + country + " (" + countryId + ") league " + league + "(" + leagueId + ")");
     }
 
+    public void getNextDaysMatches() {
+        baseDate = LocalDateTime.now().plusDays(2);
+        final String dateTomorrow = LocalDate.now().plusDays(2).format(DateTimeFormatter.ofPattern(DATE_PATTERN));
+        getMatchesByDateSelenium(dateTomorrow);
+    }
+
+    public void getTodaysMatches() {
+        baseDate = LocalDateTime.now();
+        final String date = LocalDate.now().format(DateTimeFormatter.ofPattern(DATE_PATTERN));
+        getMatchesByDateSelenium(date);
+    }
+
+    // https://stackoverflow.com/questions/14439991/skip-particular-javascript-execution-in-html-unit
+    // Skip url
+    public void getTomorrowsMatches() {
+        baseDate = LocalDateTime.now().plusDays(1);
+        final String dateTomorrow = LocalDate.now().plusDays(1).format(DateTimeFormatter.ofPattern(DATE_PATTERN));
+        getMatchesByDateSelenium(dateTomorrow);
+    }
+
+    public void getYesterdaysMatches() {
+        baseDate = LocalDateTime.now().plusDays(-1);
+        final String date = LocalDate.now().plusDays(-1).format(DateTimeFormatter.ofPattern(DATE_PATTERN));
+        getMatchesByDateSelenium(date);
+    }
+
+    private int getCountryId(List<WebElement> links) {
+        String country;
+        country = links.get(1).getText().trim();
+        country = country.replace(" ", "-");
+        country = country.replace("\\.", "");
+        return Mysql.getInstance().getCountryId(country);
+    }
+
+    private String getLastSeason(int leagueId, int countryId) {
+        String result = "";
+
+        if (!Strings.isNullOrEmpty(currentSeason) && currentLeagueId == leagueId && currentCountryId == countryId) {
+            return currentSeason;
+        } else {
+            result = Mysql.getInstance().getLastSeason(leagueId, countryId);
+        }
+
+        if (Strings.isNullOrEmpty(result)) {
+            result = String.valueOf(LocalDate.now().getYear());
+        }
+        return result;
+    }
+
+    private int getLeagueId(List<WebElement> links) {
+        String league;
+        league = links.get(2).getText().trim();
+        league = league.replace(" ", "-");
+        league = league.replace("\\.", "");
+        return Mysql.getInstance().getLeagueId(sportId, countryId, league);
+    }
+
+    private void getMatchesByDateSelenium(String date) {
+        final String soccerUrl = "https://oddsportal.com/matches/soccer/" + date;
+        parseSoccerMatchesSelenium(soccerUrl);
+    }
+
+    private void parseSoccerMatchesSelenium(final String soccerUrl) {
+        ChromeDriver driver = getSeleniumDriver();
+        sportId = Mysql.getInstance().getSportId("soccer");
+        driver.get(soccerUrl);
+
+        try {
+            Thread.sleep(400);
+
+            List<WebElement> divs = driver
+                    .findElements(By.xpath(DIV_CONTAINS_CLASS_TABS_DIV_NOT_CLASS_DIV_1_DIV));
+
+            int divsCount = divs.size();
+
+            divs = scrollAndGetAllMatchDivs(driver, divs, divsCount);
+
+            for (WebElement element : divs) {
+                ResultDTO result = new ResultDTO(SOCCER_RESULTS_TABLE_NAME);
+
+                boolean somethingWrong = false;
+                List<WebElement> subDivs = element.findElements(By.xpath("./div"));
+                if (subDivs.size() == 3) {
+                    WebElement competitionsDiv = subDivs.get(0);
+                    List<WebElement> links = competitionsDiv.findElements(By.xpath(".//a"));
+
+                    countryId = getCountryId(links);
+                    leagueId = getLeagueId(links);
+                    result.setLeagueId(leagueId);
+                    result.setCountryId(countryId);
+
+                    WebElement firstResultsDiv = subDivs.get(2);
+
+                    setGameDate(result, firstResultsDiv);
+
+                    setTeamsInfo(result, firstResultsDiv);
+
+                    setOdds(result, firstResultsDiv);
+
+                } else if (subDivs.size() == 1) {
+
+                    result.setLeagueId(leagueId);
+                    result.setCountryId(countryId);
+                    WebElement firstResultsDiv = subDivs.get(0);
+
+                    setGameDate(result, firstResultsDiv);
+                    setTeamsInfo(result, firstResultsDiv);
+
+                    setOdds(result, firstResultsDiv);
+                } else {
+                    somethingWrong = true;
+                    String message = "Subdiv size = " + subDivs.size();
+                    Logger.getGlobal().log(Level.WARNING, message);
+                }
+
+                if (!somethingWrong) {
+                    final Mysql mysql = Mysql.getInstance();
+
+                    result.setCountryId(countryId);
+                    result.setLeagueId(leagueId);
+                    result.setSeason(getLastSeason(leagueId, countryId));
+
+                    resultsToInsert.add(result);
+
+                    if (resultsToInsert.size() > 100) {
+                        Logger.getGlobal().log(Level.INFO, "INSERTING 100 results");
+                        mysql.addResults(resultsToInsert);
+                        resultsToInsert.clear();
+                    }
+
+                }
+
+            }
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+            Thread.currentThread().interrupt();
+        }
+
+        String message = "INSERTING LAST " + resultsToInsert.size() + " results";
+        Logger.getGlobal().log(Level.INFO, message);
+        Mysql.getInstance().addResults(resultsToInsert);
+        resultsToInsert.clear();
+        driver.close();
+    }
+
     private void parseTournamentTable(int sportId, int countryId, int leagueId, String season,
             HtmlTable tournamentTable, LocalDateTime gameDate,
-            DateTimeFormatter dateFormatter) throws SQLException {
+            DateTimeFormatter dateFormatter) {
         for (final HtmlTableRow tr : tournamentTable.getRows()) {
             if (tr.getAttribute(CLASS).contains("deactivate")) {
                 String homeTeam;
@@ -335,7 +337,7 @@ public class OddsPortal implements ParserJoinedFunctions {
                 if (gameDate != null && homeTeam != null && awayTeam != null && odds1 != 0 && oddsX != 0 && odds2 != 0
                         && !Strings.isNullOrEmpty(season)) { // All set.. update sql result table
                     Mysql.getInstance()
-                            .addResult(new ResultDTO("SoccerResults", gameDate, homeTeam, awayTeam, homeScore,
+                            .addResult(new ResultDTO(SOCCER_RESULTS_TABLE_NAME, gameDate, homeTeam, awayTeam, homeScore,
                                     awayScore, overtime, odds1,
                                     oddsX, odds2, countryId, season, leagueId, sportId));
                 } else {
@@ -358,4 +360,112 @@ public class OddsPortal implements ParserJoinedFunctions {
             }
         }
     }
+
+    private List<WebElement> scrollAndGetAllMatchDivs(ChromeDriver driver, List<WebElement> divs, int divsCount)
+            throws InterruptedException {
+        if (divsCount > 0) {
+            scrollElementIntoViewCenter(driver, divs.get(divsCount - 1));
+            Thread.sleep(1000);
+            divs = driver
+                    .findElements(By.xpath(DIV_CONTAINS_CLASS_TABS_DIV_NOT_CLASS_DIV_1_DIV));
+        }
+
+        while (divsCount < divs.size()) {
+            if (divsCount > 0) {
+                divsCount = divs.size();
+                scrollElementIntoViewCenter(driver, divs.get(divsCount - 1));
+                Thread.sleep(1000);
+                divs = driver
+                        .findElements(By.xpath(DIV_CONTAINS_CLASS_TABS_DIV_NOT_CLASS_DIV_1_DIV));
+            }
+        }
+        return divs;
+    }
+
+    private void setGameDate(ResultDTO result, WebElement firstResultsDiv) {
+        final List<Integer> time = new ArrayList<>();
+        if (checkIfElementExists(firstResultsDiv, "./div/a/div[1]/div/p")) {
+            String timeText = firstResultsDiv.findElement(By.xpath("./div/a/div[1]/div/p")).getText();
+            String[] timeSplit = timeText.split(":");
+            if (timeSplit.length == 2) {
+                time.add(Integer.parseInt(timeSplit[0]));
+                time.add(Integer.parseInt(timeSplit[1]));
+            } else {
+                time.add(0);
+                time.add(0);
+            }
+        } else {
+            time.add(0);
+            time.add(0);
+        }
+        final LocalDateTime dt = baseDate.withHour(time.get(0))
+                .withMinute(time.get(1)).withSecond(0)
+                .withNano(0);
+
+        result.setGameDate(dt);
+    }
+
+    private void setOdds(ResultDTO result, WebElement firstResultsDiv) {
+        final int addToOddsDivPosition;
+        if (checkIfElementExists(firstResultsDiv, "./div/div[1]/div")) {
+            String resultsText = firstResultsDiv.findElement(By.xpath("./div/div[1]/div")).getText();
+
+            String[] results = resultsText.split(":");
+
+            if (results.length == 2) {
+                result.setHomeScore(Integer.parseInt(results[0]));
+                if (!results[1].matches("[0-9]*")) {
+                    result.setOvertime(true);
+                    result.setAwayScore(Integer.parseInt(results[1].replaceAll("[^0-9]", "")));
+                } else {
+                    result.setAwayScore(Integer.parseInt(results[1]));
+                }
+                addToOddsDivPosition = 1;
+            } else {
+                addToOddsDivPosition = 0;
+            }
+        } else {
+            addToOddsDivPosition = 0;
+        }
+
+        String divStartString = "./div/div[";
+        String divEndString = "]/div/span/p";
+        if (checkIfElementExists(firstResultsDiv,
+                divStartString + (1 + addToOddsDivPosition) + divEndString)) {
+            result.setOdds1(formatFloat(
+                    firstResultsDiv
+                            .findElement(
+                                    By.xpath(divStartString + (1 + addToOddsDivPosition) + divEndString))
+                            .getText().trim()));
+        }
+        if (checkIfElementExists(firstResultsDiv,
+                divStartString + (2 + addToOddsDivPosition) + divEndString)) {
+            result.setOddsX(formatFloat(
+                    firstResultsDiv
+                            .findElement(
+                                    By.xpath(divStartString + (2 + addToOddsDivPosition) + divEndString))
+                            .getText().trim()));
+        }
+        if (checkIfElementExists(firstResultsDiv,
+                divStartString + (3 + addToOddsDivPosition) + divEndString)) {
+            result.setOdds2(formatFloat(
+                    firstResultsDiv
+                            .findElement(
+                                    By.xpath(divStartString + (3 + addToOddsDivPosition) + divEndString))
+                            .getText().trim()));
+        }
+    }
+
+    private void setTeamsInfo(ResultDTO result, WebElement firstResultsDiv) {
+        List<WebElement> teams = firstResultsDiv.findElements(By.xpath(".//div//a//div[2]//a"));
+        String homeTeamName = teams.get(0).getText().trim();
+        String awayTeamName = teams.get(1).getText().trim();
+        result.setHomeTeam(homeTeamName);
+        result.setAwayTeam(awayTeamName);
+
+        result.setHomeTeamId(
+                Mysql.getInstance().getOrInsertTeam(homeTeamName, countryId, leagueId, sportId));
+        result.setAwayTeamId(
+                Mysql.getInstance().getOrInsertTeam(awayTeamName, countryId, leagueId, sportId));
+    }
 }

+ 27 - 1
Odds/src/parser/ParserBase.java

@@ -1,5 +1,6 @@
 package parser;
 
+import java.time.Duration;
 import java.util.Collections;
 
 import org.openqa.selenium.By;
@@ -7,6 +8,7 @@ import org.openqa.selenium.JavascriptExecutor;
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.chrome.ChromeDriver;
 import org.openqa.selenium.chrome.ChromeOptions;
+import org.openqa.selenium.support.ui.WebDriverWait;
 
 public class ParserBase {
 
@@ -14,7 +16,7 @@ public class ParserBase {
         ChromeOptions options = new ChromeOptions();
 
         System.setProperty("webdriver.chrome.driver",
-                System.getProperty("user.dir") + "/odds/Odds/chromedriver.exe");
+                System.getProperty("user.dir") + "/chromedriver.exe");
         System.setProperty("webdriver.chrome.silentOutput", "true");
         // Fixing 255 Error crashes
         options.addArguments("--no-sandbox");
@@ -39,10 +41,23 @@ public class ParserBase {
         return driver;
     }
 
+    protected WebDriverWait getWaitDriver(ChromeDriver driver) {
+        return new WebDriverWait(driver, Duration.ofSeconds(30));
+    }
+
+    protected JavascriptExecutor getJsExecutor(ChromeDriver driver) {
+        return driver;
+    }
+
     protected boolean checkIfElementExists(WebElement element, String xpath) {
         return !element.findElements(By.xpath(xpath)).isEmpty();
     }
 
+    protected void scrollToTopOfPage(ChromeDriver driver) {
+        ((JavascriptExecutor) driver)
+                .executeScript("document.body.scrollTop = document.documentElement.scrollTop = 0;");
+    }
+
     protected void scrollElementIntoView(ChromeDriver driver, WebElement element) {
         ((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView();", element);
     }
@@ -50,4 +65,15 @@ public class ParserBase {
     protected void scrollElementIntoViewCenter(ChromeDriver driver, WebElement element) {
         ((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView({ block: 'center' });", element);
     }
+
+    protected float formatFloat(String string) {
+        float result = -1f;
+        try {
+            result = Float.parseFloat(string);
+        } catch (NumberFormatException e) {
+            // Empty by design
+        }
+
+        return result;
+    }
 }

+ 8 - 0
Odds/src/parser/Todo/BetssonParser.java

@@ -0,0 +1,8 @@
+package parser.Todo;
+
+import parser.ParserBase;
+
+public class BetssonParser extends ParserBase {
+
+    String url = "https://www.snabbare.com/sv/sportsbook";
+}

+ 9 - 0
Odds/src/parser/Todo/ComeOnParser.java

@@ -0,0 +1,9 @@
+package parser.Todo;
+
+import parser.ParserBase;
+
+public class ComeOnParser extends ParserBase {
+
+    String url = "https://www.comeon.com/sv/sportsbook/sports/1-fotboll/upcoming/0";
+    String url2 = "https://www.comeon.com/sv/sportsbook/sports/1-fotboll/upcoming/1";
+}

+ 8 - 0
Odds/src/parser/Todo/MrGreenParser.java

@@ -0,0 +1,8 @@
+package parser.Todo;
+
+import parser.ParserBase;
+
+public class MrGreenParser extends ParserBase {
+
+    String url = "https://sport.mrgreen.com/sv-SE/filter/football";
+}

+ 8 - 0
Odds/src/parser/Todo/SnabbareParser.java

@@ -0,0 +1,8 @@
+package parser.Todo;
+
+import parser.ParserBase;
+
+public class SnabbareParser extends ParserBase {
+
+    String url = "https://www.betsson.com/sv/odds/fotboll";
+}

+ 1 - 0
Odds/src/parser/Todo/SpeedyBetParser_KanskeBesvärlig.java

@@ -0,0 +1 @@
+package parser.Todo;

+ 7 - 0
Odds/src/parser/Todo/UnibetParser.java

@@ -0,0 +1,7 @@
+package parser.Todo;
+
+import parser.ParserBase;
+
+public class UnibetParser extends ParserBase {
+    String url = "https://www.unibet.se/betting/sports/filter/football/all/matches";
+}

+ 191 - 162
OddsJavaFx/src/controllers/AnalysisTestController.java

@@ -25,15 +25,21 @@ import javafx.scene.control.TableView;
 import javafx.scene.control.TextField;
 import javafx.scene.control.cell.MapValueFactory;
 import javafx.scene.control.cell.PropertyValueFactory;
+import javafx.scene.control.cell.TextFieldTableCell;
 import javafx.util.Callback;
+import javafx.util.converter.FloatStringConverter;
 import objects.League;
 import objects.SoccerMatch;
 import objects.SoccerMatchAnalysis;
 import objects.bets.Bet;
 import objects.bets.Bet.Status;
 
+@SuppressWarnings("rawtypes")
 public class AnalysisTestController implements Initializable {
 
+    private static final float MIN_COVER_ODDS = 1.25f;
+    private static final float MAX_COVER_ODDS = 2.25f;
+    private static final DecimalFormat FLOAT_FORMATTER = new DecimalFormat("0.00");
     @FXML
     TableView<SoccerMatch> gameViewTable;
     TableColumn<SoccerMatch, String> homeTeamNameColumn = new TableColumn<>("Home Team");
@@ -42,23 +48,25 @@ public class AnalysisTestController implements Initializable {
     TableColumn<SoccerMatch, Float> oddsXColumn = new TableColumn<>("X");
     TableColumn<SoccerMatch, Float> odds2Column = new TableColumn<>("2");
     TableColumn<SoccerMatch, String> leagueNameColumn = new TableColumn<>("Country");
+
     TableColumn<SoccerMatch, String> countryNameColumn = new TableColumn<>("League");
+
     TableColumn<SoccerMatch, String> analyzeValueColumn = new TableColumn<>("Value");
     TableColumn<SoccerMatch, Float> matchBetAmountColumn = new TableColumn<>("Bet Amount");
-
     TableColumn<SoccerMatch, Void> addBetColumn = new TableColumn<>("Add Bet");
-
     @FXML
     TableView<Bet> activeBetsTable;
     TableColumn<Bet, String> matchupColumn = new TableColumn<>("Matchup");
     TableColumn<Bet, Float> oddsColumn = new TableColumn<>("Odds");
     TableColumn<Bet, Float> betAmountColumn = new TableColumn<>("BetAmount");
     TableColumn<Bet, Bet.Status> statusColumn = new TableColumn<>("Status");
+
     TableColumn<Bet, Integer> homeScoreColumn = new TableColumn<>("Home Score");
     TableColumn<Bet, Integer> awayScoreColumn = new TableColumn<>("Away Score");
-
+    TableColumn<Bet, Integer> betCoveredNumberColumn = new TableColumn<>("Bet Covered Number");
     @FXML
-    TableView<Map<String, Object>> LeagueBetStatsTable;
+    TableView<Map<String, Object>> leagueBetStatsTable;
+
     @FXML
     TableColumn<Map, String> statsLeagueNameColumn = new TableColumn<>("League");
     @FXML
@@ -69,29 +77,26 @@ public class AnalysisTestController implements Initializable {
     TableColumn<Map, Float> statsHomePercentColumn = new TableColumn<>("Home Percent");
     @FXML
     TableColumn<Map, Integer> statsAwayWinColumn = new TableColumn<>("Away Win");
+
     @FXML
     TableColumn<Map, Integer> statsAwayLossColumn = new TableColumn<>("Away Loss");
     @FXML
     TableColumn<Map, Float> statsAwayPercentColumn = new TableColumn<>("Away Percent");
     @FXML
     TableColumn<Map, Float> statsTotalPercentColumn = new TableColumn<>("Total Percent");
-
     @FXML
     Button checkBetsButton;
     @FXML
     Button getMatchesButton;
     @FXML
     DatePicker date;
+
     @FXML
     TextField bankTextField;
     @FXML
     TextField bettingPercentTextField;
-    private float currentBetAmount = 10f;
 
-    private static final float MIN_COVER_ODDS = 1.25f;
-    private static final float MAX_COVER_ODDS = 2.25f;
-
-    private static final DecimalFormat FLOAT_FORMATTER = new DecimalFormat("0.00");
+    private float currentBetAmount = 10f;
 
     @Override
     public void initialize(URL location, ResourceBundle resources) {
@@ -116,10 +121,6 @@ public class AnalysisTestController implements Initializable {
         gameViewTable.getSelectionModel().selectedItemProperty().addListener((obj, oldValue, newValue) -> {
             if (oldValue != null) {
                 oldValue.setBetAmount(currentBetAmount);
-                Bet previousBet = oldValue.getPreviousBet();
-//                if (previousBet != null && previousBet.getStatus() != Status.COVERED) {
-//                    oldValue.setPreviousBet(null);
-//                }
             }
 
             if (newValue != null) {
@@ -135,6 +136,7 @@ public class AnalysisTestController implements Initializable {
         odds1Column.setCellValueFactory(new PropertyValueFactory<>("odds1"));
         oddsXColumn.setCellValueFactory(new PropertyValueFactory<>("oddsX"));
         odds2Column.setCellValueFactory(new PropertyValueFactory<>("odds2"));
+
         leagueNameColumn.setCellValueFactory(new PropertyValueFactory<>("leagueName"));
         countryNameColumn.setCellValueFactory(new PropertyValueFactory<>("countryName"));
         analyzeValueColumn.setCellValueFactory(new PropertyValueFactory<>("analysisValue"));
@@ -152,8 +154,6 @@ public class AnalysisTestController implements Initializable {
                             SoccerMatch data = getTableView().getItems().get(getIndex());
 
                             addToBets(data);
-
-//                            btn.setDisable(true);
                         });
                     }
 
@@ -175,7 +175,18 @@ public class AnalysisTestController implements Initializable {
 
         gameViewTable.getColumns().addAll(homeTeamNameColumn, awayTeamNameColumn, odds1Column, oddsXColumn, odds2Column,
                 countryNameColumn, leagueNameColumn, analyzeValueColumn, matchBetAmountColumn, addBetColumn);
-        gameViewTable.setEditable(false);
+        gameViewTable.setEditable(true);
+
+        odds1Column.setCellFactory(TextFieldTableCell.<SoccerMatch, Float>forTableColumn(new FloatStringConverter()));
+        odds1Column.setOnEditCommit(
+                e -> e.getTableView().getItems().get(e.getTablePosition().getRow()).setOdds1(e.getNewValue()));
+
+        oddsXColumn.setCellFactory(TextFieldTableCell.<SoccerMatch, Float>forTableColumn(new FloatStringConverter()));
+        oddsXColumn.setOnEditCommit(
+                e -> e.getTableView().getItems().get(e.getTablePosition().getRow()).setOddsX(e.getNewValue()));
+        odds2Column.setCellFactory(TextFieldTableCell.<SoccerMatch, Float>forTableColumn(new FloatStringConverter()));
+        odds2Column.setOnEditCommit(
+                e -> e.getTableView().getItems().get(e.getTablePosition().getRow()).setOdds2(e.getNewValue()));
 
         matchupColumn.setCellValueFactory(new PropertyValueFactory<>("matchup"));
         matchupColumn.setMinWidth(100d);
@@ -184,11 +195,12 @@ public class AnalysisTestController implements Initializable {
         betAmountColumn.setCellValueFactory(new PropertyValueFactory<>("betAmount"));
         homeScoreColumn.setCellValueFactory(new PropertyValueFactory<>("homeScore"));
         awayScoreColumn.setCellValueFactory(new PropertyValueFactory<>("awayScore"));
+        betCoveredNumberColumn.setCellValueFactory(new PropertyValueFactory<>("betCoveredNumber"));
 
         statusColumn.setCellValueFactory(new PropertyValueFactory<>("status"));
 
         activeBetsTable.getColumns().addAll(matchupColumn, oddsColumn, betAmountColumn, statusColumn, homeScoreColumn,
-                awayScoreColumn);
+                awayScoreColumn, betCoveredNumberColumn);
 
         getActiveBets();
 
@@ -202,6 +214,78 @@ public class AnalysisTestController implements Initializable {
         statsAwayPercentColumn.setCellValueFactory(new MapValueFactory<>("statsAwayPercent"));
         statsTotalPercentColumn.setCellValueFactory(new MapValueFactory<>("statsTotalPercent"));
 
+        initializeStatsPanel();
+    }
+
+    private void addMatchesToTable(List<SoccerMatch> matches) {
+        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 addToBets(SoccerMatch data) {
+        if (data.getAnalysisValueInt() > 0) {
+            setNewBet(data, true);
+        } else if (data.getAnalysisValueInt() < 0f) {
+            setNewBet(data, false);
+        } else {
+            System.out.println("Can't add bets with analysts value " + data.getAnalysisValueInt());
+        }
+    }
+
+    private void checkBet(Bet b) {
+        if (b.getHomeScore() >= 0 && b.getAwayScore() >= 0
+                && (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());
+            updateBank(win);
+
+        } else if (b.getHomeScore() >= 0 && b.getAwayScore() >= 0) { // Loss
+            b.setStatus(Bet.Status.LOST);
+        }
+
+        GuiMysql.getInstance().updateBetStatus(b.getId(), b.getStatus());
+        updateStatsPanel(b);
+    }
+
+    @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());
+
+            final float betAmount = Float.parseFloat(FLOAT_FORMATTER.format(bankValue * (betPercent / 100f)));
+            currentBetAmount = betAmount;
+            gameViewTable.getItems().forEach(i -> {
+                i.setBetAmount(betAmount);
+            });
+            gameViewTable.refresh();
+
+        } catch (NumberFormatException e) {
+// Ignore
+        }
     }
 
     private void getActiveBets() {
@@ -211,6 +295,56 @@ public class AnalysisTestController implements Initializable {
         activeBetsTable.refresh();
     }
 
+    private Integer getAnalyzeValue(SoccerMatch soccerMatch) {
+        int result = 0;
+
+        SoccerMatchAnalysis analysis = new SoccerMatchAnalysis(soccerMatch);
+        League leagueInfo = GuiMysql.getInstance().getLeagueInfo(soccerMatch.getHomeTeam().getTeamLeagueId());
+        if (leagueInfo != null) {
+            int homeWinsCount = analysis.winLossRatio(leagueInfo.getWinLossRatio(), true);
+            int awayWinsCount = analysis.winLossRatio(leagueInfo.getWinLossRatio(), false);
+
+            int homeWinLossRatioCount = analysis.winLossRationHomeAndAway(true,
+                    leagueInfo.getWinLossRatioHomeAndAway());
+            int awayWinLossRatioCount = analysis.winLossRationHomeAndAway(false,
+                    leagueInfo.getWinLossRatioHomeAndAway());
+
+            int homeScoringTotal = analysis.scoringTotal(leagueInfo.getScoringTotal(), true);
+            int awayScoringTotal = analysis.scoringTotal(leagueInfo.getScoringTotal(), false);
+
+            int scoringDiffLastGames = analysis.getScoringDiffLastGames(leagueInfo.getScoringDiffLastGame());
+            int winsCountDiff = homeWinsCount - awayWinsCount;
+            int winLossRatioDiff = homeWinLossRatioCount - awayWinLossRatioCount;
+            int scoringTotalDiff = homeScoringTotal - awayScoringTotal;
+
+            if (scoringDiffLastGames < 0 && winsCountDiff < 0 && winLossRatioDiff < 0 && scoringTotalDiff < 0) {
+                result = (scoringDiffLastGames + winsCountDiff + winLossRatioDiff + scoringTotalDiff) / 4;
+            } else if (scoringDiffLastGames > 0 && winsCountDiff > 0 && winLossRatioDiff > 0
+                    && scoringTotalDiff > 0) {
+                result = (scoringDiffLastGames + winsCountDiff + winLossRatioDiff + scoringTotalDiff) / 4;
+            }
+        }
+        return result;
+    }
+
+    private float getBank() {
+        float bank = 0;
+        try {
+            bank = Float.parseFloat(bankTextField.getText());
+        } catch (NumberFormatException e) {
+
+        }
+
+        return bank;
+    }
+
+    @FXML
+    private void GetMatchesAction() {
+        List<SoccerMatch> matches = GuiMysql.getInstance().getMatches(1, date.getValue().toString(), "ASC", true);
+
+        addMatchesToTable(matches);
+    }
+
     private Float getNewBetValue(SoccerMatch newValue) {
         float odds = 0f;
         float currentDebt = 0f;
@@ -225,9 +359,17 @@ public class AnalysisTestController implements Initializable {
                     .get();
 
             Bet tempBet = bet;
+            int betCoverNumber = 0;
             while (tempBet.getCoveredBetId() > 0) {
                 tempBet = GuiMysql.getInstance().getAnalysisBet(tempBet.getCoveredBetId());
                 currentDebt += tempBet.getBetAmount();
+                betCoverNumber++;
+            }
+
+            bet.setBetCoveredNumber(betCoverNumber);
+
+            if (betCoverNumber > 3 && newValue.getAnalysisValueInt() < 10 && newValue.getAnalysisValueInt() > -10) {
+                return Float.parseFloat(FLOAT_FORMATTER.format(result));
             }
 
             currentDebt += bet.getBetAmount();
@@ -248,31 +390,30 @@ public class AnalysisTestController implements Initializable {
         return Float.parseFloat(FLOAT_FORMATTER.format(result));
     }
 
-    private void checkValidBetAmount() {
-        try {
-            float bankValue = Float.parseFloat(bankTextField.getText());
-            float betPercent = Float.parseFloat(bettingPercentTextField.getText());
-
-            final float betAmount = Float.parseFloat(FLOAT_FORMATTER.format(bankValue * (betPercent / 100f)));
-            currentBetAmount = betAmount;
-            gameViewTable.getItems().forEach(i -> {
-                i.setBetAmount(betAmount);
-            });
-            gameViewTable.refresh();
-
-        } catch (NumberFormatException e) {
-// Ignore
+    private void initializeStatsPanel() {
+        List<Bet> bets = GuiMysql.getInstance().getAnalysisBetStatistics();
+        for (Bet bet : bets) {
+            updateStatsPanel(bet);
         }
     }
 
-    private void addToBets(SoccerMatch data) {
-        if (data.getAnalysisValueInt() > 0) {
-            setNewBet(data, true);
-        } else if (data.getAnalysisValueInt() < 0f) {
-            setNewBet(data, false);
-        } else {
-            System.out.println("Can't add bets with analysts value " + data.getAnalysisValueInt());
+    @FXML
+    private void RemoveDoneBetsAction() {
+        List<Bet> doneBets = activeBetsTable.getItems().stream()
+                .filter(p -> p.getStatus() == Status.DONE || p.getStatus() == Status.COVERED)
+                .toList();
+
+        for (Bet bet : doneBets) {
+            if (bet.getStatus().equals(Status.COVERED)) {
+                GuiMysql.getInstance().updateBetStatus(bet.getId(), Status.DONE);
+            }
+            activeBetsTable.getItems().remove(bet);
         }
+
+        activeBetsTable.getItems().sort((b1, b2) -> Float.compare(b2.getBetAmount(), b1.getBetAmount()));
+
+        activeBetsTable.refresh();
+
     }
 
     private void setNewBet(SoccerMatch data, boolean isHomeBet) {
@@ -300,71 +441,16 @@ public class AnalysisTestController implements Initializable {
         updateBank(-bet.getBetAmount());
     }
 
-    @FXML
-    private void GetMatchesAction() {
-        List<SoccerMatch> matches = GuiMysql.getInstance().getMatches(1, date.getValue().toString(), "ASC", true);
-
-        addMatchesToTable(matches);
-    }
-
-    private void addMatchesToTable(List<SoccerMatch> matches) {
-        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 Integer getAnalyzeValue(SoccerMatch soccerMatch) {
-        int result = 0;
-
-        SoccerMatchAnalysis analysis = new SoccerMatchAnalysis(soccerMatch);
-        League leagueInfo = GuiMysql.getInstance().getLeagueInfo(soccerMatch.getHomeTeam().getTeamLeagueId());
-        if (leagueInfo != null) {
-            int homeWinsCount = analysis.winLossRatio(leagueInfo.getWinLossRatio(), true);
-            int awayWindCount = analysis.winLossRatio(leagueInfo.getWinLossRatio(), false);
-
-            int homeWinLossRatioCount = analysis.winLossRationHomeAndAway(true,
-                    leagueInfo.getWinLossRatioHomeAndAway());
-            int awayWinLossRatioCount = analysis.winLossRationHomeAndAway(false,
-                    leagueInfo.getWinLossRatioHomeAndAway());
-
-            int homeScoringTotal = analysis.scoringTotal(leagueInfo.getScoringTotal(), true);
-            int awayScoringTotal = analysis.scoringTotal(leagueInfo.getScoringTotal(), false);
+    private void updateBank(float value) {
+        float bank;
+        try {
+            bank = Float.parseFloat(bankTextField.getText());
+            bank += value;
 
-            int scoringDiffLastGames = analysis.getScoringDiffLastGames(leagueInfo.getScoringDiffLastGame());
-            int winsCountDiff = homeWinsCount - awayWindCount;
-            int winLossRatioDiff = homeWinLossRatioCount - awayWinLossRatioCount;
-            int scoringTotalDiff = homeScoringTotal - awayScoringTotal;
+            bankTextField.setText(String.valueOf(bank));
+        } catch (NumberFormatException e) {
 
-            if (scoringDiffLastGames < 0 && winsCountDiff < 0 && winLossRatioDiff < 0 && scoringTotalDiff < 0) {
-                result = (scoringDiffLastGames + winsCountDiff + winLossRatioDiff + scoringTotalDiff) / 4;
-            } else if (scoringDiffLastGames > 0 && winsCountDiff > 0 && winLossRatioDiff > 0
-                    && scoringTotalDiff > 0) {
-                result = (scoringDiffLastGames + winsCountDiff + winLossRatioDiff + scoringTotalDiff) / 4;
-            }
         }
-        return result;
-    }
-
-    @FXML
-    private void CheckBetsAction() {
-
-        activeBetsTable.getItems().stream().filter(p -> p.getStatus() == Bet.Status.OPEN).forEach(this::checkBet);
-
-        activeBetsTable.refresh();
-
-        updateBetAmount();
-
     }
 
     private void updateBetAmount() {
@@ -377,25 +463,10 @@ public class AnalysisTestController implements Initializable {
         }
     }
 
-    private void checkBet(Bet b) {
-        if ((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());
-            updateBank(win);
-
-        } else { // Loss
-            b.setStatus(Bet.Status.LOST);
-        }
-
-        GuiMysql.getInstance().updateBetStatus(b.getId(), b.getStatus());
-        updateStatsPanel(b);
-    }
-
     private void updateStatsPanel(Bet b) {
         String leagueName = b.getMatch().getLeagueName();
 
-        Optional<Map<String, Object>> leagueStatsRow = LeagueBetStatsTable.getItems().stream()
+        Optional<Map<String, Object>> leagueStatsRow = leagueBetStatsTable.getItems().stream()
                 .filter(p -> p.get("statsLeagueName") != null && leagueName.equals(p.get("statsLeagueName")))
                 .findFirst();
 
@@ -428,7 +499,7 @@ public class AnalysisTestController implements Initializable {
                         ((statsHomeWin + statsAwayWin)
                                 / (float) (statsHomeWin + statsHomeLoss + statsAwayWin + statsAwayLoss)) * 100);
             }
-            ObservableList<Map<String, Object>> items = LeagueBetStatsTable.getItems();
+            ObservableList<Map<String, Object>> items = leagueBetStatsTable.getItems();
 
             items.add(newItem);
         } else {
@@ -461,51 +532,9 @@ public class AnalysisTestController implements Initializable {
                                 / (float) (statsHomeWin + statsHomeLoss + statsAwayWin + statsAwayLoss)) * 100);
             }
 
-            LeagueBetStatsTable.getItems().set(LeagueBetStatsTable.getItems().indexOf(map), map);
+            leagueBetStatsTable.getItems().set(leagueBetStatsTable.getItems().indexOf(map), map);
         }
-        LeagueBetStatsTable.refresh();
-    }
-
-    private void updateBank(float value) {
-        float bank;
-        try {
-            bank = Float.parseFloat(bankTextField.getText());
-            bank += value;
-
-            bankTextField.setText(String.valueOf(bank));
-        } catch (NumberFormatException e) {
-
-        }
-    }
-
-    private float getBank() {
-        float bank = 0;
-        try {
-            bank = Float.parseFloat(bankTextField.getText());
-        } catch (NumberFormatException e) {
-
-        }
-
-        return bank;
-    }
-
-    @FXML
-    private void RemoveDoneBetsAction() {
-        List<Bet> doneBets = activeBetsTable.getItems().stream()
-                .filter(p -> p.getStatus() == Status.DONE || p.getStatus() == Status.COVERED)
-                .toList();
-
-        for (Bet bet : doneBets) {
-            if (bet.getStatus().equals(Status.COVERED)) {
-                GuiMysql.getInstance().updateBetStatus(bet.getId(), Status.DONE);
-            }
-            activeBetsTable.getItems().remove(bet);
-        }
-
-        activeBetsTable.getItems().sort((b1, b2) -> Float.compare(b2.getBetAmount(), b1.getBetAmount()));
-
-        activeBetsTable.refresh();
-
+        leagueBetStatsTable.refresh();
     }
 
 }

+ 150 - 139
OddsJavaFx/src/controllers/TestsController.java

@@ -29,6 +29,7 @@ import javafx.scene.layout.Priority;
 import javafx.scene.layout.VBox;
 import parser.OddsPortal;
 import tests.AddedScoringTest;
+import tests.AnalysisBettDrawTester;
 import tests.AnalysisBettTester;
 import tests.AwayTeamWinTest;
 import tests.AwayTests2;
@@ -125,97 +126,117 @@ public class TestsController implements Initializable {
     }
 
     @FXML
-    private void getResults() {
-        countriesList.clear();
-        leaguesList.clear();
-        initCountries();
+    void getLeagueInfo() {
+        final String country = countrySelector.getValue().trim();
+        final String league = leagueSelector.getValue().trim();
+        final OddsPortal op = new OddsPortal();
+        op.getHistoricMatches("soccer", country, league, String.valueOf(LocalDate.now().getYear()));
     }
 
     @FXML
-    private void countrySelected(ActionEvent event) {
-        if (countrySelector.getValue() != null && !countrySelector.getValue().equals("Country")) {
-            leagueSelector.setDisable(false);
-            final int countryId = getCountryIdFromSelector();
-            final int sportId = getSoccerId();
+    private void addedScoreTestAction() {
+        final AddedScoringTest test = new AddedScoringTest();
 
-            leaguesList = GuiMysql.getInstance().getLeaguesByDate(sportId, countryId, date.getValue().toString());
+        test.setup("", Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), Float.valueOf(getBetMargin()),
+                Integer.valueOf(getLookback()),
+                1, getCountryIdFromSelector(), getLeagueIdFromSelector());
 
-            leagues.clear();
-            leagues.add("League");
-            leaguesList.forEach(l -> leagues.add(l.getValue()));
-        }
+        test.runTest();
     }
 
-    private Integer getCountryIdFromSelector() {
-        Optional<SimpleEntry<Integer, String>> o = countriesList.stream()
-                .filter(p -> p.getValue().equals(countrySelector.getValue())).findFirst();
-        return o.isPresent() ? o.get().getKey() : null;
+    @FXML
+    private void analysisDrawTests() {
+        final TestClass test = new AnalysisBettDrawTester();
+        test.setup(date.getValue().toString(), Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), -1.0f,
+                -1, GuiMysql.getInstance().getSportId("soccer"),
+                getCountryIdFromSelector(), getLeagueIdFromSelector());
+
+        test.runTest();
     }
 
-    private Integer getLeagueIdFromSelector() {
-        Optional<SimpleEntry<Integer, String>> o = leaguesList.stream()
-                .filter(p -> p.getValue().equals(leagueSelector.getValue())).findFirst();
-        return o.isPresent() ? o.get().getKey() : null;
+    @FXML
+    private void analysisTets() {
+        final TestClass test = new AnalysisBettTester();
+
+        test.setup(date.getValue().toString(), Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), -1.0f,
+                -1, GuiMysql.getInstance().getSportId("soccer"),
+                getCountryIdFromSelector(), getLeagueIdFromSelector());
+
+        test.runTest();
     }
 
-    private void initCountries() {
-        countrySelector.setDisable(false);
-        final int sportId = getSoccerId();
+    @FXML
+    private void awayTeamTestAction() {
+        final AwayTeamWinTest test = new AwayTeamWinTest();
 
-        countriesList.clear();
-        countriesList.addAll(GuiMysql.getInstance().getCountriesBySport(sportId, date.getValue().toString()));
+        test.setup("", Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), Float.valueOf(getBetMargin()),
+                Integer.valueOf(getLookback()),
+                1, getCountryIdFromSelector(), getLeagueIdFromSelector());
 
-        countriesList.forEach(c -> countries.add(c.getValue()));
+        test.runTest();
     }
 
-    private int getSoccerId() {
-        if (mSportId <= 0) {
-            mSportId = GuiMysql.getInstance().getSportId(MainController.SPORT);
-        }
+    @FXML
+    private void awayTestAction() {
+        final AwayTests2 test = new AwayTests2();
 
-        return mSportId;
+        test.setup("", Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), Float.valueOf(getBetMargin()),
+                Integer.valueOf(getLookback()),
+                1, getCountryIdFromSelector(), getLeagueIdFromSelector());
+
+        test.runTest();
     }
 
     @FXML
-    private void leagueSelected(ActionEvent event) {
+    private void calcBestResultsAction() {
+        final LastResultsTest test = new LastResultsTest();
 
-        if (GuiMysql.getInstance().getParsingStarted(getCountryIdFromSelector(), getLeagueIdFromSelector())) {
-            getLeagueInfoButton.setDisable(true);
-            getMoreLeagueInfoButton.setDisable(false);
-        } else {
-            getLeagueInfoButton.setDisable(false);
-            getMoreLeagueInfoButton.setDisable(true);
+        calcBestValues.setDisable(true);
+        final String buttonText = calcBestValues.getText();
+        Platform.runLater(() -> {
+            calcBestValues.setText("RUNNING...");
+            test.calcBestResults(mSportId, getCountryIdFromSelector(), getLeagueIdFromSelector());
+            calcBestValues.setDisable(false);
+
+            calcBestValues.setText(buttonText);
+        });
+    }
+
+    @FXML
+    private void countrySelected(ActionEvent event) {
+        if (countrySelector.getValue() != null && !countrySelector.getValue().equals("Country")) {
+            leagueSelector.setDisable(false);
+            final int countryId = getCountryIdFromSelector();
+            final int sportId = getSoccerId();
+
+            leaguesList = GuiMysql.getInstance().getLeaguesByDate(sportId, countryId, date.getValue().toString());
+
+            leagues.clear();
+            leagues.add("League");
+            leaguesList.forEach(l -> leagues.add(l.getValue()));
         }
-        testSettingsPanel.setVisible(true);
     }
 
     @FXML
-    private void runTestAction() {
+    private void drawTestAction() {
+        final DrawTests2 test = new DrawTests2();
 
-        final String betLevel = getBetLevel();
-        final String betM = getBetMargin();
-        final String startBank = getStartingBank();
-        final String lookBackVal = getLookback();
+        test.setup("", Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), Float.valueOf(getBetMargin()),
+                Integer.valueOf(getLookback()),
+                1, getCountryIdFromSelector(), getLeagueIdFromSelector());
 
-        final TestClass test = new LastResultsTest();
-        test.setup(date.getValue().toString(), Float.valueOf(startBank), Float.valueOf(betLevel), Float.valueOf(betM),
-                Integer.valueOf(lookBackVal),
-                mSportId, getCountryIdFromSelector(), getLeagueIdFromSelector());
         test.runTest();
     }
 
-    private String getLookback() {
-        return Strings.isNullOrEmpty(lookBack.getText()) ? lookBack.getPromptText() : lookBack.getText();
-    }
+    @FXML
+    private void fibonacciDrawTestAction() {
+        final TestClass test = new FibonacciDrawTest();
 
-    private String getStartingBank() {
-        return Strings.isNullOrEmpty(startingBank.getText()) ? startingBank.getPromptText() : startingBank.getText();
-    }
+        test.setup(date.getValue().toString(), Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), -1.0f,
+                -1, GuiMysql.getInstance().getSportId("soccer"),
+                getCountryIdFromSelector(), getLeagueIdFromSelector());
 
-    private String getBetMargin() {
-        String betM = Strings.isNullOrEmpty(betMargin.getText()) ? betMargin.getPromptText() : betMargin.getText();
-        betM = betM.replace("%", "").trim();
-        return betM;
+        test.runTest();
     }
 
     private String getBetLevel() {
@@ -225,27 +246,26 @@ public class TestsController implements Initializable {
         return betLevel;
     }
 
-    @FXML
-    private void calcBestResultsAction() {
-        final LastResultsTest test = new LastResultsTest();
+    private String getBetMargin() {
+        String betM = Strings.isNullOrEmpty(betMargin.getText()) ? betMargin.getPromptText() : betMargin.getText();
+        betM = betM.replace("%", "").trim();
+        return betM;
+    }
 
-        calcBestValues.setDisable(true);
-        final String buttonText = calcBestValues.getText();
-        Platform.runLater(() -> {
-            calcBestValues.setText("RUNNING...");
-            test.calcBestResults(mSportId, getCountryIdFromSelector(), getLeagueIdFromSelector());
-            calcBestValues.setDisable(false);
+    private Integer getCountryIdFromSelector() {
+        Optional<SimpleEntry<Integer, String>> o = countriesList.stream()
+                .filter(p -> p.getValue().equals(countrySelector.getValue())).findFirst();
+        return o.isPresent() ? o.get().getKey() : null;
+    }
 
-            calcBestValues.setText(buttonText);
-        });
+    private Integer getLeagueIdFromSelector() {
+        Optional<SimpleEntry<Integer, String>> o = leaguesList.stream()
+                .filter(p -> p.getValue().equals(leagueSelector.getValue())).findFirst();
+        return o.isPresent() ? o.get().getKey() : null;
     }
 
-    @FXML
-    void getLeagueInfo() {
-        final String country = countrySelector.getValue().trim();
-        final String league = leagueSelector.getValue().trim();
-        final OddsPortal op = new OddsPortal();
-        op.getHistoricMatches("soccer", country, league, String.valueOf(LocalDate.now().getYear()));
+    private String getLookback() {
+        return Strings.isNullOrEmpty(lookBack.getText()) ? lookBack.getPromptText() : lookBack.getText();
     }
 
     @FXML
@@ -277,40 +297,31 @@ public class TestsController implements Initializable {
     }
 
     @FXML
-    private void topLeaguesTestAction() {
-        final PrioCountriesAll prioCountriesAll = new PrioCountriesAll();
-        prioCountriesAll.runTest();
+    private void getResults() {
+        countriesList.clear();
+        leaguesList.clear();
+        initCountries();
     }
 
-    @FXML
-    private void homeTestAction() {
-        final HomeTests2 test = new HomeTests2();
-
-        test.setup("", Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), Float.valueOf(getBetMargin()),
-                Integer.valueOf(getLookback()),
-                1, getCountryIdFromSelector(), getLeagueIdFromSelector());
+    private int getSoccerId() {
+        if (mSportId <= 0) {
+            mSportId = GuiMysql.getInstance().getSportId(MainController.SPORT);
+        }
 
-        test.runTest();
+        return mSportId;
     }
 
-    @FXML
-    private void drawTestAction() {
-        final DrawTests2 test = new DrawTests2();
-
-        test.setup("", Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), Float.valueOf(getBetMargin()),
-                Integer.valueOf(getLookback()),
-                1, getCountryIdFromSelector(), getLeagueIdFromSelector());
-
-        test.runTest();
+    private String getStartingBank() {
+        return Strings.isNullOrEmpty(startingBank.getText()) ? startingBank.getPromptText() : startingBank.getText();
     }
 
     @FXML
-    private void awayTestAction() {
-        final AwayTests2 test = new AwayTests2();
+    private void goalDiffTest() {
+        final TestClass test = new BetOnDifference();
 
-        test.setup("", Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), Float.valueOf(getBetMargin()),
-                Integer.valueOf(getLookback()),
-                1, getCountryIdFromSelector(), getLeagueIdFromSelector());
+        test.setup(date.getValue().toString(), Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), -1.0f,
+                -1, GuiMysql.getInstance().getSportId("soccer"),
+                getCountryIdFromSelector(), getLeagueIdFromSelector());
 
         test.runTest();
     }
@@ -338,8 +349,8 @@ public class TestsController implements Initializable {
     }
 
     @FXML
-    private void awayTeamTestAction() {
-        final AwayTeamWinTest test = new AwayTeamWinTest();
+    private void homeTestAction() {
+        final HomeTests2 test = new HomeTests2();
 
         test.setup("", Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), Float.valueOf(getBetMargin()),
                 Integer.valueOf(getLookback()),
@@ -348,15 +359,27 @@ public class TestsController implements Initializable {
         test.runTest();
     }
 
-    @FXML
-    private void addedScoreTestAction() {
-        final AddedScoringTest test = new AddedScoringTest();
+    private void initCountries() {
+        countrySelector.setDisable(false);
+        final int sportId = getSoccerId();
 
-        test.setup("", Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), Float.valueOf(getBetMargin()),
-                Integer.valueOf(getLookback()),
-                1, getCountryIdFromSelector(), getLeagueIdFromSelector());
+        countriesList.clear();
+        countriesList.addAll(GuiMysql.getInstance().getCountriesBySport(sportId, date.getValue().toString()));
 
-        test.runTest();
+        countriesList.forEach(c -> countries.add(c.getValue()));
+    }
+
+    @FXML
+    private void leagueSelected(ActionEvent event) {
+
+        if (GuiMysql.getInstance().getParsingStarted(getCountryIdFromSelector(), getLeagueIdFromSelector())) {
+            getLeagueInfoButton.setDisable(true);
+            getMoreLeagueInfoButton.setDisable(false);
+        } else {
+            getLeagueInfoButton.setDisable(false);
+            getMoreLeagueInfoButton.setDisable(true);
+        }
+        testSettingsPanel.setVisible(true);
     }
 
     @FXML
@@ -371,15 +394,8 @@ public class TestsController implements Initializable {
     }
 
     @FXML
-    private void standingsTest() {
-        final TestClass test = new LeagueTablePositionTest();
-
-        test.runTest();
-    }
-
-    @FXML
-    private void fibonacciDrawTestAction() {
-        final TestClass test = new FibonacciDrawTest();
+    private void relevanceTest() {
+        final TestClass test = new RelevanceTest();
 
         test.setup(date.getValue().toString(), Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), -1.0f,
                 -1, GuiMysql.getInstance().getSportId("soccer"),
@@ -389,35 +405,30 @@ public class TestsController implements Initializable {
     }
 
     @FXML
-    private void goalDiffTest() {
-        final TestClass test = new BetOnDifference();
+    private void runTestAction() {
 
-        test.setup(date.getValue().toString(), Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), -1.0f,
-                -1, GuiMysql.getInstance().getSportId("soccer"),
-                getCountryIdFromSelector(), getLeagueIdFromSelector());
+        final String betLevel = getBetLevel();
+        final String betM = getBetMargin();
+        final String startBank = getStartingBank();
+        final String lookBackVal = getLookback();
 
+        final TestClass test = new LastResultsTest();
+        test.setup(date.getValue().toString(), Float.valueOf(startBank), Float.valueOf(betLevel), Float.valueOf(betM),
+                Integer.valueOf(lookBackVal),
+                mSportId, getCountryIdFromSelector(), getLeagueIdFromSelector());
         test.runTest();
     }
 
     @FXML
-    private void relevanceTest() {
-        final TestClass test = new RelevanceTest();
-
-        test.setup(date.getValue().toString(), Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), -1.0f,
-                -1, GuiMysql.getInstance().getSportId("soccer"),
-                getCountryIdFromSelector(), getLeagueIdFromSelector());
+    private void standingsTest() {
+        final TestClass test = new LeagueTablePositionTest();
 
         test.runTest();
     }
 
     @FXML
-    private void analysisTets() {
-        final TestClass test = new AnalysisBettTester();
-
-        test.setup(date.getValue().toString(), Float.valueOf(getStartingBank()), Float.valueOf(getBetLevel()), -1.0f,
-                -1, GuiMysql.getInstance().getSportId("soccer"),
-                getCountryIdFromSelector(), getLeagueIdFromSelector());
-
-        test.runTest();
+    private void topLeaguesTestAction() {
+        final PrioCountriesAll prioCountriesAll = new PrioCountriesAll();
+        prioCountriesAll.runTest();
     }
 }

+ 731 - 684
OddsJavaFx/src/data/GuiMysql.java

@@ -37,6 +37,15 @@ import objects.bets.Bet.Status;
 
 public class GuiMysql extends Mysql {
 
+    private static final String SEASON = "season";
+    private static final String AWAY_SCORE = "awayScore";
+    private static final String HOME_SCORE = "homeScore";
+    private static final String COUNTRY_NAME = "countryName";
+    private static final String DRAWS = "draws";
+    private static final String DATE_FORMAT = "yyyy-MM-dd";
+    private static final String AWAY_TEAM_ID = "awayTeamId";
+    private static final String HOME_TEAM_ID = "homeTeamId";
+    private static final String LEAGUE_NAME = "leagueName";
     private static final BigDecimal INCREMENT = BigDecimal.valueOf(0.2);
     private static final GuiMysql instance = new GuiMysql();
     private final Connection conn;
@@ -50,127 +59,151 @@ public class GuiMysql extends Mysql {
         return instance;
     }
 
-    public List<SimpleEntry<Integer, String>> getSports() {
+    public int addAnalysisBet(Bet bet) {
+        int newId = -1;
+        String sql = "INSERT INTO AnalysisBetTable (matchId, bet, betAmount, betOdds, status) VALUES (?,?,?,?,?)";
 
-        final ArrayList<AbstractMap.SimpleEntry<Integer, String>> sports = Lists.newArrayList();
-        final String sql = "SELECT id, name FROM Sport";
-        try (PreparedStatement stat = conn.prepareStatement(sql)) {
+        try (PreparedStatement stat = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
+            stat.setInt(1, bet.getMatch().getMatchId());
+            stat.setString(2, bet.getBet());
+            stat.setFloat(3, bet.getBetAmount());
+            stat.setFloat(4, bet.getBetOdds());
+            stat.setString(5, bet.getStatus().name());
 
-            final ResultSet rs = stat.executeQuery();
+            stat.execute();
 
-            while (rs.next()) {
-                final SimpleEntry<Integer, String> entry = new SimpleEntry<>(rs.getInt(Constants.ID),
-                        rs.getString("name"));
-                sports.add(entry);
+            ResultSet generatedKeys = stat.getGeneratedKeys();
+
+            while (generatedKeys.next()) {
+                newId = generatedKeys.getInt(1);
             }
-        } catch (final SQLException e) {
+
+        } catch (SQLException e) {
             e.printStackTrace();
         }
 
-        return sports;
+        return newId;
     }
 
-    public List<SimpleEntry<Integer, String>> getCountries() {
+    public void addBetSeries(BetDTO bet) {
+        String sql = "INSERT INTO ActiveBets (series, gameId, betType, bet, odds, done) VALUES (?, ?, ?, ?, ?, ?)";
 
-        final ArrayList<AbstractMap.SimpleEntry<Integer, String>> countries = Lists.newArrayList();
-        final String sql = "SELECT id, name FROM Country";
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
+            stat.setInt(1, bet.getBetSeries());
+            stat.setInt(2, getGameId(bet.getHomeTeam(), bet.getAwayTeam(), bet.getGameDate(), bet.getCountryId(),
+                    bet.getLeagueId()));
+            stat.setString(3, bet.getBetType());
+            stat.setFloat(4, bet.getBet());
+            stat.setFloat(5, bet.getOdds());
+            stat.setBoolean(6, false);
 
-            final ResultSet rs = stat.executeQuery();
-
-            while (rs.next()) {
-                final SimpleEntry<Integer, String> entry = new SimpleEntry<>(rs.getInt(Constants.ID),
-                        rs.getString("name"));
-                countries.add(entry);
-            }
-        } catch (final SQLException e) {
+            stat.execute();
+        } catch (SQLException e) {
             e.printStackTrace();
         }
-        return countries;
     }
 
-    public List<SimpleEntry<Integer, String>> getLeagues(int sportId, int countryId) {
+    public Bet getAnalysisBet(int betId) {
+        Bet result = null;
+        String sql = "SELECT * FROM AnalysisBetTable abt "
+                + "INNER JOIN SoccerResults sr ON abt.matchId = sr.id "
+                + "WHERE abt.id = ?";
 
-        final ArrayList<AbstractMap.SimpleEntry<Integer, String>> leagues = Lists.newArrayList();
-        final String sql = "SELECT id, name FROM League WHERE sportId = ? AND countryId = ? ORDER BY name ASC";
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setInt(1, sportId);
-            stat.setInt(2, countryId);
+            stat.setInt(1, betId);
 
-            final ResultSet rs = stat.executeQuery();
+            ResultSet rs = stat.executeQuery();
 
             while (rs.next()) {
-                final SimpleEntry<Integer, String> entry = new SimpleEntry<>(rs.getInt(Constants.ID),
-                        rs.getString("name"));
-                leagues.add(entry);
+                Team homeTeam = getTeam(rs.getInt(HOME_TEAM_ID));
+                Team awayTeam = getTeam(rs.getInt(AWAY_TEAM_ID));
+                SoccerMatch match = new SoccerMatch(rs.getInt("matchId"), homeTeam, awayTeam, rs.getFloat("odds1"),
+                        rs.getFloat("oddsX"), rs.getFloat("odds2"), rs.getInt(HOME_SCORE), rs.getInt(AWAY_SCORE),
+                        LocalDateTime.parse(rs.getString("gameDate")), rs.getString(SEASON));
+
+                match.setLeagueName(homeTeam.getTeamLeague());
+                match.setCountryName(homeTeam.getCountryName());
+
+                result = new Bet(rs.getInt("id"), match, rs.getString("bet"), rs.getFloat("betAmount"),
+                        rs.getFloat("betOdds"),
+                        Status.valueOf(rs.getString("status")), rs.getInt("coveredBetId"));
             }
-        } catch (final SQLException e) {
+
+        } catch (SQLException e) {
             e.printStackTrace();
         }
-        return leagues;
-    }
 
-    public List<SoccerMatch> getUpcomingMatches(String sportResultTable) {
-        final ArrayList<SoccerMatch> matches = Lists.newArrayList();
-        final String dateSql;
-        dateSql = " AND DATE(gameDate) >= DATE(now())";
+        return result;
+    }
 
-        final String sql = "SELECT res.id, homeTeamId, awayTeamId, 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, "
-                + "country.prio as prio " + "FROM " + sportResultTable + " as res "
-                + "Join Team as hTeam ON res.homeTeamId = hTeam.id "
-                + "Join Team as aTeam ON res.awayTeamId = aTeam.id "
-                + "Join League as league ON res.leagueId = league.id "
-                + "Join Country as country ON res.countryId = country.id " + "WHERE homeScore = -1 " + dateSql
-                + "AND league.name NOT LIKE '%cup%' AND league.name NOT LIKE '%group%' AND league.prio = 1 "
-                + "ORDER BY country.prio DESC, country.name ASC";
+    public List<Bet> getAnalysisBets() {
+        List<Bet> result = new ArrayList<>();
+        String sql = "SELECT * FROM AnalysisBetTable abt "
+                + "INNER JOIN SoccerResults sr ON abt.matchId = sr.id "
+                + "WHERE status IN ('LOST', 'OPEN', 'COVERED')";
 
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
+            ResultSet rs = stat.executeQuery();
 
-            final ResultSet rs = stat.executeQuery();
             while (rs.next()) {
-                final SoccerMatch sm = new SoccerMatch();
-                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(Constants.LEAGUE_NAME));
-                awayTeam.setTeamLeague(rs.getString(Constants.LEAGUE_NAME));
-                homeTeam.setCountryId(rs.getInt(Constants.COUNTRY_ID));
-                awayTeam.setCountryId(rs.getInt(Constants.COUNTRY_ID));
-                homeTeam.setCountryName(rs.getString(Constants.COUNTRY_NAME));
-                awayTeam.setCountryName(rs.getString(Constants.COUNTRY_NAME));
+                Team homeTeam = getTeam(rs.getInt(HOME_TEAM_ID));
+                Team awayTeam = getTeam(rs.getInt(AWAY_TEAM_ID));
+                SoccerMatch match = new SoccerMatch(rs.getInt("matchId"), homeTeam, awayTeam, rs.getFloat("odds1"),
+                        rs.getFloat("oddsX"), rs.getFloat("odds2"), rs.getInt(HOME_SCORE), rs.getInt(AWAY_SCORE),
+                        LocalDateTime.parse(rs.getString("gameDate")), rs.getString(SEASON));
 
-                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.setCountryPrio(rs.getBoolean("prio"));
+                match.setLeagueName(homeTeam.getTeamLeague());
+                match.setCountryName(homeTeam.getCountryName());
 
-                matches.add(sm);
+                result.add(new Bet(rs.getInt("id"), match, rs.getString("bet"), rs.getFloat("betAmount"),
+                        rs.getFloat("betOdds"),
+                        Status.valueOf(rs.getString("status")), rs.getInt("coveredBetId")));
             }
 
-        } catch (final SQLException e) {
+        } catch (SQLException e) {
             e.printStackTrace();
         }
+        return result;
+    }
 
-        return matches;
+    public List<Bet> getAnalysisBetStatistics() {
+        List<Bet> result = new ArrayList<>();
+
+        String sql = "SELECT sr.id as soccerMatchId, ht.id as homeTeamId, awt.id as awayTeamId, sr.odds1, sr.oddsX, sr.odds2, "
+                + "sr.homeScore, sr.awayScore, sr.gameDate, sr.season, l.name as leagueName, abt.id as betId, abt.bet, abt.betAmount, abt.betOdds "
+                + "FROM AnalysisBetTable abt "
+                + "INNER JOIN SoccerResults sr ON abt.matchId = sr.id "
+                + "INNER JOIN Team ht ON ht.id = sr.homeTeamId "
+                + "INNER JOIN Team awt ON awt.id = sr.awayTeamId "
+                + "INNER JOIN League l ON l.id = sr.leagueId "
+                + "WHERE abt.status != 'OPEN'";
+
+        try (PreparedStatement stat = getConnection().prepareStatement(sql)) {
+            ResultSet rs = stat.executeQuery();
+
+            while (rs.next()) {
+                Team homeTeam = getTeam(rs.getInt(HOME_TEAM_ID));
+                Team awayTeam = getTeam(rs.getInt(AWAY_TEAM_ID));
+                SoccerMatch match = new SoccerMatch(rs.getInt("soccerMatchId"), homeTeam, awayTeam,
+                        rs.getFloat("odds1"), rs.getFloat("oddsX"), rs.getFloat("odds2"), rs.getInt(HOME_SCORE),
+                        rs.getInt(AWAY_SCORE), LocalDateTime.parse(rs.getString("gameDate")), rs.getString(SEASON));
+                match.setLeagueName(rs.getString(LEAGUE_NAME));
+
+                Bet bet = new Bet(rs.getInt("betId"), match, rs.getString("bet"), rs.getFloat("betAmount"),
+                        rs.getFloat("betOdds"));
+
+                result.add(bet);
+            }
+        } catch (SQLException e) {
+            e.printStackTrace();
+        }
+        return result;
     }
 
-    public List<Float> getAvgHomeScore(int teamId) {
+    public List<Float> getAvgAwayScore(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 AND homeTeamId = ?";
+        final String sql = "SELECT AVG(homeScore) as avgConceded, AVG(awayScore) as avgScored FROM SoccerResults WHERE awayScore != -1 AND awayTeamId = ?";
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
             stat.setInt(1, teamId);
 
@@ -188,16 +221,15 @@ public class GuiMysql extends Mysql {
         return returnValue;
     }
 
-    public List<Float> getAvgHomeScoreThisSeason(int teamId, int countryId, int leagueId) {
-        return getAvgHomeScoreThisSeason(teamId, countryId, leagueId, "");
+    public List<Float> getAvgAwayScoreThisSeason(int teamId, int countryId, int leagueId) {
+        return getAvgAwayScoreThisSeason(teamId, countryId, leagueId, "");
     }
 
-    public List<Float> getAvgHomeScoreThisSeason(int teamId, int countryId, int leagueId, String gameDate) {
+    public List<Float> getAvgAwayScoreThisSeason(int teamId, int countryId, int leagueId, String gameDate) {
         final ArrayList<Float> returnValue = Lists.newArrayList();
-        final String sql = "SELECT AVG(homeScore) as avgScoredSeason, AVG(awayScore) as avgConcededSeason FROM SoccerResults WHERE homeScore != -1 AND homeTeamId = ? AND season = ? AND DATE(gameDate) < ? ORDER BY gameDate ASC";
+        final String sql = "SELECT AVG(homeScore) as avgConcededSeason, AVG(awayScore) as avgScoredSeason FROM SoccerResults WHERE awayScore != -1 AND awayTeamId = ? AND season = ? AND DATE(gameDate) < ? ORDER BY gameDate ASC";
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
             stat.setInt(1, teamId);
-
             if (Strings.isNullOrEmpty(gameDate)
                     || getSeasonFromDate(countryId, leagueId, gameDate).equals(getLastSeason(countryId, leagueId))) {
                 stat.setString(2, getLastSeason(countryId, leagueId));
@@ -206,7 +238,7 @@ public class GuiMysql extends Mysql {
                 stat.setString(2, seasonFromDate);
             }
             if (Strings.isNullOrEmpty(gameDate)) {
-                stat.setString(3, new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
+                stat.setString(3, new SimpleDateFormat(DATE_FORMAT).format(new Date()));
             } else {
                 stat.setString(3, gameDate);
             }
@@ -225,31 +257,9 @@ public class GuiMysql extends Mysql {
         return returnValue;
     }
 
-    public String getSeasonFromDate(int countryId, int leagueId, String gameDate) {
-        String sql = "SELECT season FROM SoccerResults WHERE DATE(gameDate) = ? AND countryId = ? AND leagueId = ? LIMIT 1";
-        String returnValue = "";
-        try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            if (Strings.isNullOrEmpty(gameDate)) {
-                stat.setString(1, new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
-            } else {
-                stat.setString(1, gameDate);
-            }
-            stat.setInt(2, countryId);
-            stat.setInt(3, leagueId);
-
-            ResultSet rs = stat.executeQuery();
-            while (rs.next()) {
-                returnValue = rs.getString("season");
-            }
-        } catch (SQLException e) {
-            e.printStackTrace();
-        }
-        return returnValue;
-    }
-
-    public List<Float> getAvgAwayScore(int teamId) {
+    public List<Float> getAvgHomeScore(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 AND awayTeamId = ?";
+        final String sql = "SELECT AVG(homeScore) as avgScored, AVG(awayScore) as avgConceded FROM SoccerResults WHERE homeScore != -1 AND homeTeamId = ?";
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
             stat.setInt(1, teamId);
 
@@ -267,15 +277,16 @@ public class GuiMysql extends Mysql {
         return returnValue;
     }
 
-    public List<Float> getAvgAwayScoreThisSeason(int teamId, int countryId, int leagueId) {
-        return getAvgAwayScoreThisSeason(teamId, countryId, leagueId, "");
+    public List<Float> getAvgHomeScoreThisSeason(int teamId, int countryId, int leagueId) {
+        return getAvgHomeScoreThisSeason(teamId, countryId, leagueId, "");
     }
 
-    public List<Float> getAvgAwayScoreThisSeason(int teamId, int countryId, int leagueId, String gameDate) {
+    public List<Float> getAvgHomeScoreThisSeason(int teamId, int countryId, int leagueId, String gameDate) {
         final ArrayList<Float> returnValue = Lists.newArrayList();
-        final String sql = "SELECT AVG(homeScore) as avgConcededSeason, AVG(awayScore) as avgScoredSeason FROM SoccerResults WHERE awayScore != -1 AND awayTeamId = ? AND season = ? AND DATE(gameDate) < ? ORDER BY gameDate ASC";
+        final String sql = "SELECT AVG(homeScore) as avgScoredSeason, AVG(awayScore) as avgConcededSeason FROM SoccerResults WHERE homeScore != -1 AND homeTeamId = ? AND season = ? AND DATE(gameDate) < ? ORDER BY gameDate ASC";
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
             stat.setInt(1, teamId);
+
             if (Strings.isNullOrEmpty(gameDate)
                     || getSeasonFromDate(countryId, leagueId, gameDate).equals(getLastSeason(countryId, leagueId))) {
                 stat.setString(2, getLastSeason(countryId, leagueId));
@@ -284,7 +295,7 @@ public class GuiMysql extends Mysql {
                 stat.setString(2, seasonFromDate);
             }
             if (Strings.isNullOrEmpty(gameDate)) {
-                stat.setString(3, new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
+                stat.setString(3, new SimpleDateFormat(DATE_FORMAT).format(new Date()));
             } else {
                 stat.setString(3, gameDate);
             }
@@ -303,257 +314,171 @@ public class GuiMysql extends Mysql {
         return returnValue;
     }
 
-    public List<Float> getLeagueAvarages(int leagueId, int countryId, String gameDate) {
-        final ArrayList<Float> returnValue = Lists.newArrayList();
-        final String sql = "SELECT AVG(homeScore) avgHomeScore, AVG(awayScore) as avgAwayScore"
-                + " FROM SoccerResults WHERE leagueId = ? AND countryId = ? AND DATE(gameDate) < DATE(?)";
+    public String getBetBaseAmount() {
+        String sql = "SELECT value FROM Settings WHERE name = ?";
+        String result = "";
+        try (PreparedStatement stat = conn.prepareStatement(sql)) {
+            stat.setString(1, "BetBaseAmount");
 
-        try (PreparedStatement stat = conn.prepareStatement(sql);) {
-            stat.setInt(1, leagueId);
-            stat.setInt(2, countryId);
-            stat.setString(3, gameDate);
+            ResultSet rs = stat.executeQuery();
 
-            final ResultSet rs = stat.executeQuery();
             while (rs.next()) {
-                returnValue.add(rs.getFloat("avgHomeScore"));
-                returnValue.add(rs.getFloat("avgAwayScore"));
+                result = rs.getString("value");
             }
-
-        } catch (final SQLException e) {
+        } catch (SQLException e) {
             e.printStackTrace();
         }
 
-        return returnValue;
+        return result;
     }
 
-    public Map<Integer, Integer> getGoalAvgThisSeason(int leagueId, int countryId) {
-        Map<Integer, Integer> returnValue = new HashMap<>();
-        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 (PreparedStatement goalStmt = conn.prepareStatement(goalsSql)) {
-            goalStmt.setInt(1, leagueId);
-            goalStmt.setInt(2, countryId);
-            goalStmt.setString(3, getLastSeason(countryId, leagueId));
-
-            final ResultSet goalRs = goalStmt.executeQuery();
+    public List<BetDTO> getBetSeries(boolean includeInactive) {
+        List<BetDTO> result = new ArrayList<>();
+        String sql = "SELECT ab.*, sr.gameDate as gameDate, sr.id as gameId, sr.homeScore as homeScore, sr.awayScore as awayScore, "
+                + "ht.name as homeTeam, aw.name as awayTeam " + "FROM ActiveBets ab "
+                + "INNER JOIN SoccerResults sr ON ab.gameId = sr.id "
+                + "INNER JOIN Team ht ON sr.homeTeamId = ht.id " + "INNER JOIN Team aw ON sr.awayTeamId = aw.id "
+                + "WHERE done = ? ORDER BY series ASC, sr.gameDate DESC";
 
-            while (goalRs.next()) {
-                int tg = goalRs.getInt("totalGoals");
-                if (tg < 0) {
-                    continue;
-                }
-                int numGoals = goalRs.getInt("count");
+        try (PreparedStatement stat = conn.prepareStatement(sql)) {
+            stat.setBoolean(1, includeInactive);
 
-                returnValue.put(tg, numGoals);
-            }
-        } catch (SQLException e) {
-            e.printStackTrace();
-        }
-        return returnValue;
-    }
+            ResultSet rs = stat.executeQuery();
 
-    public List<OverUnder> getStatsOverUnder(int leagueId) {
-        return getStatsOverUnder(leagueId, "");
+            while (rs.next()) {
+                BetDTO dto = new BetDTO();
+                dto.setHomeTeam(rs.getString("homeTeam"));
+                dto.setAwayTeam(rs.getString("awayTeam"));
+                dto.setBet(rs.getFloat("bet"));
+                dto.setBetType(rs.getString("betType"));
+                dto.setBetSeries(rs.getInt("series"));
+                dto.setGameId(rs.getInt("gameId"));
+                dto.setMatch(rs.getString("homeTeam"), rs.getString("awayTeam"));
+                dto.setOdds(rs.getFloat("odds"));
+                dto.setResult(rs.getInt(HOME_SCORE), rs.getInt("AwayScore"));
+                dto.setGameDate(rs.getString("gameDate"));
+                dto.setWinAmount(rs.getFloat("odds") * rs.getFloat("bet"));
+                result.add(dto);
+            }
+        } catch (SQLException e) {
+            e.printStackTrace();
+        }
+
+        return result;
     }
 
-    private List<String> getAllSeasons(int leagueId) {
-        List<String> returnValue = new ArrayList<String>();
-        String sql = "SELECT distinct(season) FROM SoccerResults WHERE leagueId = ?";
+    public int getBetSeriesEndNumber() {
+        int result = -1;
+        String sql = "SELECT MAX(series) FROM ActiveBets";
 
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setInt(1, leagueId);
-
             ResultSet rs = stat.executeQuery();
 
             while (rs.next()) {
-                returnValue.add(rs.getString("season"));
+                result = rs.getInt(1);
             }
         } catch (SQLException e) {
             e.printStackTrace();
         }
-        return returnValue;
-    }
 
-    public List<OverUnder> getStatsOverUnderWithDrawStats(int leagueId, String gameDate) {
-        final DecimalFormat df = new DecimalFormat("##.##");
-        df.setRoundingMode(RoundingMode.HALF_DOWN);
-        final ArrayList<OverUnder> result = Lists.newArrayList();
+        return result;
+    }
 
-        final String sql = "SELECT (homeScore + awayScore) as numGoals, count(case when homeScore = awayScore then 1 end) draws, ROUND((sHome.avgScored * sAway.avgConceded) + (sAway.avgScored * sHome.avgConceded),1) roundedDiff, count(*) as numGames "
-                + "FROM SoccerResults "
-                + "INNER JOIN (SELECT homeTeamId, AVG(homeScore) as avgScored, AVG(awayScore) as avgConceded FROM SoccerResults WHERE homeScore != -1 AND homeTeamId = SoccerResults.homeTeamId AND DATE(gameDate) < ? AND leagueId = ? GROUP BY homeTeamId) as sHome ON SoccerResults.homeTeamId = sHome.homeTeamId "
-                + "INNER JOIN (SELECT awayTeamId, AVG(homeScore) as avgConceded, AVG(awayScore) as avgScored FROM SoccerResults WHERE awayScore != -1 AND awayTeamId = SoccerResults.awayTeamId AND DATE(gameDate) < ? AND leagueId = ? GROUP BY awayTeamId) as sAway ON SoccerResults.awayTeamId = sAway.awayTeamId "
-                + "WHERE homeScore != -1 AND awayScore != -1 AND leagueId = ? AND DATE(gameDate) < ? GROUP BY roundedDiff;";
+    public List<SimpleEntry<Integer, String>> getCountries() {
 
-        List<String> allSeasons = getAllSeasons(leagueId);
+        final ArrayList<AbstractMap.SimpleEntry<Integer, String>> countries = Lists.newArrayList();
+        final String sql = "SELECT id, name FROM Country";
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            final String dateString;
-            if (Strings.isNullOrEmpty(gameDate)) {
-                dateString = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
-            } else {
-                dateString = gameDate;
-            }
-            for (String season : allSeasons) {
-                stat.setString(1, dateString);
-                stat.setInt(2, leagueId);
-                stat.setString(3, dateString);
-                stat.setInt(4, leagueId);
-
-                stat.setInt(5, leagueId);
-                stat.setString(6, dateString);
-
-                final ResultSet rs = stat.executeQuery();
 
-                while (rs.next()) {
-                    final float diff = rs.getFloat("roundedDiff");
-                    final int numGoals = rs.getInt("numGoals");
+            final ResultSet rs = stat.executeQuery();
 
-                    final OverUnder entry = result.stream().filter(ou -> ou.getKey().compareTo(diff) == 0)
-                            .findFirst()
-                            .orElse(new OverUnder(diff));
-                    entry.addGoalStat(numGoals);
-                    entry.setDraws(rs.getInt("draws"));
-                    entry.setTotalGames(rs.getInt("numGames"));
-                    result.add(entry);
-                }
+            while (rs.next()) {
+                final SimpleEntry<Integer, String> entry = new SimpleEntry<>(rs.getInt(Constants.ID),
+                        rs.getString("name"));
+                countries.add(entry);
             }
         } catch (final SQLException e) {
             e.printStackTrace();
         }
-        return result;
+        return countries;
     }
 
-    public List<OverUnder> getStatsOverUnder(int leagueId, String gameDate) {
-
-        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 homeTeamId, AVG(homeScore) as avgScored, AVG(awayScore) as avgConceded FROM SoccerResults WHERE homeScore != -1 AND homeTeamId = SoccerResults.homeTeamId AND DATE(gameDate) < ? AND season = ? AND leagueId = ? GROUP BY homeTeamId) as sHome ON SoccerResults.homeTeamId = sHome.homeTeamId "
-                + "INNER JOIN (SELECT awayTeamId, AVG(homeScore) as avgConceded, AVG(awayScore) as avgScored FROM SoccerResults WHERE awayScore != -1 AND awayTeamId = SoccerResults.awayTeamId AND DATE(gameDate) < ? AND season = ? AND leagueId = ? GROUP BY awayTeamId) as sAway ON SoccerResults.awayTeamId = sAway.awayTeamId "
-                + "WHERE homeScore != -1 AND awayScore != -1 AND leagueId = ? AND DATE(gameDate) < ? AND season = ? "
-                + "ORDER BY diff ASC";
-        List<String> allSeasons = getAllSeasons(leagueId);
-
+    public List<SimpleEntry<Integer, String>> getCountriesBySport(int sportId, String date) {
+        final String sql = "SELECT * FROM Country WHERE id IN (SELECT DISTINCT(countryId) FROM SoccerResults WHERE DATE(gameDate) = ?) ORDER BY prio DESC, name ASC";
+        final ArrayList<SimpleEntry<Integer, String>> result = new ArrayList<>();
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            final String dateString;
-            if (Strings.isNullOrEmpty(gameDate)) {
-                dateString = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
+            if (date.equals("")) {
+                stat.setString(1, new SimpleDateFormat(DATE_FORMAT).format(new Date()));
             } else {
-                dateString = gameDate;
+                stat.setString(1, date);
             }
-            for (String season : allSeasons) {
-                stat.setString(1, dateString);
-                stat.setString(2, season);
-                stat.setInt(3, leagueId);
-                stat.setString(4, dateString);
-                stat.setString(5, season);
-                stat.setInt(6, leagueId);
-
-                stat.setInt(7, leagueId);
-                stat.setString(8, dateString);
-                stat.setString(9, season);
-
-                final ResultSet rs = stat.executeQuery();
 
-                while (rs.next()) {
-                    final float diff = rs.getFloat("diff");
-                    final int numGoals = rs.getInt("numGoals");
-                    final Float formatted = round(BigDecimal.valueOf(diff), INCREMENT, RoundingMode.HALF_UP)
-                            .floatValue();
+            final ResultSet rs = stat.executeQuery();
 
-                    final OverUnder entry = result.stream().filter(ou -> ou.getKey().compareTo(formatted) == 0)
-                            .findFirst()
-                            .orElse(new OverUnder(formatted));
-                    entry.addGoalStat(numGoals);
-                    result.add(entry);
-                }
+            while (rs.next()) {
+                result.add(new SimpleEntry<>(rs.getInt(Constants.ID), rs.getString("name")));
             }
         } 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;
+        return result;
     }
 
-    public List<TeamStanding> getLeagueTable(int leagueId, String season, int countryId, String date) {
-        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 hometeamId team, homeScore, awayScore, season, gameDate, leagueId as league, countryId as country FROM SoccerResults "
-                + "union all SELECT awayteamId, awayScore, homeScore, season, gameDate, 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 AND DATE(gameDate) < DATE(?) group by team "
-                + "order by score desc, goal_diff desc";
+    public int getGameId(String homeTeam, String awayTeam, String gameDate, int countryId, int leagueId) {
+        int result = -1;
+        String sql = "SELECT id FROM SoccerResults WHERE homeTeamId = (SELECT id FROM Team WHERE name = ? AND countryId = ? AND leagueId = ?) AND awayTeamId = (SELECT id FROM Team WHERE name = ? AND countryId = ? AND leagueId = ?) AND DATE(gameDate) = DATE(?)";
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
+            stat.setString(1, homeTeam);
+            stat.setInt(2, countryId);
+            stat.setInt(3, leagueId);
+            stat.setString(4, awayTeam);
+            stat.setInt(5, countryId);
+            stat.setInt(6, leagueId);
+            stat.setString(7, gameDate);
 
-            stat.setString(1, season);
-            stat.setInt(2, leagueId);
-            stat.setInt(3, countryId);
-            stat.setString(4, date);
+            ResultSet rs = stat.executeQuery();
 
-            final ResultSet rs = stat.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(Constants.HOME_SCORE), rs.getFloat(Constants.AWAY_SCORE),
-                        rs.getFloat("goal_diff"));
-                result.add(ts);
+                result = rs.getInt("id");
             }
 
-        } catch (final SQLException e) {
-            Log.getLog().info("Sql vid fel: %s", sql);
+        } catch (SQLException e) {
             e.printStackTrace();
         }
 
         return result;
     }
 
-    public boolean getParsingStarted(int countryId, int leagueId) {
-        boolean returnValue = false;
-        final String sql = "SELECT parsedYear FROM League WHERE id = ? AND countryId = ?";
-        try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setInt(1, leagueId);
-            stat.setInt(2, countryId);
+    public Map<Integer, Integer> getGoalAvgThisSeason(int leagueId, int countryId) {
+        Map<Integer, Integer> returnValue = new HashMap<>();
+        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 (PreparedStatement goalStmt = conn.prepareStatement(goalsSql)) {
+            goalStmt.setInt(1, leagueId);
+            goalStmt.setInt(2, countryId);
+            goalStmt.setString(3, getLastSeason(countryId, leagueId));
 
-            final ResultSet rs = stat.executeQuery();
-            while (rs.next()) {
-                final String parsedYear = rs.getString("parsedYear");
-                if (!Strings.isNullOrEmpty(parsedYear)) {
-                    returnValue = true;
+            final ResultSet goalRs = goalStmt.executeQuery();
+
+            while (goalRs.next()) {
+                int tg = goalRs.getInt("totalGoals");
+                if (tg < 0) {
+                    continue;
                 }
+                int numGoals = goalRs.getInt("count");
+
+                returnValue.put(tg, numGoals);
             }
-        } catch (final SQLException e) {
+        } catch (SQLException e) {
             e.printStackTrace();
         }
-
         return returnValue;
     }
 
+    public BigDecimal getIncrement() {
+        return INCREMENT;
+    }
+
     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";
@@ -572,104 +497,90 @@ public class GuiMysql extends Mysql {
         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 (SELECT * FROM SoccerResults WHERE homeTeamId = ? AND "
-                    + "HomeScore >= 0 AND awayScore >= 0 AND DATE(gameDate) < DATE(NOW()) ORDER BY gameDate DESC LIMIT ?) as t";
-        } 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 (SELECT * FROM SoccerResults WHERE awayTeamId = ? AND "
-                    + "HomeScore >= 0 AND awayScore >= 0 AND DATE(gameDate) < DATE(NOW()) ORDER BY gameDate DESC LIMIT ?) as t";
-        }
+    public List<Float> getLeagueAvarages(int leagueId, int countryId, String gameDate) {
+        final ArrayList<Float> returnValue = Lists.newArrayList();
+        final String sql = "SELECT AVG(homeScore) avgHomeScore, AVG(awayScore) as avgAwayScore"
+                + " FROM SoccerResults WHERE leagueId = ? AND countryId = ? AND DATE(gameDate) < DATE(?)";
 
-        try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setInt(1, teamId);
-            stat.setInt(2, numResults);
-            final ResultSet rs = stat.executeQuery();
+        try (PreparedStatement stat = conn.prepareStatement(sql);) {
+            stat.setInt(1, leagueId);
+            stat.setInt(2, countryId);
+            stat.setString(3, gameDate);
 
+            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);
+                returnValue.add(rs.getFloat("avgHomeScore"));
+                returnValue.add(rs.getFloat("avgAwayScore"));
             }
+
         } catch (final SQLException e) {
             e.printStackTrace();
         }
 
-        return tr;
+        return returnValue;
     }
 
-    public TeamResults getTeamResultsTest(int teamId, int numResults, boolean isHomeTeam, String date) {
-        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 (SELECT * FROM SoccerResults WHERE homeTeamId = ? AND "
-                    + "HomeScore >= 0 AND awayScore >= 0 AND DATE(gameDate) < ? ORDER BY gameDate DESC LIMIT ?) as t";
-        } 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 (SELECT * FROM SoccerResults WHERE awayTeamId = ? AND "
-                    + "HomeScore >= 0 AND awayScore >= 0 AND DATE(gameDate) < ? ORDER BY gameDate DESC LIMIT ?) as t";
+    public League getLeagueInfo(int leagueId) {
+        final String sql = "SELECT * FROM League WHERE id = ?";
+        League result = null;
+        try (PreparedStatement stat = conn.prepareStatement(sql)) {
+            stat.setInt(1, leagueId);
+            final ResultSet rs = stat.executeQuery();
+
+            while (rs.next()) {
+                result = new League(rs.getInt(Constants.ID), rs.getString("name"), rs.getInt("scoringDiffLastGame"),
+                        rs.getInt("scoringTotal"),
+                        rs.getInt("winLossRatioHomeAndAway"), rs.getInt("winLossRatio"), rs.getInt("drawDiffHomeAway"),
+                        rs.getInt("drawDiffTotalGoals"), rs.getInt("drawWinningForm"),
+                        rs.getInt("drawWinningFormHomeAway"));
+            }
+        } catch (final SQLException e) {
+            e.printStackTrace();
         }
 
+        return result;
+    }
+
+    public League getLeagueInfo(String teamLeague) {
+        final String sql = "SELECT * FROM League WHERE name = ?";
+        League result = null;
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setInt(1, teamId);
-            stat.setString(2, date);
-            stat.setInt(3, numResults);
+            stat.setString(1, teamLeague);
             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);
+                result = new League(rs.getInt(Constants.ID), rs.getString("name"), rs.getInt("scoringDiffLastGame"),
+                        rs.getInt("scoringTotal"),
+                        rs.getInt("winLossRatioHomeAndAway"), rs.getInt("winLossRatio"), rs.getInt("drawDiffHomeAway"),
+                        rs.getInt("drawDiffTotalGoals"), rs.getInt("drawWinningForm"),
+                        rs.getInt("drawWinngingFormHomeAway"));
             }
-
         } catch (final SQLException e) {
             e.printStackTrace();
         }
 
-        return tr;
+        return result;
     }
 
-    public List<SimpleEntry<Integer, String>> getCountriesBySport(int sportId, String date) {
-        final String sql = "SELECT * FROM Country WHERE id IN (SELECT DISTINCT(countryId) FROM SoccerResults WHERE DATE(gameDate) = ?) ORDER BY prio DESC, name ASC";
-        final ArrayList<SimpleEntry<Integer, String>> result = new ArrayList<>();
+    public List<SimpleEntry<Integer, String>> getLeagues(int sportId, int countryId) {
+
+        final ArrayList<AbstractMap.SimpleEntry<Integer, String>> leagues = Lists.newArrayList();
+        final String sql = "SELECT id, name FROM League WHERE sportId = ? AND countryId = ? ORDER BY name ASC";
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            if (date.equals("")) {
-                stat.setString(1, new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
-            } else {
-                stat.setString(1, date);
-            }
+            stat.setInt(1, sportId);
+            stat.setInt(2, countryId);
 
             final ResultSet rs = stat.executeQuery();
 
             while (rs.next()) {
-                result.add(new SimpleEntry<>(rs.getInt(Constants.ID), rs.getString("name")));
+                final SimpleEntry<Integer, String> entry = new SimpleEntry<>(rs.getInt(Constants.ID),
+                        rs.getString("name"));
+                leagues.add(entry);
             }
         } catch (final SQLException e) {
             e.printStackTrace();
         }
-
-        return result;
+        return leagues;
     }
 
     public List<SimpleEntry<Integer, String>> getLeaguesByDate(int sportId, int countryId, String date) {
@@ -692,6 +603,48 @@ public class GuiMysql extends Mysql {
         return leagues;
     }
 
+    public List<TeamStanding> getLeagueTable(int leagueId, String season, int countryId, String date) {
+        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 hometeamId team, homeScore, awayScore, season, gameDate, leagueId as league, countryId as country FROM SoccerResults "
+                + "union all SELECT awayteamId, awayScore, homeScore, season, gameDate, 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 AND DATE(gameDate) < DATE(?) group by team "
+                + "order by score desc, goal_diff desc";
+        try (PreparedStatement stat = conn.prepareStatement(sql)) {
+
+            stat.setString(1, season);
+            stat.setInt(2, leagueId);
+            stat.setInt(3, countryId);
+            stat.setString(4, date);
+
+            final ResultSet rs = stat.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(Constants.HOME_SCORE), rs.getFloat(Constants.AWAY_SCORE),
+                        rs.getFloat("goal_diff"));
+                result.add(ts);
+            }
+
+        } catch (final SQLException e) {
+            Log.getLog().info("Sql vid fel: %s", sql);
+            e.printStackTrace();
+        }
+
+        return result;
+    }
+
     public List<SoccerMatch> getMatches(int sportId, Integer countryId, Integer leagueId, String date, String order,
             boolean exactDate,
             boolean onlyPrio) {
@@ -757,15 +710,15 @@ public class GuiMysql extends Mysql {
                 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("leagueName"));
-                awayTeam.setTeamLeague(rs.getString("leagueName"));
+                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("countryName"));
-                awayTeam.setCountryName(rs.getString("countryName"));
+                homeTeam.setCountryName(rs.getString(COUNTRY_NAME));
+                awayTeam.setCountryName(rs.getString(COUNTRY_NAME));
 
-                sm.setLeagueName(rs.getString("leagueName"));
-                sm.setCountryName(rs.getString("countryName"));
+                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);
@@ -790,480 +743,574 @@ public class GuiMysql extends Mysql {
         return matches;
     }
 
-    public League getLeagueInfo(String teamLeague) {
-        final String sql = "SELECT * FROM League WHERE name = ?";
-        League result = null;
+    public List<SoccerMatch> getMatches(int sportId, String dateString, String sortOrder, boolean exactDate) {
+        return getMatches(sportId, null, null, dateString, sortOrder, exactDate, true);
+    }
+
+    public boolean getParsingStarted(int countryId, int leagueId) {
+        boolean returnValue = false;
+        final String sql = "SELECT parsedYear FROM League WHERE id = ? AND countryId = ?";
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setString(1, teamLeague);
-            final ResultSet rs = stat.executeQuery();
+            stat.setInt(1, leagueId);
+            stat.setInt(2, countryId);
 
+            final ResultSet rs = stat.executeQuery();
             while (rs.next()) {
-                result = new League(rs.getInt(Constants.ID), rs.getString("name"), rs.getInt("scoringDiffLastGame"),
-                        rs.getInt("scoringTotal"),
-                        rs.getInt("winLossRatioHomeAndAway"), rs.getInt("winLossRatio"));
+                final String parsedYear = rs.getString("parsedYear");
+                if (!Strings.isNullOrEmpty(parsedYear)) {
+                    returnValue = true;
+                }
             }
         } catch (final SQLException e) {
             e.printStackTrace();
         }
 
-        return result;
+        return returnValue;
     }
 
-    public League getLeagueInfo(int leagueId) {
-        final String sql = "SELECT * FROM League WHERE id = ?";
-        League result = null;
-        try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setInt(1, leagueId);
-            final ResultSet rs = stat.executeQuery();
+    public Map<String, String> getPreviousMatches(int numberOfMatches, String homeTeamName, String awayTeamName,
+            String date, int countryId,
+            int leagueId) {
+        Map<String, String> result = new HashMap<>();
 
-            while (rs.next()) {
-                result = new League(rs.getInt(Constants.ID), rs.getString("name"), rs.getInt("scoringDiffLastGame"),
-                        rs.getInt("scoringTotal"),
-                        rs.getInt("winLossRatioHomeAndAway"), rs.getInt("winLossRatio"));
+        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 ?";
+        String awayTeamSql = "SELECT * FROM SoccerResults sr INNER JOIN Team t ON sr.awayTeamId = t.id WHERE t.name = ? AND sr.leagueId = ? AND DATE(gameDate) < ? ORDER BY gameDate DESC limit ?";
+        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);) {
+
+            homeTeamStat.setString(1, homeTeamName);
+            homeTeamStat.setInt(2, leagueId);
+            homeTeamStat.setString(3, date);
+            homeTeamStat.setInt(4, numberOfMatches);
+
+            awayTeamStat.setString(1, awayTeamName);
+            awayTeamStat.setInt(2, leagueId);
+            awayTeamStat.setString(3, date);
+            awayTeamStat.setInt(4, numberOfMatches);
+
+            combinedStat.setString(1, homeTeamName);
+            combinedStat.setString(2, awayTeamName);
+            combinedStat.setInt(3, leagueId);
+            combinedStat.setString(4, date);
+            combinedStat.setInt(5, numberOfMatches);
+
+            combinedReversedStat.setString(1, awayTeamName);
+            combinedReversedStat.setString(2, homeTeamName);
+            combinedReversedStat.setInt(3, leagueId);
+            combinedReversedStat.setString(4, date);
+            combinedReversedStat.setInt(5, numberOfMatches);
+
+            ResultSet homeTeamRs = homeTeamStat.executeQuery();
+            ResultSet awayTeamRs = awayTeamStat.executeQuery();
+            ResultSet combinedTeamRs = combinedStat.executeQuery();
+            ResultSet combinedReversedTeamRs = combinedReversedStat.executeQuery();
+
+            String homeTeamMeets = "";
+            while (homeTeamRs.next()) {
+                homeTeamMeets += homeTeamRs.getInt(HOME_SCORE) + "-" + homeTeamRs.getInt(AWAY_SCORE) + ", ";
             }
-        } catch (final SQLException e) {
+            String awayTeamMeets = "";
+            while (awayTeamRs.next()) {
+                awayTeamMeets += awayTeamRs.getInt(HOME_SCORE) + "-" + awayTeamRs.getInt(AWAY_SCORE) + ", ";
+            }
+            String combinedMeets = "";
+            while (combinedTeamRs.next()) {
+                combinedMeets += combinedTeamRs.getInt(HOME_SCORE) + "-" + combinedTeamRs.getInt(AWAY_SCORE) + ", ";
+            }
+            String combinedReversedMeets = "";
+            while (combinedReversedTeamRs.next()) {
+                combinedReversedMeets += combinedReversedTeamRs.getInt(HOME_SCORE) + "-"
+                        + combinedReversedTeamRs.getInt(AWAY_SCORE) + ", ";
+            }
+            if (homeTeamMeets.length() > 2) {
+                result.put("PrevHomeTeam", homeTeamMeets.substring(0, homeTeamMeets.length() - 2));
+            } else {
+                result.put("PrevHomeTeam", homeTeamMeets);
+            }
+            if (awayTeamMeets.length() > 2) {
+                result.put("PrevAwayTeam", awayTeamMeets.substring(0, awayTeamMeets.length() - 2));
+            } else {
+                result.put("PrevAwayTeam", awayTeamMeets);
+            }
+            if (combinedMeets.length() > 2) {
+                result.put("PrevCombined", combinedMeets.substring(0, combinedMeets.length() - 2));
+            } else {
+                result.put("PrevCombined", combinedMeets);
+            }
+
+            if (combinedReversedMeets.length() > 2) {
+                result.put("PrevReversedCombined",
+                        combinedReversedMeets.substring(0, combinedReversedMeets.length() - 2));
+            } else {
+                result.put("PrevReversedCombined", combinedReversedMeets);
+            }
+
+        } catch (SQLException e) {
             e.printStackTrace();
         }
 
         return result;
     }
 
-    public void setTeamMarginHome(int teamId, int marginHome) {
-        final String sql = "UPDATE Team SET marginHome = ? WHERE id = ?";
-
+    public String getSeasonFromDate(int countryId, int leagueId, String gameDate) {
+        String sql = "SELECT season FROM SoccerResults WHERE DATE(gameDate) = ? AND countryId = ? AND leagueId = ? LIMIT 1";
+        String returnValue = "";
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setInt(1, marginHome);
-            stat.setInt(2, teamId);
-
-            stat.executeUpdate();
+            if (Strings.isNullOrEmpty(gameDate)) {
+                stat.setString(1, new SimpleDateFormat(DATE_FORMAT).format(new Date()));
+            } else {
+                stat.setString(1, gameDate);
+            }
+            stat.setInt(2, countryId);
+            stat.setInt(3, leagueId);
 
-        } catch (final SQLException e) {
+            ResultSet rs = stat.executeQuery();
+            while (rs.next()) {
+                returnValue = rs.getString(SEASON);
+            }
+        } catch (SQLException e) {
             e.printStackTrace();
         }
+        return returnValue;
     }
 
-    public void setTeamMarginDraw(int teamId, int marginDraw) {
-        final String sql = "UPDATE Team SET marginDraw = ? WHERE id = ?";
+    public List<SimpleEntry<Integer, String>> getSports() {
 
+        final ArrayList<AbstractMap.SimpleEntry<Integer, String>> sports = Lists.newArrayList();
+        final String sql = "SELECT id, name FROM Sport";
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setInt(1, marginDraw);
-            stat.setInt(2, teamId);
 
-            stat.executeUpdate();
+            final ResultSet rs = stat.executeQuery();
 
+            while (rs.next()) {
+                final SimpleEntry<Integer, String> entry = new SimpleEntry<>(rs.getInt(Constants.ID),
+                        rs.getString("name"));
+                sports.add(entry);
+            }
         } catch (final SQLException e) {
             e.printStackTrace();
         }
-    }
 
-    public void setTeamMarginAway(int teamId, int marginAway) {
-        final String sql = "UPDATE Team SET marginAway = ? WHERE id = ?";
-
-        try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setInt(1, marginAway);
-            stat.setInt(2, teamId);
-
-            stat.executeUpdate();
+        return sports;
+    }
 
-        } catch (final SQLException e) {
-            e.printStackTrace();
-        }
+    public List<OverUnder> getStatsOverUnder(int leagueId) {
+        return getStatsOverUnder(leagueId, "");
     }
 
-    public void setTeamLookbackHome(int teamId, int lookbackHome) {
-        final String sql = "UPDATE Team SET lookbackHome = ? WHERE id = ?";
+    public List<OverUnder> getStatsOverUnder(int leagueId, String gameDate) {
 
-        try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setInt(1, lookbackHome);
-            stat.setInt(2, teamId);
+        final DecimalFormat df = new DecimalFormat("##.##");
+        df.setRoundingMode(RoundingMode.HALF_DOWN);
+        final ArrayList<OverUnder> result = Lists.newArrayList();
 
-            stat.executeUpdate();
+        final String sql = "SELECT ((sHome.avgScored * sAway.avgConceded) + (sAway.avgScored * sHome.avgConceded)) as diff, (homeScore + awayScore) as numGoals "
+                + "FROM SoccerResults "
+                + "INNER JOIN (SELECT homeTeamId, AVG(homeScore) as avgScored, AVG(awayScore) as avgConceded FROM SoccerResults WHERE homeScore != -1 AND homeTeamId = SoccerResults.homeTeamId AND DATE(gameDate) < ? AND season = ? AND leagueId = ? GROUP BY homeTeamId) as sHome ON SoccerResults.homeTeamId = sHome.homeTeamId "
+                + "INNER JOIN (SELECT awayTeamId, AVG(homeScore) as avgConceded, AVG(awayScore) as avgScored FROM SoccerResults WHERE awayScore != -1 AND awayTeamId = SoccerResults.awayTeamId AND DATE(gameDate) < ? AND season = ? AND leagueId = ? GROUP BY awayTeamId) as sAway ON SoccerResults.awayTeamId = sAway.awayTeamId "
+                + "WHERE homeScore != -1 AND awayScore != -1 AND leagueId = ? AND DATE(gameDate) < ? AND season = ? "
+                + "ORDER BY diff ASC";
+        List<String> allSeasons = getAllSeasons(leagueId);
 
-        } catch (final SQLException e) {
-            e.printStackTrace();
-        }
-    }
+        try (PreparedStatement stat = conn.prepareStatement(sql)) {
+            final String dateString;
+            if (Strings.isNullOrEmpty(gameDate)) {
+                dateString = new SimpleDateFormat(DATE_FORMAT).format(new Date());
+            } else {
+                dateString = gameDate;
+            }
+            for (String season : allSeasons) {
+                stat.setString(1, dateString);
+                stat.setString(2, season);
+                stat.setInt(3, leagueId);
+                stat.setString(4, dateString);
+                stat.setString(5, season);
+                stat.setInt(6, leagueId);
 
-    public void setTeamLookbackDraw(int teamId, int lookbackDraw) {
-        final String sql = "UPDATE Team SET lookbackDraw = ? WHERE id = ?";
+                stat.setInt(7, leagueId);
+                stat.setString(8, dateString);
+                stat.setString(9, season);
 
-        try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setInt(1, lookbackDraw);
-            stat.setInt(2, teamId);
+                final ResultSet rs = stat.executeQuery();
 
-            stat.executeUpdate();
+                while (rs.next()) {
+                    final float diff = rs.getFloat("diff");
+                    final int numGoals = rs.getInt("numGoals");
+                    final Float formatted = round(BigDecimal.valueOf(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 void setTeamLookbackAway(int teamId, int lookbackAway) {
-        final String sql = "UPDATE Team SET lookbackAway = ? WHERE id = ?";
+    public List<OverUnder> getStatsOverUnderWithDrawStats(int leagueId, String gameDate) {
+        final DecimalFormat df = new DecimalFormat("##.##");
+        df.setRoundingMode(RoundingMode.HALF_DOWN);
+        final ArrayList<OverUnder> result = Lists.newArrayList();
+
+        final String sql = "SELECT (homeScore + awayScore) as numGoals, count(case when homeScore = awayScore then 1 end) draws, ROUND((sHome.avgScored * sAway.avgConceded) + (sAway.avgScored * sHome.avgConceded),1) roundedDiff, count(*) as numGames "
+                + "FROM SoccerResults "
+                + "INNER JOIN (SELECT homeTeamId, AVG(homeScore) as avgScored, AVG(awayScore) as avgConceded FROM SoccerResults WHERE homeScore != -1 AND homeTeamId = SoccerResults.homeTeamId AND DATE(gameDate) < ? AND leagueId = ? GROUP BY homeTeamId) as sHome ON SoccerResults.homeTeamId = sHome.homeTeamId "
+                + "INNER JOIN (SELECT awayTeamId, AVG(homeScore) as avgConceded, AVG(awayScore) as avgScored FROM SoccerResults WHERE awayScore != -1 AND awayTeamId = SoccerResults.awayTeamId AND DATE(gameDate) < ? AND leagueId = ? GROUP BY awayTeamId) as sAway ON SoccerResults.awayTeamId = sAway.awayTeamId "
+                + "WHERE homeScore != -1 AND awayScore != -1 AND leagueId = ? AND DATE(gameDate) < ? GROUP BY roundedDiff;";
 
+        List<String> allSeasons = getAllSeasons(leagueId);
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setInt(1, lookbackAway);
-            stat.setInt(2, teamId);
+            final String dateString;
+            if (Strings.isNullOrEmpty(gameDate)) {
+                dateString = new SimpleDateFormat(DATE_FORMAT).format(new Date());
+            } else {
+                dateString = gameDate;
+            }
+            for (String season : allSeasons) {
+                stat.setString(1, dateString);
+                stat.setInt(2, leagueId);
+                stat.setString(3, dateString);
+                stat.setInt(4, leagueId);
 
-            stat.executeUpdate();
+                stat.setInt(5, leagueId);
+                stat.setString(6, dateString);
 
+                final ResultSet rs = stat.executeQuery();
+
+                while (rs.next()) {
+                    final float diff = rs.getFloat("roundedDiff");
+                    final int numGoals = rs.getInt("numGoals");
+
+                    final OverUnder entry = result.stream().filter(ou -> ou.getKey().compareTo(diff) == 0)
+                            .findFirst()
+                            .orElse(new OverUnder(diff));
+                    entry.addGoalStat(numGoals);
+                    entry.setDraws(rs.getInt(DRAWS));
+                    entry.setTotalGames(rs.getInt("numGames"));
+                    result.add(entry);
+                }
+            }
         } catch (final SQLException e) {
             e.printStackTrace();
         }
+        return result;
     }
 
-    public List<BetDTO> getBetSeries(boolean includeInactive) {
-        List<BetDTO> result = new ArrayList<>();
-        String sql = "SELECT ab.*, sr.gameDate as gameDate, sr.id as gameId, sr.homeScore as homeScore, sr.awayScore as awayScore, "
-                + "ht.name as homeTeam, aw.name as awayTeam " + "FROM ActiveBets ab "
-                + "INNER JOIN SoccerResults sr ON ab.gameId = sr.id "
-                + "INNER JOIN Team ht ON sr.homeTeamId = ht.id " + "INNER JOIN Team aw ON sr.awayTeamId = aw.id "
-                + "WHERE done = ? ORDER BY series ASC, sr.gameDate DESC";
-
+    public Team getTeam(int teamId) {
+        Team result = null;
+        String sql = "SELECT t.*, c.name as countryName, l.name AS leagueName FROM Team t "
+                + "INNER JOIN Country c ON t.countryId = c.id "
+                + "INNER JOIN League l ON t.leagueId = l.id "
+                + "WHERE t.id = ? ";
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setBoolean(1, includeInactive);
+            stat.setInt(1, teamId);
 
             ResultSet rs = stat.executeQuery();
 
             while (rs.next()) {
-                BetDTO dto = new BetDTO();
-                dto.setHomeTeam(rs.getString("homeTeam"));
-                dto.setAwayTeam(rs.getString("awayTeam"));
-                dto.setBet(rs.getFloat("bet"));
-                dto.setBetType(rs.getString("betType"));
-                dto.setBetSeries(rs.getInt("series"));
-                dto.setGameId(rs.getInt("gameId"));
-                dto.setMatch(rs.getString("homeTeam"), rs.getString("awayTeam"));
-                dto.setOdds(rs.getFloat("odds"));
-                dto.setResult(rs.getInt("homeScore"), rs.getInt("AwayScore"));
-                dto.setGameDate(rs.getString("gameDate"));
-                dto.setWinAmount(rs.getFloat("odds") * rs.getFloat("bet"));
-                result.add(dto);
+                result = new Team(rs.getInt("id"), rs.getString("name"), rs.getInt("countryId"),
+                        rs.getString(COUNTRY_NAME), rs.getInt("leagueId"), rs.getString(LEAGUE_NAME));
             }
         } catch (SQLException e) {
             e.printStackTrace();
         }
-
         return result;
     }
 
-    public void addBetSeries(BetDTO bet) {
-        String sql = "INSERT INTO ActiveBets (series, gameId, betType, bet, odds, done) VALUES (?, ?, ?, ?, ?, ?)";
-
-        try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setInt(1, bet.getBetSeries());
-            stat.setInt(2, getGameId(bet.getHomeTeam(), bet.getAwayTeam(), bet.getGameDate(), bet.getCountryId(),
-                    bet.getLeagueId()));
-            stat.setString(3, bet.getBetType());
-            stat.setFloat(4, bet.getBet());
-            stat.setFloat(5, bet.getOdds());
-            stat.setBoolean(6, false);
-
-            stat.execute();
-        } catch (SQLException e) {
-            e.printStackTrace();
+    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 (SELECT * FROM SoccerResults WHERE homeTeamId = ? AND "
+                    + "HomeScore >= 0 AND awayScore >= 0 AND DATE(gameDate) < DATE(NOW()) ORDER BY gameDate DESC LIMIT ?) as t";
+        } 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 (SELECT * FROM SoccerResults WHERE awayTeamId = ? AND "
+                    + "HomeScore >= 0 AND awayScore >= 0 AND DATE(gameDate) < DATE(NOW()) ORDER BY gameDate DESC LIMIT ?) as t";
         }
-    }
 
-    public int getGameId(String homeTeam, String awayTeam, String gameDate, int countryId, int leagueId) {
-        int result = -1;
-        String sql = "SELECT id FROM SoccerResults WHERE homeTeamId = (SELECT id FROM Team WHERE name = ? AND countryId = ? AND leagueId = ?) AND awayTeamId = (SELECT id FROM Team WHERE name = ? AND countryId = ? AND leagueId = ?) AND DATE(gameDate) = DATE(?)";
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setString(1, homeTeam);
-            stat.setInt(2, countryId);
-            stat.setInt(3, leagueId);
-            stat.setString(4, awayTeam);
-            stat.setInt(5, countryId);
-            stat.setInt(6, leagueId);
-            stat.setString(7, gameDate);
-
-            ResultSet rs = stat.executeQuery();
+            stat.setInt(1, teamId);
+            stat.setInt(2, numResults);
+            final ResultSet rs = stat.executeQuery();
 
             while (rs.next()) {
-                result = rs.getInt("id");
+                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 (SQLException e) {
+        } catch (final SQLException e) {
             e.printStackTrace();
         }
 
-        return result;
+        return tr;
     }
 
-    public Map<String, String> getPreviousMatches(int numberOfMatches, String homeTeamName, String awayTeamName,
-            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 ?";
-        String awayTeamSql = "SELECT * FROM SoccerResults sr INNER JOIN Team t ON sr.awayTeamId = t.id WHERE t.name = ? AND sr.leagueId = ? AND DATE(gameDate) < ? ORDER BY gameDate DESC limit ?";
-        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);) {
-
-            homeTeamStat.setString(1, homeTeamName);
-            homeTeamStat.setInt(2, leagueId);
-            homeTeamStat.setString(3, date);
-            homeTeamStat.setInt(4, numberOfMatches);
-
-            awayTeamStat.setString(1, awayTeamName);
-            awayTeamStat.setInt(2, leagueId);
-            awayTeamStat.setString(3, date);
-            awayTeamStat.setInt(4, numberOfMatches);
-
-            combinedStat.setString(1, homeTeamName);
-            combinedStat.setString(2, awayTeamName);
-            combinedStat.setInt(3, leagueId);
-            combinedStat.setString(4, date);
-            combinedStat.setInt(5, numberOfMatches);
-
-            combinedReversedStat.setString(1, awayTeamName);
-            combinedReversedStat.setString(2, homeTeamName);
-            combinedReversedStat.setInt(3, leagueId);
-            combinedReversedStat.setString(4, date);
-            combinedReversedStat.setInt(5, numberOfMatches);
-
-            ResultSet homeTeamRs = homeTeamStat.executeQuery();
-            ResultSet awayTeamRs = awayTeamStat.executeQuery();
-            ResultSet combinedTeamRs = combinedStat.executeQuery();
-            ResultSet combinedReversedTeamRs = combinedReversedStat.executeQuery();
-
-            String homeTeamMeets = "";
-            while (homeTeamRs.next()) {
-                homeTeamMeets += homeTeamRs.getInt("homeScore") + "-" + homeTeamRs.getInt("awayScore") + ", ";
-            }
-            String awayTeamMeets = "";
-            while (awayTeamRs.next()) {
-                awayTeamMeets += awayTeamRs.getInt("homeScore") + "-" + awayTeamRs.getInt("awayScore") + ", ";
-            }
-            String combinedMeets = "";
-            while (combinedTeamRs.next()) {
-                combinedMeets += combinedTeamRs.getInt("homeScore") + "-" + combinedTeamRs.getInt("awayScore") + ", ";
-            }
-            String combinedReversedMeets = "";
-            while (combinedReversedTeamRs.next()) {
-                combinedReversedMeets += combinedReversedTeamRs.getInt("homeScore") + "-"
-                        + combinedReversedTeamRs.getInt("awayScore") + ", ";
-            }
-            if (homeTeamMeets.length() > 2) {
-                result.put("PrevHomeTeam", homeTeamMeets.substring(0, homeTeamMeets.length() - 2));
-            } else {
-                result.put("PrevHomeTeam", homeTeamMeets);
-            }
-            if (awayTeamMeets.length() > 2) {
-                result.put("PrevAwayTeam", awayTeamMeets.substring(0, awayTeamMeets.length() - 2));
-            } else {
-                result.put("PrevAwayTeam", awayTeamMeets);
-            }
-            if (combinedMeets.length() > 2) {
-                result.put("PrevCombined", combinedMeets.substring(0, combinedMeets.length() - 2));
-            } else {
-                result.put("PrevCombined", combinedMeets);
-            }
+    public TeamResults getTeamResultsTest(int teamId, int numResults, boolean isHomeTeam, String date) {
+        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 (SELECT * FROM SoccerResults WHERE homeTeamId = ? AND "
+                    + "HomeScore >= 0 AND awayScore >= 0 AND DATE(gameDate) < ? ORDER BY gameDate DESC LIMIT ?) as t";
+        } 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 (SELECT * FROM SoccerResults WHERE awayTeamId = ? AND "
+                    + "HomeScore >= 0 AND awayScore >= 0 AND DATE(gameDate) < ? ORDER BY gameDate DESC LIMIT ?) as t";
+        }
 
-            if (combinedReversedMeets.length() > 2) {
-                result.put("PrevReversedCombined",
-                        combinedReversedMeets.substring(0, combinedReversedMeets.length() - 2));
-            } else {
-                result.put("PrevReversedCombined", combinedReversedMeets);
+        try (PreparedStatement stat = conn.prepareStatement(sql)) {
+            stat.setInt(1, teamId);
+            stat.setString(2, date);
+            stat.setInt(3, 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 (SQLException e) {
+        } catch (final SQLException e) {
             e.printStackTrace();
         }
 
-        return result;
+        return tr;
     }
 
-    public int getBetSeriesEndNumber() {
-        int result = -1;
-        String sql = "SELECT MAX(series) FROM ActiveBets";
+    public List<SoccerMatch> getUpcomingMatches(String sportResultTable) {
+        final ArrayList<SoccerMatch> matches = Lists.newArrayList();
+        final String dateSql;
+        dateSql = " AND DATE(gameDate) >= DATE(now())";
+
+        final String sql = "SELECT res.id, homeTeamId, awayTeamId, 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, "
+                + "country.prio as prio " + "FROM " + sportResultTable + " as res "
+                + "Join Team as hTeam ON res.homeTeamId = hTeam.id "
+                + "Join Team as aTeam ON res.awayTeamId = aTeam.id "
+                + "Join League as league ON res.leagueId = league.id "
+                + "Join Country as country ON res.countryId = country.id " + "WHERE homeScore = -1 " + dateSql
+                + "AND league.name NOT LIKE '%cup%' AND league.name NOT LIKE '%group%' AND league.prio = 1 "
+                + "ORDER BY country.prio DESC, country.name ASC";
 
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            ResultSet rs = stat.executeQuery();
 
+            final ResultSet rs = stat.executeQuery();
             while (rs.next()) {
-                result = rs.getInt(1);
+                final SoccerMatch sm = new SoccerMatch();
+                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(Constants.LEAGUE_NAME));
+                awayTeam.setTeamLeague(rs.getString(Constants.LEAGUE_NAME));
+                homeTeam.setCountryId(rs.getInt(Constants.COUNTRY_ID));
+                awayTeam.setCountryId(rs.getInt(Constants.COUNTRY_ID));
+                homeTeam.setCountryName(rs.getString(Constants.COUNTRY_NAME));
+                awayTeam.setCountryName(rs.getString(Constants.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.setCountryPrio(rs.getBoolean("prio"));
+
+                matches.add(sm);
             }
-        } catch (SQLException e) {
+
+        } catch (final SQLException e) {
             e.printStackTrace();
         }
 
-        return result;
+        return matches;
     }
 
-    public List<SoccerMatch> getMatches(int sportId, String dateString, String sortOrder, boolean exactDate) {
-        return getMatches(sportId, null, null, dateString, sortOrder, exactDate, true);
+    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 void updateBetBaseAmount(String value) {
-        String sql = "INSERT INTO Settings (name, value) VALUES (?, ?) ON DUPLICATE KEY UPDATE value = ?";
-
+    public void setBetCovered(int id, int coveredBetId) {
+        String sql = "UPDATE AnalysisBetTable SET coveredBetId = ? WHERE id = ?";
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setString(1, "BetBaseAmount");
-            stat.setString(2, value);
-            stat.setString(3, value);
+            stat.setInt(1, coveredBetId);
+            stat.setInt(2, id);
 
-            stat.execute();
+            stat.executeUpdate();
         } catch (SQLException e) {
             e.printStackTrace();
         }
     }
 
-    public String getBetBaseAmount() {
-        String sql = "SELECT value FROM Settings WHERE name = ?";
-        String result = "";
+    public void setTeamLookbackAway(int teamId, int lookbackAway) {
+        final String sql = "UPDATE Team SET lookbackAway = ? WHERE id = ?";
+
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setString(1, "BetBaseAmount");
+            stat.setInt(1, lookbackAway);
+            stat.setInt(2, teamId);
 
-            ResultSet rs = stat.executeQuery();
+            stat.executeUpdate();
 
-            while (rs.next()) {
-                result = rs.getString("value");
-            }
-        } catch (SQLException e) {
+        } catch (final SQLException e) {
             e.printStackTrace();
         }
-
-        return result;
     }
 
-    public void updateBetStatus(int betId, Status newStatus) {
-        String sql = "UPDATE AnalysisBetTable SET status = ? WHERE id = ?";
+    public void setTeamLookbackDraw(int teamId, int lookbackDraw) {
+        final String sql = "UPDATE Team SET lookbackDraw = ? WHERE id = ?";
 
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setString(1, newStatus.name());
-            stat.setInt(2, betId);
+            stat.setInt(1, lookbackDraw);
+            stat.setInt(2, teamId);
 
             stat.executeUpdate();
-        } catch (SQLException e) {
+
+        } catch (final SQLException e) {
             e.printStackTrace();
         }
     }
 
-    public Team getTeam(int teamId) {
-        Team result = null;
-        String sql = "SELECT t.*, c.name as countryName, l.name AS leagueName FROM Team t "
-                + "INNER JOIN Country c ON t.countryId = c.id "
-                + "INNER JOIN League l ON t.leagueId = l.id "
-                + "WHERE t.id = ? ";
+    public void setTeamLookbackHome(int teamId, int lookbackHome) {
+        final String sql = "UPDATE Team SET lookbackHome = ? WHERE id = ?";
+
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setInt(1, teamId);
+            stat.setInt(1, lookbackHome);
+            stat.setInt(2, teamId);
 
-            ResultSet rs = stat.executeQuery();
+            stat.executeUpdate();
 
-            while (rs.next()) {
-                result = new Team(rs.getInt("id"), rs.getString("name"), rs.getInt("countryId"),
-                        rs.getString("countryName"), rs.getInt("leagueId"), rs.getString("leagueName"));
-            }
-        } catch (SQLException e) {
+        } catch (final SQLException e) {
             e.printStackTrace();
         }
-        return result;
     }
 
-    public List<Bet> getAnalysisBets() {
-        List<Bet> result = new ArrayList<>();
-        String sql = "SELECT * FROM AnalysisBetTable abt "
-                + "INNER JOIN SoccerResults sr ON abt.matchId = sr.id "
-                + "WHERE status IN ('LOST', 'OPEN', 'COVERED')";
+    public void setTeamMarginAway(int teamId, int marginAway) {
+        final String sql = "UPDATE Team SET marginAway = ? WHERE id = ?";
 
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            ResultSet rs = stat.executeQuery();
+            stat.setInt(1, marginAway);
+            stat.setInt(2, teamId);
 
-            while (rs.next()) {
+            stat.executeUpdate();
 
-                Team homeTeam = getTeam(rs.getInt("homeTeamId"));
-                Team awayTeam = getTeam(rs.getInt("awayTeamId"));
-                SoccerMatch match = new SoccerMatch(rs.getInt("matchId"), homeTeam, awayTeam, rs.getFloat("odds1"),
-                        rs.getFloat("oddsX"), rs.getFloat("odds2"), rs.getInt("homeScore"), rs.getInt("awayScore"),
-                        LocalDateTime.parse(rs.getString("gameDate")), rs.getString("season"));
+        } catch (final SQLException e) {
+            e.printStackTrace();
+        }
+    }
 
-                match.setLeagueName(homeTeam.getTeamLeague());
-                match.setCountryName(homeTeam.getCountryName());
+    public void setTeamMarginDraw(int teamId, int marginDraw) {
+        final String sql = "UPDATE Team SET marginDraw = ? WHERE id = ?";
 
-                result.add(new Bet(rs.getInt("id"), match, rs.getString("bet"), rs.getFloat("betAmount"),
-                        rs.getFloat("betOdds"),
-                        Status.valueOf(rs.getString("status")), rs.getInt("coveredBetId")));
-            }
+        try (PreparedStatement stat = conn.prepareStatement(sql)) {
+            stat.setInt(1, marginDraw);
+            stat.setInt(2, teamId);
 
-        } catch (SQLException e) {
+            stat.executeUpdate();
+
+        } catch (final SQLException e) {
             e.printStackTrace();
         }
-        return result;
     }
 
-    public int addAnalysisBet(Bet bet) {
-        int newId = -1;
-        String sql = "INSERT INTO AnalysisBetTable (matchId, bet, betAmount, betOdds, status) VALUES (?,?,?,?,?)";
-
-        try (PreparedStatement stat = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
-            stat.setInt(1, bet.getMatch().getMatchId());
-            stat.setString(2, bet.getBet());
-            stat.setFloat(3, bet.getBetAmount());
-            stat.setFloat(4, bet.getBetOdds());
-            stat.setString(5, bet.getStatus().name());
-
-            stat.execute();
+    public void setTeamMarginHome(int teamId, int marginHome) {
+        final String sql = "UPDATE Team SET marginHome = ? WHERE id = ?";
 
-            ResultSet generatedKeys = stat.getGeneratedKeys();
+        try (PreparedStatement stat = conn.prepareStatement(sql)) {
+            stat.setInt(1, marginHome);
+            stat.setInt(2, teamId);
 
-            while (generatedKeys.next()) {
-                newId = generatedKeys.getInt(1);
-            }
+            stat.executeUpdate();
 
-        } catch (SQLException e) {
+        } catch (final SQLException e) {
             e.printStackTrace();
         }
-
-        return newId;
     }
 
-    public Bet getAnalysisBet(int betId) {
-        Bet result = null;
-        String sql = "SELECT * FROM AnalysisBetTable abt "
-                + "INNER JOIN SoccerResults sr ON abt.matchId = sr.id "
-                + "WHERE abt.id = ?";
+    public void updateBetBaseAmount(String value) {
+        String sql = "INSERT INTO Settings (name, value) VALUES (?, ?) ON DUPLICATE KEY UPDATE value = ?";
 
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setInt(1, betId);
-
-            ResultSet rs = stat.executeQuery();
+            stat.setString(1, "BetBaseAmount");
+            stat.setString(2, value);
+            stat.setString(3, value);
 
-            while (rs.next()) {
-                Team homeTeam = getTeam(rs.getInt("homeTeamId"));
-                Team awayTeam = getTeam(rs.getInt("awayTeamId"));
-                SoccerMatch match = new SoccerMatch(rs.getInt("matchId"), homeTeam, awayTeam, rs.getFloat("odds1"),
-                        rs.getFloat("oddsX"), rs.getFloat("odds2"), rs.getInt("homeScore"), rs.getInt("awayScore"),
-                        LocalDateTime.parse(rs.getString("gameDate")), rs.getString("season"));
+            stat.execute();
+        } catch (SQLException e) {
+            e.printStackTrace();
+        }
+    }
 
-                match.setLeagueName(homeTeam.getTeamLeague());
-                match.setCountryName(homeTeam.getCountryName());
+    public void updateBetStatus(int betId, Status newStatus) {
+        String sql = "UPDATE AnalysisBetTable SET status = ? WHERE id = ?";
 
-                result = new Bet(rs.getInt("id"), match, rs.getString("bet"), rs.getFloat("betAmount"),
-                        rs.getFloat("betOdds"),
-                        Status.valueOf(rs.getString("status")), rs.getInt("coveredBetId"));
-            }
+        try (PreparedStatement stat = conn.prepareStatement(sql)) {
+            stat.setString(1, newStatus.name());
+            stat.setInt(2, betId);
 
+            stat.executeUpdate();
         } catch (SQLException e) {
             e.printStackTrace();
         }
-
-        return result;
     }
 
-    public void setBetCovered(int id, int coveredBetId) {
-        String sql = "UPDATE AnalysisBetTable SET coveredBetId = ? WHERE id = ?";
+    private List<String> getAllSeasons(int leagueId) {
+        List<String> returnValue = new ArrayList<>();
+        String sql = "SELECT distinct(season) FROM SoccerResults WHERE leagueId = ?";
+
         try (PreparedStatement stat = conn.prepareStatement(sql)) {
-            stat.setInt(1, coveredBetId);
-            stat.setInt(2, id);
+            stat.setInt(1, leagueId);
 
-            stat.executeUpdate();
+            ResultSet rs = stat.executeQuery();
+
+            while (rs.next()) {
+                returnValue.add(rs.getString(SEASON));
+            }
         } catch (SQLException e) {
             e.printStackTrace();
         }
+        return returnValue;
     }
 }

+ 1 - 1
OddsJavaFx/src/fxml/AnalysisTesting.fxml

@@ -53,7 +53,7 @@
                                        <children>
                                           <Button fx:id="checkBetsButton" mnemonicParsing="false" onAction="#CheckBetsAction" text="Check bets" />
                                           <Button mnemonicParsing="false" onAction="#RemoveDoneBetsAction" text="Remove Done bets" />
-                                          <TableView fx:id="LeagueBetStatsTable" prefHeight="200.0" prefWidth="200.0">
+                                          <TableView fx:id="leagueBetStatsTable" prefHeight="200.0" prefWidth="200.0">
                                             <columns>
                                               <TableColumn fx:id="statsLeagueNameColumn" prefWidth="75.0" text="League" />
                                               <TableColumn fx:id="statsHomeWinColumn" prefWidth="75.0" text="Home Wins" />

+ 1 - 0
OddsJavaFx/src/fxml/Testing.fxml

@@ -67,6 +67,7 @@
                                     <Button onAction="#goalDiffTest" text="GoalDiff" />
                                     <Button onAction="#relevanceTest" text="Test for Relevance" />
                                     <Button onAction="#analysisTets" text="Analysis Test" />
+                                    <Button onAction="#analysisDrawTests" text="Analysis DRAW Test" />
                                     
                                  </children>
                               </VBox>

+ 88 - 47
OddsJavaFx/src/objects/League.java

@@ -19,15 +19,56 @@ public class League {
     int scoringTotal;
     int winLossRatioHomeAndAway;
     int winLossRatio;
+    private int drawDiffHomeAway;
+    private int drawTotalGoals;
+    private int drawWinningForm;
+    private int drawWinningFormHomeAway;
 
     public League(int leagueId, String leagueName, int scoringDiffLastGame,
-            int scoringTotal, int winLossRatioHomeAndAway, int winLossRatio) {
+            int scoringTotal, int winLossRatioHomeAndAway, int winLossRatio, int drawDiffHomeAway, int drawTotalGoals,
+            int drawWinningForm, int drawWinningFormHomeAway) {
         this.leagueId = leagueId;
         this.leagueName = leagueName;
         this.scoringDiffLastGame = scoringDiffLastGame;
         this.scoringTotal = scoringTotal;
         this.winLossRatioHomeAndAway = winLossRatioHomeAndAway;
         this.winLossRatio = winLossRatio;
+        this.drawDiffHomeAway = drawDiffHomeAway;
+        this.drawTotalGoals = drawTotalGoals;
+        this.drawWinningForm = drawWinningForm;
+        this.drawWinningFormHomeAway = drawWinningFormHomeAway;
+    }
+
+    public int getBetMargin() {
+        return betMargin;
+    }
+
+    public int getBetMarginAway() {
+        return betMarginAway;
+    }
+
+    public int getBetMarginDraw() {
+        return betMarginDraw;
+    }
+
+    public int getBetMarginHome() {
+        return betMarginHome;
+    }
+
+    public int getDrawDiffHomeAway() {
+        return drawDiffHomeAway;
+    }
+
+    public int getDrawTotalGoals() {
+        return drawTotalGoals;
+    }
+
+    public int getDrawWinningForm() {
+        return drawWinningForm;
+    }
+
+    public int getDrawWinningFormHomeAway() {
+        return drawWinningFormHomeAway;
     }
 
     public int getLeagueId() {
@@ -42,88 +83,88 @@ public class League {
         return lookback;
     }
 
-    public int getBetMargin() {
-        return betMargin;
+    public int getLookbackAway() {
+        return lookbackAway;
     }
 
-    public void setLeagueId(int leagueId) {
-        this.leagueId = leagueId;
+    public int getLookbackDraw() {
+        return lookbackDraw;
     }
 
-    public void setLeagueName(String leagueName) {
-        this.leagueName = leagueName;
+    public int getLookbackHome() {
+        return lookbackHome;
     }
 
-    public void setLookback(int lookback) {
-        this.lookback = lookback;
+    public int getScoringDiffLastGame() {
+        return scoringDiffLastGame;
     }
 
-    public void setBetMargin(int betMargin) {
-        this.betMargin = betMargin;
+    public int getScoringTotal() {
+        return scoringTotal;
     }
 
-    public int getLookbackHome() {
-        return lookbackHome;
+    public int getWinLossRatio() {
+        return winLossRatio;
     }
 
-    public int getLookbackDraw() {
-        return lookbackDraw;
+    public int getWinLossRatioHomeAndAway() {
+        return winLossRatioHomeAndAway;
     }
 
-    public int getLookbackAway() {
-        return lookbackAway;
+    public void setBetMargin(int betMargin) {
+        this.betMargin = betMargin;
     }
 
-    public int getBetMarginHome() {
-        return betMarginHome;
+    public void setBetMarginAway(int betMarginAway) {
+        this.betMarginAway = betMarginAway;
     }
 
-    public int getBetMarginDraw() {
-        return betMarginDraw;
+    public void setBetMarginDraw(int betMarginDraw) {
+        this.betMarginDraw = betMarginDraw;
     }
 
-    public int getBetMarginAway() {
-        return betMarginAway;
+    public void setBetMarginHome(int betMarginHome) {
+        this.betMarginHome = betMarginHome;
     }
 
-    public void setLookbackHome(int lookbackHome) {
-        this.lookbackHome = lookbackHome;
+    public void setDrawDiffHomeAway(int drawDiffHomeAway) {
+        this.drawDiffHomeAway = drawDiffHomeAway;
     }
 
-    public void setLookbackDraw(int lookbackDraw) {
-        this.lookbackDraw = lookbackDraw;
+    public void setDrawTotalGoals(int drawTotalGoals) {
+        this.drawTotalGoals = drawTotalGoals;
     }
 
-    public void setLookbackAway(int lookbackAway) {
-        this.lookbackAway = lookbackAway;
+    public void setDrawWinningForm(int drawWinningForm) {
+        this.drawWinningForm = drawWinningForm;
     }
 
-    public void setBetMarginHome(int betMarginHome) {
-        this.betMarginHome = betMarginHome;
+    public void setDrawWinningFormHomeAway(int drawWinningFormHomeAway) {
+        this.drawWinningFormHomeAway = drawWinningFormHomeAway;
     }
 
-    public void setBetMarginDraw(int betMarginDraw) {
-        this.betMarginDraw = betMarginDraw;
+    public void setLeagueId(int leagueId) {
+        this.leagueId = leagueId;
     }
 
-    public void setBetMarginAway(int betMarginAway) {
-        this.betMarginAway = betMarginAway;
+    public void setLeagueName(String leagueName) {
+        this.leagueName = leagueName;
     }
 
-    public int getScoringDiffLastGame() {
-        return scoringDiffLastGame;
+    public void setLookback(int lookback) {
+        this.lookback = lookback;
     }
 
-    public int getScoringTotal() {
-        return scoringTotal;
+    public void setLookbackAway(int lookbackAway) {
+        this.lookbackAway = lookbackAway;
     }
 
-    public int getWinLossRatioHomeAndAway() {
-        return winLossRatioHomeAndAway;
+    public void setLookbackDraw(int lookbackDraw) {
+        this.lookbackDraw = lookbackDraw;
     }
 
-    public int getWinLossRatio() {
-        return winLossRatio;
+    public void setLookbackHome(int lookbackHome) {
+        this.lookbackHome = lookbackHome;
     }
 
     public void setScoringDiffLastGame(int scoringDiffLastGame) {
@@ -134,12 +175,12 @@ public class League {
         this.scoringTotal = scoringTotal;
     }
 
-    public void setWinLossRatioHomeAndAway(int winLossRatioHomeAndAway) {
-        this.winLossRatioHomeAndAway = winLossRatioHomeAndAway;
-    }
-
     public void setWinLossRatio(int winLossRatio) {
         this.winLossRatio = winLossRatio;
     }
 
+    public void setWinLossRatioHomeAndAway(int winLossRatioHomeAndAway) {
+        this.winLossRatioHomeAndAway = winLossRatioHomeAndAway;
+    }
+
 }

+ 99 - 80
OddsJavaFx/src/objects/bets/Bet.java

@@ -4,10 +4,18 @@ import objects.SoccerMatch;
 
 public class Bet {
 
+    public static enum Status {
+        DONE,
+        OPEN,
+        LOST,
+        COVERED,
+        SPLIT
+    }
+
     SoccerMatch match;
     float betAmount;
-    float betOdds;
 
+    float betOdds;
     int id;
     String homeTeamName;
     String awayTeamName;
@@ -17,15 +25,10 @@ public class Bet {
     int coveredBetId;
     String bet;
 
+    int betCoveredNumber;
     Status status;
 
-    public static enum Status {
-        DONE,
-        OPEN,
-        LOST,
-        COVERED,
-        SPLIT
-    }
+    public boolean resolved = false;
 
     public Bet(int id, SoccerMatch match, String bet, float betAmount, float betOdds) {
         this(id, match, bet, betAmount, betOdds, Status.OPEN, -1);
@@ -48,60 +51,66 @@ public class Bet {
         this.coveredBetId = coveredBetId;
     }
 
-    public int getId() {
-        return id;
-    }
-
-    public void setId(int id) {
-        this.id = id;
+    public boolean correctBet() {
+        boolean result = false;
+        if (isBetOnHomeTeam() && match.getHomeScore() > match.getAwayScore()) {
+            result = true;
+        }
+        if (isBetOnDraw() && match.getHomeScore() == match.getAwayScore()) {
+            result = true;
+        }
+        if (isBetOnAwayTeam() && match.getHomeScore() < match.getAwayScore()) {
+            result = true;
+        }
+        return result;
     }
 
-    public SoccerMatch getMatch() {
-        return match;
+    public int getAwayScore() {
+        return awayScore;
     }
 
-    public float getBetAmount() {
-        return betAmount;
+    public String getAwayTeamName() {
+        return awayTeamName;
     }
 
-    public float getBetOdds() {
-        return betOdds;
+    public String getBet() {
+        return bet;
     }
 
-    public boolean isBetOnHomeTeam() {
-        return bet.equals("1");
+    public float getBetAmount() {
+        return betAmount;
     }
 
-    public boolean isBetOnDraw() {
-        return bet.equals("X");
+    public int getBetCoveredNumber() {
+        return betCoveredNumber;
     }
 
-    public boolean isBetOnAwayTeam() {
-        return bet.equals("2");
+    public float getBetOdds() {
+        return betOdds;
     }
 
-    public void setMatch(SoccerMatch match) {
-        this.match = match;
+    public int getCoveredBetId() {
+        return coveredBetId;
     }
 
-    public void setBetAmount(float betAmount) {
-        this.betAmount = betAmount;
+    public int getHomeScore() {
+        return homeScore;
     }
 
-    public void setBetOdds(float betOdds) {
-        this.betOdds = betOdds;
+    public String getHomeTeamName() {
+        return homeTeamName;
     }
 
-    public void setBetOnHomeTeam() {
-        this.bet = "1";
+    public int getId() {
+        return id;
     }
 
-    public void setBetOnDraw() {
-        this.bet = "X";
+    public SoccerMatch getMatch() {
+        return match;
     }
 
-    public void setBetOnAwayTeam() {
-        this.bet = "2";
+    public String getMatchup() {
+        return matchup;
     }
 
     public float getResult() {
@@ -117,86 +126,96 @@ public class Bet {
         return result;
     }
 
-    public boolean correctBet() {
-        boolean result = false;
-        if (isBetOnHomeTeam() && match.getHomeScore() > match.getAwayScore()) {
-            result = true;
-        }
-        if (isBetOnDraw() && match.getHomeScore() == match.getAwayScore()) {
-            result = true;
-        }
-        if (isBetOnAwayTeam() && match.getHomeScore() < match.getAwayScore()) {
-            result = true;
-        }
-        return result;
+    public Status getStatus() {
+        return status;
     }
 
-    protected boolean isDrawResult() {
-        return match.getHomeScore() == match.getAwayScore();
+    public boolean isBetOnAwayTeam() {
+        return bet.equals("2");
     }
 
-    public String getHomeTeamName() {
-        return homeTeamName;
+    public boolean isBetOnDraw() {
+        return bet.equals("X");
     }
 
-    public String getAwayTeamName() {
-        return awayTeamName;
+    public boolean isBetOnHomeTeam() {
+        return bet.equals("1");
     }
 
-    public String getMatchup() {
-        return matchup;
+    public boolean isResolved() {
+        return resolved;
     }
 
-    public void setHomeTeamName(String homeTeamName) {
-        this.homeTeamName = homeTeamName;
+    public void setAwayScore(int awayScore) {
+        this.awayScore = awayScore;
     }
 
     public void setAwayTeamName(String awayTeamName) {
         this.awayTeamName = awayTeamName;
     }
 
-    public void setMatchup() {
-        this.matchup = homeTeamName + " - " + awayTeamName;
+    public void setBet(String bet) {
+        this.bet = bet;
     }
 
-    public int getHomeScore() {
-        return homeScore;
+    public void setBetAmount(float betAmount) {
+        this.betAmount = betAmount;
     }
 
-    public int getAwayScore() {
-        return awayScore;
+    public void setBetCoveredNumber(int betCoverNumber) {
+        this.betCoveredNumber = betCoverNumber;
+    }
+
+    public void setBetOdds(float betOdds) {
+        this.betOdds = betOdds;
+    }
+
+    public void setBetOnAwayTeam() {
+        this.bet = "2";
+    }
+
+    public void setBetOnDraw() {
+        this.bet = "X";
+    }
+
+    public void setBetOnHomeTeam() {
+        this.bet = "1";
+    }
+
+    public void setCoveredBetId(int coveredBetId) {
+        this.coveredBetId = coveredBetId;
     }
 
     public void setHomeScore(int homeScore) {
         this.homeScore = homeScore;
     }
 
-    public void setAwayScore(int awayScore) {
-        this.awayScore = awayScore;
+    public void setHomeTeamName(String homeTeamName) {
+        this.homeTeamName = homeTeamName;
     }
 
-    public Status getStatus() {
-        return status;
+    public void setId(int id) {
+        this.id = id;
     }
 
-    public void setStatus(Status status) {
-        this.status = status;
+    public void setMatch(SoccerMatch match) {
+        this.match = match;
     }
 
-    public int getCoveredBetId() {
-        return coveredBetId;
+    public void setMatchup() {
+        this.matchup = homeTeamName + " - " + awayTeamName;
     }
 
-    public void setCoveredBetId(int coveredBetId) {
-        this.coveredBetId = coveredBetId;
+    public void setResolved(boolean resolved) {
+        this.resolved = resolved;
     }
 
-    public String getBet() {
-        return bet;
+    public void setStatus(Status status) {
+        this.status = status;
     }
 
-    public void setBet(String bet) {
-        this.bet = bet;
+    protected boolean isDrawResult() {
+        return match.getHomeScore() == match.getAwayScore();
     }
 
 }

+ 302 - 304
OddsJavaFx/src/parser/OddsPortal.java

@@ -26,308 +26,306 @@ import object.ResultDTO;
 
 public class OddsPortal implements ParserJoinedFunctions {
 
-	private LocalDateTime baseDate;
-	private int currentParsePage;
-	private int sportId;
-	private int countryId;
-	private int leagueId;
-	private LocalDateTime gameDate;
-
-	// https://stackoverflow.com/questions/14439991/skip-particular-javascript-execution-in-html-unit
-	// Skip url
-	public void getMatchesByDate(String date) {
-		final String soccerUrl = "https://oddsportal.com/matches/soccer/" + date;
-		// final String hockeyUrl = "https://oddsportal.com/matches/hockey/" + date;
-
-		final WebClient webClient = new WebClient();
-		webClient.getOptions().setUseInsecureSSL(true);
-		webClient.getOptions().setCssEnabled(false);
-		webClient.getOptions().setJavaScriptEnabled(true);
-		webClient.getOptions().setThrowExceptionOnScriptError(false);
-		Logger.getLogger("com.gargoylesoftware").setLevel(Level.OFF);
-
-		webClient.waitForBackgroundJavaScript(3000);
-		parseSoccerMatches(soccerUrl, webClient);
-
-		webClient.close();
-	}
-
-	private void parseSoccerMatches(final String soccerUrl, final WebClient webClient) {
-		try {
-			System.out.println("Getting Webpage");
-			final HtmlPage soccerMatches = webClient.getPage(soccerUrl);
-			final HtmlTable matchesTable = soccerMatches.getFirstByXPath("//table[contains(@class, table-main)]");
-			final List<HtmlTableRow> rows = matchesTable.getRows();
-			String countryName = "";
-			String leagueName = "";
-			int i = 1;
-			final int size = rows.size();
-			for (final HtmlTableRow tr : rows) {
-				System.out.println("Processing " + i++ + " of " + size);
-				if (tr.getAttribute("class").equals("dark center")) {
-					final List<HtmlAnchor> countryLeague = tr.getByXPath(".//a");
-					countryName = countryLeague.get(0).getTextContent().toLowerCase().trim();
-					leagueName = countryLeague.get(1).getTextContent().toLowerCase().trim();
-					leagueName = leagueName.replaceAll(" ", "-");
-					leagueName = leagueName.replaceAll("\\.", "");
-					countryName = countryName.replaceAll(" ", "-");
-					countryName = countryName.replaceAll("\\.", "");
-				} else {
-					final List<HtmlTableCell> cells = tr.getCells();
-					final String[] time = cells.get(0).getTextContent().split(":");
-					final String[] teams = cells.get(1).getTextContent().split(" - ");
-					float odds1 = 0F;
-					float oddsX = 0F;
-					float odds2 = 0F;
-					int homeScore = -1;
-					int awayScore = -1;
-					boolean overtime = false;
-
-					boolean abandon = false;
-
-					try {
-						for (final HtmlTableCell tc : cells) {
-							if (tc.getAttribute("class").contains("live-score")) {
-								abandon = true;
-								break;
-							}
-							// Score
-							if (tc.getAttribute("class").contains("table-score")) {
-								final String[] scoreValue = tc.getTextContent().split(":");
-								homeScore = Integer.valueOf(scoreValue[0]);
-								if (scoreValue[1].matches("\\D+")) {
-									overtime = true;
-								}
-								awayScore = Integer.valueOf(scoreValue[1].replaceAll("\\D+", ""));
-							}
-							if (tc.getAttribute("class").contains("odds-nowrp")) {
-								if (tc.getTextContent().matches("[+-][0-9][0-9][0-9]")) {
-									if (odds1 == 0F) {
-										odds1 = convertAmericanOddsToDecimal(Integer.valueOf(tc.getTextContent()));
-									} else if (oddsX == 0F) {
-										oddsX = convertAmericanOddsToDecimal(Integer.valueOf(tc.getTextContent()));
-									} else if (odds2 == 0F) {
-										odds2 = convertAmericanOddsToDecimal(Integer.valueOf(tc.getTextContent()));
-									}
-								} else if (tc.getTextContent().matches("[0-9].[0-9]+")) {
-									if (odds1 == 0F) {
-										odds1 = Float.valueOf(tc.getTextContent());
-									} else if (oddsX == 0F) {
-										oddsX = Float.valueOf(tc.getTextContent());
-									} else if (odds2 == 0F) {
-										odds2 = Float.valueOf(tc.getTextContent());
-									}
-								}
-							}
-
-						}
-					} catch (final NumberFormatException e) {
-						System.out
-								.println("Failed to get the match between " + teams[0].trim() + " and "
-										+ teams[1].trim() + " at "
-										+ baseDate.withHour(Integer.valueOf(time[0]))
-												.withMinute(Integer.valueOf(time[1]))
-										+ " odds1: " + odds1 + " oddsX: " + oddsX + " odds2: " + odds2 + " homeScore "
-										+ homeScore + " awayScore " + awayScore + " overtime: "
-										+ (overtime ? "true" : "false"));
-						continue;
-					}
-
-					if (abandon) {
-						continue;
-					}
-					final Mysql mysql = Mysql.getInstance();
-					final int leagueId = mysql.addLeague(leagueName, countryName, "soccer");
-					final int countryId = mysql.getCountryId(countryName);
-					final int sportId = mysql.getSportId("soccer");
-
-					String season = mysql.getLastParsedYear(leagueName, countryId);
-
-					if (Strings.isNullOrEmpty(season)) {
-						season = String.valueOf(LocalDateTime.now().getYear());
-					}
-
-					final LocalDateTime dt = baseDate.withHour(Integer.valueOf(time[0]))
-							.withMinute(Integer.valueOf(time[1])).withSecond(0).withNano(0);
-					mysql.addResult(new ResultDTO("SoccerResults", dt, teams[0].trim(), teams[1].trim(), homeScore,
-							awayScore, overtime, odds1, oddsX, odds2, countryId, season, leagueId, sportId));
-				}
-			}
-		} catch (FailingHttpStatusCodeException | IOException e) {
-			e.printStackTrace();
-		} catch (final SQLException e) {
-			e.printStackTrace();
-		}
-	}
-
-	public void getHistoricMatches(String sport, String country, String league, String year) {
-		final String url = "https://www.oddsportal.com/";
-		final String resultsPage = "/results";
-		final WebClient webClient = new WebClient();
-		webClient.getOptions().setUseInsecureSSL(true);
-		webClient.getOptions().setCssEnabled(false);
-		webClient.getOptions().setJavaScriptEnabled(true);
-		webClient.getOptions().setThrowExceptionOnScriptError(false);
-		Logger.getLogger("com.gargoylesoftware").setLevel(Level.OFF);
-
-		league = league.replaceAll(" ", "-");
-		league = league.replaceAll("\\.", "");
-		country = country.replaceAll(" ", "-");
-		league = league.replaceAll("\\.", "");
-		final Mysql mysql = Mysql.getInstance();
-
-		currentParsePage = 1;
-
-		final String urlYearPart;
-		if (year.equals(String.valueOf(LocalDate.now().getYear()))) {
-			urlYearPart = "";
-		} else {
-			urlYearPart = "-" + year;
-		}
-
-		try {
-			sportId = mysql.getSportId(sport);
-			countryId = mysql.getCountryId(country);
-			leagueId = mysql.getLeagueId(sportId, countryId, league);
-			String season = "";
-
-			final HtmlPage leaguePage = webClient
-					.getPage(url + "/" + sport + "/" + country + "/" + league + urlYearPart + resultsPage);
-			final List<HtmlAnchor> yearFilter = leaguePage.getByXPath("//ul[contains(@class,'main-filter')]//a");
-			for (final HtmlAnchor a : yearFilter) {
-				System.out.println("Year filter: " + a.getHrefAttribute());
-				final String active = ((HtmlSpan) a.getParentNode().getParentNode()).getAttribute("class");
-				if (active.contains("active") && !active.contains("inactive")) {
-					season = a.getTextContent();
-					year = season.replace('/', '-');
-				}
-			}
-
-			HtmlDivision tournamentTableDiv = leaguePage.getHtmlElementById("tournamentTable");
-			HtmlTable tournamentTable = (HtmlTable) tournamentTableDiv.getFirstChild();
-
-			gameDate = LocalDateTime.now();
-			final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd MMM yyyy", Locale.ENGLISH);
-			parseTournamentTable(sportId, countryId, leagueId, season, tournamentTable, gameDate, dateFormatter);
-			final HtmlDivision paginationLinksDiv = (HtmlDivision) tournamentTableDiv.getLastChild();
-			final List<HtmlAnchor> pagiantionLinks = paginationLinksDiv
-					.getByXPath(".//a[contains(@href, 'page') and not(.//span[contains(@class, 'arrow')])]");
-			for (final HtmlAnchor a : pagiantionLinks) {
-				System.out.println("Continuing with Pagination: " + a.getHrefAttribute());
-				// When done with start page click pagiantion
-				final int parsePage = Integer.valueOf(a.getTextContent());
-				if (parsePage > currentParsePage) {
-					a.click();
-					webClient.waitForBackgroundJavaScript(1000);
-
-					tournamentTableDiv = leaguePage.getHtmlElementById("tournamentTable");
-					tournamentTable = (HtmlTable) tournamentTableDiv.getFirstChild();
-					parseTournamentTable(sportId, countryId, leagueId, season, tournamentTable, gameDate,
-							dateFormatter);
-					currentParsePage = parsePage;
-				}
-				// process new tournament table content
-			}
-		} catch (FailingHttpStatusCodeException | IOException e) {
-			e.printStackTrace();
-		} catch (final SQLException sqle) {
-			sqle.printStackTrace();
-		} catch (final ClassCastException cce) {
-			System.out.println("No pagination table");
-			// cce.printStackTrace();
-		} finally {
-			Mysql.getInstance().setParsingForLeague(leagueId, sportId, countryId, gameDate, currentParsePage, year);
-		}
-		webClient.close();
-		System.out.println("DONE with " + country + " (" + countryId + ") league " + league + "(" + leagueId + ")");
-	}
-
-	private void parseTournamentTable(int sportId, int countryId, int leagueId, String season,
-			HtmlTable tournamentTable, LocalDateTime gameDate, DateTimeFormatter dateFormatter) throws SQLException {
-		for (final HtmlTableRow tr : tournamentTable.getRows()) {
-			if (tr.getAttribute("class").contains("deactivate")) {
-				String homeTeam;
-				String awayTeam;
-				int homeScore = -1;
-				int awayScore = -1;
-				float odds1 = 0f;
-				float oddsX = 0f;
-				float odds2 = 0f;
-				boolean overtime = false;
-
-				final HtmlTableCell timeCell = tr.getCell(0);
-				final HtmlTableCell participantsCell = tr.getCell(1);
-
-				// Game Time
-				final String[] timeValue = timeCell.getTextContent().split(":");
-				gameDate = gameDate.withHour(Integer.valueOf(timeValue[0]));
-				gameDate = gameDate.withMinute(Integer.valueOf(timeValue[1]));
-
-				// Teams
-				final String[] participantsValue = participantsCell.getTextContent().split(" - ");
-				homeTeam = participantsValue[0].trim();
-				awayTeam = participantsValue[1].trim();
-
-				final List<HtmlTableCell> cells = tr.getCells();
-				for (final HtmlTableCell tc : cells) {
-					// Score
-					if (tc.getAttribute("class").contains("table-score")) {
-						final String[] scoreValue = tc.getTextContent().split(":");
-						if (scoreValue[0].matches("\\D+")) {
-							continue;
-						}
-						homeScore = Integer.valueOf(scoreValue[0]);
-						if (scoreValue[1].matches("\\D+")) {
-							overtime = true;
-						}
-						awayScore = Integer.valueOf(scoreValue[1].replaceAll("\\D+", ""));
-					}
-
-					if (tc.getAttribute("class").contains("odds-nowrp")) {
-						if (tc.getTextContent().matches("[+-][0-9][0-9][0-9]")) {
-							if (odds1 == 0F) {
-								odds1 = convertAmericanOddsToDecimal(Integer.valueOf(tc.getTextContent()));
-							} else if (oddsX == 0F) {
-								oddsX = convertAmericanOddsToDecimal(Integer.valueOf(tc.getTextContent()));
-							} else if (odds2 == 0F) {
-								odds2 = convertAmericanOddsToDecimal(Integer.valueOf(tc.getTextContent()));
-							}
-						} else if (tc.getTextContent().matches("[0-9].[0-9]+")) {
-							if (odds1 == 0F) {
-								odds1 = Float.valueOf(tc.getTextContent());
-							} else if (oddsX == 0F) {
-								oddsX = Float.valueOf(tc.getTextContent());
-							} else if (odds2 == 0F) {
-								odds2 = Float.valueOf(tc.getTextContent());
-							}
-						}
-					}
-				}
-
-				if (gameDate != null && homeTeam != null && awayTeam != null && odds1 != 0 && oddsX != 0 && odds2 != 0
-						&& !Strings.isNullOrEmpty(season)) { // All set.. update sql result table
-					System.out.println("Adding game between " + homeTeam + " and " + awayTeam + " with score "
-							+ homeScore + "-" + awayScore);
-					Mysql.getInstance().addResult(new ResultDTO("SoccerResults", gameDate, homeTeam, awayTeam,
-							homeScore, awayScore, overtime, odds1, oddsX, odds2, countryId, season, leagueId, sportId));
-				} else {
-					System.out.println(String.format(
-							"Not adding, missing somethind.. gameDate: %s, homeTeam %s, awayTeam %s, odds1 %s, oddsX %s, odds2 %s, "
-									+ "season %s",
-							gameDate, homeTeam, awayTeam, odds1, oddsX, odds2, season));
-				}
-
-			} else if (tr.getAttribute("class").contains("center nob-border")) { // Datum rader
-				final List<HtmlSpan> dateSpan = tr.getByXPath(".//span[contains(@class, 'datet')]");
-				final String dateString = dateSpan.get(0).getTextContent();
-				if (dateString.toLowerCase().contains("yesterday")) {
-					gameDate = LocalDateTime.now().minusDays(1);
-				} else if (dateString.toLowerCase().contains("today")) {
-					gameDate = LocalDateTime.now();
-				} else {
-					gameDate = LocalDate.parse(dateString, dateFormatter).atStartOfDay();
-				}
-			}
-		}
-	}
+    private LocalDateTime baseDate;
+    private int currentParsePage;
+    private int sportId;
+    private int countryId;
+    private int leagueId;
+    private LocalDateTime gameDate;
+
+    public void getHistoricMatches(String sport, String country, String league, String year) {
+        final String url = "https://www.oddsportal.com/";
+        final String resultsPage = "/results";
+        final WebClient webClient = new WebClient();
+        webClient.getOptions().setUseInsecureSSL(true);
+        webClient.getOptions().setCssEnabled(false);
+        webClient.getOptions().setJavaScriptEnabled(true);
+        webClient.getOptions().setThrowExceptionOnScriptError(false);
+        Logger.getLogger("com.gargoylesoftware").setLevel(Level.OFF);
+
+        league = league.replaceAll(" ", "-");
+        league = league.replaceAll("\\.", "");
+        country = country.replaceAll(" ", "-");
+        league = league.replaceAll("\\.", "");
+        final Mysql mysql = Mysql.getInstance();
+
+        currentParsePage = 1;
+
+        final String urlYearPart;
+        if (year.equals(String.valueOf(LocalDate.now().getYear()))) {
+            urlYearPart = "";
+        } else {
+            urlYearPart = "-" + year;
+        }
+
+        try {
+            sportId = mysql.getSportId(sport);
+            countryId = mysql.getCountryId(country);
+            leagueId = mysql.getLeagueId(sportId, countryId, league);
+            String season = "";
+
+            final HtmlPage leaguePage = webClient
+                    .getPage(url + "/" + sport + "/" + country + "/" + league + urlYearPart + resultsPage);
+            final List<HtmlAnchor> yearFilter = leaguePage.getByXPath("//ul[contains(@class,'main-filter')]//a");
+            for (final HtmlAnchor a : yearFilter) {
+                System.out.println("Year filter: " + a.getHrefAttribute());
+                final String active = ((HtmlSpan) a.getParentNode().getParentNode()).getAttribute("class");
+                if (active.contains("active") && !active.contains("inactive")) {
+                    season = a.getTextContent();
+                    year = season.replace('/', '-');
+                }
+            }
+
+            HtmlDivision tournamentTableDiv = leaguePage.getHtmlElementById("tournamentTable");
+            HtmlTable tournamentTable = (HtmlTable) tournamentTableDiv.getFirstChild();
+
+            gameDate = LocalDateTime.now();
+            final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd MMM yyyy", Locale.ENGLISH);
+            parseTournamentTable(sportId, countryId, leagueId, season, tournamentTable, gameDate, dateFormatter);
+            final HtmlDivision paginationLinksDiv = (HtmlDivision) tournamentTableDiv.getLastChild();
+            final List<HtmlAnchor> pagiantionLinks = paginationLinksDiv
+                    .getByXPath(".//a[contains(@href, 'page') and not(.//span[contains(@class, 'arrow')])]");
+            for (final HtmlAnchor a : pagiantionLinks) {
+                System.out.println("Continuing with Pagination: " + a.getHrefAttribute());
+                // When done with start page click pagiantion
+                final int parsePage = Integer.valueOf(a.getTextContent());
+                if (parsePage > currentParsePage) {
+                    a.click();
+                    webClient.waitForBackgroundJavaScript(1000);
+
+                    tournamentTableDiv = leaguePage.getHtmlElementById("tournamentTable");
+                    tournamentTable = (HtmlTable) tournamentTableDiv.getFirstChild();
+                    parseTournamentTable(sportId, countryId, leagueId, season, tournamentTable, gameDate,
+                            dateFormatter);
+                    currentParsePage = parsePage;
+                }
+                // process new tournament table content
+            }
+        } catch (FailingHttpStatusCodeException | IOException e) {
+            e.printStackTrace();
+        } catch (final SQLException sqle) {
+            sqle.printStackTrace();
+        } catch (final ClassCastException cce) {
+            System.out.println("No pagination table");
+            // cce.printStackTrace();
+        } finally {
+            Mysql.getInstance().setParsingForLeague(leagueId, sportId, countryId, gameDate, currentParsePage, year);
+        }
+        webClient.close();
+        System.out.println("DONE with " + country + " (" + countryId + ") league " + league + "(" + leagueId + ")");
+    }
+
+    // https://stackoverflow.com/questions/14439991/skip-particular-javascript-execution-in-html-unit
+    // Skip url
+    public void getMatchesByDate(String date) {
+        final String soccerUrl = "https://oddsportal.com/matches/soccer/" + date;
+        // final String hockeyUrl = "https://oddsportal.com/matches/hockey/" + date;
+
+        final WebClient webClient = new WebClient();
+        webClient.getOptions().setUseInsecureSSL(true);
+        webClient.getOptions().setCssEnabled(false);
+        webClient.getOptions().setJavaScriptEnabled(true);
+        webClient.getOptions().setThrowExceptionOnScriptError(false);
+        Logger.getLogger("com.gargoylesoftware").setLevel(Level.OFF);
+
+        webClient.waitForBackgroundJavaScript(3000);
+        parseSoccerMatches(soccerUrl, webClient);
+
+        webClient.close();
+    }
+
+    private void parseSoccerMatches(final String soccerUrl, final WebClient webClient) {
+        try {
+            System.out.println("Getting Webpage");
+            final HtmlPage soccerMatches = webClient.getPage(soccerUrl);
+            final HtmlTable matchesTable = soccerMatches.getFirstByXPath("//table[contains(@class, table-main)]");
+            final List<HtmlTableRow> rows = matchesTable.getRows();
+            String countryName = "";
+            String leagueName = "";
+            int i = 1;
+            final int size = rows.size();
+            for (final HtmlTableRow tr : rows) {
+                System.out.println("Processing " + i++ + " of " + size);
+                if (tr.getAttribute("class").equals("dark center")) {
+                    final List<HtmlAnchor> countryLeague = tr.getByXPath(".//a");
+                    countryName = countryLeague.get(0).getTextContent().toLowerCase().trim();
+                    leagueName = countryLeague.get(1).getTextContent().toLowerCase().trim();
+                    leagueName = leagueName.replaceAll(" ", "-");
+                    leagueName = leagueName.replaceAll("\\.", "");
+                    countryName = countryName.replaceAll(" ", "-");
+                    countryName = countryName.replaceAll("\\.", "");
+                } else {
+                    final List<HtmlTableCell> cells = tr.getCells();
+                    final String[] time = cells.get(0).getTextContent().split(":");
+                    final String[] teams = cells.get(1).getTextContent().split(" - ");
+                    float odds1 = 0F;
+                    float oddsX = 0F;
+                    float odds2 = 0F;
+                    int homeScore = -1;
+                    int awayScore = -1;
+                    boolean overtime = false;
+
+                    boolean abandon = false;
+
+                    try {
+                        for (final HtmlTableCell tc : cells) {
+                            if (tc.getAttribute("class").contains("live-score")) {
+                                abandon = true;
+                                break;
+                            }
+                            // Score
+                            if (tc.getAttribute("class").contains("table-score")) {
+                                final String[] scoreValue = tc.getTextContent().split(":");
+                                homeScore = Integer.valueOf(scoreValue[0]);
+                                if (scoreValue[1].matches("\\D+")) {
+                                    overtime = true;
+                                }
+                                awayScore = Integer.valueOf(scoreValue[1].replaceAll("\\D+", ""));
+                            }
+                            if (tc.getAttribute("class").contains("odds-nowrp")) {
+                                if (tc.getTextContent().matches("[+-][0-9][0-9][0-9]")) {
+                                    if (odds1 == 0F) {
+                                        odds1 = convertAmericanOddsToDecimal(Integer.valueOf(tc.getTextContent()));
+                                    } else if (oddsX == 0F) {
+                                        oddsX = convertAmericanOddsToDecimal(Integer.valueOf(tc.getTextContent()));
+                                    } else if (odds2 == 0F) {
+                                        odds2 = convertAmericanOddsToDecimal(Integer.valueOf(tc.getTextContent()));
+                                    }
+                                } else if (tc.getTextContent().matches("[0-9].[0-9]+")) {
+                                    if (odds1 == 0F) {
+                                        odds1 = Float.valueOf(tc.getTextContent());
+                                    } else if (oddsX == 0F) {
+                                        oddsX = Float.valueOf(tc.getTextContent());
+                                    } else if (odds2 == 0F) {
+                                        odds2 = Float.valueOf(tc.getTextContent());
+                                    }
+                                }
+                            }
+
+                        }
+                    } catch (final NumberFormatException e) {
+                        System.out
+                                .println("Failed to get the match between " + teams[0].trim() + " and "
+                                        + teams[1].trim() + " at "
+                                        + baseDate.withHour(Integer.valueOf(time[0]))
+                                                .withMinute(Integer.valueOf(time[1]))
+                                        + " odds1: " + odds1 + " oddsX: " + oddsX + " odds2: " + odds2 + " homeScore "
+                                        + homeScore + " awayScore " + awayScore + " overtime: "
+                                        + (overtime ? "true" : "false"));
+                        continue;
+                    }
+
+                    if (abandon) {
+                        continue;
+                    }
+                    final Mysql mysql = Mysql.getInstance();
+                    final int leagueId = mysql.addLeague(leagueName, countryName, "soccer");
+                    final int countryId = mysql.getCountryId(countryName);
+                    final int sportId = mysql.getSportId("soccer");
+
+                    String season = mysql.getLastParsedYear(leagueName, countryId);
+
+                    if (Strings.isNullOrEmpty(season)) {
+                        season = String.valueOf(LocalDateTime.now().getYear());
+                    }
+
+                    final LocalDateTime dt = baseDate.withHour(Integer.valueOf(time[0]))
+                            .withMinute(Integer.valueOf(time[1])).withSecond(0).withNano(0);
+                    mysql.addResult(new ResultDTO("SoccerResults", dt, teams[0].trim(), teams[1].trim(), homeScore,
+                            awayScore, overtime, odds1, oddsX, odds2, countryId, season, leagueId, sportId));
+                }
+            }
+        } catch (FailingHttpStatusCodeException | IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    private void parseTournamentTable(int sportId, int countryId, int leagueId, String season,
+            HtmlTable tournamentTable, LocalDateTime gameDate, DateTimeFormatter dateFormatter) throws SQLException {
+        for (final HtmlTableRow tr : tournamentTable.getRows()) {
+            if (tr.getAttribute("class").contains("deactivate")) {
+                String homeTeam;
+                String awayTeam;
+                int homeScore = -1;
+                int awayScore = -1;
+                float odds1 = 0f;
+                float oddsX = 0f;
+                float odds2 = 0f;
+                boolean overtime = false;
+
+                final HtmlTableCell timeCell = tr.getCell(0);
+                final HtmlTableCell participantsCell = tr.getCell(1);
+
+                // Game Time
+                final String[] timeValue = timeCell.getTextContent().split(":");
+                gameDate = gameDate.withHour(Integer.valueOf(timeValue[0]));
+                gameDate = gameDate.withMinute(Integer.valueOf(timeValue[1]));
+
+                // Teams
+                final String[] participantsValue = participantsCell.getTextContent().split(" - ");
+                homeTeam = participantsValue[0].trim();
+                awayTeam = participantsValue[1].trim();
+
+                final List<HtmlTableCell> cells = tr.getCells();
+                for (final HtmlTableCell tc : cells) {
+                    // Score
+                    if (tc.getAttribute("class").contains("table-score")) {
+                        final String[] scoreValue = tc.getTextContent().split(":");
+                        if (scoreValue[0].matches("\\D+")) {
+                            continue;
+                        }
+                        homeScore = Integer.valueOf(scoreValue[0]);
+                        if (scoreValue[1].matches("\\D+")) {
+                            overtime = true;
+                        }
+                        awayScore = Integer.valueOf(scoreValue[1].replaceAll("\\D+", ""));
+                    }
+
+                    if (tc.getAttribute("class").contains("odds-nowrp")) {
+                        if (tc.getTextContent().matches("[+-][0-9][0-9][0-9]")) {
+                            if (odds1 == 0F) {
+                                odds1 = convertAmericanOddsToDecimal(Integer.valueOf(tc.getTextContent()));
+                            } else if (oddsX == 0F) {
+                                oddsX = convertAmericanOddsToDecimal(Integer.valueOf(tc.getTextContent()));
+                            } else if (odds2 == 0F) {
+                                odds2 = convertAmericanOddsToDecimal(Integer.valueOf(tc.getTextContent()));
+                            }
+                        } else if (tc.getTextContent().matches("[0-9].[0-9]+")) {
+                            if (odds1 == 0F) {
+                                odds1 = Float.valueOf(tc.getTextContent());
+                            } else if (oddsX == 0F) {
+                                oddsX = Float.valueOf(tc.getTextContent());
+                            } else if (odds2 == 0F) {
+                                odds2 = Float.valueOf(tc.getTextContent());
+                            }
+                        }
+                    }
+                }
+
+                if (gameDate != null && homeTeam != null && awayTeam != null && odds1 != 0 && oddsX != 0 && odds2 != 0
+                        && !Strings.isNullOrEmpty(season)) { // All set.. update sql result table
+                    System.out.println("Adding game between " + homeTeam + " and " + awayTeam + " with score "
+                            + homeScore + "-" + awayScore);
+                    Mysql.getInstance().addResult(new ResultDTO("SoccerResults", gameDate, homeTeam, awayTeam,
+                            homeScore, awayScore, overtime, odds1, oddsX, odds2, countryId, season, leagueId, sportId));
+                } else {
+                    System.out.println(String.format(
+                            "Not adding, missing somethind.. gameDate: %s, homeTeam %s, awayTeam %s, odds1 %s, oddsX %s, odds2 %s, "
+                                    + "season %s",
+                            gameDate, homeTeam, awayTeam, odds1, oddsX, odds2, season));
+                }
+
+            } else if (tr.getAttribute("class").contains("center nob-border")) { // Datum rader
+                final List<HtmlSpan> dateSpan = tr.getByXPath(".//span[contains(@class, 'datet')]");
+                final String dateString = dateSpan.get(0).getTextContent();
+                if (dateString.toLowerCase().contains("yesterday")) {
+                    gameDate = LocalDateTime.now().minusDays(1);
+                } else if (dateString.toLowerCase().contains("today")) {
+                    gameDate = LocalDateTime.now();
+                } else {
+                    gameDate = LocalDate.parse(dateString, dateFormatter).atStartOfDay();
+                }
+            }
+        }
+    }
 }

+ 294 - 0
OddsJavaFx/src/tests/AnalysisBettDrawTester.java

@@ -0,0 +1,294 @@
+package tests;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.stream.Collectors;
+
+import data.TestDatabase;
+import objects.League;
+import objects.SoccerMatch;
+import objects.SoccerMatchAnalysis;
+import objects.bets.AsianHandicap;
+import objects.bets.Bet;
+import tests.objects.LeagueDTO;
+
+public class AnalysisBettDrawTester extends TestClass {
+
+    public class DifferenceAsianBetDTO extends AsianHandicap {
+        boolean resolved = false;
+
+        public DifferenceAsianBetDTO(SoccerMatch match, float betAmount, boolean betOnHomeTeam, float handicap) {
+            super(match, betOnHomeTeam ? "1" : "2", betAmount, betOnHomeTeam ? match.getOdds1() : match.getOdds2(),
+                    handicap);
+        }
+
+        @Override
+        public String toString() {
+            return String.format(
+                    "%s \t%s - %s \t\tbet amount %s \todds %s \twinner %s \t result %s-%s \tdiff %s with results %s",
+                    getMatch().getGameDate().toLocalDate(),
+                    getMatch().getHomeTeamName(),
+                    getMatch().getAwayTeamName(), getBetAmount(), super.getBetOdds(),
+                    super.isBetOnHomeTeam() ? "1" : "2", getMatch().getHomeScore(),
+                    getMatch().getAwayScore(), getMatch().getGoalsDiff(), getResult());
+        }
+    }
+
+    public class DifferenceBetDTO extends Bet {
+        boolean resolved = false;
+
+        public DifferenceBetDTO(SoccerMatch match, float betAmount, boolean betOnHomeTeam) {
+            super(0, match, betOnHomeTeam ? "1" : "2", betAmount, betOnHomeTeam ? match.getOdds1() : match.getOdds2());
+        }
+
+        @Override
+        public String toString() {
+            return String.format("%s \t%s - %s \t\tbet amount %s \todds %s \twinner %s \t result %s-%s \tdiff %s",
+                    getMatch().getGameDate().toLocalDate(),
+                    getMatch().getHomeTeamName(),
+                    getMatch().getAwayTeamName(), getBetAmount(), super.getBetOdds(),
+                    super.isBetOnHomeTeam() ? "1" : "2", getMatch().getHomeScore(),
+                    getMatch().getAwayScore(), getMatch().getGoalsDiff());
+        }
+    }
+
+    class LocalSoccerMatch extends SoccerMatch {
+        String decider;
+        SoccerMatch match;
+
+        public LocalSoccerMatch(SoccerMatch match, String decider) {
+            this.decider = decider;
+            this.match = match;
+        }
+    }
+
+    Map<String, List<Bet>> placedBets = new HashMap<>();
+    TestDatabase database;
+
+    List<LocalSoccerMatch> betsToPlace = new ArrayList<>();
+    float betAmount;
+
+    List<Bet> bets = new ArrayList<>();
+    int wins = 0;
+    int losses = 0;
+
+    float bank;
+
+    private List<Bet> betSeries = new ArrayList<>();
+
+    private League leagueInfo;
+    private int betsLost = 0;
+
+    @Override
+    public void runTest() {
+        bank = startingBank;
+        database = TestDatabase.getInstance();
+
+        leagueInfo = database.getLeagueInfo(leagueId);
+
+        LeagueDTO leagueDTO = database.getLeagueDTO(leagueId);
+        LinkedHashMap<String, List<SoccerMatch>> matches = getMatchesOrderedBySeason(leagueDTO);
+        this.betAmount = startingBank * (bettingLevel / 100.0f);
+
+        boolean skipFirst = false;
+        for (Entry<String, List<SoccerMatch>> seasonMatches : matches.entrySet()) {
+            wins = 0;
+            losses = 0;
+            bank = startingBank;
+            placedBets.clear();
+            if (skipFirst) {
+                skipFirst = false;
+                continue;
+            }
+            analyze(seasonMatches.getValue());
+            printResults();
+            System.out
+                    .println(
+                            String.format(seasonMatches.getKey() + " Wins %s Losses %s %s total bank: %s", wins, losses,
+                                    wins / (float) (wins + losses) + "%", bank));
+//            break;
+        }
+
+    }
+
+    private void addBet(SoccerMatch match, String deciders) {
+        betsToPlace.add(new LocalSoccerMatch(match, deciders));
+    }
+
+    private void analyze(List<SoccerMatch> seasonMatches) {
+
+        LocalDate currentMatchDate = seasonMatches.get(0).getGameDate().toLocalDate();
+
+        for (SoccerMatch match : seasonMatches) {
+
+            if (currentMatchDate.isBefore(match.getGameDate().toLocalDate())) {
+                placeBets();
+                checkBetResults();
+
+                betAmount = bank * (bettingLevel / 100.0f);
+            }
+
+            SoccerMatchAnalysis analysis = new SoccerMatchAnalysis(match);
+
+            int homeTotalGoals = analysis.scoringTotal(leagueInfo.getDrawTotalGoals(), true);
+            int awayTotalGoals = analysis.scoringTotal(leagueInfo.getDrawTotalGoals(), false);
+            int totalGoalsDecider = homeTotalGoals - awayTotalGoals;
+
+            int homeTotalGoalsHomeAway = analysis.goalsScoredHomeAndAway(true, leagueInfo.getDrawDiffHomeAway());
+            int awayTotalGoalsHomeAway = analysis.goalsScoredHomeAndAway(false, leagueInfo.getDrawDiffHomeAway());
+            int totalGoalsHomeAwayDecider = homeTotalGoalsHomeAway - awayTotalGoalsHomeAway;
+
+            int homeFormHomeAndAway = analysis.winLossRationHomeAndAway(true,
+                    leagueInfo.getDrawWinningFormHomeAway());
+            int awayFormHomeAndAway = analysis.winLossRationHomeAndAway(false,
+                    leagueInfo.getDrawWinningFormHomeAway());
+            int formHomeAwayDecider = homeFormHomeAndAway - awayFormHomeAndAway;
+
+            int homeWiningForm = analysis.winLossRatio(leagueInfo.getDrawWinningForm(), true);
+            int awayWiningForm = analysis.winLossRatio(leagueInfo.getDrawWinningForm(), false);
+            int winningFormDecider = homeWiningForm - awayWiningForm;
+
+//            if (totalGoalsDecider == 0 && totalGoalsHomeAwayDecider == 0 && formHomeAwayDecider == 0
+//                    && winningFormDecider == 0) {
+//                addBet(match, "ALL");
+//            } else if (totalGoalsDecider == 0 && totalGoalsHomeAwayDecider == 0 && formHomeAwayDecider == 0) {
+//                addBet(match, "NOT winningFormDecider");
+//            } else if (totalGoalsDecider == 0 && totalGoalsHomeAwayDecider == 0 && winningFormDecider == 0) {
+//                addBet(match, "NOT formHomeAwayDecider");
+//            } else if (totalGoalsDecider == 0 && formHomeAwayDecider == 0 && winningFormDecider == 0) {
+//                addBet(match, "NOT totalGoalsHomeAwayDecider");
+//            } else if (totalGoalsHomeAwayDecider == 0 && formHomeAwayDecider == 0 && winningFormDecider == 0) {
+//                addBet(match, "NOT totalGoalsDecider");
+//            } else
+            if (totalGoalsDecider == 0 && totalGoalsHomeAwayDecider == 0) {
+                addBet(match, "totalGoalsDecider, totalGoalsHomeAwayDecider");
+            } else if (totalGoalsDecider == 0 && formHomeAwayDecider == 0) {
+                addBet(match, "totalGoalsDecider, formHomeAwayDecider");
+            } else if (totalGoalsDecider == 0 && winningFormDecider == 0) {
+                addBet(match, "totalGoalsDecider, winningFormDecider");
+            } else if (totalGoalsHomeAwayDecider == 0 && formHomeAwayDecider == 0) {
+                addBet(match, "totalGoalsHomeAwayDecider, formHomeAwayDecider");
+            } else if (totalGoalsHomeAwayDecider == 0 && winningFormDecider == 0) {
+                addBet(match, "totalGoalsHomeAwayDecider, winningFormDecider");
+            } else if (formHomeAwayDecider == 0 && winningFormDecider == 0) {
+                addBet(match, "formHomeAwayDecider, winningFormDecider");
+//            } else if (totalGoalsDecider == 0) {
+//                addBet(match, "totalGoalsDecider");
+//            } else if (totalGoalsHomeAwayDecider == 0) {
+//                addBet(match, "totalGoalsHomeAwayDecider");
+//            } else if (formHomeAwayDecider == 0) {
+//                addBet(match, "formHomeAwayDecider");
+//            } else if (winningFormDecider == 0) {
+//                addBet(match, "winningFormDecider");
+            }
+
+            currentMatchDate = match.getGameDate().toLocalDate();
+        }
+    }
+
+    private void checkBetResults() {
+
+        placedBets.forEach((decider, betList) -> {
+            List<Bet> activeBets = betList.stream().filter(b -> !b.resolved).toList();
+            for (Bet bet : activeBets) {
+                if (bet.getHomeScore() == bet.getAwayScore()) {
+                    bank += bet.getBetAmount() * bet.getBetOdds();
+                    wins++;
+                } else {
+                    losses++;
+                    betSeries.add(bet);
+                }
+
+                bet.setResolved(true);
+            }
+        });
+
+        /*-  OLD checkBetResults left for inspiration
+        List<DifferenceBetDTO> activeBets = bets.stream().filter(p -> !p.resolved).toList();
+        for (DifferenceBetDTO bet : activeBets) {
+            if (bet.getResult() > 0) {
+                bank += bet.getResult(); // bet.getBetAmount() * bet.getBetOdds();
+                String winText = bet.correctBet() ? bet.isBetOnHomeTeam() ? "HOME WIN " : "AWAY WIN" : "HALF WIN";
+                System.out.println(String.format(winText + "\t" + "%s \t\tnew bank %s", bet, bank));
+                wins++;
+            } else {
+                // LOSS
+                System.out.println(String.format("LOSS\t\t%s \t\t bank: %s", bet, bank));
+                losses++;
+                betSeries.add(bet);
+            }
+            bet.resolved = true;
+        }
+        if (!betSeries.isEmpty()) {
+            System.out.println("Outstanding bets:");
+            betSeries.forEach(b -> System.out.println(b));
+        }
+        */
+    }
+
+    private void placeBets() {
+        for (LocalSoccerMatch soccerMatch : betsToPlace) {
+            Bet bet = new Bet(-1, soccerMatch.match, "X", betAmount, soccerMatch.match.getOddsX());
+
+            if (!betSeries.isEmpty()) {
+                betSeries.sort((b1, b2) -> Float.compare(b2.getBetAmount(), b1.getBetAmount()));
+                bet.setBetAmount(bet.getBetAmount() + betSeries.get(0).getBetAmount());
+                betSeries.remove(0);
+            }
+
+            bank -= bet.getBetAmount();
+            List<Bet> betsList = placedBets.get(soccerMatch.decider);
+
+            if (betsList == null) {
+                betsList = new ArrayList<>();
+            }
+            betsList.add(bet);
+            placedBets.put(soccerMatch.decider, betsList);
+
+            // För att täcka upp föregående bets
+
+//            float currentBetAmount = 0;
+////            betSeries.sort((b1, b2) -> Float.compare(b2.getBetAmount(), b1.getBetAmount()));
+//            if (!betSeries.isEmpty() && !betsToPlace.isEmpty()) {
+//                currentBetAmount += betSeries.get(0).getBetAmount();
+//                betSeries.remove(0);
+//            }
+//            if (soccerMatch.getGoalsDiff().floatValue() > 0f) {
+//                if (currentBetAmount > 0) {
+//                    currentBetAmount = (float) (currentBetAmount / (soccerMatch.getOdds1() - 1.0));
+//                }
+//                bets.add(new DifferenceBetDTO(soccerMatch, currentBetAmount + betAmount, true));
+//            } else if (soccerMatch.getGoalsDiff().floatValue() < 0f) {
+//                if (currentBetAmount > 0) {
+//                    currentBetAmount = (float) (currentBetAmount / (soccerMatch.getOdds2() - 1.0));
+//                }
+//                bets.add(new DifferenceBetDTO(soccerMatch, currentBetAmount + betAmount, false));
+//            }
+//
+//            bank -= currentBetAmount + betAmount;
+        }
+
+        betsToPlace.clear();
+    }
+
+    private void printResults() {
+
+        placedBets.forEach((decider, bets) -> {
+            List<Bet> correctBets = bets.stream().filter(p -> p.getHomeScore() == p.getAwayScore()).toList();
+            Double winnings = correctBets.stream()
+                    .collect(Collectors.summingDouble(d -> (double) d.getBetAmount() * (double) d.getBetOdds()));
+            Double totalBetAmount = bets.stream().collect(Collectors.summingDouble(Bet::getBetAmount));
+
+            System.out.println(decider + " total matches betted " + bets.size() + " correct " + correctBets.size() + " "
+                    + (correctBets.size() / (float) bets.size()) * 100 + "% total cost " + totalBetAmount
+                    + " totalWinnings "
+                    + winnings + " sum " + (winnings - totalBetAmount) + System.lineSeparator());
+
+        });
+    }
+}

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

@@ -74,7 +74,7 @@ public class AnalysisBettTester extends TestClass {
             SoccerMatchAnalysis analysis = new SoccerMatchAnalysis(match);
 
             int homeWinsCount = analysis.winLossRatio(leagueInfo.getWinLossRatio(), true);
-            int awayWindCount = analysis.winLossRatio(leagueInfo.getWinLossRatio(), false);
+            int awayWinsCount = analysis.winLossRatio(leagueInfo.getWinLossRatio(), false);
 
             int homeWinLossRatioCount = analysis.winLossRationHomeAndAway(true,
                     leagueInfo.getWinLossRatioHomeAndAway());
@@ -85,7 +85,7 @@ public class AnalysisBettTester extends TestClass {
             int awayScoringTotal = analysis.scoringTotal(leagueInfo.getScoringTotal(), false);
 
             int scoringDiffLastGames = analysis.getScoringDiffLastGames(leagueInfo.getScoringDiffLastGame());
-            int winsCountDiff = homeWinsCount - awayWindCount;
+            int winsCountDiff = homeWinsCount - awayWinsCount;
             int winLossRatioDiff = homeWinLossRatioCount - awayWinLossRatioCount;
             int scoringTotalDiff = homeScoringTotal - awayScoringTotal;
 

+ 29 - 27
OddsJavaFx/src/tests/HomeDrawAwayTest.java

@@ -22,6 +22,32 @@ public class HomeDrawAwayTest extends TestClass {
     private float activeOddsX;
     private float activeOdds2;
 
+    public ArrayList<SoccerMatch> getMatches() {
+        final ArrayList<SoccerMatch> matches = new ArrayList<>();
+        prioLeagues = getPrioLeagues();
+
+        final ArrayList<String> leagueIds = Lists.newArrayList();
+        prioLeagues.forEach(p -> leagueIds.add(String.valueOf(p.getLeagueId())));
+
+        final String sql = "SELECT res.*, " + "hTeam.name as homeTeamName, aTeam.name as awayTeamName "
+                + "FROM SoccerResults as res "
+                + "Join Team as hTeam ON res.homeTeam = hTeam.id " + "Join Team as aTeam ON res.awayTeam = aTeam.id "
+                + "WHERE "
+                + "DATE(gameDate) > '2021-07-01' AND " + "homeScore >= 0 AND " + "awayScore >= 0 AND "
+                + "res.leagueId IN ("
+                + String.join(",", leagueIds) + ") " + "ORDER BY gameDate ASC";
+
+        PreparedStatement stmt;
+        try {
+            stmt = getConnection().prepareStatement(sql);
+            matches.addAll(super.getMatches(stmt));
+        } catch (final SQLException e) {
+            e.printStackTrace();
+        }
+
+        return matches;
+    }
+
     @Override
     public void runTest() {
         float betAmount;
@@ -183,32 +209,6 @@ public class HomeDrawAwayTest extends TestClass {
         return result;
     }
 
-    public ArrayList<SoccerMatch> getMatches() {
-        final ArrayList<SoccerMatch> matches = new ArrayList<>();
-        prioLeagues = getPrioLeagues();
-
-        final ArrayList<String> leagueIds = Lists.newArrayList();
-        prioLeagues.forEach(p -> leagueIds.add(String.valueOf(p.getLeagueId())));
-
-        final String sql = "SELECT res.*, " + "hTeam.name as homeTeamName, aTeam.name as awayTeamName "
-                + "FROM SoccerResults as res "
-                + "Join Team as hTeam ON res.homeTeam = hTeam.id " + "Join Team as aTeam ON res.awayTeam = aTeam.id "
-                + "WHERE "
-                + "DATE(gameDate) > '2021-07-01' AND " + "homeScore >= 0 AND " + "awayScore >= 0 AND "
-                + "res.leagueId IN ("
-                + String.join(",", leagueIds) + ") " + "ORDER BY gameDate ASC";
-
-        PreparedStatement stmt;
-        try {
-            stmt = getConnection().prepareStatement(sql);
-            matches.addAll(super.getMatches(stmt));
-        } catch (final SQLException e) {
-            e.printStackTrace();
-        }
-
-        return matches;
-    }
-
     private ArrayList<League> getPrioLeagues() {
         final String sql = "SELECT * FROM League WHERE prio = 1";
         final ArrayList<League> result = Lists.newArrayList();
@@ -219,7 +219,9 @@ public class HomeDrawAwayTest extends TestClass {
             while (rs.next()) {
                 result.add(new League(rs.getInt("id"), rs.getString("name"), rs.getInt("scoringDiffLastGame"),
                         rs.getInt("scoringTotal"),
-                        rs.getInt("winLossRatioHomeAndAway"), rs.getInt("winLossRatio")));
+                        rs.getInt("winLossRatioHomeAndAway"), rs.getInt("winLossRatio"), rs.getInt("drawDiffHomeAway"),
+                        rs.getInt("drawDiffTotalGoals"), rs.getInt("drawWinningForm"),
+                        rs.getInt("drawWinngingFormHomeAway")));
             }
         } catch (final SQLException e) {
             e.printStackTrace();

+ 112 - 98
OddsJavaFx/src/tests/LeagueTablePositionTest.java

@@ -14,121 +14,135 @@ import tests.objects.Standing;
 
 public class LeagueTablePositionTest extends TestClass {
 
-	@Override public void runTest() {
-		List<LeagueDTO> prioLeagues = TestDatabase.getInstance().getPrioLeagues();
+    @Override
+    public void runTest() {
+        List<LeagueDTO> prioLeagues = TestDatabase.getInstance().getPrioLeagues();
 
-		for (LeagueDTO league : prioLeagues) {
-			if (league.getName().equals("championship")) {
-				runLeagueTest(league);
-			}
-		}
+        for (LeagueDTO league : prioLeagues) {
+            if (league.getName().equals("championship")) {
+                runLeagueTest(league);
+            }
+        }
 
-	}
+    }
 
-	private void runLeagueTest(LeagueDTO league) {
-		getMatches(league);
-	}
+    private void runLeagueTest(LeagueDTO league) {
+        getMatches(league);
+    }
 
-	private void getMatches(LeagueDTO league) {
+    private void getMatches(LeagueDTO league) {
 
-		List<SoccerMatch> matches = TestDatabase.getInstance().getMatches(league);
-		List<String> seasons = matches.stream().map(SoccerMatch::getSeason).distinct().sorted().toList();
+        List<SoccerMatch> matches = TestDatabase.getInstance().getMatches(league);
+        List<String> seasons = matches.stream().map(SoccerMatch::getSeason).distinct().sorted().toList();
 
-		for (String season : seasons.subList(1, seasons.size())) {
-			List<SoccerMatch> seasonMatches = matches.stream().filter(p -> p.getSeason().equals(season)).toList();
-			Map<String, Integer> intervals = getIntervals(seasonMatches);
-			int skipFirstXMatches = 10;
-			int currentMatch = 0;
+        for (String season : seasons.subList(1, seasons.size())) {
+            List<SoccerMatch> seasonMatches = matches.stream().filter(p -> p.getSeason().equals(season)).toList();
+            Map<String, Integer> intervals = getIntervals(seasonMatches);
+            int skipFirstXMatches = 10;
+            int currentMatch = 0;
 
-			int testValue = 0;
+            int testValue = 0;
 
-			seasonMatches = seasonMatches.stream().sorted((m1, m2) -> m1.getGameDate().compareTo(m2.getGameDate())).toList();
+            seasonMatches = seasonMatches.stream().sorted((m1, m2) -> m1.getGameDate().compareTo(m2.getGameDate()))
+                    .toList();
 
-			for (SoccerMatch match : seasonMatches) {
-				List<Standing> standings = getStandings(seasonMatches.stream().filter(p -> p.getGameDate().isBefore(match.getGameDate())).toList());
+            for (SoccerMatch match : seasonMatches) {
+                List<Standing> standings = getStandings(
+                        seasonMatches.stream().filter(p -> p.getGameDate().isBefore(match.getGameDate())).toList());
 
-				standings = standings.stream().sorted((s1, s2) -> Integer.compare(s2.getPoints(), s1.getPoints())).toList();
+                standings = standings.stream().sorted((s1, s2) -> Integer.compare(s2.getPoints(), s1.getPoints()))
+                        .toList();
 
-				Optional<Standing> homeTeamStanding = standings.stream().filter(p -> p.getTeamName().equals(match.getHomeTeam().getTeamName()))
-						.findFirst();
-				Optional<Standing> awayTeamStanding = standings.stream().filter(p -> p.getTeamName().equals(match.getAwayTeam().getTeamName()))
-						.findFirst();
-				if (homeTeamStanding.isPresent() && awayTeamStanding.isPresent() && homeTeamStanding.get().getGamesPlayed() >= skipFirstXMatches) {
-					Standing hts = homeTeamStanding.get();
-					Standing ats = awayTeamStanding.get();
+                Optional<Standing> homeTeamStanding = standings.stream()
+                        .filter(p -> p.getTeamName().equals(match.getHomeTeam().getTeamName()))
+                        .findFirst();
+                Optional<Standing> awayTeamStanding = standings.stream()
+                        .filter(p -> p.getTeamName().equals(match.getAwayTeam().getTeamName()))
+                        .findFirst();
+                if (homeTeamStanding.isPresent() && awayTeamStanding.isPresent()
+                        && homeTeamStanding.get().getGamesPlayed() >= skipFirstXMatches) {
+                    Standing hts = homeTeamStanding.get();
+                    Standing ats = awayTeamStanding.get();
 
-					int homeTeamPosition = standings.indexOf(hts);
-					int awayTeamPosition = standings.indexOf(ats);
+                    int homeTeamPosition = standings.indexOf(hts);
+                    int awayTeamPosition = standings.indexOf(ats);
 
 //					System.out.println(String.format("%s Hometeam %s position %s Awayteam %s position %s Diff %s", season, hts.getTeamName(),
 //							homeTeamPosition, ats.getTeamName(), awayTeamPosition, homeTeamPosition - awayTeamPosition));
 //					standings.forEach(s -> System.out.println(String.format("%s \t\t wins %s \t draws %s \t losses %s \t points %s \t gamesPlayed %s",
 //							s.getTeamName(), s.getWins(), s.getDraws(), s.getLosses(), s.getPoints(), s.getGamesPlayed())));
 
-					List<SoccerMatch> matchesBefore = matches.stream().filter(p -> p.getGameDate().isBefore(match.getGameDate())).toList();
-					matchesBefore = matchesBefore.stream().sorted((m1, m2) -> m1.getGameDate().compareTo(m2.getGameDate())).toList();
-					float avgGoals = getAvgGoalsWithSameDiff(matchesBefore, Math.abs(homeTeamPosition - awayTeamPosition));
-					List<Float> leagueAvarages = TestDatabase.getInstance().getLeagueAvarages(match.getHomeTeam().getTeamLeagueId(),
-							match.getHomeTeam().getCountryId(), match.getGameDate().format(DateTimeFormatter.BASIC_ISO_DATE));
-					if (Math.abs(avgGoals - (leagueAvarages.get(0) + leagueAvarages.get(1))) > 0.5) {
-						System.out.println(String.format(
-								"%s homeTeam: %s (%s) - awayTeam: %s (%s) Avg goals with diff %s is %s and leagueAvg is %s makes diff %s intervals is low %s mid %s high %s",
-								match.getGameDate(), match.getHomeTeam().getTeamName(), homeTeamPosition, match.getAwayTeam().getTeamName(),
-								awayTeamPosition, Math.abs(homeTeamPosition - awayTeamPosition), avgGoals,
-								leagueAvarages.get(0) + leagueAvarages.get(1), avgGoals - (leagueAvarages.get(0) + leagueAvarages.get(1)),
-								intervals.get("Low"), intervals.get("Low") + intervals.get("Mid"),
-								intervals.get("Low") + intervals.get("Mid") + intervals.get("High")));
-					}
-//					if (testValue++ > 100) {
-//						break; // TODO Testing
-//					}
-				}
-
-			}
-//			break; // TODO Testing
-		}
-	}
-
-	private float getAvgGoalsWithSameDiff(List<SoccerMatch> matchesBefore, int placementDiff) {
-		List<Standing> tempStanding = new ArrayList<>();
-		float result = 0.0f;
-		int matchedMatches = 0;
-		for (SoccerMatch match : matchesBefore) {
-			Optional<Standing> homeTeamStanding = tempStanding.stream().filter(ts -> ts.getTeamName().equals(match.getHomeTeam().getTeamName()))
-					.findFirst();
-			Optional<Standing> awayTeamStanding = tempStanding.stream().filter(ts -> ts.getTeamName().equals(match.getAwayTeam().getTeamName()))
-					.findFirst();
-
-			if (homeTeamStanding.isPresent() && awayTeamStanding.isPresent()) {
-				int homeTeamPosition = tempStanding.indexOf(homeTeamStanding.get());
-				int awayTeamPosition = tempStanding.indexOf(awayTeamStanding.get());
-
-				int diff = Math.abs(homeTeamPosition - awayTeamPosition);
-
-				if (diff == placementDiff) {
-					matchedMatches++;
-					result += match.getHomeScore() + match.getAwayScore();
-				}
-			}
-			updateStanding(tempStanding, match,
-					tempStanding.stream().filter(p -> p.getTeamName().equals(match.getHomeTeam().getTeamName())).findFirst(),
-					tempStanding.stream().filter(p -> p.getTeamName().equals(match.getAwayTeam().getTeamName())).findFirst());
-
-			tempStanding.sort((s1, s2) -> Integer.compare(s2.getPoints(), s1.getPoints()));
-		}
-
-		return matchedMatches > 0 ? result / matchedMatches : 0f;
-	}
-
-	private Map<String, Integer> getIntervals(List<SoccerMatch> seasonMatches) {
-		Map<String, Integer> result = new HashMap<>();
-
-		List<String> teams = seasonMatches.stream().map(m -> m.getHomeTeam().getTeamName()).distinct().toList();
-		result.put("Low", (int) Math.floor(teams.size() / 3.0));
-		result.put("Mid", (int) Math.ceil(teams.size() / 3.0));
-		result.put("High", (int) Math.floor(teams.size() / 3.0));
-
-		return result;
-	}
+                    List<SoccerMatch> matchesBefore = matches.stream()
+                            .filter(p -> p.getGameDate().isBefore(match.getGameDate())).toList();
+                    matchesBefore = matchesBefore.stream()
+                            .sorted((m1, m2) -> m1.getGameDate().compareTo(m2.getGameDate())).toList();
+                    float avgGoals = getAvgGoalsWithSameDiff(matchesBefore,
+                            Math.abs(homeTeamPosition - awayTeamPosition));
+                    List<Float> leagueAvarages = TestDatabase.getInstance().getLeagueAvarages(
+                            match.getHomeTeam().getTeamLeagueId(),
+                            match.getHomeTeam().getCountryId(),
+                            match.getGameDate().format(DateTimeFormatter.BASIC_ISO_DATE));
+                    if (Math.abs(avgGoals - (leagueAvarages.get(0) + leagueAvarages.get(1))) > 0.5) {
+                        System.out.println(String.format(
+                                "%s homeTeam: %s (%s) - awayTeam: %s (%s) Avg goals with diff %s is %s and leagueAvg is %s makes diff %s intervals is low %s mid %s high %s",
+                                match.getGameDate(), match.getHomeTeam().getTeamName(), homeTeamPosition,
+                                match.getAwayTeam().getTeamName(),
+                                awayTeamPosition, Math.abs(homeTeamPosition - awayTeamPosition), avgGoals,
+                                leagueAvarages.get(0) + leagueAvarages.get(1),
+                                avgGoals - (leagueAvarages.get(0) + leagueAvarages.get(1)),
+                                intervals.get("Low"), intervals.get("Low") + intervals.get("Mid"),
+                                intervals.get("Low") + intervals.get("Mid") + intervals.get("High")));
+                    }
+                }
+
+            }
+        }
+    }
+
+    private float getAvgGoalsWithSameDiff(List<SoccerMatch> matchesBefore, int placementDiff) {
+        List<Standing> tempStanding = new ArrayList<>();
+        float result = 0.0f;
+        int matchedMatches = 0;
+        for (SoccerMatch match : matchesBefore) {
+            Optional<Standing> homeTeamStanding = tempStanding.stream()
+                    .filter(ts -> ts.getTeamName().equals(match.getHomeTeam().getTeamName()))
+                    .findFirst();
+            Optional<Standing> awayTeamStanding = tempStanding.stream()
+                    .filter(ts -> ts.getTeamName().equals(match.getAwayTeam().getTeamName()))
+                    .findFirst();
+
+            if (homeTeamStanding.isPresent() && awayTeamStanding.isPresent()) {
+                int homeTeamPosition = tempStanding.indexOf(homeTeamStanding.get());
+                int awayTeamPosition = tempStanding.indexOf(awayTeamStanding.get());
+
+                int diff = Math.abs(homeTeamPosition - awayTeamPosition);
+
+                if (diff == placementDiff) {
+                    matchedMatches++;
+                    result += match.getHomeScore() + match.getAwayScore();
+                }
+            }
+            updateStanding(tempStanding, match,
+                    tempStanding.stream().filter(p -> p.getTeamName().equals(match.getHomeTeam().getTeamName()))
+                            .findFirst(),
+                    tempStanding.stream().filter(p -> p.getTeamName().equals(match.getAwayTeam().getTeamName()))
+                            .findFirst());
+
+            tempStanding.sort((s1, s2) -> Integer.compare(s2.getPoints(), s1.getPoints()));
+        }
+
+        return matchedMatches > 0 ? result / matchedMatches : 0f;
+    }
+
+    private Map<String, Integer> getIntervals(List<SoccerMatch> seasonMatches) {
+        Map<String, Integer> result = new HashMap<>();
+
+        List<String> teams = seasonMatches.stream().map(m -> m.getHomeTeam().getTeamName()).distinct().toList();
+        result.put("Low", (int) Math.floor(teams.size() / 3.0));
+        result.put("Mid", (int) Math.ceil(teams.size() / 3.0));
+        result.put("High", (int) Math.floor(teams.size() / 3.0));
+
+        return result;
+    }
 
 }

+ 27 - 33
OddsJavaFx/src/tests/PrioCountriesAll.java

@@ -19,6 +19,30 @@ public class PrioCountriesAll extends TestClass {
 
     private ArrayList<League> prioLeagues;
 
+    public ArrayList<SoccerMatch> getMatches() {
+        final ArrayList<SoccerMatch> matches = new ArrayList<>();
+        prioLeagues = getPrioLeagues();
+
+        final ArrayList<String> leagueIds = Lists.newArrayList();
+        prioLeagues.forEach(p -> leagueIds.add(String.valueOf(p.getLeagueId())));
+
+        final String sql = "SELECT res.*, " + "hTeam.name as homeTeamName, aTeam.name as awayTeamName "
+                + "FROM SoccerResults as res "
+                + "Join Team as hTeam ON res.homeTeam = hTeam.id " + "Join Team as aTeam ON res.awayTeam = aTeam.id "
+                + "WHERE " + "res.leagueId IN ("
+                + String.join(",", leagueIds) + ") " + "ORDER BY gameDate ASC";
+
+        PreparedStatement stmt;
+        try {
+            stmt = getConnection().prepareStatement(sql);
+            matches.addAll(super.getMatches(stmt));
+        } catch (final SQLException e) {
+            e.printStackTrace();
+        }
+
+        return matches;
+    }
+
     @Override
     public void runTest() {
         float bank = 1000;
@@ -116,30 +140,6 @@ public class PrioCountriesAll extends TestClass {
         return returnValue;
     }
 
-    public ArrayList<SoccerMatch> getMatches() {
-        final ArrayList<SoccerMatch> matches = new ArrayList<>();
-        prioLeagues = getPrioLeagues();
-
-        final ArrayList<String> leagueIds = Lists.newArrayList();
-        prioLeagues.forEach(p -> leagueIds.add(String.valueOf(p.getLeagueId())));
-
-        final String sql = "SELECT res.*, " + "hTeam.name as homeTeamName, aTeam.name as awayTeamName "
-                + "FROM SoccerResults as res "
-                + "Join Team as hTeam ON res.homeTeam = hTeam.id " + "Join Team as aTeam ON res.awayTeam = aTeam.id "
-                + "WHERE " + "res.leagueId IN ("
-                + String.join(",", leagueIds) + ") " + "ORDER BY gameDate ASC";
-
-        PreparedStatement stmt;
-        try {
-            stmt = getConnection().prepareStatement(sql);
-            matches.addAll(super.getMatches(stmt));
-        } catch (final SQLException e) {
-            e.printStackTrace();
-        }
-
-        return matches;
-    }
-
     private ArrayList<League> getPrioLeagues() {
         final String sql = "SELECT * FROM League WHERE prio = 1";
         final ArrayList<League> result = Lists.newArrayList();
@@ -150,7 +150,9 @@ public class PrioCountriesAll extends TestClass {
             while (rs.next()) {
                 result.add(new League(rs.getInt("id"), rs.getString("name"), rs.getInt("scoringDiffLastGame"),
                         rs.getInt("scoringTotal"),
-                        rs.getInt("winLossRatioHomeAndAway"), rs.getInt("winLossRatio")));
+                        rs.getInt("winLossRatioHomeAndAway"), rs.getInt("winLossRatio"), rs.getInt("drawDiffHomeAway"),
+                        rs.getInt("drawDiffTotalGoals"), rs.getInt("drawWinningForm"),
+                        rs.getInt("drawWinngingFormHomeAway")));
             }
         } catch (final SQLException e) {
             e.printStackTrace();
@@ -159,12 +161,4 @@ public class PrioCountriesAll extends TestClass {
         return result;
     }
 
-    @Override
-    public void setup(String date, float startingBank, float bettingLevel, Float betMargin, int lookBack, int sportId,
-            Integer countryId,
-            Integer leagueId) {
-        // TODO Auto-generated method stub
-
-    }
-
 }

+ 158 - 54
OddsJavaFx/src/tests/RelevanceTest.java

@@ -1,11 +1,12 @@
 package tests;
 
-import java.util.Collections;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Optional;
 import java.util.TreeMap;
 
 import data.TestDatabase;
@@ -13,6 +14,7 @@ import objects.SoccerMatch;
 import objects.SoccerMatchAnalysis;
 import tests.objects.LeagueDTO;
 
+@java.lang.SuppressWarnings("squid:S106")
 public class RelevanceTest extends TestClass {
 
     // Premiere League Siffror
@@ -45,12 +47,10 @@ public class RelevanceTest extends TestClass {
     // best lookback 7 winLossRationHomeAndAway
     // best lookback 15 winLossRatio
 
-    private TestDatabase database;
-
     int scoringDiffLastGames = 8;
     int scoringTotal = 4;
     int winLossRationHomeAndAway = 12;
-    int WinLossRatio = 2;
+    int winLossRatio = 2;
 
     Map<Float, Integer> winsOnDiff = new HashMap<>();
     Map<Float, Integer> lossesOnDiff = new HashMap<>();
@@ -64,67 +64,104 @@ public class RelevanceTest extends TestClass {
     float bestPercent = 0;
     int bestLookback = 0;
 
-    Map<Integer, Float> resultsDiffTotalGoals = new HashMap<>();
-    Map<Integer, Float> resultsDiffHomeAway = new HashMap<>();
-    Map<Integer, Float> resultsWinningForm = new HashMap<>();
-    Map<Integer, Float> resultsWinnignFormHomeVsAway = new HashMap<>();
-    Map<Integer, Float> results = new HashMap<>();
+    List<Res> resultsDiffTotalGoals = new ArrayList<>();
+    List<Res> resultsDiffHomeAway = new ArrayList<>();
+    List<Res> resultsWinningForm = new ArrayList<>();
+    List<Res> resultsWinnignFormHomeVsAway = new ArrayList<>();
+
+    List<Res> results = new ArrayList<>();
     Map<String, Float> resultsCombined = new HashMap<>();
 
     String season;
 
+    private float bestDrawPercent;
+
     @Override
     public void runTest() {
-        database = TestDatabase.getInstance();
+        TestDatabase database = TestDatabase.getInstance();
         LeagueDTO leagueDTO = database.getLeagueDTO(leagueId);
         LinkedHashMap<String, List<SoccerMatch>> matches = getMatchesOrderedBySeason(leagueDTO);
 
-        boolean skipFirst = true;
+        boolean skipFirst = false;
         for (Entry<String, List<SoccerMatch>> seasonMatches : matches.entrySet()) {
             if (skipFirst) {
                 skipFirst = false;
                 continue;
             }
-//            for (int i = 1; i < 20; i++) {
-//                gamesLookback = i;
-            season = seasonMatches.getKey();
-//            analyzeDiffHomeAway(seasonMatches.getValue(), resultsDiffHomeAway);
-//            analyzeDiffTotalGoals(seasonMatches.getValue(), resultsDiffTotalGoals);
-//            analyzeWinnigForm(seasonMatches.getValue(), resultsWinningForm);
-//            analyzeWinnigFormHomeVsAway(seasonMatches.getValue(), resultsWinnignFormHomeVsAway);
-            System.out.println("Season " + seasonMatches.getKey());
-            analyzeCombination(seasonMatches.getValue());
+            for (int i = 1; i < 20; i++) {
+                gamesLookback = i;
+                season = seasonMatches.getKey();
+                analyzeDiffHomeAway(seasonMatches.getValue(), resultsDiffHomeAway);
+                analyzeDiffTotalGoals(seasonMatches.getValue(), resultsDiffTotalGoals);
+                analyzeWinnigForm(seasonMatches.getValue(), resultsWinningForm);
+                analyzeWinnigFormHomeVsAway(seasonMatches.getValue(), resultsWinnignFormHomeVsAway);
+//            System.out.println("Season " + seasonMatches.getKey());
+//            analyzeCombination(seasonMatches.getValue());
 //            break;
-//            }
+            }
         }
 
         resultsCombined.forEach((k, v) -> System.out.println(k + " result " + v));
 
-//        resultsDiffHomeAway.entrySet().stream().sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
-//                .limit(5)
-//                .forEach(e -> System.out
-//                        .println("resultsDiffHomeAway Lookback " + e.getKey() + " value " + e.getValue()));
-//        resultsDiffTotalGoals.entrySet().stream().sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
-//                .limit(5)
-//                .forEach(e -> System.out
-//                        .println("resultsDiffTotalGoals Lookback " + e.getKey() + " value " + e.getValue()));
-//        resultsWinningForm.entrySet().stream().sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
-//                .limit(5)
-//                .forEach(e -> System.out
-//                        .println("resultsWinningForm Lookback " + e.getKey() + " value " + e.getValue()));
-//        resultsWinnignFormHomeVsAway.entrySet().stream().sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
-//                .limit(5)
-//                .forEach(e -> System.out
-//                        .println("resultsWinnignFormHomeVsAway Lookback " + e.getKey() + " value " + e.getValue()));
-
-        results.entrySet().stream().sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
+        resultsDiffHomeAway.stream().sorted((r1, r2) -> Float.compare(r2.getResult(), r1.getResult()))
+                .limit(5)
+                .forEach(e -> System.out
+                        .println("resultsDiffHomeAway Lookback " + e.getLookback() + " value " + e.getResult()));
+        resultsDiffTotalGoals.stream().sorted((r1, r2) -> Float.compare(r2.getResult(), r1.getResult()))
+                .limit(5)
+                .forEach(e -> System.out
+                        .println("resultsDiffTotalGoals Lookback " + e.getLookback() + " value " + e.getResult()));
+
+        resultsWinningForm.stream().sorted((r1, r2) -> Float.compare(r2.getResult(), r1.getResult()))
+                .limit(5)
+                .forEach(e -> System.out
+                        .println("resultsWinningForm Lookback " + e.getLookback() + " value " + e.getResult()));
+
+        resultsWinnignFormHomeVsAway.stream().sorted((r1, r2) -> Float.compare(r2.getResult(), r1.getResult()))
                 .limit(5)
-                .forEach(e -> System.out.println("Lookback " + e.getKey() + " value " + e.getValue()));
+                .forEach(e -> System.out
+                        .println("resultsWinnignFormHomeVsAway Lookback " + e.getLookback() + " value "
+                                + e.getResult()));
+
+        resultsDiffHomeAway.stream()
+                .sorted((r1, r2) -> Float
+                        .compare(r2.getDrawPercent(), r1.getDrawPercent()))
+                .limit(5)
+                .forEach(e -> System.out
+                        .println("resultsDiffHomeAway Draws correct " + e.getDrawPercent()
+                                + " played "
+                                + e.getDrawsPlayed() + " lookback " + e.getLookback()));
+
+        resultsDiffTotalGoals.stream()
+                .sorted((r1, r2) -> Float.compare(r2.getDrawPercent(), r1.getDrawPercent()))
+                .limit(5)
+                .forEach(e -> System.out
+                        .println("resultsDiffTotalGoals Draws correct " + e.getDrawPercent()
+                                + " played "
+                                + e.getDrawsPlayed() + " lookback " + e.getLookback()));
+
+        resultsWinningForm.stream()
+                .sorted((r1, r2) -> Float
+                        .compare(r2.getDrawPercent(), r1.getDrawPercent()))
+                .limit(5)
+                .forEach(e -> System.out
+                        .println("resultsWinningForm Draws correct " + e.getDrawPercent()
+                                + " played "
+                                + e.getDrawsPlayed() + " lookback " + e.getLookback()));
+
+        resultsWinnignFormHomeVsAway.stream()
+                .sorted((r1, r2) -> Float.compare(r2.getDrawPercent(), r1.getDrawPercent()))
+                .limit(5)
+                .forEach(e -> System.out
+                        .println("resultsWinnignFormHomeVsAway Draws correct " + e.getDrawPercent()
+                                + " played "
+                                + e.getDrawsPlayed() + " lookback " + e.getLookback()));
+
         System.out.println("Best percent " + bestPercent + " best lookback " + bestLookback);
 
     }
 
-    private void analyzeDiffHomeAway(List<SoccerMatch> matches, Map<Integer, Float> resultsDiffHomeAway) {
+    private void analyzeDiffHomeAway(List<SoccerMatch> matches, List<Res> resultsDiffHomeAway) {
         System.out.println("Analysis Diff Home Away");
         winsOnDiff = new HashMap<>();
         lossesOnDiff = new HashMap<>();
@@ -135,9 +172,7 @@ public class RelevanceTest extends TestClass {
 
         for (SoccerMatch soccerMatch : matches) {
             SoccerMatchAnalysis soccerMatchAnalysis = new SoccerMatchAnalysis(soccerMatch);
-            float scoringDiffLastGames = soccerMatchAnalysis.getScoringDiffLastGames(gamesLookback);
-
-            checkBetResults(soccerMatch, scoringDiffLastGames);
+            checkBetResults(soccerMatch, soccerMatchAnalysis.getScoringDiffLastGames(gamesLookback));
         }
 
         TreeMap<Float, Integer> lossesSorted = sortMap(lossesOnDiff);
@@ -152,7 +187,7 @@ public class RelevanceTest extends TestClass {
         return winsSorted;
     }
 
-    private void analyzeDiffTotalGoals(List<SoccerMatch> matches, Map<Integer, Float> resultsDiffTotalGoals) {
+    private void analyzeDiffTotalGoals(List<SoccerMatch> matches, List<Res> resultsDiffTotalGoals) {
         System.out.println("Analysis Diff total goals");
         winsOnDiff = new HashMap<>();
         lossesOnDiff = new HashMap<>();
@@ -177,7 +212,7 @@ public class RelevanceTest extends TestClass {
         printResults(winsSorted, lossesSorted, true, resultsDiffTotalGoals);
     }
 
-    private void analyzeWinnigForm(List<SoccerMatch> matches, Map<Integer, Float> resultsWinningForm) {
+    private void analyzeWinnigForm(List<SoccerMatch> matches, List<Res> resultsWinningForm) {
         System.out.println("annalysis Winning form homeAndAway!");
         winsOnDiff = new HashMap<>();
         lossesOnDiff = new HashMap<>();
@@ -203,7 +238,7 @@ public class RelevanceTest extends TestClass {
     }
 
     private void analyzeWinnigFormHomeVsAway(List<SoccerMatch> matches,
-            Map<Integer, Float> resultsWinnignFormHomeVsAway) {
+            List<Res> resultsWinnignFormHomeVsAway) {
         System.out.println("annalysis Winning form homeVsAway!");
         winsOnDiff = new HashMap<>();
         lossesOnDiff = new HashMap<>();
@@ -244,8 +279,8 @@ public class RelevanceTest extends TestClass {
 
         for (SoccerMatch soccerMatch : matches) {
             SoccerMatchAnalysis analysis = new SoccerMatchAnalysis(soccerMatch);
-            int homeWinsCount = analysis.winLossRatio(WinLossRatio, true);
-            int awayWindCount = analysis.winLossRatio(WinLossRatio, false);
+            int homeWinsCount = analysis.winLossRatio(winLossRatio, true);
+            int awayWindCount = analysis.winLossRatio(winLossRatio, false);
 
             int homeWinLossRatioCount = analysis.winLossRationHomeAndAway(true, winLossRationHomeAndAway);
             int awayWinLossRatioCount = analysis.winLossRationHomeAndAway(false, winLossRationHomeAndAway);
@@ -311,7 +346,7 @@ public class RelevanceTest extends TestClass {
     }
 
     private void printResults(TreeMap<Float, Integer> winsSorted, TreeMap<Float, Integer> lossesSorted,
-            boolean onlyPercentages, Map<Integer, Float> resultsArray) {
+            boolean onlyPercentages, List<Res> resultsArray) {
         StringBuilder winsBuilder = new StringBuilder();
         winsSorted.forEach((k, v) -> winsBuilder.append(k + " wins " + v + "\n"));
         StringBuilder lossesBuilder = new StringBuilder();
@@ -326,18 +361,87 @@ public class RelevanceTest extends TestClass {
         }
 
         float winValue = totalWins / (float) (totalWins + totalLosses);
-        Float res = results.getOrDefault(gamesLookback, 0f);
-
-        resultsArray.put(gamesLookback, res + winValue);
+        Optional<Res> optional = resultsArray.stream().filter(p -> p.getLookback() == gamesLookback).findFirst();
+        Res result;
+        if (optional.isPresent()) {
+            result = optional.get();
+            result.setResult(result.getResult() + winValue);
+            result.setDrawsPlayed(result.getDrawsPlayed() + draws);
+            result.setDrawCorrect(result.getDrawCorrect() + drawsCorrect);
+            resultsArray.set(gamesLookback, result);
+        } else {
+            result = new Res(gamesLookback, winValue, drawsCorrect, draws);
+            resultsArray.add(result);
+        }
 
         if (winValue > bestPercent) {
             bestPercent = winValue;
             bestLookback = gamesLookback;
         }
 
-        System.out.println("Totals");
+        float drawValue = drawsCorrect / (float) draws;
+        if (drawValue > bestDrawPercent) {
+            bestDrawPercent = drawValue;
+            bestDrawLookback = gamesLookback;
+        }
+
+        System.out.println("Totals " + gamesLookback);
         System.out.println(winValue + " % total " + (totalWins + totalLosses));
         System.out.println("Draws " + drawsCorrect / (float) draws + " % total " + draws);
     }
 
+    class Res {
+
+        int lookback = 0;
+        float result = 0;
+        float drawCorrect = 0;
+        int drawsPlayed = 0;
+
+        public Res() {
+        }
+
+        public Res(int lookback, float result, float drawCorrect, int drawsPlayed) {
+            super();
+            this.lookback = lookback;
+            this.result = result;
+            this.drawCorrect = drawCorrect;
+            this.drawsPlayed = drawsPlayed;
+        }
+
+        public int getLookback() {
+            return lookback;
+        }
+
+        public float getResult() {
+            return result;
+        }
+
+        public float getDrawCorrect() {
+            return drawCorrect;
+        }
+
+        public int getDrawsPlayed() {
+            return drawsPlayed;
+        }
+
+        public void setLookback(int lookback) {
+            this.lookback = lookback;
+        }
+
+        public void setResult(float result) {
+            this.result = result;
+        }
+
+        public void setDrawCorrect(float drawResult) {
+            this.drawCorrect = drawResult;
+        }
+
+        public void setDrawsPlayed(int drawsPlayed) {
+            this.drawsPlayed = drawsPlayed;
+        }
+
+        public float getDrawPercent() {
+            return drawCorrect / drawsPlayed;
+        }
+    }
 }

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

@@ -137,8 +137,8 @@ public abstract class TestClass {
                 this.bestDrawBank = startingBank;
                 this.bestAwayBank = startingBank;
 
-                // TODO Fixa s� att man kontrollerar 1 �r bak�t i tiden som Filtered Matches,
-                // plocka bort om possitive results �r f�rre �n 50%
+                // TODO Fixa s� att man kontrollerar 1 år bakåt i tiden som Filtered Matches,
+                // plocka bort om possitive results är färreän 50%
                 recalcHome(matches);
                 recalcDraw(matches);
                 recalcAway(matches);