void UpdateWeapons()
        {
            GeckoElement collection = (GeckoElement)m_browser.Document.GetElementById("weaponsInfo");

            if (collection == null) return;

            // Load formatted html with javascript results into reader stream.
            System.IO.TextReader reader = new System.IO.StringReader(collection.InnerHtml);

            // Parse HTML by loading the text stream.
            HtmlAgilityPack.HtmlDocument htmlDoc = new HtmlAgilityPack.HtmlDocument();
            htmlDoc.Load(reader);

            float totalKills = 0;
            float totalHS = 0;

            // Rows
            HtmlNodeCollection rows = htmlDoc.DocumentNode.SelectNodes("//div[@class='wepRow']");
            for (int i = 0; i < rows.Count; i++)
            {
                // Initialize new event.
                Weapon weapon = new Weapon();

                weapon.Initialize();

                // Columns
                // Name, kills, kills/min, accuracy, fire count, headshots, hitscount, score.
                // Only bring in absolute numbers. Accuracy and HS % will be calculated by this program.
                weapon.name = rows[i].SelectSingleNode(".//div[@class='wpName']").InnerText;
                weapon.kills = float.Parse(rows[i].SelectSingleNode(".//div[@class='kills sorted']").InnerText);
                weapon.fireCount = float.Parse(rows[i].SelectSingleNode(".//div[@class='fireCount']").InnerText);
                weapon.headShots = float.Parse(rows[i].SelectSingleNode(".//div[@class='headshots']").InnerText);
                weapon.hitsCount = float.Parse(rows[i].SelectSingleNode(".//div[@class='hitCount']").InnerText);

                // Update total stats.
                totalKills += weapon.kills;
                totalHS += weapon.headShots;

                bool skipWeapon = false;

                // Weapon already exists. Check to see if it changed.
                if (m_weapons.ContainsKey(weapon.name))
                {
                    Weapon lastWeapon = m_weapons[weapon.name];
                    // The weapon has been fired.
                    if (lastWeapon.lastFireCount < weapon.fireCount)
                    {
                        // Check if the weapon is a MAX arm. Ignore in this case-- there is no way to distinguish left/right currently.
                        for (int j = 0; j < rows.Count; j++)
                        {
                            if (i != j)
                            {
                                if (rows[j].SelectSingleNode(".//div[@class='wpName']").InnerText == weapon.name)
                                {
                                    skipWeapon = true;
                                    break;
                                }
                            }
                        }
                        if (!skipWeapon)
                            AddSessionWeapon(weapon, lastWeapon, true);

                    }
                }
                if (!skipWeapon)
                {
                    weapon.lastFireCount = weapon.fireCount;
                    // Add the weapon to the global list.
                    m_weapons[weapon.name] = weapon;
                    // Load session start weapons.
                    if (!m_weaponsUpdated)
                        m_sesStartWeapons[weapon.name] = weapon;
                }
            }

            UpdateWeaponTextFields(m_weapons, this.weaponsGridView);
            UpdateWeaponTextFields(m_sessionWeapons, this.sessionWeaponsGridView);

            // Update overall hs stats.
            if (!m_weaponsUpdated)
            {
                // Reset overall hsr so it can be updated again.
                m_sessionStartHSR = 0.0f;
                m_sessionStartKDR = 0.0f;
                UpdateOverallStats(0, totalHS, 0);
            }

            m_weaponsUpdated = true;
            m_updatingWeapons = false;
        }
        void AddSessionWeapon(EventLog newEvent)
        {
            Weapon newWeapon = new Weapon();
            Weapon oldWeapon = new Weapon();
            oldWeapon.Initialize();
            newWeapon.Initialize();
            newWeapon.name = newEvent.method;
            newWeapon.kills += newEvent.IsKill() ? 1 : 0;
            newWeapon.headShots += newEvent.headshot ? 1 : 0;

            // Add to total deaths.
            if (m_sessionStarted)
            {
                if (!newEvent.IsKill())
                {
                    UpdateOverallStats(0, 0, 1);
                }
                // Update overall stats. Should only be called once overall stats have been set initially.
                // *Additionally it will not update a weapon not found in the All Weapons section.
                else
                {
                    // * Testing with always updating stats regardless of if weapon was used previously.
                    //if (m_weaponsUpdated && IsWeaponInAllWeapons(newWeapon.name))
                    //{
                    // Do not give kills or headshots for team kills.
                    if(newEvent.faction != m_userFaction)
                        UpdateOverallStats(newWeapon.kills, newWeapon.headShots, 0);
                    //}
                }
            }
            // Add session weapon stats unless this event was a death or team kill.
            if(!newEvent.death && newEvent.faction != m_userFaction)
                AddSessionWeapon(newWeapon, oldWeapon);
        }
        void AddSessionWeapon(Weapon updatedWeapon, Weapon oldWeapon, bool skipKillsHS = false)
        {
            float kills = updatedWeapon.kills - oldWeapon.kills;
            float hits = updatedWeapon.hitsCount - oldWeapon.hitsCount;
            float hs = updatedWeapon.headShots - oldWeapon.headShots;
            float fired = updatedWeapon.fireCount - oldWeapon.fireCount;

            Weapon sessionWeapon;
            if (!m_sessionWeapons.ContainsKey(updatedWeapon.name))
            {
                sessionWeapon = new Weapon();
                sessionWeapon.Initialize();
                sessionWeapon.name = updatedWeapon.name;
            }
            else
            {
                sessionWeapon = m_sessionWeapons[updatedWeapon.name];
            }

            if (!skipKillsHS)
            {
                sessionWeapon.kills += kills;
                sessionWeapon.headShots += hs;
            }

            sessionWeapon.fireCount += fired;
            sessionWeapon.hitsCount += hits;

            m_sessionWeapons[updatedWeapon.name] = sessionWeapon;
        }
 Weapon GetLastWeapon(Dictionary<string, Weapon> weapons, List<EventLog> log)
 {
     // Search from most recent down. Skip deaths.
     for (int i = 0; i < log.Count; i++) {
         if (log[i].IsKill()) {
             string id = log[i].isVehicle ? "V" : "";
             id += log[i].methodID;
             if (weapons.ContainsKey(id)) {
                 return weapons[id];
             }
         }
     }
     Weapon weapon = new Weapon();
     weapon.Initialize();
     return weapon;
 }
        async Task AddSessionWeapon(Weapon updatedWeapon, Weapon oldWeapon, bool skipKillsHS = false) {
            float kills = updatedWeapon.kills - oldWeapon.kills;
            float hits = updatedWeapon.hitsCount - oldWeapon.hitsCount;
            float hs = updatedWeapon.headShots - oldWeapon.headShots;
            float fired = updatedWeapon.fireCount - oldWeapon.fireCount;

            if (kills < 0 || hits < 0 || hs < 0 || fired < 0)
                return;

            string id = GetBestWeaponID(updatedWeapon);

            Weapon sessionWeapon;
            if (!m_sessionStats.weapons.ContainsKey(id)) {
                sessionWeapon = new Weapon();
                sessionWeapon.Initialize();
                sessionWeapon.id = updatedWeapon.id;
                sessionWeapon.vehicleId = updatedWeapon.vehicleId;
            } else {
                sessionWeapon = m_sessionStats.weapons[id];
            }

            if (!skipKillsHS) {
                sessionWeapon.kills += kills;
                sessionWeapon.headShots += hs;
            }

            sessionWeapon.fireCount += fired;
            sessionWeapon.hitsCount += hits;

            sessionWeapon.name = await GetItemName(GetBestWeaponID(sessionWeapon));

            m_sessionStats.weapons[id] = sessionWeapon;
        }
        async Task AddSessionWeapon(EventLog newEvent) {
            Weapon newWeapon = new Weapon();
            Weapon oldWeapon = new Weapon();
            oldWeapon.Initialize();
            newWeapon.Initialize();
            if (newEvent.isVehicle) {
                newWeapon.id = "0";
                newWeapon.vehicleId = newEvent.methodID;
            } else
                newWeapon.id = newEvent.methodID;

            newWeapon.name = await GetItemName(GetBestWeaponID(newWeapon));
            newWeapon.kills += newEvent.IsKill() ? 1 : 0;
            newWeapon.headShots += newEvent.headshot ? 1 : 0;

            // Add to total deaths.
            if (m_sessionStarted || m_countEvents) {
                if (!newEvent.IsKill()) {
                    UpdateOverallStats(0, 0, 1);
                }
                    // Update overall stats. Should only be called once overall stats have been set initially.
                else {
                    // Do not give kills or headshots for team kills.
                    // TODO: If you kill someone that is so brand new that even their ID does not come through,
                    // the defender will be null. So if the defender is null then a kill is currently counted. However,
                    // the defender might be a team mate. The only fix I know of is to keep track of this and check it
                    // occasionally and reverse the kill once the name is resolved and same faction is discovered.
                    if (newEvent.defender == null || (newEvent.defender != null && newEvent.defender.faction != m_player.faction))
                        UpdateOverallStats(newWeapon.kills, newWeapon.headShots, 0);
                }
            }
            // Add session weapon stats unless this event was a death or team kill.
            if (!newEvent.death && (newEvent.defender == null || (newEvent.defender != null && newEvent.defender.faction != m_player.faction)))
                await AddSessionWeapon(newWeapon, oldWeapon);
        }
        // Will return either a weapon or vehicle ID.
        public string GetBestWeaponID(Weapon weapon) {
            if (weapon.id != null && weapon.id != "0") {
                return weapon.id;
            }
            if (weapon.vehicleId != null && weapon.vehicleId != "0") {
                return VEHICLE_OFFSET + weapon.vehicleId;
            }

            return "0";
        }
 public object Clone() {
     Player outPlayer = new Player();
     outPlayer = (Player)this.MemberwiseClone();
     outPlayer.weapons = new Dictionary<string, Weapon>();
     foreach (KeyValuePair<string, Weapon> element in this.weapons) {
         Weapon weapon = new Weapon();
         weapon = (Weapon)element.Value.Clone();
         outPlayer.weapons.Add(element.Key, weapon);
     }
     return outPlayer;
 }