Files
Tritone/HorseRacingPredictor/HorseRacingPredictor/Main.cs
Alberto Balbo 72bd778d56 Migrazione UI a WPF e integrazione Racing API moderna
Transizione completa da WinForms a WPF con interfaccia moderna (sidebar, pagine, palette Catppuccin Mocha).
Aggiunta integrazione con The Racing API per le corse dei cavalli, inclusi nuovi moduli di backend e parsing dati.
Introdotti componenti UI personalizzati (CardPanel, ModernButton, ModernProgressBar, NavButton, ModernTheme) per un look coerente e moderno.
Gestione avanzata delle impostazioni, esportazione CSV migliorata, refactoring della logica di business e maggiore robustezza nelle chiamate API.
Aggiunti stub CsvHelper e file di progetto di backup per facilitare la compatibilità e la migrazione.
2026-02-25 18:49:48 +01:00

397 lines
14 KiB
C#

using BettingPredictor.UI;
using System;
using System.Data;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace BettingPredictor
{
public partial class Main : Form
{
private readonly HorseRacingPredictor.Football.Main footballManager;
private HorseRacingPredictor.HorseRacing.Main racingManager;
private DataTable footballData;
private DataTable racingData;
// Credenziali predefinite Racing API
private const string DefaultRacingUser = "qi1mHOHPquDY9KNDASAeGipy";
private const string DefaultRacingPass = "RXNFU1YX27R9rTnk8Vop8ZfH";
// Pagine e nav gestiti come array per semplificare la navigazione
private Panel[] pages;
private NavButton[] navButtons;
private string[] pageTitles;
public Main()
{
InitializeComponent();
footballManager = new HorseRacingPredictor.Football.Main();
racingManager = new HorseRacingPredictor.HorseRacing.Main(DefaultRacingUser, DefaultRacingPass);
pages = new[] { pageFootball, pageHorseRacing, pageSettings, pageInfo };
navButtons = new[] { navFootball, navHorseRacing, navSettings, navInfo };
pageTitles = new[] { "Calcio", "Corse Cavalli", "Impostazioni", "Informazioni" };
}
#region Navigation
private void ShowPage(int index)
{
for (int i = 0; i < pages.Length; i++)
{
pages[i].Visible = (i == index);
navButtons[i].IsActive = (i == index);
}
labelPageTitle.Text = pageTitles[index];
}
private void navFootball_Click(object sender, EventArgs e) => ShowPage(0);
private void navHorseRacing_Click(object sender, EventArgs e) => ShowPage(1);
private void navSettings_Click(object sender, EventArgs e) => ShowPage(2);
private void navInfo_Click(object sender, EventArgs e) => ShowPage(3);
#endregion
#region Football
private async Task DownloadFootballFixturesAsync(DateTime selectedDate)
{
try
{
progressBarFootball.Minimum = 0;
progressBarFootball.Maximum = 100;
progressBarFootball.Value = 0;
labelStatusFootball.Text = "Scaricamento elenco partite...";
dateTimePicker.Enabled = false;
btnDownload.Enabled = false;
btnExportCsv.Enabled = false;
var progress = new Progress<int>(v => progressBarFootball.Value = v);
var status = new Progress<string>(s => labelStatusFootball.Text = s);
var table = await Task.Run(() =>
footballManager.GetTodayFixtures(selectedDate, progress, status));
footballData = table;
dataGridViewFootball.DataSource = footballData;
if (footballData != null && footballData.Rows.Count > 0)
{
btnExportCsv.Enabled = true;
labelStatusFootball.Text = $"Scaricate {footballData.Rows.Count} partite";
}
else
{
labelStatusFootball.Text = "Nessuna partita trovata per la data selezionata";
}
}
catch (Exception ex)
{
MessageBox.Show($"Errore durante lo scaricamento:\n{ex.Message}",
"Errore", MessageBoxButtons.OK, MessageBoxIcon.Error);
labelStatusFootball.Text = "Errore nello scaricamento";
progressBarFootball.Value = 0;
}
finally
{
dateTimePicker.Enabled = true;
btnDownload.Enabled = true;
}
}
private void ExportFootballToCsv()
{
if (footballData == null || footballData.Rows.Count == 0)
{
MessageBox.Show("Nessun dato da esportare. Scarica prima le partite.",
"Nessun dato", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
string folder = txtExportPath.Text;
string filePath = null;
if (!string.IsNullOrEmpty(folder) && Directory.Exists(folder))
{
filePath = Path.Combine(folder, $"Partite_{dateTimePicker.Value:yyyy-MM-dd}.csv");
}
else
{
using (var dlg = new SaveFileDialog())
{
dlg.Filter = "File CSV|*.csv";
dlg.FileName = $"Partite_{dateTimePicker.Value:yyyy-MM-dd}.csv";
if (dlg.ShowDialog() != DialogResult.OK) return;
filePath = dlg.FileName;
}
}
try
{
var sb = new StringBuilder();
var headers = new string[footballData.Columns.Count];
for (int i = 0; i < footballData.Columns.Count; i++)
headers[i] = footballData.Columns[i].ColumnName;
sb.AppendLine(string.Join(";", headers));
foreach (DataRow row in footballData.Rows)
{
var vals = new string[footballData.Columns.Count];
for (int i = 0; i < footballData.Columns.Count; i++)
{
var v = row[i]?.ToString() ?? "";
if (v.Contains(";") || v.Contains("\""))
v = "\"" + v.Replace("\"", "\"\"") + "\"";
vals[i] = v;
}
sb.AppendLine(string.Join(";", vals));
}
File.WriteAllText(filePath, sb.ToString(), Encoding.UTF8);
labelStatusFootball.Text = $"CSV esportato: {Path.GetFileName(filePath)}";
MessageBox.Show($"Esportate {footballData.Rows.Count} partite in:\n{filePath}",
"Esportazione completata", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show($"Errore durante l'esportazione CSV:\n{ex.Message}",
"Errore", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
#endregion
#region Horse Racing
private async Task DownloadRacecardsAsync()
{
try
{
progressBarRacing.Minimum = 0;
progressBarRacing.Maximum = 100;
progressBarRacing.Value = 0;
labelStatusRacing.Text = "Scaricamento racecard...";
cmbRacingDay.Enabled = false;
btnDownloadRacing.Enabled = false;
btnExportRacingCsv.Enabled = false;
var progress = new Progress<int>(v => progressBarRacing.Value = v);
var status = new Progress<string>(s => labelStatusRacing.Text = s);
string day = cmbRacingDay.SelectedIndex == 0 ? "today" : "tomorrow";
var table = await Task.Run(() =>
racingManager.GetRacecards(day, progress, status));
racingData = table;
dataGridViewRacing.DataSource = racingData;
if (racingData != null && racingData.Rows.Count > 0)
{
btnExportRacingCsv.Enabled = true;
labelStatusRacing.Text = $"Trovate {racingData.Rows.Count} corse";
}
else
{
labelStatusRacing.Text = "Nessuna corsa trovata";
}
}
catch (Exception ex)
{
MessageBox.Show($"Errore durante lo scaricamento:\n{ex.Message}",
"Errore", MessageBoxButtons.OK, MessageBoxIcon.Error);
labelStatusRacing.Text = "Errore nello scaricamento";
progressBarRacing.Value = 0;
}
finally
{
cmbRacingDay.Enabled = true;
btnDownloadRacing.Enabled = true;
}
}
private void ExportRacingToCsv()
{
if (racingData == null || racingData.Rows.Count == 0)
{
MessageBox.Show("Nessun dato da esportare. Scarica prima le corse.",
"Nessun dato", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
string folder = txtExportPath.Text;
string dayLabel = cmbRacingDay.SelectedIndex == 0 ? "oggi" : "domani";
string filePath = null;
if (!string.IsNullOrEmpty(folder) && Directory.Exists(folder))
{
filePath = Path.Combine(folder, $"Corse_{dayLabel}_{DateTime.Now:yyyy-MM-dd}.csv");
}
else
{
using (var dlg = new SaveFileDialog())
{
dlg.Filter = "File CSV|*.csv";
dlg.FileName = $"Corse_{dayLabel}_{DateTime.Now:yyyy-MM-dd}.csv";
if (dlg.ShowDialog() != DialogResult.OK) return;
filePath = dlg.FileName;
}
}
try
{
var sb = new StringBuilder();
var headers = new string[racingData.Columns.Count];
for (int i = 0; i < racingData.Columns.Count; i++)
headers[i] = racingData.Columns[i].ColumnName;
sb.AppendLine(string.Join(";", headers));
foreach (DataRow row in racingData.Rows)
{
var vals = new string[racingData.Columns.Count];
for (int i = 0; i < racingData.Columns.Count; i++)
{
var v = row[i]?.ToString() ?? "";
if (v.Contains(";") || v.Contains("\""))
v = "\"" + v.Replace("\"", "\"\"") + "\"";
vals[i] = v;
}
sb.AppendLine(string.Join(";", vals));
}
File.WriteAllText(filePath, sb.ToString(), Encoding.UTF8);
labelStatusRacing.Text = $"CSV esportato: {Path.GetFileName(filePath)}";
MessageBox.Show($"Esportate {racingData.Rows.Count} corse in:\n{filePath}",
"Esportazione completata", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show($"Errore durante l'esportazione CSV:\n{ex.Message}",
"Errore", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
#endregion
#region Settings
private string SettingsFilePath =>
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "settings.ini");
private void LoadSettings()
{
try
{
// Imposta valori predefiniti Racing API
txtRacingUser.Text = DefaultRacingUser;
txtRacingPass.Text = DefaultRacingPass;
if (!File.Exists(SettingsFilePath)) return;
foreach (var line in File.ReadAllLines(SettingsFilePath))
{
var idx = line.IndexOf('=');
if (idx < 0) continue;
var key = line.Substring(0, idx).Trim();
var val = line.Substring(idx + 1).Trim();
if (key == "ApiKey") txtApiKey.Text = val;
else if (key == "ExportPath") txtExportPath.Text = val;
else if (key == "RacingUser") txtRacingUser.Text = val;
else if (key == "RacingPass") txtRacingPass.Text = val;
}
// Aggiorna il manager con le credenziali caricate
racingManager.UpdateCredentials(txtRacingUser.Text, txtRacingPass.Text);
}
catch { }
}
private void SaveSettings()
{
try
{
var sb = new StringBuilder();
sb.AppendLine($"ApiKey={txtApiKey.Text.Trim()}");
sb.AppendLine($"ExportPath={txtExportPath.Text.Trim()}");
sb.AppendLine($"RacingUser={txtRacingUser.Text.Trim()}");
sb.AppendLine($"RacingPass={txtRacingPass.Text.Trim()}");
File.WriteAllText(SettingsFilePath, sb.ToString(), Encoding.UTF8);
// Aggiorna il manager con le nuove credenziali
racingManager.UpdateCredentials(txtRacingUser.Text.Trim(), txtRacingPass.Text.Trim());
MessageBox.Show("Impostazioni salvate con successo.",
"Salvato", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show($"Errore nel salvataggio:\n{ex.Message}",
"Errore", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
#endregion
#region Event handlers
private void Main_Load(object sender, EventArgs e)
{
dateTimePicker.Value = DateTime.Today;
progressBarFootball.Value = 0;
labelStatusFootball.Text = "Pronto";
progressBarRacing.Value = 0;
labelStatusRacing.Text = "Pronto";
LoadSettings();
LayoutToolbars();
}
private void Main_Resize(object sender, EventArgs e)
{
LayoutToolbars();
}
private void btnDownload_Click(object sender, EventArgs e)
{
_ = DownloadFootballFixturesAsync(dateTimePicker.Value);
}
private void btnExportCsv_Click(object sender, EventArgs e)
{
ExportFootballToCsv();
}
private void btnDownloadRacing_Click(object sender, EventArgs e)
{
_ = DownloadRacecardsAsync();
}
private void btnExportRacingCsv_Click(object sender, EventArgs e)
{
ExportRacingToCsv();
}
private void btnBrowseExport_Click(object sender, EventArgs e)
{
using (var dlg = new FolderBrowserDialog())
{
dlg.Description = "Seleziona la cartella di esportazione CSV";
if (dlg.ShowDialog() == DialogResult.OK)
txtExportPath.Text = dlg.SelectedPath;
}
}
private void btnSaveSettings_Click(object sender, EventArgs e)
{
SaveSettings();
}
#endregion
}
}