private async void ToggleSearch(object sender, EventArgs e) { if (_searchCancelToken != null) { _searchCancelToken.Cancel(); _searchCancelToken = null; return; } var levelPattern = LevPatternBox.Text; var errorFiles = new List <string>(); bool searchForFastestReplays; bool searchForAllReplays; var clickedButton = (Button)sender; if (clickedButton.Equals(SearchButton)) { searchForAllReplays = fastestSlowestSelect.SelectedOption == 2; searchForFastestReplays = fastestSlowestSelect.SelectedOption == 0; } else { searchForAllReplays = true; searchForFastestReplays = false; } var searchOnlyMissingLev = clickedButton.Equals(ReplaysWithoutLevFileButton); var searchOnlyWrongLev = clickedButton.Equals(ReplaysIncorrectLevButton); if (!Utils.RecDirectoryExists()) { Utils.ShowError(Constants.RecDirNotFound); return; } var p1Apples = Range <int> .FromNumericBoxes(TextBox1, TextBox14); var p2Apples = Range <int> .FromNumericBoxes(TextBox3, TextBox16); var p1Turns = Range <int> .FromNumericBoxes(TextBox2, TextBox23); var p2Turns = Range <int> .FromNumericBoxes(TextBox10, TextBox15); var p1Gt = Range <int> .FromNumericBoxes(TextBox11, TextBox24); var p2Gt = Range <int> .FromNumericBoxes(TextBox12, TextBox13); var p1Sv = Range <int> .FromNumericBoxes(TextBox4, TextBox21); var p2Sv = Range <int> .FromNumericBoxes(TextBox9, TextBox22); var p1Rv = Range <int> .FromNumericBoxes(TextBox6, TextBox19); var p2Rv = Range <int> .FromNumericBoxes(TextBox7, TextBox20); var p1Lv = Range <int> .FromNumericBoxes(TextBox8, TextBox17); var p2Lv = Range <int> .FromNumericBoxes(TextBox5, TextBox18); Range <double> time; try { time = Utils.GetTimeRange(TimeMinBox.Text, TimeMaxBox.Text); } catch (Exception) { Utils.ShowError("Time bound is in wrong format. Make sure it is 9 characters long."); return; } var size = new Range <int>((int)minFileSizeBox.Value * 1024, (int)maxFileSizeBox.Value * 1024); Regex levFilenameMatcher; try { levFilenameMatcher = new Regex(levelPattern, RegexOptions.IgnoreCase); } catch (Exception) { levFilenameMatcher = new Regex(string.Empty); } var searchParams = new ReplaySearchParameters { InternalRec = SearchParameters.GetBoolOptionFromTriSelect(intExtSelect), AcrossLev = SearchParameters.GetBoolOptionFromTriSelect(elmaAcrossSelect), Date = new Range <DateTime>(minDateTime.Value, maxDateTime.Value), Finished = SearchParameters.GetBoolOptionFromTriSelect(finishedSelect), LevExists = BoolOption.Dontcare, WrongLev = BoolOption.Dontcare, LevFilenameMatcher = levFilenameMatcher, MultiPlayer = SearchParameters.GetBoolOptionFromTriSelect(singleMultiSelect), Size = size, Time = time, P1Bounds = new ReplaySearchParameters.PlayerBounds { Apples = p1Apples, GroundTouches = p1Gt, LeftVolts = p1Lv, RightVolts = p1Rv, SuperVolts = p1Sv, Turns = p1Turns }, P2Bounds = new ReplaySearchParameters.PlayerBounds { Apples = p2Apples, GroundTouches = p2Gt, LeftVolts = p2Lv, RightVolts = p2Rv, SuperVolts = p2Sv, Turns = p2Turns } }; if (searchOnlyMissingLev) { searchParams.ResetOptions(); searchParams.LevExists = BoolOption.False; } if (searchOnlyWrongLev) { searchParams.ResetOptions(); searchParams.WrongLev = BoolOption.True; } var allFiles = Directory.GetFiles(Global.AppSettings.General.ReplayDirectory, "*.rec", Global.AppSettings.ReplayManager.RecDirSearchOption); var replayFiles = searchOnlyMissingLev || searchOnlyWrongLev ? allFiles.ToList() : Utils.FilterByRegex(allFiles, SearchPattern).ToList(); ObjectList.ClearObjects(); var oldButtonText = clickedButton.Text; _searchCancelToken = new CancellationTokenSource(); DuplicateButton.Enabled = false; DuplicateFilenameButton.Enabled = false; ConfigButton.Enabled = false; clickedButton.Text = "Stop"; var foundReplays = new List <Replay>(); ToolStripProgressBar1.Maximum = replayFiles.Count; var recsByLevel = new Dictionary <string, List <Replay> >(); var token = _searchCancelToken.Token; var progressHandler = new Progress <(int progress, int levels, int recs, int phase)>(value => { var(progressValue, levels, recs, phase) = value; ToolStripProgressBar1.Value = progressValue; if (searchForAllReplays) { statusLabel.Text = $"Found {recs} replays so far"; } else { statusLabel.Text = phase == 1 ? $"Phase 1: {levels} levels" : $"Phase 2: {recs} replays"; } }); var progress = (IProgress <(int progress, int levels, int recs, int phase)>)progressHandler; var iter = 0; try { await Task.Run(() => { foreach (var replayFile in replayFiles) { iter++; Replay srp; try { srp = new Replay(replayFile); } catch (ArgumentException) { errorFiles.Add(replayFile); continue; } if (searchParams.Matches(srp)) { if (!searchForAllReplays) { var key = srp.LevelFilename.ToLower() + srp.IsMulti; recsByLevel.TryGetValue(key, out var recs); if (recs == null) { recs = new List <Replay>(); recsByLevel[key] = recs; } recs.Add(srp); } else { foundReplays.Add(srp); } } if (iter % 10 == 0) { progress.Report((iter, recsByLevel.Count, foundReplays.Count, 1)); } token.ThrowIfCancellationRequested(); } }, token); } catch (OperationCanceledException) { Finalize(); return; } if (!searchForAllReplays) { ToolStripProgressBar1.Maximum = recsByLevel.Count; iter = 0; try { await Task.Run(() => { foreach (var rbl in recsByLevel) { iter++; var matchedReplay = rbl.Value[0]; foreach (var z in rbl.Value.Where(z => !z.WrongLevelVersion)) { if (searchForFastestReplays) { if (!matchedReplay.Finished && z.Finished) { matchedReplay = z; } else if (matchedReplay.Finished && z.Finished && z.Time < matchedReplay.Time) { matchedReplay = z; } else if (!matchedReplay.Finished && !z.Finished && z.Player1.Apples > matchedReplay.Player1.Apples) { matchedReplay = z; } } else { if (matchedReplay.Finished && !z.Finished) { matchedReplay = z; } else if (matchedReplay.Finished && z.Finished && z.Time > matchedReplay.Time) { matchedReplay = z; } else if (!matchedReplay.Finished && !z.Finished && (z.Player1.Apples < matchedReplay.Player1.Apples || matchedReplay.Time > z.Time)) { matchedReplay = z; } } } if (searchForFastestReplays || rbl.Value.Count > 1) { foundReplays.Add(matchedReplay); } if (iter % 10 == 0) { progress.Report((iter, recsByLevel.Count, foundReplays.Count, 2)); } token.ThrowIfCancellationRequested(); } }, token); } catch (OperationCanceledException) { } } Finalize(); void Finalize() { ObjectList.SetObjects(foundReplays); statusLabel.Text = "Ready"; ToolStripProgressBar1.Value = 0; _searchCancelToken = null; DuplicateButton.Enabled = true; DuplicateFilenameButton.Enabled = true; ConfigButton.Enabled = true; clickedButton.Text = oldButtonText; DisplaySelectionInfo(); if (errorFiles.Count > 0) { using (var ef = new ErrorForm(errorFiles)) { ef.ShowDialog(); } } } }