private void CalcHasteAndManaProcs()
        {
            float nonProcHaste = StatUtils.CalcSpellHaste(PreProcStats);

            if (Options.NoProcs)
            {
                WeightedStat staticHaste = new WeightedStat();
                staticHaste.Chance = 1f;
                staticHaste.Value  = nonProcHaste;
                Haste = new List <WeightedStat> {
                    staticHaste
                };
                AvgHaste = nonProcHaste;
                return;
            }

            // the trigger rates are all guestimates at this point, since the
            // real values depend on haste (which obviously has not been
            // finalized yet)
            Dictionary <int, float> periods
                = new Dictionary <int, float>();
            Dictionary <int, float> chances
                = new Dictionary <int, float>();
            float corruptionPeriod = 0f;

            if (Options.GetActiveRotation().Contains("Corruption"))
            {
                corruptionPeriod = 3.1f;
                if (Talents.GlyphQuickDecay)
                {
                    corruptionPeriod /= nonProcHaste;
                }
            }
            PopulateTriggers(
                periods,
                chances,
                CalculationsWarlock.AVG_UNHASTED_CAST_TIME / nonProcHaste
                + Options.Latency,
                1 / 1.5f,
                corruptionPeriod,
                1f);

            // calculate the haste procs
            Haste = new List <WeightedStat>();
            WeightedStat[] percentages
                = GetUptimes(
                      Stats,
                      periods,
                      chances,
                      s => s.SpellHaste,
                      (a, b, c, d, e, f, g, h)
                      => SpecialEffect
                      .GetAverageCombinedUptimeCombinationsMultiplicative(
                          a, b, c, d, e, f, g, h));
            WeightedStat[] ratings
                = GetUptimes(
                      Stats,
                      periods,
                      chances,
                      s => s.HasteRating,
                      (a, b, c, d, e, f, g, h)
                      => SpecialEffect.GetAverageCombinedUptimeCombinations(
                          a, b, c, d, e, f, g, h));
            for (int p = percentages.Length, f = 0; --p >= 0;)
            {
                if (percentages[p].Chance == 0)
                {
                    continue;
                }

                for (int r = ratings.Length; --r >= 0; ++f)
                {
                    if (ratings[r].Chance == 0)
                    {
                        continue;
                    }
                    WeightedStat s = new WeightedStat();
                    s.Chance = percentages[p].Chance * ratings[r].Chance;
                    s.Value
                        = (1 + percentages[p].Value)
                          * (1 + StatConversion.GetSpellHasteFromRating(
                                 ratings[r].Value + Stats.HasteRating))
                          * (1 + Stats.SpellHaste);
                    Haste.Add(s);
                    AvgHaste += s.Chance * s.Value;
                }
            }

            // calculate mana procs
            Stats procStats = new Stats();

            foreach (SpecialEffect effect in Stats.SpecialEffects())
            {
                if (!periods.ContainsKey((int)effect.Trigger))
                {
                    continue;
                }

                Stats proc = effect.GetAverageStats(
                    periods[(int)effect.Trigger],
                    chances[(int)effect.Trigger],
                    CalculationsWarlock.AVG_UNHASTED_CAST_TIME,
                    Options.Duration);
                if (proc.ManaRestore > 0)
                {
                    proc.ManaRestore *= Options.Duration;
                }
                procStats.Accumulate(proc);
            }
            Stats.Mana        += procStats.Mana;
            Stats.ManaRestore += procStats.ManaRestore;
            Stats.ManaRestoreFromBaseManaPPM
                += procStats.ManaRestoreFromBaseManaPPM;
            Stats.ManaRestoreFromMaxManaPerSecond
                      += procStats.ManaRestoreFromMaxManaPerSecond;
            Stats.Mp5 += procStats.Mp5;
        }