// Define the event handlers.
        private void OnChanged(object source, FileSystemEventArgs e)
        {
            Thread.Sleep(500);
            // Specify what is done when a file is changed, created, or deleted.
            var competitorsRawResults = CompetitorService.ReadFile(Path.Combine(path, filename));
            var maxNumberOfTimes = 0;
            this.Dispatcher.Invoke(() =>
            {
                DataGrid1.DataContext = generateViewModelResults(competitorsRawResults, ref maxNumberOfTimes);

                if (maxNumberOfTimes < 5) maxNumberOfTimes = 5;
                // Hide unused columns
                for (int k = 1; k <= maxNumberOfTimes; k++)
                {
                    DataGrid1.Columns[k + 4].Visibility = Visibility.Visible;
                }
                for (int k = maxNumberOfTimes; k < 20; k++)
                {
                    DataGrid1.Columns[k + 4].Visibility = Visibility.Hidden;
                }
            });

            // Update window title to reflect changes
            var lastUpdated = File.GetLastWriteTime(Path.Combine(path, filename));
            _vm.AppTitle = string.Concat("ERC Axware - last updated: ", lastUpdated.ToString());
            finalResultsGenerated = false;
        }
        private void openFileClick(object sender, RoutedEventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Filter = "Axware RGG files (*.rgg)|*.rgg";
            if (openFileDialog.ShowDialog() == true)
            {
                var fullDir = openFileDialog.FileName;
                filename = Path.GetFileName(fullDir);
                path = Path.GetDirectoryName(fullDir);
                var competitorsRawResults = CompetitorService.ReadFile(fullDir);
                int maxNumberOfTimes = 0;
                competitorsResults = generateViewModelResults(competitorsRawResults, ref maxNumberOfTimes);
                DataGrid1.DataContext = competitorsResults;

                // Display at least 5 time columns
                if (maxNumberOfTimes < 5) maxNumberOfTimes = 5;
                // Hide unused columns
                for (int k = 1; k <= maxNumberOfTimes; k++)
                {
                    DataGrid1.Columns[k + 4].Visibility = Visibility.Visible;
                }
                for (int k = maxNumberOfTimes; k < 20; k++)
                {
                    DataGrid1.Columns[k + 4].Visibility = Visibility.Hidden;
                }

                var lastUpdated = File.GetLastWriteTime(fullDir);
                _vm.AppTitle = string.Concat("ERC Axware - last updated: ", lastUpdated.ToString());
                CreateFileWatcher(path, filename);
            }

        }
        private void generateResults(object sender, RoutedEventArgs e)
        {
            overallCompetitors.Clear();
            n2Competitors.Clear();
            n4Competitors.Clear();
            e2Competitors.Clear();
            e4Competitors.Clear();
            proCompetitors.Clear();
            truckCompetitors.Clear();
            // Generate ERC results
            if (path != null)
            {
                if (generateFinalResults(CompetitorService.ReadFile(Path.Combine(path, filename))))
                {
                    // Set final results flag as true - it is used to determine if championship points can be updated
                    finalResultsGenerated = true;
                    MessageBox.Show("Resuls saved to:\n" + Path.Combine(path, "ERCresult.csv"), "Success");

                }
            }
            else
                MessageBox.Show("No results to calculate", "Error");
        }
        private bool generateFinalResults(List<CompetitorAxware> competitorsRawResults)
        {
            int maxNumberOfTimes = 0;
            string[] timesStr = new string[20];
            double[] times = new double[20];

            double overallFastestLap = Double.MaxValue;
            double n2FastestLap = Double.MaxValue;
            double n4FastestLap = Double.MaxValue;
            double e2FastestLap = Double.MaxValue;
            double e4FastestLap = Double.MaxValue;
            double proFastestLap = Double.MaxValue;

            double truckFastestLap = Double.MaxValue;
            // Holders to find the best times in class
            double[] overallCompetitorTimes = new double[competitorsRawResults.Count()];
            List<double> n2CompetitorTimes = new List<double>();
            List<double> n4CompetitorTimes = new List<double>();
            List<double> e2CompetitorTimes = new List<double>();
            List<double> e4CompetitorTimes = new List<double>();
            List<double> proCompetitorTimes = new List<double>();
            List<double> truckCompetitorTimes = new List<double>();

            // Container to hold calculated results, but unordered
            //  List<CompetitorResult> competitorsProcessedResults = new List<CompetitorResult>();
            int competitorIndex = 0;

            // First find how many runs each competitor have completed and find the maximum value;
            foreach (CompetitorAxware competitor in competitorsRawResults)
            {
                var timeList = new List<string> { competitor.Run1, competitor.Run2, competitor.Run3,competitor.Run4,competitor.Run5,competitor.Run6,competitor.Run7,competitor.Run8, competitor.Run9,competitor.Run10,competitor.Run11,
                    competitor.Run12,competitor.Run13,competitor.Run14,competitor.Run15,competitor.Run16,competitor.Run17,competitor.Run18,competitor.Run19,competitor.Run20 };
                var numberOfTimes = timeList.Count(k => k != "");
                if (numberOfTimes > maxNumberOfTimes)
                    maxNumberOfTimes = numberOfTimes;
            }

            // Calculate total time and position for each competitor
            foreach (CompetitorAxware competitor in competitorsRawResults)
            {
                var competitorFinalResult = new CompetitorResult
                {
                    // Assign the basic properties
                    Car = competitor.Car,
                    Name = competitor.Name,
                    //Class = competitor.Class,
                    Number = competitor.Number
                };

                if (maxNumberOfTimes > 0)
                {
                    int penalties = 0;
                    var timeList = new List<string> { competitor.Run1, competitor.Run2, competitor.Run3,competitor.Run4,competitor.Run5,competitor.Run6,competitor.Run7,competitor.Run8, competitor.Run9,competitor.Run10,competitor.Run11,
                    competitor.Run12,competitor.Run13,competitor.Run14,competitor.Run15,competitor.Run16,competitor.Run17,competitor.Run18,competitor.Run19,competitor.Run20 };
                    var penaltyList = new List<string> { competitor.Pen1, competitor.Pen2, competitor.Pen3, competitor.Pen4, competitor.Pen5, competitor.Pen6, competitor.Pen7, competitor.Pen8, competitor.Pen9, competitor.Pen10,
                    competitor.Pen11, competitor.Pen12,competitor.Pen13, competitor.Pen14,competitor.Pen15, competitor.Pen16,competitor.Pen17, competitor.Pen18,competitor.Pen19, competitor.Pen20};

                    // Add times to an array
                    int i = 0;
                    foreach (var time in timeList)
                    {
                        timesStr[i] = time;
                        i++;
                    }

                    // Update time string with penalties (if applicable). Times over 300s or Off-course are capped
                    i = 0;
                    foreach (string penalty in penaltyList)
                    {
                        times[i] = singleTimeValidation(ref timesStr[i], penalty);
                        if (penalty != "")
                        {
                            try
                            {
                                penalties += Convert.ToInt32(penalty);
                            }
                            catch (Exception)
                            {
                                // Cannot convert (off/dnf/dns)
                                //continue;
                            }
                        }
                        i++;
                    }

                    // If competitor has less timed runs than the maximum number of timed runs, add 300s to the missed runs
                    if (times.Count(k => k > 0) < maxNumberOfTimes)
                    {
                        for (int j = times.Count(k => k > 0); j < maxNumberOfTimes; j++)
                        {
                            times[j] = 300;
                            timesStr[j] = "300.000";
                        }
                    }

                    // Update result field with times + penalty
                    competitorFinalResult.Time1 = timesStr[0];
                    competitorFinalResult.Time2 = timesStr[1];
                    competitorFinalResult.Time3 = timesStr[2];
                    competitorFinalResult.Time4 = timesStr[3];
                    competitorFinalResult.Time5 = timesStr[4];
                    competitorFinalResult.Time6 = timesStr[5];
                    competitorFinalResult.Time7 = timesStr[6];
                    competitorFinalResult.Time8 = timesStr[7];
                    competitorFinalResult.Time9 = timesStr[8];
                    competitorFinalResult.Time10 = timesStr[9];
                    competitorFinalResult.Time11 = timesStr[10];
                    competitorFinalResult.Time12 = timesStr[11];
                    competitorFinalResult.Time13 = timesStr[12];
                    competitorFinalResult.Time14 = timesStr[13];
                    competitorFinalResult.Time15 = timesStr[14];
                    competitorFinalResult.Time16 = timesStr[15];
                    competitorFinalResult.Time17 = timesStr[16];
                    competitorFinalResult.Time18 = timesStr[17];
                    competitorFinalResult.Time19 = timesStr[18];
                    competitorFinalResult.Time20 = timesStr[19];
                    competitorFinalResult.Penalties = penalties;

                    // Raw time (all summed up)
                    competitorFinalResult.RawTime = times.Sum();

                    //Discard the slowest time if competitor has more than one timed run
                    if (maxNumberOfTimes > 1)
                        competitorFinalResult.MinusSlowest = times.Sum() - times.Max();
                    else
                        competitorFinalResult.MinusSlowest = times.Sum();

                    overallCompetitorTimes[competitorIndex] = competitorFinalResult.MinusSlowest;

                    competitorFinalResult.FastestLap = times.Where(f => f > 0).Min();
                }

                if (competitorFinalResult.FastestLap < overallFastestLap)
                    overallFastestLap = competitorFinalResult.FastestLap;

                switch (competitor.Class)
                {
                    case CompetitionClass.n2:
                        n2CompetitorTimes.Add(competitorFinalResult.MinusSlowest);
                        n2Competitors.Add(competitorFinalResult);
                        if (competitorFinalResult.FastestLap < n2FastestLap)
                            n2FastestLap = competitorFinalResult.FastestLap;
                        break;
                    case CompetitionClass.n4:
                        n4CompetitorTimes.Add(competitorFinalResult.MinusSlowest);
                        n4Competitors.Add(competitorFinalResult);
                        if (competitorFinalResult.FastestLap < n4FastestLap)
                            n4FastestLap = competitorFinalResult.FastestLap;
                        break;
                    case CompetitionClass.e2:
                        e2CompetitorTimes.Add(competitorFinalResult.MinusSlowest);
                        e2Competitors.Add(competitorFinalResult);
                        if (competitorFinalResult.FastestLap < e2FastestLap)
                            e2FastestLap = competitorFinalResult.FastestLap;
                        break;
                    case CompetitionClass.e4:
                        e4CompetitorTimes.Add(competitorFinalResult.MinusSlowest);
                        e4Competitors.Add(competitorFinalResult);
                        if (competitorFinalResult.FastestLap < e4FastestLap)
                            e4FastestLap = competitorFinalResult.FastestLap;
                        break;
                    case CompetitionClass.pro:
                    case CompetitionClass.p2:
                    case CompetitionClass.p4:
                        proCompetitorTimes.Add(competitorFinalResult.MinusSlowest);
                        proCompetitors.Add(competitorFinalResult);
                        if (competitorFinalResult.FastestLap < proFastestLap)
                            proFastestLap = competitorFinalResult.FastestLap;
                        break;
                    case CompetitionClass.truck:
                        truckCompetitorTimes.Add(competitorFinalResult.MinusSlowest);
                        truckCompetitors.Add(competitorFinalResult);
                        if (competitorFinalResult.FastestLap < truckFastestLap)
                            truckFastestLap = competitorFinalResult.FastestLap;
                        break;
                    default:
                        break;
                }
                // Clone the object, so it can be used in two different lists independently
                overallCompetitors.Add((CompetitorResult)competitorFinalResult.Clone());
                competitorIndex++;
            }

            // Find out what is the overall position for each competitor
            double[] n2CompetitorTimesArray = n2CompetitorTimes.ToArray();
            double[] n4CompetitorTimesArray = n4CompetitorTimes.ToArray();
            double[] e2CompetitorTimesArray = e2CompetitorTimes.ToArray();
            double[] e4CompetitorTimesArray = e4CompetitorTimes.ToArray();
            double[] proCompetitorTimesArray = proCompetitorTimes.ToArray();
            double[] truckCompetitorTimesArray = truckCompetitorTimes.ToArray();

            //Sort array by fastest times
            Array.Sort(overallCompetitorTimes);
            Array.Sort(n2CompetitorTimesArray);
            Array.Sort(n4CompetitorTimesArray);
            Array.Sort(e2CompetitorTimesArray);
            Array.Sort(e4CompetitorTimesArray);
            Array.Sort(proCompetitorTimesArray);
            Array.Sort(truckCompetitorTimesArray);

            // Set classification + competitors in class + fastest lap points
            int[] pointsScheme = { 20, 18, 16, 14, 12, 10, 8, 7, 6, 5, 4, 3, 2, 1 };
            int bestLap = 3;

            foreach (var competitor in overallCompetitors)
            {
                competitor.Position = Array.IndexOf(overallCompetitorTimes, competitor.MinusSlowest) + 1;
                competitor.CompetitorsInClassPoints = overallCompetitors.Count();
                competitor.FastestLapPoints = competitor.FastestLap == overallFastestLap ? bestLap : 0;
                competitor.PositionPoints = competitor.Position < pointsScheme.Length ? pointsScheme[competitor.Position - 1] : 0;
                competitor.Points = competitor.FastestLapPoints + competitor.CompetitorsInClassPoints + competitor.PositionPoints;
            }

            foreach (var competitor in n2Competitors)
            {
                competitor.Position = Array.IndexOf(n2CompetitorTimesArray, competitor.MinusSlowest) + 1;
                competitor.CompetitorsInClassPoints = n2Competitors.Count();
                competitor.FastestLapPoints = competitor.FastestLap == n2FastestLap ? bestLap : 0;
                competitor.PositionPoints = competitor.Position < pointsScheme.Length ? pointsScheme[competitor.Position - 1] : 0;
                competitor.Points = competitor.FastestLapPoints + competitor.CompetitorsInClassPoints + competitor.PositionPoints;
            }

            foreach (var competitor in n4Competitors)
            {
                competitor.Position = Array.IndexOf(n4CompetitorTimesArray, competitor.MinusSlowest) + 1;
                competitor.CompetitorsInClassPoints = n4Competitors.Count();
                competitor.FastestLapPoints = competitor.FastestLap == n4FastestLap ? bestLap : 0;
                competitor.PositionPoints = competitor.Position < pointsScheme.Length ? pointsScheme[competitor.Position - 1] : 0;
                competitor.Points = competitor.FastestLapPoints + competitor.CompetitorsInClassPoints + competitor.PositionPoints;
            }

            foreach (var competitor in e2Competitors)
            {
                competitor.Position = Array.IndexOf(e2CompetitorTimesArray, competitor.MinusSlowest) + 1;
                competitor.CompetitorsInClassPoints = e2Competitors.Count();
                competitor.FastestLapPoints = competitor.FastestLap == e2FastestLap ? bestLap : 0;
                competitor.PositionPoints = competitor.Position < pointsScheme.Length ? pointsScheme[competitor.Position - 1] : 0;
                competitor.Points = competitor.FastestLapPoints + competitor.CompetitorsInClassPoints + competitor.PositionPoints;
            }

            foreach (var competitor in e4Competitors)
            {
                competitor.Position = Array.IndexOf(e4CompetitorTimesArray, competitor.MinusSlowest) + 1;
                competitor.CompetitorsInClassPoints = e4Competitors.Count();
                competitor.FastestLapPoints = competitor.FastestLap == e4FastestLap ? bestLap : 0;
                competitor.PositionPoints = competitor.Position < pointsScheme.Length ? pointsScheme[competitor.Position - 1] : 0;
                competitor.Points = competitor.FastestLapPoints + competitor.CompetitorsInClassPoints + competitor.PositionPoints;
            }
            foreach (var competitor in proCompetitors)
            {
                competitor.Position = Array.IndexOf(proCompetitorTimesArray, competitor.MinusSlowest) + 1;
                competitor.CompetitorsInClassPoints = proCompetitors.Count();
                competitor.FastestLapPoints = competitor.FastestLap == proFastestLap ? bestLap : 0;
                competitor.PositionPoints = competitor.Position < pointsScheme.Length ? pointsScheme[competitor.Position - 1] : 0;
                competitor.Points = competitor.FastestLapPoints + competitor.CompetitorsInClassPoints + competitor.PositionPoints;
            }
            foreach (var competitor in truckCompetitors)
            {
                competitor.Position = Array.IndexOf(truckCompetitorTimesArray, competitor.MinusSlowest) + 1;
                competitor.CompetitorsInClassPoints = truckCompetitors.Count();
                competitor.FastestLapPoints = competitor.FastestLap == truckFastestLap ? bestLap : 0;
                competitor.PositionPoints = competitor.Position < pointsScheme.Length ? pointsScheme[competitor.Position - 1] : 0;
                competitor.Points = competitor.FastestLapPoints + competitor.CompetitorsInClassPoints + competitor.PositionPoints;
            }
            // Order by position
            overallCompetitors = overallCompetitors.OrderBy(o => o.Position).ToList();
            n2Competitors = n2Competitors.OrderBy(o => o.Position).ToList();
            n4Competitors = n4Competitors.OrderBy(o => o.Position).ToList();
            e2Competitors = e2Competitors.OrderBy(o => o.Position).ToList();
            e4Competitors = e4Competitors.OrderBy(o => o.Position).ToList();
            proCompetitors = proCompetitors.OrderBy(o => o.Position).ToList();
            truckCompetitors = truckCompetitors.OrderBy(o => o.Position).ToList();

            // Write to file
            return CompetitorService.WriteResultsFile(Path.Combine(path, "ERCresult.csv"), overallCompetitors, n2Competitors, n4Competitors, e2Competitors, e4Competitors, proCompetitors, truckCompetitors);
        }