private string GetStats(Rally rallyInfo) { var outputSb = new StringBuilder("Stats"); outputSb.AppendLine(Environment.NewLine); // participation stats var driversFinished = rallyInfo.DriverCount - rallyInfo.DriversDnf; outputSb.AppendLine("Participation Stats"); outputSb.AppendLine("Drivers Entered," + rallyInfo.DriverCount); outputSb.AppendLine("Drivers Finished," + (driversFinished)); outputSb.AppendLine("Drivers DNFd," + rallyInfo.DriversDnf); outputSb.AppendLine(String.Format("Completion Rate,{0:P2}", ((double)driversFinished / rallyInfo.DriverCount))); // stage wins outputSb.AppendLine(); outputSb.AppendLine("Stage Wins"); var stageWinners = rallyInfo.DriverInfoDict.Values.Where(x => x.StagesWon != 0).OrderByDescending(x => x.StagesWon); foreach (var driverInfo in stageWinners) { outputSb.AppendLine(driverInfo.Name + "," + driverInfo.StagesWon); } // manufacturer count outputSb.AppendLine(); outputSb.AppendLine("Manufacturer Count"); var carCounts = rallyInfo.VehicleCounts.OrderByDescending(x => x.Value); foreach (var car in carCounts) { outputSb.AppendLine(car.Key + "," + car.Value); } return(outputSb.ToString()); }
private string GetCsvChartOutput(Rally rallyData) { var positiveOutputSB = new StringBuilder("Chart Data").AppendLine(); var negativeOutputSB = new StringBuilder("Negated Chart Data").AppendLine(); var positionDict = new Dictionary <string, List <int> >(); List <KeyValuePair <string, DriverTime> > sortedStageData = null; foreach (Stage stage in rallyData) { sortedStageData = stage.DriverTimes.ToList(); sortedStageData.OrderBy(x => x.Value.OverallPosition == 0).ThenBy(x => x.Value.OverallPosition); foreach (KeyValuePair <string, DriverTime> driverTimeKvp in sortedStageData) { if (driverTimeKvp.Value == null) { continue; } var driverKey = driverTimeKvp.Key; var position = driverTimeKvp.Value.OverallPosition; if (!positionDict.ContainsKey(driverKey)) { positionDict.Add(driverKey, new List <int>()); } positionDict[driverKey].Add(position); } } // sortedStageData should contain the last stage, sorted by overall position if (sortedStageData == null) { return(null); } // keep a list of positionList that contains zeros var dnfDict = new Dictionary <string, List <int> >(); var driverList = rallyData.DriverInfoDict.Values.OrderBy(x => x.OverallPosition == 0).ThenBy(x => x.OverallPosition); foreach (var driver in driverList) { var positionList = positionDict[driver.Name]; if (positionList.Contains(0)) { dnfDict.Add(driver.Name, positionList); continue; } string posline = driver.Name + "," + String.Join(",", positionList); string negline = driver.Name + "," + String.Join(",", positionList.Select(x => x * -1)); positiveOutputSB.AppendLine(posline); negativeOutputSB.AppendLine(negline); } // remove zeros from dnfList foreach (var positionList in dnfDict.Values) { positionList.RemoveAll(x => x == 0); } foreach (var driverKvp in dnfDict.OrderByDescending(x => x.Value.Count)) { string posline = driverKvp.Key + "," + String.Join(",", driverKvp.Value); string negline = driverKvp.Key + "," + String.Join(",", driverKvp.Value.Select(x => x * -1)); positiveOutputSB.AppendLine(posline); negativeOutputSB.AppendLine(negline); } return(positiveOutputSB.ToString() + Environment.NewLine + negativeOutputSB.ToString()); }
private string GetCsvOverallTimes(Rally rallyData) { var outputSB = new StringBuilder(); int stageCount = 1; foreach (Stage stage in rallyData) { var dnfList = new List <DriverTime>(); outputSB.AppendLine("SS" + stageCount + " - " + stage.Name); outputSB.AppendLine("Overall Times"); outputSB.AppendLine("Pos, Pos Chng, Name, Vehicle, Time, Diff 1st, Diff Prev"); List <KeyValuePair <string, DriverTime> > sortedStageData = stage.DriverTimes.ToList(); sortedStageData.Sort((x, y) => { if (x.Value != null && y.Value == null) { return(-1); } else if (x.Value == null && y.Value != null) { return(1); } else if (x.Value == null && y.Value == null) { return(0); } else { return(x.Value.OverallTime.CompareTo(y.Value.OverallTime)); } }); foreach (KeyValuePair <string, DriverTime> driverTimeKvp in sortedStageData) { var driverName = driverTimeKvp.Key; var driverTime = driverTimeKvp.Value; // put DNFs into a separate list if (driverTime.IsDnf) { dnfList.Add(driverTime); continue; } if (driverTime != null) { var formatString = @"hh\:mm\:ss\.fff"; var line = driverTime.OverallPosition + "," + driverTime.PositionChange + "," + driverTime.DriverName + "," + driverTime.Vehicle + "," + driverTime.OverallTime.ToString(formatString) + "," + driverTime.OverallDiffFirst.ToString(formatString) + "," + driverTime.OverallDiffPrevious.ToString(formatString); outputSB.AppendLine(line); } else { outputSB.AppendLine(",,," + driverName + ",,DNF"); } } // put DNFs at the bottom foreach (var driverTime in dnfList) { outputSB.AppendLine(",," + driverTime.DriverName + "," + driverTime.Vehicle + ",DNF"); } outputSB.AppendLine(""); stageCount++; } return(outputSB.ToString()); }
private string GetCsvStageTimes(Rally rallyData) { var outputSB = new StringBuilder(); int stageCount = 1; foreach (Stage stage in rallyData) { var dnfList = new List <DriverTime>(); outputSB.AppendLine("SS" + stageCount + " - " + stage.Name); outputSB.AppendLine("Stage Times"); outputSB.AppendLine("Pos, Name, Vehicle, Time, Diff 1st, Diff Prev"); List <KeyValuePair <string, DriverTime> > sortedStageData = stage.DriverTimes.ToList(); sortedStageData.Sort((x, y) => { if (x.Value != null && y.Value == null) { return(-1); } else if (x.Value == null && y.Value != null) { return(1); } else if (x.Value == null && y.Value == null) { return(0); } else { return(x.Value.StageTime.CompareTo(y.Value.StageTime)); } }); foreach (KeyValuePair <string, DriverTime> driverTimeKvp in sortedStageData) { var driverName = driverTimeKvp.Key; var driverTime = driverTimeKvp.Value; // put DNFs into separate list if (driverTime.IsDnf) { dnfList.Add(driverTime); continue; } // if a driver did not complete the pervious stage due to alt+f4 or a crash, the next stage // will have a zero time for the CalculatedStageTime, so enter DNF if (driverTime == null) { outputSB.AppendLine(",," + driverName + ",,DNF"); } else { var formatString = @"hh\:mm\:ss\.fff"; var line = driverTime.StagePosition + "," + driverTime.DriverName + "," + driverTime.Vehicle + "," + driverTime.StageTime.ToString(formatString) + "," + driverTime.StageDiffFirst.ToString(formatString) + "," + driverTime.StageDiffPrevious.ToString(formatString); outputSB.AppendLine(line); } } // put DNFs at the bottom foreach (var driverTime in dnfList) { outputSB.AppendLine("," + driverTime.DriverName + "," + driverTime.Vehicle + ",DNF"); } outputSB.AppendLine(""); stageCount++; } return(outputSB.ToString()); }
// Given a championship ID, event ID, and a file path: // Fetch all the stage data for the event // convert the stage data to CSV // save the data to disk public async Task SaveStageDataToCsv(string championshipId, string eventId, string filePath) { if (clubInfoCache == null) { return; // TODO error handling? } // this gets the event results from the cache Event eventToOutput = null; for (int i = 0; i < clubInfoCache.RecentResults.Championships.Length; i++) { if (clubInfoCache.Championships[i].Id == championshipId) { var championship = clubInfoCache.RecentResults.Championships[i]; for (int j = 0; j < championship.Events.Length; j++) { if (championship.Events[j].ChallengeId == eventId) { eventToOutput = championship.Events[j]; break; } } } } // if we didn't find the event, bail if (eventToOutput == null) { return; } // get the stage results from the event var stageResultResponses = new List <Tuple <HttpStatusCode, string> >(); for (int i = 0; i < eventToOutput.Stages.Length; i++) { stageResultResponses.Add(await racenetApi.GetStageResults(eventToOutput.ChallengeId, eventToOutput.Id, i.ToString())); } var rallyData = new Rally(); // go thru each response and create the internal data used for (int i = 0; i < stageResultResponses.Count; i++) { var stageResultResponse = stageResultResponses[i]; if (stageResultResponse.Item1 != HttpStatusCode.OK || String.IsNullOrWhiteSpace(stageResultResponse.Item2)) { return; // TODO error handling } var stageApiData = JsonConvert.DeserializeObject <LeaderboardApiModel>(stageResultResponse.Item2); if (stageApiData == null) { return; // TODO error handling } var stageData = new Stage(eventToOutput.Stages[i].Name); foreach (var driverEntry in stageApiData.Entries) { stageData.AddDriver(CreateDriverTime(driverEntry)); } rallyData.AddStage(stageData); } // now crunch the numbers // this will generate any data that is not provided by the API rallyData.ProcessResults(); // get the CSV formatted output and write it to file // TODO this should probably be somewhere else for encapsulation and separation of concerns var outputString = GetHeaderData(championshipId, eventId, eventToOutput.Id); outputString += Environment.NewLine; outputString += GetCsvStageTimes(rallyData); outputString += Environment.NewLine; outputString += GetCsvOverallTimes(rallyData); outputString += Environment.NewLine; outputString += GetStats(rallyData); outputString += Environment.NewLine; outputString += GetCsvChartOutput(rallyData); File.WriteAllText(filePath, outputString, Encoding.UTF8); }