1.2.11.12 Online Events

This commit is contained in:
2024-08-20 17:51:32 +01:00
parent 780e6778e5
commit 41db4e63d4
158 changed files with 6945 additions and 666 deletions
+6
View File
@@ -213,6 +213,12 @@ namespace Saxonite.Net.Core.Web.Base.App
return GetCodeTypeCaption(Sax.CodeType.Gender, gender);
}
// Sport Grouping.
public String GetSportGroupingCaption(Sax.SportGrouping sportGrouping)
{
return GetCodeTypeCaption(Sax.CodeType.SportGrouping, sportGrouping);
}
// Sport Speciality label.
public String GetSportSpecialityLabelCaption(Sax.SportSpecialityLabel sportSpecialityLabel)
{
@@ -1,14 +1,20 @@
using Sacs.Web.Components;
using Microsoft.AspNetCore.Mvc;
using Sacs.Web.Components;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Email;
using Sarand.Net.Standard.Base.Utils;
using Saxonite.Net.Core.Web.Base.App;
using Saxonite.Net.Standard.Base.App;
using Saxonite.Net.Standard.Base.Bus;
using Saxonite.Net.Standard.Base.Consoles;
using Saxonite.Net.Standard.Base.Mgr;
using Saxonite.Net.Standard.Base.Mgr.Reference;
using Saxonite.Net.Standard.Base.Mgr.Support;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Saxonite.Net.Core.Web.Base.Controllers
{
@@ -65,6 +71,7 @@ namespace Saxonite.Net.Core.Web.Base.Controllers
public SaxSupportMgr SupportMgr { get { return Internals.SupportMgr; } }
// System codes.
public List<TypeCodeDesc> DataItemTypeCodes { get { return Internals.DataItemTypeCodes; } }
public List<TypeCodeDesc> SportGroupingCodes { get { return Internals.SportGroupingCodes; } }
public List<TypeCodeDesc> SportSpecialityLabelCodes { get { return Internals.SportSpecialityLabelCodes; } }
public List<TypeCodeDesc> SportContactTypeCodes { get { return Internals.SportContactTypeCodes; } }
public List<TypeCodeDesc> SportParticipatingCodes { get { return Internals.SportParticipatingCodes; } }
@@ -88,6 +95,52 @@ namespace Saxonite.Net.Core.Web.Base.Controllers
public SaEmailConfig EmailConfig { get { return App.EmailConfig; } }
public SaxEmailConsole EmailConsole { get { return Internals.EmailConsole; } }
//-------------------------------------------------------------------
[NonAction]
/// <summary>
/// Retrieve sport by matching the name and include groups as required.
/// </summary>
/// <param name="sportName"></param>
/// <param name="includeGroups"></param>
/// <returns>List of matching sports.</returns>
public List<SaxSport.Data> GetSportsByName(String sportName, bool includeGroups = false)
{
List<SaxSport.Data> sportsData = new List<SaxSport.Data>();
if (DataCacheConsole != null)
{
List<SaxSport.Data> allSports = DataCacheConsole.GetActiveSports();
foreach (SaxSport.Data sport in allSports.Where(item => item.Name.EqualsCI(sportName)))
{
sportsData.Add(sport);
if (!includeGroups) continue;
foreach (SaxSport.Data sportParent in allSports.Where(item => item.Id.Equals(sport.SportIdParent)))
sportsData.Add(sportParent);
}
}
else
{
// Data cache is not available.
// Query direct from the database (Admin).
Dictionary<SysId, SaxSport> sports = new Dictionary<SysId, SaxSport>();
// Sport by name.
SaxSport.Params prmSport = new SaxSport.Params();
prmSport.NameFull = sportName;
sports.AddRange(ReferenceMgr.GetSportList(prmSport).ToDictionary(item => item.Id));
if (includeGroups)
{
// Parent sports.
prmSport = new SaxSport.Params();
prmSport.IdsIncluded.AddIds(sports.Values.Where(item => SysId.IsValid(item.SportIdParent)).Select(item => item.SportIdParent));
if (prmSport.IdsIncluded.Any())
sports.AddRange(ReferenceMgr.GetSportList(prmSport).ToDictionary(item => item.Id));
}
sportsData = sports.Values.Select(item => item.GetData()).ToList();
}
return sportsData;
}
//-------------------------------------------------------------------
}
//=======================================================================
@@ -69,7 +69,7 @@ namespace Saxonite.Net.Core.Web.Base.Controllers
// Some actions (eg. score password) don't need to.
if (StoreSessionData)
{
String sessionDataJson = JsonConvert.SerializeObject(SessionData);
String sessionDataJson = NewtonsoftJsonUtil.SerializeObject(SessionData);
HttpContext.Session.Set(SessionStorage.SessionKey_SessionData, SessionStorage.sessionDataEncoding.GetBytes(sessionDataJson));
}
}
@@ -73,6 +73,7 @@ namespace Saxonite.Net.Core.Web.Base.Models
// System codes.
public List<TypeCodeDesc> DataItemTypeCodes { get { return Internals.DataItemTypeCodes; } }
public List<TypeCodeDesc> YesNoCodes { get { return Internals.YesNoCodes; } }
public List<TypeCodeDesc> SportGroupingCodes { get { return Internals.SportGroupingCodes; } }
public List<TypeCodeDesc> SportSpecialityLabelCodes { get { return Internals.SportSpecialityLabelCodes; } }
public List<TypeCodeDesc> SportContactTypeCodes { get { return Internals.SportContactTypeCodes; } }
public List<TypeCodeDesc> SportParticipatingCodes { get { return Internals.SportParticipatingCodes; } }
@@ -292,6 +293,18 @@ namespace Saxonite.Net.Core.Web.Base.Models
}
}
/// <summary>List of Sport Grouping for dropdown.</summary>
public IEnumerable<SelectListItem> SportGroupingCodesForSelect
{
get
{
List<SelectListItem> values = new List<SelectListItem>();
foreach (TypeCodeDesc sportGrouping in SportGroupingCodes)
values.Add(new SelectListItem(Localiser.GetSportGroupingCaption((Sax.SportGrouping)sportGrouping.Type), sportGrouping.Code));
return values;
}
}
/// <summary>List of Sport Speciality Labels for dropdown.</summary>
public IEnumerable<SelectListItem> SportSpecialityLabelCodesForSelect
{
@@ -207,7 +207,7 @@ namespace Saxonite.Net.Core.Web.Base.Procs
// 5a. Active Country with no Provinces.
{
bool populateCountryNoProvinces = SacsRandomHelper.GetInt32(1, 3) == 1;
bool populateCountryNoProvinces = SacsRandomHelper.GetInt32(1, 17) == 1;
if (populateCountryNoProvinces)
{
SaxGolfUsgaCountry.Params prmCountry = new SaxGolfUsgaCountry.Params();
@@ -227,7 +227,7 @@ namespace Saxonite.Net.Core.Web.Base.Procs
// 5b. Active Province with no Facilities (courses).
{
bool populateProvinceNoFacilities = SacsRandomHelper.GetInt32(1, 4) == 1;
bool populateProvinceNoFacilities = SacsRandomHelper.GetInt32(1, 3) == 1;
if (populateProvinceNoFacilities)
{
// Active Provinces with no Facilities.
@@ -307,7 +307,7 @@ namespace Saxonite.Net.Core.Web.Base.Procs
List<String> annotations = new List<string>();
if (usgaCourse.Priority) annotations.Add("Priority");
if (fallback) annotations.Add("Fallback");
SaLogger.Info($"{SysUtil.Fn} USGA Markers " + (refresh ? "refreshed" : "populated") + $" for {usgaCountry.CountryCode} {usgaCountry.CountryName} - {usgaProvince.ProvinceCode} {usgaProvince.ProvinceName} - {usgaCourse.Caption} [Id: {usgaCourse.UsgaCourseId}" + (annotations.Any() ? $"{annotations.Concat("",", ")}" : "") + $"]: {markersData.Count}.", true);
SaLogger.Info($"{SysUtil.Fn} USGA Markers " + (refresh ? "refreshed" : "populated") + $" for {usgaCountry.CountryCode} {usgaCountry.CountryName} - {usgaProvince.ProvinceCode} {usgaProvince.ProvinceName} - {usgaCourse.Caption} [Id: {usgaCourse.UsgaCourseId}" + (annotations.Any() ? $"{annotations.Concat("", ", ")}" : "") + $"]: {markersData.Count}.", true);
}
else SaLogger.Error($"{SysUtil.Fn} Missing Country for Province {usgaProvince.ProvinceName}. Country Id: {usgaProvince.CountryId}.");
}
@@ -11,6 +11,7 @@ using Sarand.Net.Standard.Base.Dbas;
using Sarand.Net.Standard.Base.Helpers;
using Sarand.Net.Standard.Base.Net;
using Sarand.Net.Standard.Base.Utils;
using Saxonite.Net.Core.Web.Base.Controllers;
using Saxonite.Net.Standard.Base.App;
using Saxonite.Net.Standard.Base.Bus.Reference;
using Saxonite.Net.Standard.Base.Mgr.Reference;
@@ -33,13 +34,18 @@ namespace Saxonite.Net.Core.Web.Base.Procs
// Definitions.
public enum Task
{
CleanseCourseCaptions,
CleanseCourses,
CleanseMarkers
}
public new class Config : SaxProcess_Web.Config
{
public Config(SaxSessionContext sessionContext, DbUpdateInfo dbUpdateInfo) : base(sessionContext, dbUpdateInfo)
{ }
/// <summary>Restrict countries by Id.</summary>
public HashSet<SysId> UsgaCountryIdsIncluded { get; } = new HashSet<SysId>();
/// <summary>Restrict countries by Code.</summary>
public HashSet<String> UsgaCountryCodesIncluded { get; } = new HashSet<String>(StringComparer.OrdinalIgnoreCase);
/// <summary>Tasks to be run under this instance of the USGA Data Lookup process.</summary>
public HashSet<Task> Tasks { get; } = new HashSet<Task>();
}
@@ -108,12 +114,31 @@ namespace Saxonite.Net.Core.Web.Base.Procs
public class MarkerData
{
[JsonConstructor]
private MarkerData() { }
public MarkerData(SysId courseId, short holes, string holesCaption)
{
this.CourseId = courseId;
this.Holes = holes;
this.HolesCaption = holesCaption;
}
public MarkerData(SaxGolfUsgaCourse course, SaxGolfUsgaMarker marker) : this(course.UsgaCourseId, marker)
{
}
public MarkerData(SysId usgaCourseId, SaxGolfUsgaMarker marker)
{
this.CourseId = usgaCourseId;
this.CourseId = marker.UsgaMarkerId;
this.Holes = marker.Holes;
this.HolesCaption = marker.HolesCaption;
this.Tee = marker.Tee;
this.Gender = marker.Gender;
this.SlopeRating = marker.SlopeRating;
this.Par = marker.Par;
this.CourseRating = marker.CourseRating;
this.BogeyRating = marker.BogeyRating;
this.Length = marker.Length;
}
public SysId CourseId { get; }
public SysId MarkerId { get; set; }
public string Caption { get { return StringUtil.TrimWhitespace(StringUtil.OnBlank(Tee) + " " + StringUtil.OnBlank(HolesCaption) + " " + StringUtil.OnBlank(Gender)); } }
@@ -166,8 +191,11 @@ namespace Saxonite.Net.Core.Web.Base.Procs
{
switch (task)
{
case Task.CleanseCourseCaptions:
CleanseCourseCaptions();
case Task.CleanseCourses:
CleanseCourses();
break;
case Task.CleanseMarkers:
CleanseMarkers();
break;
}
if (!OK) break;
@@ -307,8 +335,7 @@ namespace Saxonite.Net.Core.Web.Base.Procs
countryData.CountryName = usgaCountry.Name;
countriesData.Add(countryData);
}
ReferenceGolfMgr.BulkUpdateUsgaCountries(countriesData, DbUpdateInfo);
if (ReferenceGolfMgr.HasErrorState())
if (!ReferenceGolfMgr.BulkUpdateUsgaCountries(countriesData, DbUpdateInfo))
SaLogger.Warn($"{SysUtil.Fn} Error bulk updating USGA countries: {ReferenceGolfMgr.ErrorStateMessage}.");
}
@@ -333,7 +360,9 @@ namespace Saxonite.Net.Core.Web.Base.Procs
using (DisposableCollection<SacsDisposable> disposableItems = new DisposableCollection<SacsDisposable>())
{
// Retrieve and validate country.
SaxGolfUsgaCountry usgaCountry = ReferenceGolfMgr.GetUsgaCountry(new SaxGolfUsgaCountry.Params() { CountryCodeFull = countryCode });
SaxGolfUsgaCountry.Params prmCountry = new SaxGolfUsgaCountry.Params();
prmCountry.CountryCodesIncluded.Add(countryCode);
SaxGolfUsgaCountry usgaCountry = ReferenceGolfMgr.GetUsgaCountry(prmCountry);
disposableItems.Add(usgaCountry);
if (usgaCountry == null)
{
@@ -344,7 +373,8 @@ namespace Saxonite.Net.Core.Web.Base.Procs
{
// Clear country 'priority' flag.
usgaCountry.Priority = false;
ReferenceGolfMgr.UpdateUsgaCountry(usgaCountry, DbUpdateInfo);
if (!ReferenceGolfMgr.UpdateUsgaCountry(usgaCountry, DbUpdateInfo))
SaLogger.Warn($"{SysUtil.Fn} Error updating Country '{usgaCountry.CountryCode}' - {ReferenceGolfMgr.ErrorStateMessage}");
}
try
@@ -417,7 +447,8 @@ namespace Saxonite.Net.Core.Web.Base.Procs
// Provinces stored OK = update Country.
usgaCountry.ProvincesUpdateAt = DateTime.Now;
usgaCountry.Priority = false;
ReferenceGolfMgr.UpdateUsgaCountry(usgaCountry, DbUpdateInfo);
if (!ReferenceGolfMgr.UpdateUsgaCountry(usgaCountry, DbUpdateInfo))
SaLogger.Warn($"{SysUtil.Fn} Error updating Country '{usgaCountry.CountryCode}' - {ReferenceGolfMgr.ErrorStateMessage}");
}
else SaLogger.Warn($"{SysUtil.Fn} Error bulk updating USGA provinces: {ReferenceGolfMgr.ErrorStateMessage}.");
}
@@ -443,7 +474,9 @@ namespace Saxonite.Net.Core.Web.Base.Procs
using (DisposableCollection<SacsDisposable> disposableItems = new DisposableCollection<SacsDisposable>())
{
// Retrieve and validate country.
SaxGolfUsgaCountry usgaCountry = ReferenceGolfMgr.GetUsgaCountry(new SaxGolfUsgaCountry.Params() { CountryCodeFull = countryCode });
SaxGolfUsgaCountry.Params prmCountry = new SaxGolfUsgaCountry.Params();
prmCountry.CountryCodesIncluded.Add(countryCode);
SaxGolfUsgaCountry usgaCountry = ReferenceGolfMgr.GetUsgaCountry(prmCountry);
disposableItems.Add(usgaCountry);
if (usgaCountry == null)
{
@@ -462,7 +495,8 @@ namespace Saxonite.Net.Core.Web.Base.Procs
{
// Clear province 'priority' flag.
usgaProvince.Priority = false;
ReferenceGolfMgr.UpdateUsgaProvince(usgaProvince, DbUpdateInfo);
if (!ReferenceGolfMgr.UpdateUsgaProvince(usgaProvince, DbUpdateInfo))
SaLogger.Warn($"{SysUtil.Fn} Error updating Province '{usgaProvince.ProvinceCode}' - {ReferenceGolfMgr.ErrorStateMessage}");
}
try
@@ -492,7 +526,7 @@ namespace Saxonite.Net.Core.Web.Base.Procs
if (!StringUtil.IsBlank(response.Data))
{
HashSet<String> UnrecognisedCourseProperties = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
HashSet<String> UnrecognisedCourseProperties = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
dynamic coursesJson = SacsJsonHelper.DeserializeJsonObject(response.Data);
if (coursesJson is JArray)
{
@@ -569,8 +603,7 @@ namespace Saxonite.Net.Core.Web.Base.Procs
countryData.EntCountryCode = usgaCourse.EntCountryCode;
countriesData[countryData.CountryCode] = countryData;
}
ReferenceGolfMgr.BulkUpdateUsgaCountries(countriesData.Values.ToList(), DbUpdateInfo);
if (ReferenceGolfMgr.HasErrorState())
if (!ReferenceGolfMgr.BulkUpdateUsgaCountries(countriesData.Values.ToList(), DbUpdateInfo))
SaLogger.Warn($"{SysUtil.Fn} Error bulk updating USGA countries: {ReferenceGolfMgr.ErrorStateMessage}.");
// Store provinces.
@@ -583,8 +616,7 @@ namespace Saxonite.Net.Core.Web.Base.Procs
provinceData.EntProvinceCode = usgaCourse.EntProvinceCode;
provincesData[provinceData.ProvinceCode] = provinceData;
}
ReferenceGolfMgr.BulkUpdateUsgaProvinces(provincesData.Values.ToList(), DbUpdateInfo);
if (ReferenceGolfMgr.HasErrorState())
if (!ReferenceGolfMgr.BulkUpdateUsgaProvinces(provincesData.Values.ToList(), DbUpdateInfo))
SaLogger.Warn($"{SysUtil.Fn} Error bulk updating USGA provinces: {ReferenceGolfMgr.ErrorStateMessage}.");
// Store facilities.
@@ -603,8 +635,7 @@ namespace Saxonite.Net.Core.Web.Base.Procs
}
facilitiesData[facilityData.UsgaFacilityId] = facilityData;
}
ReferenceGolfMgr.BulkUpdateUsgaFacilities(facilitiesData.Values.ToList(), DbUpdateInfo);
if (ReferenceGolfMgr.HasErrorState())
if (!ReferenceGolfMgr.BulkUpdateUsgaFacilities(facilitiesData.Values.ToList(), DbUpdateInfo))
SaLogger.Warn($"{SysUtil.Fn} Error bulk updating USGA facilities: {ReferenceGolfMgr.ErrorStateMessage}.");
// Store courses.
@@ -637,7 +668,8 @@ namespace Saxonite.Net.Core.Web.Base.Procs
// Courses stored OK - update Province.
usgaProvince.CoursesUpdateAt = DateTime.Now;
usgaProvince.Priority = false;
ReferenceGolfMgr.UpdateUsgaProvince(usgaProvince, DbUpdateInfo);
if (!ReferenceGolfMgr.UpdateUsgaProvince(usgaProvince, DbUpdateInfo))
SaLogger.Warn($"{SysUtil.Fn} Error updating Province '{usgaProvince.ProvinceCode}' - {ReferenceGolfMgr.ErrorStateMessage}");
}
else SaLogger.Warn($"{SysUtil.Fn} Error bulk updating USGA courses: {ReferenceGolfMgr.ErrorStateMessage}.");
}
@@ -715,7 +747,7 @@ namespace Saxonite.Net.Core.Web.Base.Procs
}
//------------------------------------------------------------------
public bool CleanseCourseCaptions()
public bool CleanseCourses()
{
SaLogger.Info($"{SysUtil.Fn} START", true);
DateTime startedAt = DateTime.Now;
@@ -729,10 +761,13 @@ namespace Saxonite.Net.Core.Web.Base.Procs
using (DisposableCollection<SacsDisposable> disposables = new DisposableCollection<SacsDisposable>())
{
// Local function to allow break/return from within nested loop.
void CompareCourseCaptions()
void CompareCourse()
{
// Countries.
foreach (SaxGolfUsgaCountry country in ReferenceGolfMgr.GetUsgaCountryList(new SaxGolfUsgaCountry.Params()))
SaxGolfUsgaCountry.Params prmCountry = new SaxGolfUsgaCountry.Params();
prmCountry.IdsIncluded.AddIds(config.UsgaCountryIdsIncluded);
prmCountry.CountryCodesIncluded.UnionWith(config.UsgaCountryCodesIncluded);
foreach (SaxGolfUsgaCountry country in ReferenceGolfMgr.GetUsgaCountryList(prmCountry))
{
disposables.Add(country);
@@ -750,6 +785,7 @@ namespace Saxonite.Net.Core.Web.Base.Procs
// Facilities.
SaxGolfUsgaFacility.Params prmFacility = new SaxGolfUsgaFacility.Params();
prmFacility.ProvinceIdsIncluded.Add(province.Id);
prmFacility.HasCourses = SacsHierarchyItem.Params.BoolState.True;
foreach (SaxGolfUsgaFacility facility in ReferenceGolfMgr.GetUsgaFacilityList(prmFacility))
{
disposablesProvince.Add(facility);
@@ -770,7 +806,7 @@ namespace Saxonite.Net.Core.Web.Base.Procs
if (ReferenceGolfMgr.UpdateUsgaCourse(course, DbUpdateInfo))
{
courseCaptionsCorrected++;
SaLogger.Info($"{SysUtil.Fn} Course caption corrected. Found: {course.Caption}.Corrected: {courseCaption}.");
SaLogger.Info($"{SysUtil.Fn} Course caption corrected. Found: {course.Caption}. Corrected: {courseCaption}.");
}
else
{
@@ -791,7 +827,7 @@ namespace Saxonite.Net.Core.Web.Base.Procs
}
}
// Invoke local function.
CompareCourseCaptions();
CompareCourse();
}
// Log statistics.
@@ -855,7 +891,8 @@ namespace Saxonite.Net.Core.Web.Base.Procs
if (usgaCourse.Priority)
{
usgaCourse.Priority = false;
ReferenceGolfMgr.UpdateUsgaCourse(usgaCourse, DbUpdateInfo);
if (!ReferenceGolfMgr.UpdateUsgaCourse(usgaCourse, DbUpdateInfo))
SaLogger.Warn($"{SysUtil.Fn} Error updating Course '{usgaCourse.FullName}' - {ReferenceGolfMgr.ErrorStateMessage}");
}
try
@@ -1049,10 +1086,11 @@ namespace Saxonite.Net.Core.Web.Base.Procs
{
// Markers stored OK - update Course.
if (markersData.Markers.Any())
usgaCourse.MarkersData = JsonConvert.SerializeObject(markersData);
usgaCourse.MarkersData = NewtonsoftJsonUtil.SerializeObject(markersData, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore });
usgaCourse.MarkersUpdateAt = DateTime.Now;
usgaCourse.Priority = false;
ReferenceGolfMgr.UpdateUsgaCourse(usgaCourse, DbUpdateInfo);
if (!ReferenceGolfMgr.UpdateUsgaCourse(usgaCourse, DbUpdateInfo))
SaLogger.Warn($"{SysUtil.Fn} Error updating Course '{usgaCourse.FullName}' - {ReferenceGolfMgr.ErrorStateMessage}");
}
else SaLogger.Warn($"{SysUtil.Fn} Error bulk updating USGA markers: {ReferenceGolfMgr.ErrorStateMessage}.");
}
@@ -1065,6 +1103,182 @@ namespace Saxonite.Net.Core.Web.Base.Procs
}
//------------------------------------------------------------------
/// <summary>
/// Front and Back 9 likely missing par values - derive from other properties.
/// </summary>
/// <param name="marker">Marker to have its par calulated.</param>
/// <param name="markers">Full list of markers for the course.</param>
/// <returns></returns>
private short CalculateMarkerParByCourseRating(MarkerData marker, List<MarkerData> markers)
{
if (marker.Holes > 9) return marker.Par;
// Locate the corresponding marker for the other half of the course (F9/B9).
String holesCaptionOpp = marker.HolesCaption.EqualsCI("F9") ? "B9" : marker.HolesCaption.EqualsCI("B9") ? "F9" : "";
MarkerData marker18 = markers.Find(item => item.Holes == 18 && item.Tee == marker.Tee && item.Gender == marker.Gender);
MarkerData markerOpp = markers.Find(item => item.HolesCaption.EqualsCI(holesCaptionOpp) && item.Tee == marker.Tee && item.Gender == marker.Gender);
if (marker18 != null && markerOpp != null)
{
decimal combined9sCourseRating = marker.CourseRating + markerOpp.CourseRating;
return (short)Math.Round(marker18.Par * marker.CourseRating / combined9sCourseRating);
}
return marker.Par;
}
/// <summary>
/// Front and Back 9 likely missing par values - derive from other properties.
/// </summary>
/// <param name="marker">Marker to have its par calulated.</param>
/// <param name="markers">Full list of markers for the course.</param>
/// <returns></returns>
private short CalculateMarkerParBySlopeRating(MarkerData marker, List<MarkerData> markers)
{
if (marker.Holes > 9) return marker.Par;
// Locate the corresponding marker for the other half of the course (F9/B9).
String holesCaptionOpp = marker.HolesCaption.EqualsCI("F9") ? "B9" : marker.HolesCaption.EqualsCI("B9") ? "F9" : "";
MarkerData marker18 = markers.Find(item => item.Holes == 18 && item.Tee == marker.Tee && item.Gender == marker.Gender);
MarkerData markerOpp = markers.Find(item => item.HolesCaption.EqualsCI(holesCaptionOpp) && item.Tee == marker.Tee && item.Gender == marker.Gender);
if (marker18 != null && markerOpp != null)
{
decimal combined9sSlopeRating = marker.SlopeRating + markerOpp.SlopeRating;
return (short)Math.Round(marker18.Par * marker.SlopeRating / combined9sSlopeRating);
}
return marker.Par;
}
//------------------------------------------------------------------
public bool CleanseMarkers()
{
SaLogger.Info($"{SysUtil.Fn} START", true);
DateTime startedAt = DateTime.Now;
ClearProcessMessages();
int markerCount = 0;
int courseCount = 0;
int maxMarkers = 0;
int markersCorrected = 0;
using (DisposableCollection<SacsDisposable> disposables = new DisposableCollection<SacsDisposable>())
{
// Local function to allow break/return from within nested loop.
void CleanseMarkers()
{
// Countries.
SaxGolfUsgaCountry.Params prmCountry = new SaxGolfUsgaCountry.Params();
prmCountry.IdsIncluded.AddIds(config.UsgaCountryIdsIncluded);
prmCountry.CountryCodesIncluded.UnionWith(config.UsgaCountryCodesIncluded);
foreach (SaxGolfUsgaCountry country in ReferenceGolfMgr.GetUsgaCountryList(prmCountry))
{
disposables.Add(country);
// Provinces.
SaxGolfUsgaProvince.Params prmProvince = new SaxGolfUsgaProvince.Params();
prmProvince.CountryIdsIncluded.Add(country.Id);
foreach (SaxGolfUsgaProvince province in ReferenceGolfMgr.GetUsgaProvinceList(prmProvince))
{
disposables.Add(province);
// Separate disposables for each province to restrict volume handled on each disposal.
using (DisposableCollection<SacsDisposable> disposablesProvince = new DisposableCollection<SacsDisposable>())
{
// Facilities.
SaxGolfUsgaFacility.Params prmFacility = new SaxGolfUsgaFacility.Params();
prmFacility.ProvinceIdsIncluded.Add(province.Id);
foreach (SaxGolfUsgaFacility facility in ReferenceGolfMgr.GetUsgaFacilityList(prmFacility))
{
disposablesProvince.Add(facility);
// Courses.
SaxGolfUsgaCourse.Params prmCourse = new SaxGolfUsgaCourse.Params();
prmCourse.FacilityIdsIncluded.Add(facility.Id);
prmCourse.HasMarkers = SacsHierarchyItem.Params.BoolState.True;
foreach (SaxGolfUsgaCourse course in ReferenceGolfMgr.GetUsgaCourseList(prmCourse))
{
disposablesProvince.Add(course);
courseCount++;
int markersModified = 0;
// Extract markers from data.
MarkersData markersData = null;
try
{
markersData = JsonConvert.DeserializeObject<MarkersData>(course.MarkersData, new JsonSerializerSettings() { });
}
catch (Exception exc)
{
SaLogger.Warn($"{SysUtil.Fn} {ExceptionUtil.GetLogMessage(exc, 4)}");
}
markersData = markersData ?? new MarkersData();
// Markers.
SaxGolfUsgaMarker.Params prmMarker = new SaxGolfUsgaMarker.Params();
prmMarker.CourseIdsIncluded.Add(course.Id);
List<SaxGolfUsgaMarker> markers = ReferenceGolfMgr.GetUsgaMarkerList(prmMarker);
if (!markersData.Markers.Any() && markers.Any())
{
// Generate Markers data from stored markers.
SaLogger.Warn($"{SysUtil.Fn} Regenerating missing markers data. Course: {country.CountryCode} {province.ProvinceCode} {course.Caption}.");
markersData = new MarkersData();
foreach (SaxGolfUsgaMarker marker in markers)
markersData.Markers.Add(new MarkerData(course.UsgaCourseId, marker));
}
markerCount += markersData.Markers.Count;
// Validate number of markers against data.
if (markers.Count != markersData.Markers.Count)
{
SaLogger.Warn($"{SysUtil.Fn} Inconsistent marker count. Course: {country.CountryCode} {province.ProvinceCode} {course.Caption}. Markers data: {markersData.Markers.Count}. Markers: {markers.Count}.");
continue;
}
markerCount += markersData.Markers.Count;
foreach (MarkerData markerData in markersData.Markers)
{
// Calulate Par by Course Rating.
short parCalulatedByCourseRating = CalculateMarkerParByCourseRating(markerData, markersData.Markers);
if (markerData.Par != parCalulatedByCourseRating)
{
SaLogger.Warn($"{SysUtil.Fn} Marker par recalculated by Course Rating. Course: {country.CountryCode} {province.ProvinceCode} {course.Caption}. Marker: {markerData.Tee} {markerData.HolesCaption} {markerData.Gender}. Par found: {markerData.Par}. Recalculated: {parCalulatedByCourseRating}.");
//markerData.Par = parCalulated;
// markersModified ++;
}
// Calulate Par by Slope Rating.
short parCalulatedBySlopeRating = CalculateMarkerParBySlopeRating(markerData, markersData.Markers);
if (markerData.Par != parCalulatedBySlopeRating)
{
SaLogger.Warn($"{SysUtil.Fn} Marker par recalculated by Slope Rating. Course: {country.CountryCode} {province.ProvinceCode} {course.Caption}. Marker: {markerData.Tee} {markerData.HolesCaption} {markerData.Gender}. Par found: {markerData.Par}. Recalculated: {parCalulatedBySlopeRating}.");
//markerData.Par = parCalulated;
// markersModified ++;
}
}
if (markersModified > 0)
{
// ToDo Bulk update the markers to apply changes.
}
}
}
}
}
}
}
// Invoke local function.
CleanseMarkers();
}
// Log statistics.
SaLogger.Info($"{SysUtil.Fn} Markers corrected: {markersCorrected}. Markers checked: {markerCount}.", true);
SaLogger.Info($"{SysUtil.Fn} END Elapsed: {DateUtil.FormatNumberOfSeconds((DateTime.Now - startedAt).TotalSeconds)}", true);
return OK;
}
//------------------------------------------------------------------
}
//======================================================================
}