private void HandleReplayChanged(Replay r, Beatmap b)
 {
     Chart.SuspendLayout();
     Chart.Series[0].Points.Clear();
     Chart.ChartAreas[0].AxisX.ScaleView.ZoomReset(0);
     Chart.ChartAreas[0].AxisY.ScaleView.ZoomReset(0);
     for (int i = 0; i < oRA.Data.ReplayObjects.Count; i++ )
     {
         Chart.Series[0].Points.AddXY(i + 1, Math.Sqrt(Math.Pow(oRA.Data.ReplayObjects[i].Frame.X - oRA.Data.ReplayObjects[i].Object.Location.X, 2) + 
                                             Math.Pow(oRA.Data.ReplayObjects[i].Frame.Y - oRA.Data.ReplayObjects[i].Object.Location.Y, 2)));
     }
     Chart.ResumeLayout();
 }
 private void HandleReplayChanged(Replay r, Beatmap b)
 {
     Chart.SuspendLayout();
     Chart.Series[3].Points.Clear();
     Chart.ChartAreas[0].AxisX.ScaleView.ZoomReset(0);
     Chart.ChartAreas[0].AxisY.ScaleView.ZoomReset(0);
     Chart.ChartAreas[0].AxisY.Minimum = -oRA.Data.TimingWindows[0];
     Chart.ChartAreas[0].AxisY.Maximum = oRA.Data.TimingWindows[0];
     for (int i = 0; i < oRA.Data.ReplayObjects.Count; i++)
     {
         Chart.Series[3].Points.AddXY(i + 1, oRA.Data.ReplayObjects[i].Frame.Time - oRA.Data.ReplayObjects[i].Object.StartTime); 
     }         
     Chart.Series[0].Points.Clear();
     Chart.Series[0].Points.AddXY(0, oRA.Data.TimingWindows[2], -oRA.Data.TimingWindows[2]);
     Chart.Series[0].Points.AddXY(oRA.Data.ReplayObjects.Count, oRA.Data.TimingWindows[2], -oRA.Data.TimingWindows[2]);
     Chart.Series[1].Points.Clear();
     Chart.Series[1].Points.AddXY(0, oRA.Data.TimingWindows[1], -oRA.Data.TimingWindows[1]);
     Chart.Series[1].Points.AddXY(oRA.Data.ReplayObjects.Count, oRA.Data.TimingWindows[1], -oRA.Data.TimingWindows[1]);
     Chart.Series[2].Points.Clear();
     Chart.Series[2].Points.AddXY(0, oRA.Data.TimingWindows[0], -oRA.Data.TimingWindows[0]);
     Chart.Series[2].Points.AddXY(oRA.Data.ReplayObjects.Count, oRA.Data.TimingWindows[0], -oRA.Data.TimingWindows[0]);
     Chart.ResumeLayout();
 }
        public void HandleReplayChanged(Replay r, Beatmap b)
        {
            float totalTime = 0;
            if (b.HitObjects.Count > 0)
                totalTime = b.HitObjects[b.HitObjects.Count - 1].StartTime - b.HitObjects[0].StartTime;

            tpDifficulty tp = new tpDifficulty();
            tp.tpHitObjects = new List<tpHitObject>(b.HitObjects.Count);
            foreach (CircleObject hitObject in b.HitObjects)
                tp.tpHitObjects.Add(new tpHitObject(hitObject));

            customListView1.Items.Clear();
            customListView1.Items.Add(new ListViewItem());
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_Format"], b.Format.ToString() }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_FName"], b.Filename }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_FSize"], File.OpenRead(b.Filename).Length + " bytes" }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_FHash"], r.MapHash }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_TotalHitObjects"], b.HitObjects.Count.ToString(CultureInfo.InvariantCulture) }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapAFN"], b.AudioFilename }));
            customListView1.Items.Add(new ListViewItem());
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapName"], b.Title + (!string.IsNullOrEmpty(b.TitleUnicode) && b.TitleUnicode != b.Title ? "(" + b.TitleUnicode + ")" : "") }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapArtist"], b.Artist + (!string.IsNullOrEmpty(b.ArtistUnicode) && b.ArtistUnicode != b.Artist ? "(" + b.ArtistUnicode + ")" : "") }));
            if (b.Source != null)
                customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapSource"], b.Source }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapCreator"], b.Creator }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapVersion"], b.Version }));
            if (b.BeatmapID != null)
                customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapID"], b.BeatmapID.ToString() }));
            if (b.BeatmapSetID != null)
                customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapSetID"], b.BeatmapSetID.ToString() }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapTags"], string.Join(", ", b.Tags) }));
            customListView1.Items.Add(new ListViewItem());
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapOD"], b.OverallDifficulty.ToString("0.00") }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapAR"], b.ApproachRate.ToString("0.00") }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapHP"], b.HPDrainRate.ToString("0.00") }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapCS"], b.CircleSize.ToString("0.00") }));
            customListView1.Items.Add(new ListViewItem());
            foreach (Combo combo in b.ComboColours)
            {
                ListViewItem li = new ListViewItem(oRA.Data.Language["oRA_MapComboColour"] + " " + combo.ComboNumber + ":");
                ListViewItem.ListViewSubItem colorItem = new ListViewItem.ListViewSubItem();
                colorItem.Text = combo.Colour.R + @", " + combo.Colour.G + @", " + combo.Colour.B;
                colorItem.ForeColor = Color.FromArgb(255, combo.Colour.R, combo.Colour.G, combo.Colour.B);
                li.SubItems.Add(colorItem);
                customListView1.Items.Add(li);
            }
            customListView1.Items.Add(new ListViewItem());
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapTotalTime"], TimeSpan.FromMilliseconds(totalTime).Minutes + ":" + TimeSpan.FromMilliseconds(totalTime).Seconds.ToString("00") }));
            totalTime = b.Events.Where(brk => brk.GetType() == typeof(BreakEvent)).Aggregate(totalTime, (current, brk) => current - (((BreakEvent)brk).EndTime - brk.StartTime));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_MapDrainTime"], TimeSpan.FromMilliseconds(totalTime).Minutes + ":" + TimeSpan.FromMilliseconds(totalTime).Seconds.ToString("00") }));
            if (tp.CalculateStrainValues())
            {
                double SpeedDifficulty = tp.CalculateDifficulty(tpDifficulty.DifficultyType.Speed);
                double AimDifficulty = tp.CalculateDifficulty(tpDifficulty.DifficultyType.Aim);
                double SpeedStars = Math.Sqrt(SpeedDifficulty) * tpDifficulty.STAR_SCALING_FACTOR;
                double AimStars = Math.Sqrt(AimDifficulty) * tpDifficulty.STAR_SCALING_FACTOR;
                double StarRating = SpeedStars + AimStars + Math.Abs(SpeedStars - AimStars) * tpDifficulty.EXTREME_SCALING_FACTOR;
                customListView1.Items.Add(new ListViewItem());
                customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_SpeedDifficulty"], SpeedDifficulty.ToString("0.00") }));
                customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_AimDifficulty"], AimDifficulty.ToString("0.00") }));
                customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_SpeedStars"], SpeedStars.ToString("0.00") }));
                customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_AimStars"], AimStars.ToString("0.00") }));
                customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_TotalStars"], StarRating.ToString("0.00") }));
            }

        }
        private void ReplaysList_AfterSelect(object sender, TreeViewEventArgs e)
        {
            //Failsafe
            if (!File.Exists(e.Node.Name))
            {
                MessageBox.Show(Language["oRA_ReplayInexistent"] + '\n' + e.Node.Name);
                return;
            }
            
            using (CurrentReplay = new Replay(e.Node.Name))
            {
                DataRow dR = DBHelper.GetRecord(DBConnection, "Beatmaps", "Hash", CurrentReplay.MapHash);
                if (dR != null)
                {
                    CurrentBeatmap = new Beatmap(dR["Filename"].ToString());

                    /* Start Timing Windows tab */

                    //Determine the timing windows for 300,100,50
                    //First modify the beatmap attributes according by player mods
                    if ((CurrentReplay.Mods & Modifications.HardRock) == Modifications.HardRock)
                    {
                        CurrentBeatmap.OverallDifficulty = Math.Min(CurrentBeatmap.OverallDifficulty *= 1.4f, 10);
                        CurrentBeatmap.CircleSize = CurrentBeatmap.CircleSize * 1.4f;

                        //Y-mirror objects
                        foreach (CircleObject obj in CurrentBeatmap.HitObjects)
                            obj.Location.Y = 384 - obj.Location.Y;
                    }
                    if ((CurrentReplay.Mods & Modifications.DoubleTime) == Modifications.DoubleTime)
                    {
                        CurrentBeatmap.OverallDifficulty = (float)Math.Min(13.0 / 3.0 + (2.0 / 3.0) * CurrentBeatmap.OverallDifficulty, 11);
                        CurrentBeatmap.ApproachRate = (float)Math.Min(13.0 / 3.0 + (2.0 / 3.0) * CurrentBeatmap.ApproachRate, 11);
                    }
                    if ((CurrentReplay.Mods & Modifications.HalfTime) == Modifications.HalfTime)
                    {
                        CurrentBeatmap.OverallDifficulty = (float)((3.0 / 2.0) * CurrentBeatmap.OverallDifficulty - 13.0 / 2.0);
                        CurrentBeatmap.ApproachRate = (float)((3.0 / 2.0) * CurrentBeatmap.ApproachRate - 13.0 / 2.0);
                    }
                    if ((CurrentReplay.Mods & Modifications.Easy) == Modifications.Easy)
                    {
                        CurrentBeatmap.OverallDifficulty = CurrentBeatmap.OverallDifficulty / 2;
                    }

                    //Timing windows are determined by linear interpolation
                    for (int i = 2; i >= 0; i--)
                    {
                        oRAData.TimingWindows[i] = CurrentBeatmap.OverallDifficulty < 5 ? (200 - 60 * i) + (CurrentBeatmap.OverallDifficulty) * ((150 - 50 * i) - (200 - 60 * i)) / 5 : (150 - 50 * i) + (CurrentBeatmap.OverallDifficulty - 5) * ((100 - 40 * i) - (150 - 50 * i)) / 5;
                    }

                    oRAData.ReplayObjects.Clear();

                    if (CurrentReplay.ReplayFrames.Count == 0)
                        return;

                    //Match up beatmap objects to replay clicks
                    HashSet<ReplayInfo> iteratedObjects = new HashSet<ReplayInfo>();
                    for (int i = 0; i < CurrentBeatmap.HitObjects.Count; i++)
                    {
                        //Todo: Consider if hitobject containspoint
                        ReplayInfo c = CurrentReplay.ClickFrames.Find(click => (Math.Abs(click.Time - CurrentBeatmap.HitObjects[i].StartTime) < oRAData.TimingWindows[2]) && !iteratedObjects.Contains(click)) ??
                                        CurrentReplay.ClickFrames.Find(click => (Math.Abs(click.Time - CurrentBeatmap.HitObjects[i].StartTime) < oRAData.TimingWindows[1]) && !iteratedObjects.Contains(click)) ??
                                        CurrentReplay.ClickFrames.Find(click => (Math.Abs(click.Time - CurrentBeatmap.HitObjects[i].StartTime) < oRAData.TimingWindows[0]) && !iteratedObjects.Contains(click));
                        if (c != null)
                        {
                            iteratedObjects.Add(c);
                            oRAData.ReplayObjects.Add(new ReplayObject { Frame = c, Object = CurrentBeatmap.HitObjects[i] });
                        }
                    }

                    ReplayTimeline.DataSource = iteratedObjects.ToList();
                    if (ReplayTimeline.Columns.Count > 0)
                    {
                        foreach (DataGridViewColumn c in ReplayTimeline.Columns)
                        {
                            c.SortMode = DataGridViewColumnSortMode.NotSortable;
                        }
                    }
                    if (ReplayTimeline.Rows.Count > 0)
                        ReplayTimeline.Rows[0].Selected = true;

                    oRAData.UpdateStatus(CurrentReplay, CurrentBeatmap);
                }
            }
        }
        public void HandleReplayChanged(Replay r, Beatmap b)
        {

            //Calculate UR and avg timing windows
            double unstableRate = 0, negativeErrorAverage = 0, positiveErrorAverage = 0, max = 0, min = 0, variance = 0;
            int nErrAvgCount = 0, pErrAvgCount = 0;
            double[] keyPAverage = new double[4];
            double[] keyNAverage = new double[4];
            double[] keyUnstableRate = new double[4];
            double[] keyVariance = new double[4];
            int[] keyPAverageCount = new int[4];
            int[] keyNAverageCount = new int[4];
            int[] keyCount = new int[4];

            for (int i = 0; i < oRA.Data.ReplayObjects.Count; i++)
            {
                double diff = oRA.Data.ReplayObjects[i].Frame.Time - oRA.Data.ReplayObjects[i].Object.StartTime;

                //For now, this will be used as the mean
                //We must calculate this before the actual unstable rate
                unstableRate += diff;

                //Because the enum has 5 and 10 which contain 1 and 2 K1 will trigger M1 and K2 will trigged M2
                //Therefore, we need to XOR K1,K1 out.
                //Or NOT, but it's quicker to XOR (compound assignment)
                //But we do not want to set the variable since it's used later, so we'll use a temp variable
                KeyData tKD = oRA.Data.ReplayObjects[i].Frame.Keys;
                if ((tKD & KeyData.K1) == KeyData.K1)
                {
                    tKD ^= KeyData.K1;
                    keyUnstableRate[0] += diff;
                    keyCount[0] += 1;
                }
                if ((tKD & KeyData.K2) == KeyData.K2)
                {
                    tKD ^= KeyData.K2;
                    keyUnstableRate[1] += diff;
                    keyCount[1] += 1;
                }
                if ((tKD & KeyData.M1) == KeyData.M1)
                {
                    keyUnstableRate[2] += diff;
                    keyCount[2] += 1;
                }
                if ((tKD & KeyData.M2) == KeyData.M2)
                {
                    keyUnstableRate[3] += diff;
                    keyCount[3] += 1;
                }
            }

            if (oRA.Data.ReplayObjects.Count > 0)
            {
                unstableRate /= oRA.Data.ReplayObjects.Count;
                for (int i = 0; i < 4; i++)
                {
                    if (keyCount[i] != 0)
                        keyUnstableRate[i] /= keyCount[i];
                }
            }

            for (int i = 0; i < oRA.Data.ReplayObjects.Count; i++)
            {
                double diff = oRA.Data.ReplayObjects[i].Frame.Time - oRA.Data.ReplayObjects[i].Object.StartTime;

                //This is a bit messy, but I'm too tired to improve it
                //Follows the same XOR-ing procedure as above
                KeyData tKD = oRA.Data.ReplayObjects[i].Frame.Keys;
                if (diff > 0)
                {
                    positiveErrorAverage += diff;
                    pErrAvgCount += 1;
                    if ((tKD & KeyData.K1) == KeyData.K1)
                    {
                        tKD ^= KeyData.K1;
                        keyVariance[0] += Math.Pow(diff - keyUnstableRate[0], 2);
                        keyPAverage[0] += diff;
                        keyPAverageCount[0] += 1;
                    }
                    if ((tKD & KeyData.K2) == KeyData.K2)
                    {
                        tKD ^= KeyData.K2;
                        keyVariance[1] += Math.Pow(diff - keyUnstableRate[0], 2);
                        keyPAverage[1] += diff;
                        keyPAverageCount[1] += 1;
                    }
                    if ((tKD & KeyData.M1) == KeyData.M1)
                    {
                        keyVariance[2] += Math.Pow(diff - keyUnstableRate[0], 2);
                        keyPAverage[2] += diff;
                        keyPAverageCount[2] += 1;
                    }
                    if ((tKD & KeyData.M2) == KeyData.M2)
                    {
                        keyVariance[3] += Math.Pow(diff - keyUnstableRate[0], 2);
                        keyPAverage[3] += diff;
                        keyPAverageCount[3] += 1;
                    }
                }
                else
                {
                    negativeErrorAverage += diff;
                    nErrAvgCount += 1;
                    if ((tKD & KeyData.K1) == KeyData.K1)
                    {
                        tKD ^= KeyData.K1;
                        keyVariance[0] += Math.Pow(diff - keyUnstableRate[0], 2);
                        keyNAverage[0] += diff;
                        keyNAverageCount[0] += 1;
                    }
                    if ((tKD & KeyData.K2) == KeyData.K2)
                    {
                        tKD ^= KeyData.K2;
                        keyVariance[1] += Math.Pow(diff - keyUnstableRate[0], 2);
                        keyNAverage[1] += diff;
                        keyNAverageCount[1] += 1;
                    }
                    if ((tKD & KeyData.M1) == KeyData.M1)
                    {
                        keyVariance[2] += Math.Pow(diff - keyUnstableRate[0], 2);
                        keyNAverage[2] += diff;
                        keyNAverageCount[2] += 1;
                    }
                    if ((tKD & KeyData.M2) == KeyData.M2)
                    {
                        keyVariance[3] += Math.Pow(diff - keyUnstableRate[0], 2);
                        keyNAverage[3] += diff;
                        keyNAverageCount[3] += 1;
                    }
                }
                variance += Math.Pow(diff - unstableRate, 2);

                if (diff > max)
                    max = diff;
                if (diff < min)
                    min = diff;
            }

            positiveErrorAverage = pErrAvgCount != 0 ? positiveErrorAverage / pErrAvgCount : 0;
            negativeErrorAverage = nErrAvgCount != 0 ? negativeErrorAverage / nErrAvgCount : 0;
            for (int i = 0; i < 4; i++)
            {
                //Calculate error rate
                if (keyPAverageCount[i] != 0)
                    keyPAverage[i] /= keyPAverageCount[i];
                if (keyNAverageCount[i] != 0)
                    keyNAverage[i] /= keyNAverageCount[i];
            }
            if (oRA.Data.ReplayObjects.Count > 0)
            {
                //Calculate unstable rate
                unstableRate = Math.Round(Math.Sqrt(variance / oRA.Data.ReplayObjects.Count) * 10, 2);
                for (int i = 0; i < 4; i++)
                {
                    if (keyCount[i] != 0)
                        keyUnstableRate[i] = Math.Round(Math.Sqrt(keyVariance[i] / keyCount[i]) * 10, 2);
                }
            }

            customListView1.Items.Clear();
            customListView1.Items.Add(new ListViewItem());
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_Format"], r.FileFormat.ToString(CultureInfo.InvariantCulture) }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_FName"], r.Filename }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_FSize"], File.OpenRead(r.Filename).Length + " " + oRA.Data.Language["oRA_bytes"] }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_FHash"], r.ReplayHash }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_ReplayFrames"], r.ReplayFrames.Count.ToString(CultureInfo.InvariantCulture) }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_KeysPressed"], r.ClickFrames.Count.ToString(CultureInfo.InvariantCulture) }));
            //Display individual key counts
            if (keyCount[0] != 0)
                customListView1.Items.Add(new ListViewItem(new[] { "K1 " + oRA.Data.Language["oRA_PressCount"], keyCount[0].ToString(CultureInfo.InvariantCulture) }));
            if (keyCount[1] != 0)
                customListView1.Items.Add(new ListViewItem(new[] { "K2 " + oRA.Data.Language["oRA_PressCount"], keyCount[1].ToString(CultureInfo.InvariantCulture) }));
            if (keyCount[2] != 0)
                customListView1.Items.Add(new ListViewItem(new[] { "M1 " + oRA.Data.Language["oRA_PressCount"], keyCount[2].ToString(CultureInfo.InvariantCulture) }));
            if (keyCount[3] != 0)
                customListView1.Items.Add(new ListViewItem(new[] { "M2 " + oRA.Data.Language["oRA_PressCount"], keyCount[3].ToString(CultureInfo.InvariantCulture) }));
            customListView1.Items.Add(new ListViewItem());
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_RepMode"], r.GameMode.ToString() }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_RepPlayer"], r.PlayerName }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_RepScore"], r.TotalScore.ToString(CultureInfo.InvariantCulture) }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_RepCombo"], r.MaxCombo.ToString(CultureInfo.InvariantCulture) }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_Rep300Count"], r.Count_300.ToString(CultureInfo.InvariantCulture) }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_Rep100Count"], r.Count_100.ToString(CultureInfo.InvariantCulture) }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_Rep50Count"], r.Count_50.ToString(CultureInfo.InvariantCulture) }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_RepMissCount"], r.Count_Miss.ToString(CultureInfo.InvariantCulture) }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_RepGekiCount"], r.Count_Geki.ToString(CultureInfo.InvariantCulture) }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_RepKatuCount"], r.Count_Katu.ToString(CultureInfo.InvariantCulture) }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_Grade"], GetRank(r.Count_300, r.Count_100, r.Count_50, r.Count_Miss, (r.Mods & Modifications.FlashLight) > 0 || (r.Mods & Modifications.Hidden) > 0) }));

            customListView1.Items.Add(new ListViewItem());
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_RepMods"], r.Mods.ToString() }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_ErrorRate"], negativeErrorAverage.ToString("0.00") + "ms ~ " + "+" + positiveErrorAverage.ToString("0.00") + "ms" }));
            customListView1.Items.Add(new ListViewItem(new[] { oRA.Data.Language["oRA_UnstableRate"], unstableRate.ToString("0.00") }));
            customListView1.Items.Add(new ListViewItem());
            if (keyNAverageCount[0] != 0 || keyPAverageCount[0] != 0)
                customListView1.Items.Add(new ListViewItem(new[] { "K1 " + oRA.Data.Language["oRA_ErrorRate"], keyNAverage[0].ToString("0.00") + "ms ~ " + "+" + keyPAverage[0].ToString("0.00") + "ms" }));
            if (keyNAverageCount[1] != 0 || keyPAverageCount[1] != 0)
                customListView1.Items.Add(new ListViewItem(new[] { "K2 " + oRA.Data.Language["oRA_ErrorRate"], keyNAverage[1].ToString("0.00") + "ms ~ " + "+" + keyPAverage[1].ToString("0.00") + "ms" }));
            if (keyNAverageCount[2] != 0 || keyPAverageCount[2] != 0)
                customListView1.Items.Add(new ListViewItem(new[] { "M1 " + oRA.Data.Language["oRA_ErrorRate"], keyNAverage[2].ToString("0.00") + "ms ~ " + "+" + keyPAverage[2].ToString("0.00") + "ms" }));
            if (keyNAverageCount[3] != 0 || keyPAverageCount[3] != 0)
                customListView1.Items.Add(new ListViewItem(new[] { "M2 " + oRA.Data.Language["oRA_ErrorRate"], keyNAverage[3].ToString("0.00") + "ms ~ " + "+" + keyPAverage[3].ToString("0.00") + "ms" }));
            if (keyCount[0] != 0)
                customListView1.Items.Add(new ListViewItem(new[] { "K1 " + oRA.Data.Language["oRA_UnstableRate"], keyUnstableRate[0].ToString("0.00") }));
            if (keyCount[1] != 0)
                customListView1.Items.Add(new ListViewItem(new[] { "K2 " + oRA.Data.Language["oRA_UnstableRate"], keyUnstableRate[1].ToString("0.00") }));
            if (keyCount[2] != 0)
                customListView1.Items.Add(new ListViewItem(new[] { "M1 " + oRA.Data.Language["oRA_UnstableRate"], keyUnstableRate[2].ToString("0.00") }));
            if (keyCount[3] != 0)
                customListView1.Items.Add(new ListViewItem(new[] { "M2 " + oRA.Data.Language["oRA_UnstableRate"], keyUnstableRate[3].ToString("0.00") }));
        }
 private void HandleReplayChanged(Replay r, Beatmap b)
 {
     Chart.SuspendLayout();
     Chart.Series.Clear();
     Chart.ChartAreas[0].AxisX.ScaleView.ZoomReset(0);
     Chart.ChartAreas[0].AxisY.ScaleView.ZoomReset(0);
     int currentSpinnerNumber = 1;
     foreach (var spinner in b.HitObjects.Where(o => o.GetType() == typeof(SpinnerObject)))
     {
         Point2 currentPosition = new Point2(-500, -500);
         Dictionary<double, int> RPMCount = new Dictionary<double, int>();
         double currentTime = 0;
         foreach (ReplayInfo repPoint in r.ReplayFrames.Where(repPoint => repPoint.Time < ((SpinnerObject)spinner).EndTime && repPoint.Time > spinner.StartTime))
         {
             if ((int)currentPosition.X == -500)
             {
                 currentPosition.X = repPoint.X;
                 currentPosition.Y = repPoint.Y;
             }
             else
             {
                 currentTime += repPoint.TimeDiff;
                 if (RPMCount.Keys.Contains(currentTime))
                     continue;
                 double ptsDist = currentPosition.DistanceTo(new Point2(repPoint.X, repPoint.Y));
                 double p1CDist = currentPosition.DistanceTo(spinner.Location);
                 double p2CDist = new Point2(repPoint.X, repPoint.Y).DistanceTo(spinner.Location);
                 double travelDegrees = Math.Acos((Math.Pow(p1CDist, 2) + Math.Pow(p2CDist, 2) - Math.Pow(ptsDist, 2)) / (2 * p1CDist * p2CDist)) * (180 / Math.PI);
                 RPMCount.Add(currentTime, (int)Math.Min((travelDegrees / (0.006 * repPoint.TimeDiff)), 477));
                 currentPosition.X = repPoint.X;
                 currentPosition.Y = repPoint.Y;
             }
         }
         int count = 0;
         int valueAmnt = 0;
         Series spinnerSeries = new Series
         {
             ChartType = SeriesChartType.Spline,
             BorderWidth = 2,
             Name = oRA.Data.Language["oRA_Spinner"] + " " + currentSpinnerNumber
         };
         foreach (var frame in RPMCount)
         {
             valueAmnt += frame.Value;
             count += 1;
             if (count == 5)
             {
                 spinnerSeries.Points.AddXY(frame.Key, Convert.ToInt32(valueAmnt / count));
                 count = 0;
                 valueAmnt = 0;
             }
         }
         Chart.Series.Add(spinnerSeries);
         currentSpinnerNumber += 1;
     }
     Chart.ResumeLayout();
 }
 public void UpdateStatus(Replay Replay, Beatmap Beatmap)
 {
     if (ReplayChanged != null)
         ReplayChanged(Replay, Beatmap);
 }
 private void HandleReplayChanged(Replay r, Beatmap b)
 {
     CurrentBeatmap = b;
     LoadContent();
 }