public static bool UpdateDamageInformation(Dictionary <string, Dictionary <string, DamageEntry> > damageDealt, bool healing = false)
        {
            bool newDamage = false;
            Dictionary <string, DamageData> totalResults = healing ? totalHealingResults : totalDamageResults;

            lock (totalResults) {
                foreach (KeyValuePair <string, Dictionary <string, DamageEntry> > kvp in damageDealt)
                {
                    string player = kvp.Key;
                    Dictionary <string, DamageEntry> playerDamage = kvp.Value;
                    if (!totalResults.ContainsKey(player))
                    {
                        totalResults.Add(player, new DamageData {
                            damagePerMinute = new Dictionary <string, DamageEntry>(), totalDamage = 0
                        });
                    }
                    DamageData data = totalResults[player];
                    foreach (KeyValuePair <string, DamageEntry> kvp2 in playerDamage)
                    {
                        string      timestamp = kvp2.Key;
                        DamageEntry entry     = kvp2.Value;
                        int         damage    = entry.damage;
                        // if the damage for the given timestamp does not exist yet, add it
                        if (!data.damagePerMinute.ContainsKey(timestamp))
                        {
                            data.damagePerMinute.Add(timestamp, entry);
                            data.totalDamage += damage;
                            newDamage         = true;
                        }
                        // if it does exist, select the biggest of the two
                        // the reason we select the biggest of the two is:
                        // - if the timestamp is 'the current time', totalDamageResults may hold an old value, so we update it
                        // - if timestamp is old, a part of the log for the time could have already been removed (because the log was full)
                        //    so the 'new' damage is only part of the damage for this timestamp
                        else if (data.damagePerMinute[timestamp].damage < damage)
                        {
                            data.totalDamage += damage - data.damagePerMinute[timestamp].damage;
                            data.damagePerMinute[timestamp] = entry;
                            newDamage = true;
                        }
                    }
                }
            }
            return(newDamage);
        }
        public static void GenerateDamageResults(Dictionary <string, DamageResult> damageResults, List <string> times, bool healing = false)
        {
            Dictionary <string, DamageData> totalResults = healing ? totalHealingResults : totalDamageResults;

            lock (totalResults) {
                foreach (KeyValuePair <string, DamageData> kvp in totalResults)
                {
                    DamageResult result  = new DamageResult();
                    string       player  = kvp.Key;
                    DamageData   data    = kvp.Value;
                    int          damage  = 0;
                    int          minutes = 0;
                    foreach (string t in times)
                    {
                        if (data.damagePerMinute.ContainsKey(t))
                        {
                            foreach (var creatureDamage in data.damagePerMinute[t].targetDamage)
                            {
                                string cr  = creatureDamage.Key;
                                int    dmg = creatureDamage.Value;
                                if (!result.damagePerCreature.ContainsKey(cr))
                                {
                                    result.damagePerCreature.Add(cr, dmg);
                                }
                                else
                                {
                                    result.damagePerCreature[cr] += dmg;
                                }
                            }
                            damage += data.damagePerMinute[t].damage;
                            minutes++;
                        }
                    }
                    if (damage > 0)
                    {
                        result.damagePerSecond = damage / (minutes * 60.0);
                        result.totalDamage     = data.totalDamage;
                        damageResults.Add(player, result);
                    }
                }
            }
        }
        public static void GenerateDamageTakenResults(Dictionary <string, DamageResult> damageResults, List <string> times)
        {
            Dictionary <string, DamageData> totalResults = totalDamageResults;

            lock (totalResults) {
                foreach (KeyValuePair <string, DamageData> kvp in totalResults)
                {
                    string     damageSource = kvp.Key;
                    DamageData data         = kvp.Value;
                    foreach (string t in times)
                    {
                        if (data.damagePerMinute.ContainsKey(t))
                        {
                            foreach (var creatureDamage in data.damagePerMinute[t].targetDamage)
                            {
                                string target = creatureDamage.Key;
                                int    dmg    = creatureDamage.Value;
                                if (!damageResults.ContainsKey(target))
                                {
                                    damageResults.Add(target, new DamageResult());
                                }
                                DamageResult result = damageResults[target];
                                if (!result.damagePerCreature.ContainsKey(damageSource))
                                {
                                    result.damagePerCreature.Add(damageSource, dmg);
                                }
                                else
                                {
                                    result.damagePerCreature[damageSource] += dmg;
                                }
                                result.totalDamage += dmg;
                            }
                        }
                    }
                }
            }
        }