/Projects/OSRR.Parsing/NR2003Parser.cs
C# | 1464 lines | 992 code | 335 blank | 137 comment | 201 complexity | 904e3bf80ba4d9e0304c248cee8ed93d MD5 | raw file
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using OSRR.Core;
- using System.IO;
- using System.Xml;
- using System.Xml.Linq;
- using OSRR.Parsing.NR2003;
- using OSRR.Parsing.Auxiliary;
- using System.Data;
- using System.Collections;
- using System.Globalization;
- using System.Reflection;
- namespace OSRR.Parsing
- {
- public class NR2003Parser : IResultParser
- {
- #region Class members
- private OSRRDocument _osrrDoc;
- private string _HTMLFileName;
- private string _RAXMLFileName;
-
-
- #endregion
- #region Helper members
- private string HTMLFileContents;
- private List<string> excludedCarNumbers;
- #endregion
- #region Properties
- /// <summary>
- /// Gets the generated OSRR document
- /// </summary>
- public OSRRDocument OSRRDoc
- {
- get { return this._osrrDoc; }
- }
- /// <summary>
- /// Gets or sets the filepath and name of the HTML result file
- /// </summary>
- public string HTMLFileName
- {
- get { return this._HTMLFileName; }
- set { this._HTMLFileName = value; }
- }
- /// <summary>
- /// Gets or sets the filepath and name of the Replay Analyzer XML result file
- /// </summary>
- public string RAXMLFileName
- {
- get { return this._RAXMLFileName; }
- set { this._RAXMLFileName = value; }
- }
- #endregion
- #region Constructors
- /// <summary>
- /// Default parameterless constructor
- /// </summary>
- public NR2003Parser()
- {
- this.excludedCarNumbers = new List<string>();
- this.excludedCarNumbers.Add("-1");
-
- }
- /// <summary>
- /// Constructor providing the location of the HTML and/or Replay Analyzer XML export result(s). You can specify a parameter as null if not applicable
- /// </summary>
- /// <param name="htmlFileName">The filepath and name of the HTML result file. Pass null if not applicable</param>
- /// <param name="xmlFileName">The filepath and name of the Replay Analyzer XML result file. Pass null if not applicable</param>
- /// <param name="serverCarNumber">In combination with the Replay Analyzer XML file, specify the car number of the server. This car will then be excluded from scoring</par
- public NR2003Parser(string HTMLFileName, string RAXMLFileName, string serverCarNumber) : this()
- {
- this._HTMLFileName = HTMLFileName;
- this._RAXMLFileName = RAXMLFileName;
- if(serverCarNumber != null)
- this.excludedCarNumbers.Add(serverCarNumber);
- }
- #endregion
- #region Public methods
- /// <summary>
- /// Parses the HTML result and/or the Replay Analyzer XML result
- /// </summary>
- /// <returns>A OSRR object containing the results, combined from HTML and XML if both were specified</returns>
- public OSRRDocument Parse()
- {
- //PARSE THE HTML RESULT
- NR2003HTMLResult htmlResult = this.ParseHTML();
- //LOAD THE RA XML RESULT
- XDocument RAXML = this.LoadRAXML();
- //CREATE THE EVENTS
- Event evHtml = this.CreateEventFromHTMLResult(htmlResult);
- Event evRAXml = this.CreateEventFromXMLResult(RAXML);
- //FOR TESTING, SERIALIZE
- //if (evHtml != null)
- // evHtml.SaveToFile(@"D:\Test\OSRR_Event_HTML.xml");
- //if (evRAXml != null)
- // evRAXml.SaveToFile(@"D:\Test\OSRR_Event_RA.xml");
- //ASSIGN THE EVENT TO THE OSRR DOCUMENT
- this._osrrDoc = new OSRRDocument();
- this._osrrDoc.Event = this.CombineEvents(evHtml, evRAXml);
- return this._osrrDoc;
- }
- /// <summary>
- /// Adds a carNumber to the list of carnumbers to be excluded from scoring
- /// </summary>
- /// <param name="carNumber">The carNumber to exclude</param>
- public void AddExcludedCarNumber(string carNumber)
- {
- if (this.excludedCarNumbers != null && !this.excludedCarNumbers.Contains(carNumber))
- {
- this.excludedCarNumbers.Add(carNumber);
- }
- }
- #endregion
- #region Private Methods
- /// <summary>
- /// This method is primarily used to combine the Event objects of HTML output and RA XML output together. In normal circumstances, the HTML file should take priority over the RA XML file.
- /// </summary>
- /// <param name="primary">This Event will serve as base for the combination. This is in most cases the Event generated from the HTML output</param>
- /// <param name="secondary">This Event will be used to provide additional information to the primary Event. This is in most cases the Event generated from the RA XML output</param>
- /// <returns></returns>
- private Event CombineEvents(Event primary, Event secondary)
- {
- Event returnEvent = null;
- if (primary != null && secondary != null)
- {
- returnEvent = Event.Deserialize(primary.Serialize());
- this.CombineObjects(returnEvent, secondary);
- //COMBINE TIMEDSESSIONS
- if (returnEvent.TimedSessions != null && secondary.TimedSessions != null)
- {
- //MERGE SAME SESSIONS
- foreach(Core.TimedSession timedSession in returnEvent.TimedSessions)
- {
- var q = from s in secondary.TimedSessions
- where s.Name.Equals(timedSession.Name)
- select s;
- if(q.Count() > 0)
- {
- Core.TimedSession secondaryTimedSession = q.First();
- this.CombineObjects(timedSession, secondaryTimedSession);
- //MERGE SAME SESSIONRESULTS
- foreach (Core.TimedSessionResult timedSessionResult in timedSession.Results)
- {
- var q2 = from sr in secondaryTimedSession.Results
- where sr.CarNumber.Equals(timedSessionResult.CarNumber)
- select sr;
- if (q2.Count() > 0)
- {
- Core.TimedSessionResult secondaryTimedSessionResult = q2.First();
- this.CombineObjects(timedSessionResult, secondaryTimedSessionResult);
- Driver driver = timedSessionResult.Drivers[0];
- Driver secondaryDriver = secondaryTimedSessionResult.Drivers[0];
- if (secondaryDriver.LastName.Contains(driver.LastName) || driver.LastName.Contains(secondaryDriver.LastName))
- {
- if (secondaryDriver.FirstName.StartsWith(driver.FirstName))
- {
- driver.FirstName = secondaryDriver.FirstName;
- }
- }
- }
- }
- //ADD SESSIONRESULTS THAT EXIST IN SECONDARY BUT NOT IN PRIMARY
- var q3 = from sr in secondaryTimedSession.Results
- where timedSession.Results.Find(res => res.CarNumber == sr.CarNumber) == null
- orderby sr.Position ascending
- select sr;
- foreach (Core.TimedSessionResult res in q3)
- {
- timedSession.Results.Add(res);
- }
- }
-
- }
- //ADD SESSIONS FROM SECONDARY THAT DO NOT EXIST IN PRIMARY
- //todo: to be determined if necessary
- }
- //COMBINE RACESESSIONS
- if (returnEvent.RaceSessions != null && secondary.RaceSessions != null)
- {
- //MERGE SAME SESSIONS
- foreach (Core.RaceSession raceSession in returnEvent.RaceSessions)
- {
- var q = from s in secondary.RaceSessions
- where s.Name.Equals(raceSession.Name)
- select s;
- if (q.Count() > 0)
- {
- Core.RaceSession secondaryRaceSession = q.First();
- this.CombineObjects(raceSession, secondaryRaceSession);
- //MERGE SAME SESSIONRESULTS
- foreach (Core.RaceSessionResult raceSessionResult in raceSession.Results)
- {
- var q2 = from sr in secondaryRaceSession.Results
- where sr.CarNumber.Equals(raceSessionResult.CarNumber)
- select sr;
- if (q2.Count() > 0)
- {
- Core.RaceSessionResult secondaryRaceSessionResult = q2.First();
- this.CombineObjects(raceSessionResult, secondaryRaceSessionResult);
- Driver driver = raceSessionResult.Drivers[0];
- Driver secondaryDriver = secondaryRaceSessionResult.Drivers[0];
- if (secondaryDriver.LastName.Contains(driver.LastName) || driver.LastName.Contains(secondaryDriver.LastName))
- {
- if (secondaryDriver.FirstName.StartsWith(driver.FirstName))
- {
- driver.FirstName = secondaryDriver.FirstName;
- }
- }
- }
- }
- //ADD SESSIONRESULTS THAT EXIST IN SECONDARY BUT NOT IN PRIMARY
- var q3 = from sr in secondaryRaceSession.Results
- where raceSession.Results.Find(res => res.CarNumber == sr.CarNumber) == null
- orderby sr.Position ascending
- select sr;
- foreach (Core.RaceSessionResult res in q3)
- {
- raceSession.Results.Add(res);
- }
- }
- }
- //ADD SESSIONS FROM SECONDARY THAT DO NOT EXIST IN PRIMARY
-
- //todo: to be determined if necessary
- }
- }
- return returnEvent;
- }
- /// <summary>
- /// Normalizes the positions in a list of SessionResult object. This is to avoid "gaps" in the position sequence, induced by for instance excluding certain carnumbers from scoring
- /// </summary>
- /// <typeparam name="T">A type inheriting of OSRR.Core.SessionResult (either a TimedSessionResult or a RaceSessionResult)</typeparam>
- /// <param name="sessionResults">The list of SessionResult objects to normalize</param>
- private void NormalizePositions<T>(List<T> sessionResults) where T : Core.SessionResult
- {
- if (sessionResults != null)
- {
- sessionResults.OrderBy(res => res.Position);
- int pos = 1;
- foreach (Core.SessionResult result in sessionResults)
- {
- result.Position = pos;
- pos++;
- }
- }
- }
- /// <summary>
- /// A general method used to combine the properties of two objects, using reflection. This method is mainly called from the CombineEvents method.
- /// The target's property value will be set from the source's, only if the target's is null
- /// </summary>
- /// <typeparam name="T">Can be any class</typeparam>
- /// <param name="target">The target object to modify</param>
- /// <param name="source">The source object to take data from</param>
- private void CombineObjects<T>(T target, T source) where T : class
- {
-
- if (target != null & source != null)
- {
- Type objectType = target.GetType();
- foreach (PropertyInfo pi in objectType.GetProperties())
- {
- Console.WriteLine(objectType.Name + " - " + pi.Name + " - " + pi.PropertyType.FullName);
- try
- {
- if (pi.GetValue(target, null) == null)
- {
- Console.WriteLine("Setting " + pi.Name + " to " + pi.GetValue(source, null).ToString());
- pi.SetValue(target, pi.GetValue(source, null), null);
- //For correctly serializing to XML, we need to set any boolean property with this propertyName + "Specified" to true
- PropertyInfo piSpecified = objectType.GetProperty(pi.Name + "Specified", typeof(bool));
- if (piSpecified != null)
- {
- if (pi.GetValue(source, null) != null)
- {
- Console.WriteLine("Setting " + piSpecified.Name + " to " + piSpecified.GetValue(source, null).ToString());
- piSpecified.SetValue(target, piSpecified.GetValue(source, null), null);
- }
- }
- }
- else if (!pi.PropertyType.IsValueType)
- {
- this.CombineObjects(pi.GetValue(target, null), pi.GetValue(source, null));
- }
- }
- catch { }
- }
- }
- }
- /// <summary>
- /// Creates an OSRR Event object from a given NR2003HTMLResult
- /// </summary>
- /// <param name="htmlResult">The NR2003HTMLResult object to be processed</param>
- /// <returns>An OSRR Event based on the NR2003HTMLResult object</returns>
- private Event CreateEventFromHTMLResult(NR2003HTMLResult htmlResult)
- {
- Event ev = new Event();
-
- ev.IsMultiClass = false;
- ev.IsMultiDriver = false;
- ev.SpeedUnitSpecified = true;
- ev.SpeedUnit = SpeedUnit.mph;
- //HOLD ALL DIFFERENT DRIVERS IN A SEPARATE DICTIONARY. THE KEY OF THE DICTIONARY SHOULD BE SOMETHING WE CAN USE TO UNIQUELY IDENTIFY A DRIVER IN THE CURRENT CONTEXT.
- //IN THE CASE OF NR2003, THIS IS THE CARNUMBER, WHICH IS A STRING.
- Dictionary<string, Core.Driver> drivers = new Dictionary<string, Driver>();
- if (htmlResult != null)
- {
- ev.Schedule = new Schedule();
- ev.Schedule.BeginDateSpecified = true;
- ev.Schedule.BeginDate = htmlResult.General.Date;
- ev.Track = new Track();
- ev.Track.Name = htmlResult.General.Track;
- //PROCESS THE TIMEDSESSIONS
- Dictionary<string, NR2003.TimedSession> nr2003TimedSessions = new Dictionary<string, NR2003.TimedSession>();
- nr2003TimedSessions.Add("Practice", htmlResult.PracticeSession);
- nr2003TimedSessions.Add("Qualifying", htmlResult.QualifyingSession);
- nr2003TimedSessions.Add("Happy Hour", htmlResult.HappyHourSession);
-
-
- foreach (KeyValuePair<string, NR2003.TimedSession> nr2003TimedSessionKVP in nr2003TimedSessions)
- {
- NR2003.TimedSession nr2003TimedSession = nr2003TimedSessionKVP.Value;
- if (nr2003TimedSession != null)
- {
- Core.TimedSession timedSession = null;
-
- timedSession = new Core.TimedSession();
- if (ev.TimedSessions == null)
- ev.TimedSessions = new List<Core.TimedSession>();
- timedSession.Name = nr2003TimedSessionKVP.Key;
- timedSession.Schedule = ev.Schedule;
- timedSession.Weather = new Core.Weather();
- if (nr2003TimedSession.Weather != null)
- {
- timedSession.Weather.Conditions = nr2003TimedSession.Weather.Conditions;
- timedSession.Weather.Temperature = nr2003TimedSession.Weather.Temperature;
- timedSession.Weather.WindDirection = nr2003TimedSession.Weather.WindDirection;
- timedSession.Weather.WindSpeed = nr2003TimedSession.Weather.WindSpeed;
- }
- if (nr2003TimedSession.Results != null)
- {
- if (timedSession.Results == null)
- timedSession.Results = new List<Core.TimedSessionResult>();
- foreach (NR2003.TimedSessionResult nr2003Result in nr2003TimedSession.Results)
- {
- if (!this.excludedCarNumbers.Contains(nr2003Result.CarNumber))
- {
- Driver driver;
- if (!drivers.Keys.Contains(nr2003Result.CarNumber)) //CREATE THE DRIVER IF ITS CARNUMBER DOES NOT YET EXIST IN THE DICTIONARY
- {
- driver = new Driver();
- int driverSpacePosition = nr2003Result.Driver.IndexOf(" "); //THE FIRST SPACE SPLITS THE FIRSTNAME FROM THE LASTNAME
- if (driverSpacePosition == -1) //NO SPACE, SO PUT EVERYTING IN THE LASTNAME
- {
- driver.LastName = nr2003Result.Driver.Trim();
- }
- else
- {
- driver.FirstName = nr2003Result.Driver.Substring(0, driverSpacePosition).Trim();
- driver.LastName = nr2003Result.Driver.Substring(driverSpacePosition + 1).Trim();
- }
- drivers.Add(nr2003Result.CarNumber, driver);
- }
- else //IF THE CARNUMBER ALREADY EXISTS IN THE DICTIONARY, RETRIEVE THE DRIVER FROM THERE
- {
- driver = drivers[nr2003Result.CarNumber];
- }
- Core.TimedSessionResult result = new Core.TimedSessionResult();
- result.Drivers = new List<Driver>();
- result.Drivers.Add(driver);
- result.Position = nr2003Result.Position;
- result.CarNumber = nr2003Result.CarNumber;
- if (nr2003Result.Time.HasValue)
- {
- result.BestLapTimeSpecified = true;
- result.BestLapTime = nr2003Result.Time;
- }
- if (nr2003Result.Speed.HasValue)
- {
- result.BestLapSpeedSpecified = true;
- result.BestLapSpeed = nr2003Result.Speed;
- }
- timedSession.Results.Add(result);
- }
- }
- }
- this.NormalizePositions(timedSession.Results);
- ev.TimedSessions.Add(timedSession);
- }
- }
- //PROCESS THE RACESESSION
- NR2003.RaceSession nr2003RaceSession = htmlResult.RaceSession;
- if (nr2003RaceSession != null)
- {
- Core.RaceSession raceSession = null;
- raceSession = new Core.RaceSession();
- if (ev.RaceSessions == null)
- ev.RaceSessions = new List<Core.RaceSession>();
- raceSession.Name = "Race";
- raceSession.Schedule = ev.Schedule;
- raceSession.Weather = new Core.Weather();
-
- if (nr2003RaceSession.Weather != null)
- {
- raceSession.Weather.Conditions = nr2003RaceSession.Weather.Conditions;
- raceSession.Weather.Temperature = nr2003RaceSession.Weather.Temperature;
- raceSession.Weather.WindDirection = nr2003RaceSession.Weather.WindDirection;
- raceSession.Weather.WindSpeed = nr2003RaceSession.Weather.WindSpeed;
- }
- if (nr2003RaceSession.CautionFlags.HasValue)
- {
- raceSession.CautionsSpecified = true;
- raceSession.Cautions = nr2003RaceSession.CautionFlags;
- }
- if (nr2003RaceSession.CautionLaps.HasValue)
- {
- raceSession.CautionLapsSpecified = true;
- raceSession.CautionLaps = nr2003RaceSession.CautionLaps;
- }
- if (nr2003RaceSession.LeadChanges.HasValue)
- {
- raceSession.LeadChangesSpecified = true;
- raceSession.LeadChanges = nr2003RaceSession.LeadChanges;
- }
- if (nr2003RaceSession.LeadDrivers.HasValue)
- {
- raceSession.LeadDriversSpecified = true;
- raceSession.LeadDrivers = nr2003RaceSession.LeadDrivers;
- }
- if (nr2003RaceSession.Results != null)
- {
- if (raceSession.Results == null)
- raceSession.Results = new List<Core.RaceSessionResult>();
- foreach (NR2003.RaceSessionResult nr2003Result in nr2003RaceSession.Results)
- {
- if (!this.excludedCarNumbers.Contains(nr2003Result.CarNumber))
- {
- Driver driver;
- if (!drivers.Keys.Contains(nr2003Result.CarNumber)) //CREATE THE DRIVER IF ITS CARNUMBER DOES NOT YET EXIST IN THE DICTIONARY
- {
- driver = new Driver();
- int driverSpacePosition = nr2003Result.Driver.IndexOf(" "); //THE FIRST SPACE SPLITS THE FIRSTNAME FROM THE LASTNAME
- if (driverSpacePosition == -1) //NO SPACE, SO PUT EVERYTING IN THE LASTNAME
- {
- driver.LastName = nr2003Result.Driver.Trim();
- }
- else
- {
- driver.FirstName = nr2003Result.Driver.Substring(0, driverSpacePosition).Trim();
- driver.LastName = nr2003Result.Driver.Substring(driverSpacePosition + 1).Trim();
- }
- drivers.Add(nr2003Result.CarNumber, driver);
- }
- else //IF THE CARNUMBER ALREADY EXISTS IN THE DICTIONARY, RETRIEVE THE DRIVER FROM THERE
- {
- driver = drivers[nr2003Result.CarNumber];
- }
- Core.RaceSessionResult result = new Core.RaceSessionResult();
- result.Drivers = new List<Driver>();
- result.Drivers.Add(driver);
- result.Position = nr2003Result.Position;
- result.CarNumber = nr2003Result.CarNumber;
- result.Status = nr2003Result.Status;
- if (result.Status.Equals("Running"))
- result.IsRunning = true;
- result.LapsSpecified = true;
- result.Laps = nr2003Result.Laps;
- result.LapsLedSpecified = true;
- result.LapsLed = nr2003Result.LapsLed;
- if (result.Laps.HasValue && result.Laps == 0) //SET RESULTS WITH ZERO LAPS TO NOT RUNNING AND STATUS DNS
- {
- result.IsRunning = false;
- result.Status = "DNS";
- }
- if (result.Position != 1) //SET INTERVAL TO WINNER
- {
- decimal interval;
- bool intervalParsable = Decimal.TryParse(nr2003Result.Interval.Replace(".", System.Globalization.NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator), out interval);
- if (intervalParsable)
- {
- result.IntervalToWinnerSpecified = true;
- result.IntervalToWinner = Math.Abs(interval);
- }
- }
- else //ON 1ST POSITION, THE AVERAGE SPEED IS INDICATED
- {
- decimal avgSpeed;
- bool avgSpeedParsable = Decimal.TryParse(nr2003Result.Interval.Replace(".", System.Globalization.NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator), out avgSpeed);
- if (avgSpeedParsable)
- {
- result.AverageLapSpeedSpecified = true;
- result.AverageLapSpeed = avgSpeed;
- }
- }
- //GET THE PENALTIES ASSOCIATED WITH THIS DRIVER
- if (htmlResult.Penalties != null)
- {
- var q = from p in htmlResult.Penalties
- where p.CarNumber.Equals(result.CarNumber)
- select p;
- foreach (NR2003.Penalty nr2003Penalty in q)
- {
- if (result.Penalties == null)
- result.Penalties = new List<Core.Penalty>();
- Core.Penalty penalty = new Core.Penalty();
- penalty.LapSpecified = true;
- penalty.Lap = nr2003Penalty.Lap;
- penalty.Infraction = nr2003Penalty.Infraction;
- penalty.PenaltyDescription = nr2003Penalty.PenaltyDescription;
- result.Penalties.Add(penalty);
- }
- }
- raceSession.Results.Add(result);
- }
- }
- }
- this.NormalizePositions(raceSession.Results);
- ev.RaceSessions.Add(raceSession);
- }
- }
- return ev;
- }
- /// <summary>
- /// Creates an OSRR Event object from a given Replay Analyzer XML XDocument
- /// </summary>
- /// <param name="RAXML">The RA XDocument to be processed</param>
- /// <returns>An OSRR Event based on the Replay Analyzer XDocument object</returns>
- private Event CreateEventFromXMLResult(XDocument RAXML)
- {
- Event ev = new Event();
- ev.IsMultiClass = false;
- ev.IsMultiDriver = false;
- ev.SpeedUnitSpecified = true;
- ev.SpeedUnit = SpeedUnit.mph;
- //HOLD ALL DIFFERENT DRIVERS IN A SEPARATE DICTIONARY. THE KEY OF THE DICTIONARY SHOULD BE SOMETHING WE CAN USE TO UNIQUELY IDENTIFY A DRIVER IN THE CURRENT CONTEXT.
- //IN THE CASE OF NR2003, THIS IS THE CARNUMBER, WHICH IS A STRING.
- Dictionary<string, Core.Driver> drivers = new Dictionary<string, Driver>();
- if (RAXML != null)
- {
-
- ev.Track = new Track();
- ev.Track.Name = RAXML.Root.Element("general").Element("track").Value;
- IEnumerable<XElement> qPracticeResults = null;
- IEnumerable<XElement> qQualifyingResults = null;
- IEnumerable<XElement> qHappyHourResults = null;
- IEnumerable<XElement> qRaceResults = null;
- try
- {
- qPracticeResults = from res in RAXML.Root.Element("practice").Elements("practice-time")
- select res;
- }
- catch { }
- try
- {
- qQualifyingResults = from res in RAXML.Root.Element("qualify").Elements("qualify-time")
- select res;
- }
- catch { }
- try
- {
- qHappyHourResults = from res in RAXML.Root.Element("happy-hour").Elements("happy-hour-time")
- select res;
- }
- catch { }
- try
- {
- qRaceResults = from res in RAXML.Root.Element("race").Element("race-results").Elements("race-result")
- select res;
- }
- catch { }
- //PROCESS THE SESSIONRESULTS
- Dictionary<string, IEnumerable<XElement>> RAXMLSessionResultsList = new Dictionary<string, IEnumerable<XElement>>();
- RAXMLSessionResultsList.Add("Practice", qPracticeResults);
- RAXMLSessionResultsList.Add("Qualifying", qQualifyingResults);
- RAXMLSessionResultsList.Add("Happy Hour", qHappyHourResults);
- RAXMLSessionResultsList.Add("Race", qRaceResults);
- foreach(KeyValuePair<string, IEnumerable<XElement>> RAXMLSessionResultsKVP in RAXMLSessionResultsList)
- {
- IEnumerable<XElement> RAXMLSessionResults = RAXMLSessionResultsKVP.Value;
- if (RAXMLSessionResults != null && RAXMLSessionResults.Count() > 0)
- {
- if (!RAXMLSessionResultsKVP.Key.Equals("Race") && ev.TimedSessions == null)
- ev.TimedSessions = new List<Core.TimedSession>();
- else if (RAXMLSessionResultsKVP.Key.Equals("Race") && ev.RaceSessions == null)
- ev.RaceSessions = new List<Core.RaceSession>();
- Core.Session session;
- if (RAXMLSessionResultsKVP.Key.Equals("Race"))
- {
- session = new Core.RaceSession();
- ((Core.RaceSession)(session)).Results = new List<Core.RaceSessionResult>();
- }
- else
- {
- session = new Core.TimedSession();
- ((Core.TimedSession)(session)).Results = new List<Core.TimedSessionResult>();
- }
-
- session.Name = RAXMLSessionResultsKVP.Key;
-
- foreach (XElement RAXMLSessionResult in RAXMLSessionResults)
- {
- string carNumber = RAXMLSessionResult.Element("car-number").Value.Trim();
- if (!this.excludedCarNumbers.Contains(carNumber))
- {
- string driverFullName = RAXMLSessionResult.Element("driver").Attribute("name").Value.Trim();
- Driver driver;
- if (!drivers.Keys.Contains(carNumber)) //CREATE THE DRIVER IF ITS CARNUMBER DOES NOT YET EXIST IN THE DICTIONARY
- {
- driver = new Driver();
- int driverSpacePosition = driverFullName.IndexOf(" "); //THE FIRST SPACE SPLITS THE FIRSTNAME FROM THE LASTNAME
- if (driverSpacePosition == -1) //NO SPACE, SO PUT EVERYTING IN THE LASTNAME
- {
- driver.LastName = driverFullName;
- }
- else
- {
- driver.FirstName = driverFullName.Substring(0, driverSpacePosition).Trim();
- driver.LastName = driverFullName.Substring(driverSpacePosition + 1).Trim();
- }
- drivers.Add(carNumber, driver);
- }
- else //IF THE CARNUMBER ALREADY EXISTS IN THE DICTIONARY, RETRIEVE THE DRIVER FROM THERE
- {
- driver = drivers[carNumber];
- }
- int position;
- decimal time;
- bool timeParsable;
- decimal speed;
- bool speedParsable;
- int laps;
- bool lapsParsable;
- Int32.TryParse(RAXMLSessionResult.Attribute("position").Value.Trim(), out position);
- timeParsable = Decimal.TryParse(RAXMLSessionResult.Element("time").Value.Trim().Replace(".", System.Globalization.NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator), out time);
- speedParsable = Decimal.TryParse(RAXMLSessionResult.Element("speed").Value.Trim().Replace(".", System.Globalization.NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator), out speed);
- lapsParsable = Int32.TryParse(RAXMLSessionResult.Element("laps").Value.Trim().Replace(".", System.Globalization.NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator), out laps);
- Core.SessionResult result;
- if (session is Core.TimedSession)
- result = new Core.TimedSessionResult();
- else
- result = new Core.RaceSessionResult();
- result.Drivers = new List<Driver>();
- result.Drivers.Add(driver);
- result.Position = position;
- result.CarNumber = carNumber;
- if (timeParsable)
- {
- if (result is Core.TimedSessionResult)
- {
- result.BestLapTimeSpecified = true;
- result.BestLapTime = time;
- }
- else
- {
- ((Core.RaceSessionResult)(result)).TotalRaceTimeSpecified = true;
- ((Core.RaceSessionResult)(result)).TotalRaceTime = time;
- }
- }
- if (speedParsable)
- {
- if (result is Core.TimedSessionResult)
- {
- result.BestLapSpeedSpecified = true;
- result.BestLapSpeed = speed;
- }
- else
- {
- result.AverageLapSpeedSpecified = true;
- result.AverageLapSpeed = speed;
- }
- }
- if (lapsParsable)
- {
- result.LapsSpecified = true;
- result.Laps = laps;
- }
- if (session is Core.RaceSession)
- {
- string problem = RAXMLSessionResult.Element("problem").Value.Trim();
- if (problem == null || problem.Equals("") || problem.ToLower().Equals("running"))
- {
- ((Core.RaceSessionResult)(result)).IsRunning = true;
- result.Status = "Running";
- }
- else
- {
- ((Core.RaceSessionResult)(result)).IsRunning = false;
- result.Status = problem;
- }
- if (result.Laps.HasValue && result.Laps == 0) //SET RESULTS WITH ZERO LAPS TO NOT RUNNING AND STATUS DNS
- {
- ((Core.RaceSessionResult)(result)).IsRunning = false;
- result.Status = "DNS";
- }
- }
- if(session is Core.TimedSession)
- ((Core.TimedSession)(session)).Results.Add((Core.TimedSessionResult)(result));
- else
- ((Core.RaceSession)(session)).Results.Add((Core.RaceSessionResult)(result));
- }
- }
- if (session is Core.TimedSession)
- {
- this.NormalizePositions(((Core.TimedSession)(session)).Results);
- ev.TimedSessions.Add((Core.TimedSession)(session));
- }
- else
- {
- this.NormalizePositions(((Core.RaceSession)(session)).Results);
- ev.RaceSessions.Add((Core.RaceSession)(session));
- }
- }
- }
- }
- return ev;
- }
- /// <summary>
- /// Parses the NR2003 exported HTML result file associated with this NR2003Parser object
- /// </summary>
- /// <returns>A NR2003HTMLResult object</returns>
- private NR2003HTMLResult ParseHTML()
- {
- NR2003HTMLResult nresult = null;
-
- if (this._HTMLFileName != null && File.Exists(this._HTMLFileName))
- {
- this.HTMLFileContents = File.ReadAllText(this._HTMLFileName, Encoding.UTF8);
- if (!this.HTMLFileContents.Contains("NASCAR Racing 2003 Season EXPORTED STANDINGS"))
- {
- throw new ArgumentException("HTML file is not a valid NR2003 result file");
- }
- else
- {
- nresult = new NR2003HTMLResult();
- nresult.General = new GeneralInfo();
-
- //string lineBreak = "\n";
- //TRACK
- int trackStart = this.HTMLFileContents.IndexOf("Track:");
- if (trackStart != -1)
- {
- trackStart += 7;
- int trackEnd = this.HTMLFileContents.IndexOf("</", trackStart);
- string trackName = this.HTMLFileContents.Substring(trackStart, trackEnd - trackStart).Trim();
- nresult.General.Track = trackName;
- }
- //DATE
- int dateStart = this.HTMLFileContents.IndexOf("Date:");
- if (dateStart != -1)
- {
- dateStart += 6;
- int dateEnd = this.HTMLFileContents.IndexOf("</", dateStart);
- string date = this.HTMLFileContents.Substring(dateStart, dateEnd - dateStart).Trim();
- try
- {
- nresult.General.Date = DateTime.ParseExact(date, "MM/dd/yy", CultureInfo.InvariantCulture);
- }
- catch (Exception ex)
- {
- Console.WriteLine("Could not parse date " + date + ": " + ex.ToString());
- }
- }
- //PRACTICE SESSION
- int practiceStart = this.HTMLFileContents.IndexOf("Session: Practice");
- if (practiceStart != -1)
- {
- nresult.PracticeSession = new NR2003.TimedSession();
- DataTable dtPractice = null;
- int practiceTableStart = this.HTMLFileContents.IndexOf("<table", practiceStart, StringComparison.InvariantCultureIgnoreCase);
- if (practiceTableStart != -1)
- {
- int practiceTableEnd = this.HTMLFileContents.IndexOf("</table", practiceTableStart, StringComparison.InvariantCultureIgnoreCase);
- if (practiceTableEnd != -1)
- {
- dtPractice = this.NR2003HTMLTableToDatatable(this.HTMLFileContents.Substring(practiceTableStart, practiceTableEnd - practiceTableStart).Trim());
- }
- }
- //DATATABLE TO SESSIONRESULT
- nresult.PracticeSession.Results = this.DataTableToTimedSessionsResults(dtPractice);
- //WEATHER
- int weatherStart = this.HTMLFileContents.IndexOf("Weather:", practiceStart);
- if (weatherStart != -1)
- {
- weatherStart += 9;
- int weatherEnd = this.HTMLFileContents.IndexOf("</h3", weatherStart, StringComparison.InvariantCultureIgnoreCase);
- string weather = this.HTMLFileContents.Substring(weatherStart, weatherEnd - weatherStart).Trim();
- nresult.PracticeSession.Weather = this.GetWeatherFromString(weather);
-
- }
- }
- //QUALIFYING SESSION
- int qualifyingStart = this.HTMLFileContents.IndexOf("Session: Qualifying");
- if (qualifyingStart != -1)
- {
- nresult.QualifyingSession = new NR2003.TimedSession();
- DataTable dtQualifying = null;
- int qualifyingTableStart = this.HTMLFileContents.IndexOf("<table", qualifyingStart, StringComparison.InvariantCultureIgnoreCase);
- if (qualifyingTableStart != -1)
- {
- int qualifyingTableEnd = this.HTMLFileContents.IndexOf("</table", qualifyingTableStart, StringComparison.InvariantCultureIgnoreCase);
- if (qualifyingTableEnd != -1)
- {
- dtQualifying = this.NR2003HTMLTableToDatatable(this.HTMLFileContents.Substring(qualifyingTableStart, qualifyingTableEnd - qualifyingTableStart).Trim());
- }
- }
- //DATATABLE TO SESSIONRESULT
- nresult.QualifyingSession.Results = this.DataTableToTimedSessionsResults(dtQualifying);
- //WEATHER
- int weatherStart = this.HTMLFileContents.IndexOf("Weather:", qualifyingStart);
- if (weatherStart != -1)
- {
- weatherStart += 9;
- int weatherEnd = this.HTMLFileContents.IndexOf("</h3", weatherStart, StringComparison.InvariantCultureIgnoreCase);
- string weather = this.HTMLFileContents.Substring(weatherStart, weatherEnd - weatherStart).Trim();
- string[] weatherSplit = weather.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
- nresult.QualifyingSession.Weather = this.GetWeatherFromString(weather);
- }
- }
- //HAPPYHOUR SESSION
- int happyhourStart = this.HTMLFileContents.IndexOf("Session: Happy Hour");
- if (happyhourStart != -1)
- {
- nresult.HappyHourSession = new NR2003.TimedSession();
- DataTable dtHappyHour = null;
- int happyhourTableStart = this.HTMLFileContents.IndexOf("<table", happyhourStart, StringComparison.InvariantCultureIgnoreCase);
- if (happyhourTableStart != -1)
- {
- int happyhourTableEnd = this.HTMLFileContents.IndexOf("</table", happyhourTableStart, StringComparison.InvariantCultureIgnoreCase);
- if (happyhourTableEnd != -1)
- {
- dtHappyHour = this.NR2003HTMLTableToDatatable(this.HTMLFileContents.Substring(happyhourTableStart, happyhourTableEnd - happyhourTableStart).Trim());
- }
- }
- //DATATABLE TO SESSIONRESULT
- nresult.HappyHourSession.Results = this.DataTableToTimedSessionsResults(dtHappyHour);
- //WEATHER
- int weatherStart = this.HTMLFileContents.IndexOf("Weather:", happyhourStart);
- if (weatherStart != -1)
- {
- weatherStart += 9;
- int weatherEnd = this.HTMLFileContents.IndexOf("</h3", weatherStart, StringComparison.InvariantCultureIgnoreCase);
- string weather = this.HTMLFileContents.Substring(weatherStart, weatherEnd - weatherStart).Trim();
- string[] weatherSplit = weather.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
- nresult.HappyHourSession.Weather = this.GetWeatherFromString(weather);
- }
- }
- //RACE SESSION
- int raceStart = this.HTMLFileContents.IndexOf("Session: Race");
- if (raceStart != -1)
- {
- nresult.RaceSession = new NR2003.RaceSession();
- DataTable dtRace = null;
- int raceTableStart = this.HTMLFileContents.IndexOf("<table", raceStart, StringComparison.InvariantCultureIgnoreCase);
- if (raceTableStart != -1)
- {
- int raceTableEnd = this.HTMLFileContents.IndexOf("</table", raceTableStart, StringComparison.InvariantCultureIgnoreCase);
- if (raceTableEnd != -1)
- {
- dtRace = this.NR2003HTMLTableToDatatable(this.HTMLFileContents.Substring(raceTableStart, raceTableEnd - raceTableStart).Trim());
- }
- }
- //DATATABLE TO SESSIONRESULT
- nresult.RaceSession.Results = this.DataTableToRaceSessionResults(dtRace);
- //CAUTIONS
- int cautionStart = this.HTMLFileContents.IndexOf("Caution Flags:", raceStart);
- if (cautionStart != -1)
- {
- cautionStart += 15;
- int cautionEnd = this.HTMLFileContents.IndexOf("</h3", cautionStart, StringComparison.InvariantCultureIgnoreCase);
- string cautionFlags = this.HTMLFileContents.Substring(cautionStart, cautionEnd - cautionStart).Trim();
- try { nresult.RaceSession.CautionFlags = Int32.Parse(cautionFlags.Substring(0, cautionFlags.IndexOf(" ")).Trim()); }
- catch { }
- try { nresult.RaceSession.CautionLaps = Int32.Parse(cautionFlags.Substring(cautionFlags.IndexOf("(") + 1, cautionFlags.IndexOf("laps") - cautionFlags.IndexOf("(") - 1).Trim()); }
- catch { }
- }
- //LEADCHANGES
- int leadchangesStart = this.HTMLFileContents.IndexOf("Lead Changes:", raceStart);
- if (leadchangesStart != -1)
- {
- leadchangesStart += 14;
- int leadchangesEnd = this.HTMLFileContents.IndexOf("</h3", leadchangesStart, StringComparison.InvariantCultureIgnoreCase);
- string leadchanges = this.HTMLFileContents.Substring(leadchangesStart, leadchangesEnd - leadchangesStart).Trim();
- try { nresult.RaceSession.LeadChanges = Int32.Parse(leadchanges.Substring(0, leadchanges.IndexOf(" ")).Trim()); }
- catch { }
- try { nresult.RaceSession.LeadDrivers = Int32.Parse(leadchanges.Substring(leadchanges.IndexOf("(") + 1, leadchanges.IndexOf("drivers") - leadchanges.IndexOf("(") - 1).Trim()); }
- catch { }
- }
- //WEATHER
- int weatherStart = this.HTMLFileContents.IndexOf("Weather:", raceStart);
- if (weatherStart != -1)
- {
- weatherStart += 9;
- int weatherEnd = this.HTMLFileContents.IndexOf("</h3", weatherStart, StringComparison.InvariantCultureIgnoreCase);
- string weather = this.HTMLFileContents.Substring(weatherStart, weatherEnd - weatherStart).Trim();
- nresult.RaceSession.Weather = this.GetWeatherFromString(weather);
-
- }
- //PENALTIES
- int penaltiesStart = this.HTMLFileContents.IndexOf("PENALTIES", weatherStart);
- if (penaltiesStart != -1)
- {
- DataTable dtPenalty = null;
- int penaltiesTableStart = this.HTMLFileContents.IndexOf("<table", penaltiesStart, StringComparison.InvariantCultureIgnoreCase);
- if (penaltiesTableStart != -1)
- {
- int penaltiesTableEnd = this.HTMLFileContents.IndexOf("</table", penaltiesTableStart, StringComparison.InvariantCultureIgnoreCase);
- if (penaltiesTableEnd != -1)
- {
- dtPenalty = this.NR2003HTMLTableToDatatable(this.HTMLFileContents.Substring(penaltiesTableStart, penaltiesTableEnd - penaltiesTableStart).Trim());
- }
- }
- //DATATABLE TO PENALTYLIST
- nresult.Penalties = this.DataTableToPenalties(dtPenalty);
- }
- }
- }
- }
- return nresult;
-
- }
- /// <summary>
- /// Loads the Replay Analyzer XML result file associated with this NR2003Parser object into memory
- /// </summary>
- /// <returns></returns>
- private XDocument LoadRAXML()
- {
- if (this._RAXMLFileName != null && File.Exists(this._RAXMLFileName))
- {
- XDocument doc = XDocument.Load(this._RAXMLFileName);
- if (doc.Root.Name.LocalName.Equals("n2003ra"))
- return doc;
- else
- throw new ArgumentException("XML file is not a valid NR2003 RA XML export file");
- }
- else
- {
- return null;
- }
-
- }
- /// <summary>
- /// Converts a datatable generated from a NR2003 HTML result into a list of NR2003.TimedSessionResult objects
- /// </summary>
- /// <param name="dt">The source datatable</param>
- /// <returns>A list of NR2003.TimedSessionResult objects</returns>
- private List<NR2003.TimedSessionResult> DataTableToTimedSessionsResults(DataTable dt)
- {
- List<NR2003.TimedSessionResult> resultList = null;
- if (dt != null)
- {
- resultList = new List<NR2003.TimedSessionResult>();
- foreach (DataRow dr in dt.Rows)
- {
- NR2003.TimedSessionResult result = new NR2003.TimedSessionResult();
- int position;
- string carNumber;
- string driver;
- bool timeParsable = false;
- decimal time = 0;
- bool speedParsable = false;
- decimal speed = 0;
- Int32.TryParse(dr["P"].ToString(), out position);
- carNumber = dr["#"].ToString();
- driver = dr["DRIVER"].ToString();
- if (!dr["TIME"].ToString().Contains("mph")) //TIME
- {
- timeParsable = Decimal.TryParse(dr["TIME"].ToString().Replace(".", System.Globalization.NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator), out time);
- }
- else //SPEED
- {
- speedParsable = Decimal.TryParse(dr["TIME"].ToString().Replace(".", System.Globalization.NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator).Substring(0, dr["TIME"].ToString().IndexOf(" ")).Trim(), out speed);
- }
- result.Position = position;
- result.CarNumber = carNumber;
- result.Driver = driver;
- if (timeParsable)
- result.Time = time;
- if (speedParsable)
- result.Speed = speed;
-
- resultList.Add(result);
- }
- }
- return resultList;
- }
- /// <summary>
- /// Converts a datatable generated from a NR2003 HTML result into a list of NR2003.RaceSessionResult objects
- /// </summary>
- /// <param name="dt">The source datatable</param>
- /// <returns>A list of NR2003.RaceSessionResult objects</returns>
- private List<NR2003.RaceSessionResult> DataTableToRaceSessionResults(DataTable dt)
- {
- List<NR2003.RaceSessionResult> resultList = null;
- if (dt != null)
- {
- resultList = new List<NR2003.RaceSessionResult>();
- foreach (DataRow dr in dt.Rows)
- {
- NR2003.RaceSessionResult result = new NR2003.RaceSessionResult();
- int position;
- int startingPosition;
- string carNumber;
- string driver;
- string interval;
- int laps;
- int lapsLed;
- bool mostLapsLed = false;
- bool pointsParsable;
- int points;
- string status;
-
- Int32.TryParse(dr["F"].ToString(), out position);
- Int32.TryParse(dr["S"].ToString(), out startingPosition);
- carNumber = dr["#"].ToString();
- driver = dr["DRIVER"].ToString();
- interval = dr["INTERVAL"].ToString();
- Int32.TryParse(dr["LAPS"].ToString(), out laps);
- Int32.TryParse(dr["LED"].ToString().Trim(new char[]{'*'}), out lapsLed);
- if (dr["LED"].ToString().Contains("*"))
- mostLapsLed = true;
- pointsParsable = Int32.TryParse(dr["POINTS"].ToString(), out points);
- status = dr["STATUS"].ToString();
- result.Position = position;
- result.StartingPosition = startingPosition;
- result.CarNumber = carNumber;
- result.Driver = driver;
- result.Interval = interval;
- result.Laps = laps;
- result.LapsLed = lapsLed;
- result.MostLapsLed = mostLapsLed;
- if (pointsParsable)
- result.Points = points;
- result.Status = status;
-
- resultList.Add(result);
- }
- }
- return resultList;
- }
- /// <summary>
- /// Converts a datatable generated from a NR2003 HTML result into a list of NR2003.Penalty objects
- /// </summary>
- /// <param name="dt">The source datatable</param>
- /// <returns>A list of NR2003.Penalty objects</returns>
- private List<NR2003.Penalty> DataTableToPenalties(DataTable dt)
- {
- List<NR2003.Penalty> penaltyList = null;
- if (dt != null)
- {
- penaltyList = new List<NR2003.Penalty>();
- foreach (DataRow dr in dt.Rows)
- {
- NR2003.Penalty penalty = new NR2003.Penalty();
-
- string carNumber;
- int lap;
- string infraction;
- string penaltyDescription;
- carNumber = dr["#"].ToString();
- Int32.TryParse(dr["LAP"].ToString(), out lap);
- infraction = dr["INFRACTION"].ToString();
- penaltyDescription = dr["PENALTY"].ToString();
- penalty.CarNumber = carNumber;
- penalty.Lap = lap;
- penalty.Infraction = infraction;
- penalty.PenaltyDescription = penaltyDescription;
- penaltyList.Add(penalty);
- }
- }
- return penaltyList;
- }
- /// <summary>
- /// Parses the weather information in a NR2003 HTML result file into a NR2003.Weather object
- /// </summary>
- /// <param name="weather">The weather information string</param>
- /// <returns>A NR2003.Weather object</returns>
- private NR2003.Weather GetWeatherFromString(string weather)
- {
- NR2003.Weather w = new NR2003.Weather();
-
- string[] weatherSplit = weather.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
- try { w.Conditions = weatherSplit[0].Trim(); }
- catch { }
- try { w.Temperature = weatherSplit[1].Trim(); }
- catch { }
- try { w.WindDirection = weatherSplit[2].Trim().Substring(0, weatherSplit[2].Trim().IndexOf(" ")).Trim(); }
- catch { }
- try { w.WindSpeed = weatherSplit[2].Trim().Substring(weatherSplit[2].Trim().IndexOf(" ") + 1).Trim(); }
- catch { }
- return w;
- }
- /// <summary>
- /// Converts a HTML table from a NR2003 HTML result file into a datatable
- /// </summary>
- /// <param name="htmlTable">The HTML table (starting from the "table" or the first "tr" tag)</param>
- /// <returns>A datatable mirroring the HTML table</returns>
- private DataTable NR2003HTMLTableToDatatable(string htmlTable)
- {
- try
- {
- DataTable dt = new DataTable();
- htmlTable = htmlTable.Substring(htmlTable.IndexOf("<tr", StringComparison.InvariantCultureIgnoreCase));
- string[] rowSplitter = { "<tr", "<TR" };
- string[] columnSplitter = { "</td>", "</TD>" };
-
- string[] rows = htmlTable.Split(rowSplitter, StringSplitOptions.RemoveEmptyEntries);
- int rowIndex = 0;
- foreach (string r in rows)
- {
- string row = r.Trim();
- //int startOfTR = row.IndexOf("<tr", StringComparison.InvariantCultureIgnoreCase);
-
- int endOfTR = row.IndexOf(">");
- row = row.Remove(0, endOfTR + 1).Trim();
- int columnCount = 0;
- string[] columns = row.Split(columnSplitter, StringSplitOptions.RemoveEmptyEntries);
- Hashtable columnText = new Hashtable();
- foreach (string c in columns)
- {
- string column = c.Trim();
- int startOfTD = column.IndexOf("<td", StringComparison.InvariantCultureIgnoreCase);
- if (startOfTD != -1)
- {
- int endOfTD = column.IndexOf(">", startOfTD);
- column = column.Remove(startOfTD, endOfTD - startOfTD + 1).Trim();
- columnText.Add(columnCount, column);
- if (rowIndex == 0)
- {
- dt.Columns.Add(column);
- }
- columnCount++;
- }
- }
- if (rowIndex > 0)
- {
- DataRow dr = dt.NewRow();
- IDictionaryEnumerator e = columnText.GetEnumerator();
- while (e.MoveNext())
- {
- dr[(int)e.Key] = (string)e.Value;
- }
- dt.Rows.Add(dr);
- }
-
- rowIndex++;
- }
- return dt;
- }
- catch (Exception ex)
- {
- Console.WriteLine("Error in converting HTML Table to DataTable: " + ex.ToString());
- return null;
- }
- }
- #endregion
- }
- }