Files
Tritone/HorseRacingPredictor/HorseRacingPredictor/HorseRacing/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

267 lines
9.9 KiB
C#

using System;
using System.Data;
using System.Text.Json;
using HorseRacingPredictor.HorseRacing.API;
namespace HorseRacingPredictor.HorseRacing
{
/// <summary>
/// Gestore centralizzato per la sezione Corse dei Cavalli.
/// Scarica i dati da The Racing API e li converte in DataTable.
/// </summary>
public class Main
{
private RacingApiClient _client;
public Main(string username, string password)
{
_client = new RacingApiClient(username, password);
}
/// <summary>
/// Aggiorna le credenziali API
/// </summary>
public void UpdateCredentials(string username, string password)
{
_client = new RacingApiClient(username, password);
}
/// <summary>
/// Scarica le racecard (programma corse) per oggi o domani e le restituisce come DataTable
/// </summary>
public DataTable GetRacecards(string day, IProgress<int> progress = null, IProgress<string> status = null)
{
try
{
status?.Report("Connessione a The Racing API...");
progress?.Report(10);
var response = _client.GetRacecardsFree(day);
progress?.Report(60);
status?.Report("Elaborazione racecard...");
var table = ParseRacecardsResponse(response.Content);
progress?.Report(100);
status?.Report($"Trovate {table.Rows.Count} corse");
return table;
}
catch (Exception ex)
{
status?.Report($"Errore: {ex.Message}");
return CreateEmptyRacecardsTable();
}
}
/// <summary>
/// Scarica i risultati per un intervallo di date
/// </summary>
public DataTable GetResults(DateTime startDate, DateTime endDate,
IProgress<int> progress = null, IProgress<string> status = null)
{
try
{
status?.Report("Scaricamento risultati...");
progress?.Report(10);
var response = _client.GetResults(startDate, endDate);
progress?.Report(60);
status?.Report("Elaborazione risultati...");
var table = ParseResultsResponse(response.Content);
progress?.Report(100);
status?.Report($"Trovati {table.Rows.Count} risultati");
return table;
}
catch (Exception ex)
{
status?.Report($"Errore: {ex.Message}");
return CreateEmptyResultsTable();
}
}
#region DataTable creation
private DataTable CreateEmptyRacecardsTable()
{
var dt = new DataTable();
dt.Columns.Add("Ora", typeof(string));
dt.Columns.Add("Ippodromo", typeof(string));
dt.Columns.Add("Regione", typeof(string));
dt.Columns.Add("Corsa", typeof(string));
dt.Columns.Add("Distanza", typeof(string));
dt.Columns.Add("Tipo", typeof(string));
dt.Columns.Add("Classe", typeof(string));
dt.Columns.Add("Terreno", typeof(string));
dt.Columns.Add("N. Corridori", typeof(int));
dt.Columns.Add("Età", typeof(string));
dt.Columns.Add("Premio", typeof(string));
return dt;
}
private DataTable CreateEmptyResultsTable()
{
var dt = new DataTable();
dt.Columns.Add("Data", typeof(string));
dt.Columns.Add("Ippodromo", typeof(string));
dt.Columns.Add("Corsa", typeof(string));
dt.Columns.Add("Distanza", typeof(string));
dt.Columns.Add("Terreno", typeof(string));
dt.Columns.Add("1° Classificato", typeof(string));
dt.Columns.Add("2° Classificato", typeof(string));
dt.Columns.Add("3° Classificato", typeof(string));
dt.Columns.Add("Fantino 1°", typeof(string));
dt.Columns.Add("SP 1°", typeof(string));
return dt;
}
#endregion
#region JSON Parsing
private DataTable ParseRacecardsResponse(string json)
{
var dt = CreateEmptyRacecardsTable();
if (string.IsNullOrEmpty(json)) return dt;
try
{
using (var doc = JsonDocument.Parse(json))
{
var root = doc.RootElement;
if (!root.TryGetProperty("racecards", out var racecardsEl))
return dt;
foreach (var rc in racecardsEl.EnumerateArray())
{
try
{
var row = dt.NewRow();
row["Ora"] = GetString(rc, "off_time", "");
row["Ippodromo"] = GetString(rc, "course", "");
row["Regione"] = GetString(rc, "region", "");
row["Corsa"] = GetString(rc, "race_name", "");
row["Distanza"] = GetString(rc, "distance", "");
row["Tipo"] = GetString(rc, "type", "");
row["Classe"] = GetString(rc, "race_class", "");
row["Terreno"] = GetString(rc, "going", "");
row["Età"] = GetString(rc, "age_band", "");
row["Premio"] = GetString(rc, "prize", "");
if (rc.TryGetProperty("runners", out var runnersEl) &&
runnersEl.ValueKind == JsonValueKind.Array)
{
row["N. Corridori"] = runnersEl.GetArrayLength();
}
else if (rc.TryGetProperty("field_size", out var fsEl) &&
fsEl.ValueKind == JsonValueKind.Number)
{
row["N. Corridori"] = fsEl.GetInt32();
}
else
{
row["N. Corridori"] = 0;
}
dt.Rows.Add(row);
}
catch
{
// Salta righe problematiche
}
}
}
}
catch
{
// Restituisci tabella vuota in caso di errore di parsing
}
return dt;
}
private DataTable ParseResultsResponse(string json)
{
var dt = CreateEmptyResultsTable();
if (string.IsNullOrEmpty(json)) return dt;
try
{
using (var doc = JsonDocument.Parse(json))
{
var root = doc.RootElement;
if (!root.TryGetProperty("results", out var resultsEl))
return dt;
foreach (var res in resultsEl.EnumerateArray())
{
try
{
var row = dt.NewRow();
row["Data"] = GetString(res, "date", "");
row["Ippodromo"] = GetString(res, "course", "");
row["Corsa"] = GetString(res, "race_name", "");
row["Distanza"] = GetString(res, "distance", "");
row["Terreno"] = GetString(res, "going", "");
if (res.TryGetProperty("runners", out var runnersEl) &&
runnersEl.ValueKind == JsonValueKind.Array)
{
int idx = 0;
foreach (var runner in runnersEl.EnumerateArray())
{
var pos = GetString(runner, "position", "");
if (pos == "1" || idx == 0)
{
row["1° Classificato"] = GetString(runner, "horse", "");
row["Fantino 1°"] = GetString(runner, "jockey", "");
row["SP 1°"] = GetString(runner, "sp", "");
}
else if (pos == "2" || idx == 1)
{
row["2° Classificato"] = GetString(runner, "horse", "");
}
else if (pos == "3" || idx == 2)
{
row["3° Classificato"] = GetString(runner, "horse", "");
}
idx++;
if (idx >= 3) break;
}
}
dt.Rows.Add(row);
}
catch
{
// Salta righe problematiche
}
}
}
}
catch
{
// Restituisci tabella vuota in caso di errore di parsing
}
return dt;
}
private static string GetString(JsonElement el, string property, string defaultValue)
{
if (el.TryGetProperty(property, out var prop) && prop.ValueKind == JsonValueKind.String)
return prop.GetString() ?? defaultValue;
if (el.TryGetProperty(property, out prop) && prop.ValueKind == JsonValueKind.Number)
return prop.ToString();
return defaultValue;
}
#endregion
}
}