protected void HandleBombExploded(object sender, BombEventArgs e)
		{
			if (!IsMatchStarted || e.Player == null) return;

			BombExplodedEvent bombExplodedEvent = new BombExplodedEvent(Parser.IngameTick, Parser.CurrentTime)
			{
				Site = e.Site.ToString(),
				PlanterSteamId = e.Player.SteamID,
				PlanterName = e.Player.Name
			};

			PlayerExtended planter = Demo.Players.FirstOrDefault(p => p.SteamId == e.Player.SteamID);
			if (planter != null) planter.BombExplodedCount++;

			Demo.BombExploded.Add(bombExplodedEvent);
			CurrentRound.BombExploded = bombExplodedEvent;

			if (AnalyzePlayersPosition && planter != null)
			{
				PositionPoint positionPoint = new PositionPoint
				{
					X = Demo.BombPlanted.Last().X,
					Y = Demo.BombPlanted.Last().Y,
					PlayerSteamId = e.Player.SteamID,
					PlayerName = e.Player.Name,
					Team = e.Player.Team,
					Event = bombExplodedEvent,
					RoundNumber = CurrentRound.Number
				};
				Demo.PositionsPoint.Add(positionPoint);
			}
		}
		/// <summary>
		/// Draw icon when a decoy start "screaming"
		/// </summary>
		/// <param name="positionPoint"></param>
		public void DrawDecoyStarted(PositionPoint positionPoint)
		{
			try
			{
				Bitmap icon = new Bitmap(Properties.Resources.decoy_screaming);
				DrawIcon(DecoyLayer, icon, positionPoint);

				icon.Dispose();
			}
			catch (Exception e)
			{
				Logger.Instance.Log(e);
			}
		}
		/// <summary>
		/// Draw a specific icon on WriteableBitmapEvents layer
		/// </summary>
		/// <param name="layer"></param>
		/// <param name="icon"></param>
		/// <param name="positionPoint"></param>
		private void DrawIcon(WriteableBitmap layer, Bitmap icon, PositionPoint positionPoint)
		{
			BitmapData data = icon.LockBits(new Rectangle(0, 0, icon.Width, icon.Height),
			ImageLockMode.ReadOnly, PixelFormat.Format32bppPArgb);

			IntPtr ptr = data.Scan0;

			// Declare an array to hold the bytes of the bitmap.
			int bytes = Math.Abs(data.Stride) * icon.Height;
			byte[] rgbValues = new byte[bytes];

			// Copy the RGB values into the array.
			Marshal.Copy(ptr, rgbValues, 0, bytes);

			layer.WritePixels(
				new Int32Rect(0, 0, icon.Width, icon.Height),
				rgbValues,
				data.Stride,
				(int)positionPoint.X - icon.Width / 2,
				(int)positionPoint.Y - icon.Height / 2);

			icon.UnlockBits(data);
		}
		/// <summary>
		/// Draw icon when a hegrenade exploded
		/// </summary>
		/// <param name="positionPoint"></param>
		public async void DrawExplosiveNadeExploded(PositionPoint positionPoint)
		{
			try
			{
				Bitmap icon = new Bitmap(Properties.Resources.he_exploded);
				DrawIcon(HegrenadeLayer, icon, positionPoint);

				await Task.Delay(2000);

				ClearIcon(HegrenadeLayer, icon, positionPoint);

				icon.Dispose();
			}
			catch (Exception e)
			{
				Logger.Instance.Log(e);
			}
		}
		/// <summary>
		/// Draw icon when the bomb has been planted
		/// </summary>
		/// <param name="positionPoint"></param>
		public void DrawBombPlanted(PositionPoint positionPoint)
		{
			try
			{
				Bitmap icon = new Bitmap(Properties.Resources.bomb);
				DrawIcon(WeaponLayer, icon, positionPoint);

				icon.Dispose();
			}
			catch (Exception e)
			{
				Logger.Instance.Log(e);
			}
		}
		/// <summary>
		/// Draw weapon icon
		/// </summary>
		/// <param name="positionPoint"></param>
		public async void DrawWeapon(PositionPoint positionPoint)
		{
			var ev = (WeaponFire)positionPoint.Event;
			Bitmap icon = null;
			switch (ev.Weapon.Name)
			{
				case "Flashbang":
					icon = new Bitmap(Properties.Resources.flashbang);
					break;
				case "He grenade":
					icon = new Bitmap(Properties.Resources.hegrenade);
					break;
				case "Smoke":
					icon = new Bitmap(Properties.Resources.smokegrenade);
					break;
				case "Decoy":
					icon = new Bitmap(Properties.Resources.decoy);
					break;
				case "Molotov":
					icon = new Bitmap(Properties.Resources.molotov);
					break;
				case "Incendiary":
					icon = new Bitmap(Properties.Resources.incendiary);
					break;
			}

			if (icon != null)
			{
				try
				{
					DrawIcon(WeaponLayer, icon, positionPoint);

					await Task.Delay(2000);

					ClearIcon(WeaponLayer, icon, positionPoint);

					icon.Dispose();
				}
				catch (Exception e)
				{
					Logger.Instance.Log(e);
				}
			}
		}
		/// <summary>
		/// Clear smoke icon when a smoke ended
		/// </summary>
		/// <param name="positionPoint"></param>
		public void DrawSmokeEnded(PositionPoint positionPoint)
		{
			try
			{
				Bitmap icon = new Bitmap(Properties.Resources.smoke);
				ClearIcon(SmokeLayer, icon, positionPoint);
				icon.Dispose();
			}
			catch (Exception e)
			{
				Logger.Instance.Log(e);
			}
		}
		protected void HandleBombDefused(object sender, BombEventArgs e)
		{
			if (!IsMatchStarted) return;

			BombDefusedEvent bombDefusedEvent = new BombDefusedEvent(Parser.IngameTick);
			if (e.Player.SteamID != 0)
			{
				PlayerExtended player = Demo.Players.FirstOrDefault(p => p.SteamId == e.Player.SteamID);
				if (player != null)
				{
					player.BombDefusedCount++;
					bombDefusedEvent.Player = player;
				}
			}
			Demo.BombDefused.Add(bombDefusedEvent);
			CurrentRound.BombDefused.Add(bombDefusedEvent);

			if (AnalyzePlayersPosition && bombDefusedEvent.Player != null)
			{
				PositionPoint positionPoint = new PositionPoint
				{
					X = Demo.BombPlanted.Last().X,
					Y = Demo.BombPlanted.Last().Y,
					Player = bombDefusedEvent.Player,
					Team = e.Player.Team,
					Event = bombDefusedEvent,
					Round = CurrentRound
				};
				Demo.PositionsPoint.Add(positionPoint);
			}
		}
		protected void HandleBombExploded(object sender, BombEventArgs e)
		{
			if (!IsMatchStarted) return;

			BombExplodedEvent bombExplodedEvent = new BombExplodedEvent(Parser.IngameTick)
			{
				Site = e.Site.ToString()
			};

			if (e.Player != null) bombExplodedEvent.Player = Demo.Players.FirstOrDefault(p => p.SteamId == e.Player.SteamID);

			Demo.BombExploded.Add(bombExplodedEvent);
			CurrentRound.BombExploded.Add(bombExplodedEvent);

			if (AnalyzePlayersPosition && bombExplodedEvent.Player != null)
			{
				PositionPoint positionPoint = new PositionPoint
				{
					X = Demo.BombPlanted.Last().X,
					Y = Demo.BombPlanted.Last().Y,
					Player = bombExplodedEvent.Player,
					Team = e.Player.Team,
					Event = bombExplodedEvent,
					Round = CurrentRound
				};
				Demo.PositionsPoint.Add(positionPoint);
			}
		}
		protected void HandleSmokeNadeStarted(object sender, SmokeEventArgs e)
		{
			if (!AnalyzePlayersPosition && !AnalyzeHeatmapPoint || !IsMatchStarted || e.ThrownBy == null) return;

			PlayerExtended thrower = Demo.Players.FirstOrDefault(player => player.SteamId == e.ThrownBy.SteamID);

			SmokeNadeStartedEvent smokeEvent = new SmokeNadeStartedEvent(Parser.IngameTick, Parser.CurrentTime)
			{
				ThrowerSteamId = thrower?.SteamId ?? 0,
				ThrowerName = thrower == null ? string.Empty : thrower.Name
			};

			if (AnalyzeHeatmapPoint && thrower != null)
			{
				smokeEvent.Point = new HeatmapPoint
				{
					X = e.Position.X,
					Y = e.Position.Y,
					Player = thrower,
					Team = e.ThrownBy.Team,
					Round = CurrentRound
				};
			}

			CurrentRound.SmokesStarted.Add(smokeEvent);

			if (AnalyzePlayersPosition && thrower != null)
			{
				PositionPoint positionPoint = new PositionPoint
				{
					X = e.Position.X,
					Y = e.Position.Y,
					PlayerSteamId = e.ThrownBy.SteamID,
					PlayerName = e.ThrownBy.Name,
					Team = e.ThrownBy.Team,
					Event = smokeEvent,
					RoundNumber = CurrentRound.Number
				};
				Demo.PositionsPoint.Add(positionPoint);
			}
		}
		/// <summary>
		/// Handle each tick
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		protected void HandleTickDone(object sender, TickDoneEventArgs e)
		{
			if (!IsMatchStarted || IsFreezetime || !AnalyzePlayersPosition) return;

			if (Parser.PlayingParticipants.Any())
			{
				if (Demo.Players.Any())
				{
					// Reset bomber
					foreach (PlayerExtended playerExtended in Demo.Players)
					{
						playerExtended.HasBomb = false;
					}

					// Update players position
					foreach (Player player in Parser.PlayingParticipants)
					{
						if (!player.IsAlive) continue;
						PlayerExtended pl = Demo.Players.FirstOrDefault(p => p.SteamId == player.SteamID);
						if (pl == null || pl.SteamId == 0) continue;

						// Set the bomber
						if (player.Weapons.FirstOrDefault(w => w.Weapon == EquipmentElement.Bomb) != null) pl.HasBomb = true;

						PositionPoint positionPoint = new PositionPoint
						{
							X = player.Position.X,
							Y = player.Position.Y,
							Round = CurrentRound,
							Team = player.Team,
							Player = pl.Clone()
						};
						Demo.PositionsPoint.Add(positionPoint);
					}
				}
			}
		}
		protected void HandleFlashNadeExploded(object sender, FlashEventArgs e)
		{
			if(!IsMatchStarted || e.ThrownBy == null || !PlayersFlashQueue.Any()) return;

			if (PlayersFlashQueue.Any())
			{
				LastPlayerExplodedFlashbang = PlayersFlashQueue.Dequeue();
				// update flash intensity value for each player when the flash poped
				foreach (Player player in Parser.PlayingParticipants)
				{
					PlayerExtended pl = Demo.Players.FirstOrDefault(p => p.SteamId == player.SteamID);
					if (pl != null) pl.FlashDurationTemp = player.FlashDuration;
				}
				// set it to true to start analyzing flashbang status at each tick
				AnalyzeFlashbang = true;
			}

			if (!AnalyzePlayersPosition && !AnalyzeHeatmapPoint) return;

			PlayerExtended thrower = Demo.Players.FirstOrDefault(player => player.SteamId == e.ThrownBy.SteamID);
			FlashbangExplodedEvent flashbangEvent = new FlashbangExplodedEvent(Parser.IngameTick, Parser.CurrentTime)
			{
				ThrowerSteamId = thrower?.SteamId ?? 0,
				ThrowerName = thrower == null ? string.Empty : thrower.Name
			};

			if (e.FlashedPlayers != null)
			{
				foreach (Player player in e.FlashedPlayers)
				{
					PlayerExtended playerExtended = Demo.Players.FirstOrDefault(p => p.SteamId == player.SteamID);
					if (playerExtended != null)
					{
						flashbangEvent.FlashedPlayerSteamIdList.Add(playerExtended.SteamId);
					}
				}
			}

			if (AnalyzeHeatmapPoint && thrower != null)
			{
				flashbangEvent.Point = new HeatmapPoint
				{
					X = e.Position.X,
					Y = e.Position.Y,
					Player = thrower,
					Team = e.ThrownBy.Team,
					Round = CurrentRound
				};
			}

			CurrentRound.FlashbangsExploded.Add(flashbangEvent);

			if (AnalyzePlayersPosition && thrower != null)
			{
				PositionPoint positionPoint = new PositionPoint
				{
					X = e.Position.X,
					Y = e.Position.Y,
					PlayerSteamId = e.ThrownBy.SteamID,
					PlayerName = e.ThrownBy.Name,
					Team = e.ThrownBy.Team,
					RoundNumber = CurrentRound.Number,
					Event = flashbangEvent
				};
				Demo.PositionsPoint.Add(positionPoint);
			}
		}
		protected void HandleFireNadeStarted(object sender, FireEventArgs e)
		{
			if (!AnalyzePlayersPosition && !AnalyzeHeatmapPoint || !IsMatchStarted) return;

			switch (e.NadeType)
			{
				case EquipmentElement.Incendiary:
				case EquipmentElement.Molotov:
					MolotovFireStartedEvent molotovEvent = new MolotovFireStartedEvent(Parser.IngameTick, Parser.CurrentTime);
					PlayerExtended thrower = null;
					
					if (e.ThrownBy != null)
					{
						thrower = Demo.Players.First(p => p.SteamId == e.ThrownBy.SteamID);
					}

					if (AnalyzePlayersPosition || AnalyzeHeatmapPoint && LastPlayersThrownMolotov.Any())
					{
						LastPlayersFireStartedMolotov.Enqueue(LastPlayersThrownMolotov.Peek());
						// Remove the last player who thrown a molo
						thrower = LastPlayersThrownMolotov.Dequeue();
					}

					if (thrower != null)
					{
						molotovEvent.ThrowerSteamId = thrower.SteamId;
						molotovEvent.ThrowerName = thrower.Name;

						if (AnalyzePlayersPosition)
						{
							PositionPoint positionPoint = new PositionPoint
							{
								X = e.Position.X,
								Y = e.Position.Y,
								PlayerSteamId = thrower.SteamId,
								PlayerName = thrower.Name,
								Team = thrower.Side,
								Event = molotovEvent,
								RoundNumber = CurrentRound.Number
							};
							Demo.PositionsPoint.Add(positionPoint);
						}
					}

					if (AnalyzeHeatmapPoint)
					{
						molotovEvent.Point = new HeatmapPoint
						{
							X = e.Position.X,
							Y = e.Position.Y,
							Player = thrower,
							Team = thrower?.Side ?? Team.Spectate,
							Round = CurrentRound
						};
						Demo.MolotovFireStarted.Add(molotovEvent);
					}
					
					break;
			}
		}
		protected void HandleWeaponFired(object sender, WeaponFiredEventArgs e)
		{
			if (!IsMatchStarted || e.Shooter == null) return;

			if (!IsFirstShotOccured)
			{
				IsFirstShotOccured = true;
				// update the equipement value for each player
				foreach (Player pl in Parser.PlayingParticipants)
				{
					PlayerExtended player = Demo.Players.FirstOrDefault(p => p.SteamId == pl.SteamID);
					if (player != null && !player.EquipementValueRounds.ContainsKey(CurrentRound.Number))
					{
						player.EquipementValueRounds.Add(CurrentRound.Number, pl.CurrentEquipmentValue);
					}
				}

				if (IsHalfMatch)
				{
					CurrentRound.EquipementValueTeam1 = Parser.Participants.Where(a => a.Team == Team.Terrorist).Sum(a => a.CurrentEquipmentValue);
					CurrentRound.EquipementValueTeam2 = Parser.Participants.Where(a => a.Team == Team.CounterTerrorist).Sum(a => a.CurrentEquipmentValue);
				}
				else
				{
					CurrentRound.EquipementValueTeam1 = Parser.Participants.Where(a => a.Team == Team.CounterTerrorist).Sum(a => a.CurrentEquipmentValue);
					CurrentRound.EquipementValueTeam2 = Parser.Participants.Where(a => a.Team == Team.Terrorist).Sum(a => a.CurrentEquipmentValue);
				}

				// Not 100% accurate maybe improved it with current equipement...
				if (CurrentRound.StartMoneyTeam1 == 4000 && CurrentRound.StartMoneyTeam2 == 4000)
				{
					CurrentRound.Type = RoundType.PISTOL_ROUND;
				}
				else
				{
					double diffPercent = Math.Abs(Math.Round((((double)CurrentRound.EquipementValueTeam1 - CurrentRound.EquipementValueTeam2) / (((double)CurrentRound.EquipementValueTeam1 + CurrentRound.EquipementValueTeam2) / 2) * 100), 2));
					if (diffPercent >= 90)
					{
						CurrentRound.Type = RoundType.ECO;
					}
					else if (diffPercent >= 75 && diffPercent < 90)
					{
						CurrentRound.Type = RoundType.SEMI_ECO;
					}
					else if (diffPercent >= 50 && diffPercent < 75)
					{
						CurrentRound.Type = RoundType.FORCE_BUY;
					}
					else
					{
						CurrentRound.Type = RoundType.NORMAL;
					}

					if (CurrentRound.Type != RoundType.NORMAL)
					{
						if (IsOvertime)
						{
							if (IsHalfMatch)
							{
								if (CurrentRound.EquipementValueTeam1 > CurrentRound.EquipementValueTeam2)
								{
									CurrentRound.TeamTroubleName = Demo.TeamCT.Name;
									CurrentRound.SideTrouble = Team.CounterTerrorist;
								}
								else
								{
									CurrentRound.TeamTroubleName = Demo.TeamT.Name;
									CurrentRound.SideTrouble = Team.Terrorist;
								}
							}
							else
							{
								if (CurrentRound.EquipementValueTeam1 > CurrentRound.EquipementValueTeam2)
								{
									CurrentRound.TeamTroubleName = Demo.TeamT.Name;
									CurrentRound.SideTrouble = Team.CounterTerrorist;
								}
								else
								{
									CurrentRound.TeamTroubleName = Demo.TeamCT.Name;
									CurrentRound.SideTrouble = Team.Terrorist;
								}
							}
						}
						else
						{
							if (IsHalfMatch)
							{
								if (CurrentRound.EquipementValueTeam1 > CurrentRound.EquipementValueTeam2)
								{
									CurrentRound.TeamTroubleName = Demo.TeamCT.Name;
									CurrentRound.SideTrouble = Team.Terrorist;
								}
								else
								{
									CurrentRound.TeamTroubleName = Demo.TeamT.Name;
									CurrentRound.SideTrouble = Team.CounterTerrorist;
								}
							}
							else
							{
								if (CurrentRound.EquipementValueTeam1 > CurrentRound.EquipementValueTeam2)
								{
									CurrentRound.TeamTroubleName = Demo.TeamT.Name;
									CurrentRound.SideTrouble = Team.Terrorist;
								}
								else
								{
									CurrentRound.TeamTroubleName = Demo.TeamCT.Name;
									CurrentRound.SideTrouble = Team.CounterTerrorist;
								}
							}
						}
					}
						
				}
			}

			PlayerExtended shooter = Demo.Players.FirstOrDefault(p => p.SteamId == e.Shooter.SteamID);
			Weapon weapon = Weapon.WeaponList.FirstOrDefault(w => w.Element == e.Weapon.Weapon);
			if (shooter == null || weapon == null) return;

			switch (e.Weapon.Weapon)
			{
				case EquipmentElement.Incendiary:
					CurrentRound.IncendiaryThrownCount++;
					shooter.IncendiaryThrownCount++;
					break;
				case EquipmentElement.Molotov:
					CurrentRound.MolotovThrownCount++;
					shooter.MolotovThrownCount++;
					break;
				case EquipmentElement.Decoy:
					CurrentRound.DecoyThrownCount++;
					shooter.DecoyThrownCount++;
					break;
				case EquipmentElement.Flash:
					CurrentRound.FlashbangThrownCount++;
					shooter.FlashbangThrownCount++;
					PlayersFlashQueue.Enqueue(shooter);
					break;
				case EquipmentElement.HE:
					CurrentRound.HeGrenadeThrownCount++;
					shooter.HeGrenadeThrownCount++;
					break;
				case EquipmentElement.Smoke:
					CurrentRound.SmokeThrownCount++;
					shooter.SmokeThrownCount++;
					break;
			}

			WeaponFire shoot = new WeaponFire(Parser.IngameTick, Parser.CurrentTime)
			{
				ShooterSteamId = shooter.SteamId,
				ShooterName = shooter.Name,
				Weapon = weapon,
				RoundNumber = CurrentRound.Number,
				ShooterVelocityX = e.Shooter.Velocity.X,
				ShooterVelocityY = e.Shooter.Velocity.Y,
				ShooterVelocityZ = e.Shooter.Velocity.Z
			};
			Demo.WeaponFired.Add(shoot);

			if (AnalyzeHeatmapPoint || AnalyzePlayersPosition)
			{
				if (AnalyzeHeatmapPoint)
				{
					shoot.Point = new HeatmapPoint
					{
						X = e.Shooter.Position.X,
						Y = e.Shooter.Position.Y,
						Round = CurrentRound,
						Player = Demo.Players.First(p => p.SteamId == shoot.ShooterSteamId),
						Team = e.Shooter.Team
					};
				}

				if (AnalyzePlayersPosition || AnalyzeHeatmapPoint)
				{
					if (e.Shooter.SteamID == 0) return;

					switch (e.Weapon.Weapon)
					{
						case EquipmentElement.Incendiary:
						case EquipmentElement.Molotov:
							LastPlayersThrownMolotov.Enqueue(Demo.Players.First(p => p.SteamId == e.Shooter.SteamID));
							if (AnalyzeHeatmapPoint) return;
							goto case EquipmentElement.Decoy;
						case EquipmentElement.Decoy:
						case EquipmentElement.Flash:
						case EquipmentElement.HE:
						case EquipmentElement.Smoke:
							PositionPoint positionPoint = new PositionPoint
							{
								X = e.Shooter.Position.X,
								Y = e.Shooter.Position.Y,
								PlayerSteamId = e.Shooter.SteamID,
								PlayerName = e.Shooter.Name,
								Team = e.Shooter.Team,
								Event = shoot,
								RoundNumber = CurrentRound.Number
							};
							Demo.PositionsPoint.Add(positionPoint);
							break;
					}
				}
			}
		}
		/// <summary>
		/// Draw a pixel on main overview
		/// </summary>
		/// <param name="positionPoint"></param>
		public void DrawPixel(PositionPoint positionPoint)
		{
			OverviewLayer.SetPixel((int)positionPoint.X, (int)positionPoint.Y, positionPoint.Color);
		}
		protected void HandleWeaponFired(object sender, WeaponFiredEventArgs e)
		{
			if (!IsMatchStarted || e.Shooter == null) return;

			if (!IsFirstShotOccured)
			{
				IsFirstShotOccured = true;
				if (IsHalfMatch)
				{
					CurrentRound.EquipementValueTeam1 = Parser.Participants.Where(a => a.Team == Team.Terrorist).Sum(a => a.CurrentEquipmentValue);
					CurrentRound.EquipementValueTeam2 = Parser.Participants.Where(a => a.Team == Team.CounterTerrorist).Sum(a => a.CurrentEquipmentValue);
				}
				else
				{
					CurrentRound.EquipementValueTeam1 = Parser.Participants.Where(a => a.Team == Team.CounterTerrorist).Sum(a => a.CurrentEquipmentValue);
					CurrentRound.EquipementValueTeam2 = Parser.Participants.Where(a => a.Team == Team.Terrorist).Sum(a => a.CurrentEquipmentValue);
				}

				// Not 100% accurate maybe improved it with current equipement...
				if (CurrentRound.StartMoneyTeam1 == 4000 && CurrentRound.StartMoneyTeam2 == 4000)
				{
					CurrentRound.Type = RoundType.PISTOL_ROUND;
				}
				else
				{
					double diffPercent = Math.Abs(Math.Round((((double)CurrentRound.EquipementValueTeam1 - CurrentRound.EquipementValueTeam2) / (((double)CurrentRound.EquipementValueTeam1 + CurrentRound.EquipementValueTeam2) / 2) * 100), 2));
					if (diffPercent >= 90)
					{
						CurrentRound.Type = RoundType.ECO;
					}
					else if (diffPercent >= 75 && diffPercent < 90)
					{
						CurrentRound.Type = RoundType.SEMI_ECO;
					}
					else if (diffPercent >= 50 && diffPercent < 75)
					{
						CurrentRound.Type = RoundType.FORCE_BUY;
					}
					else
					{
						CurrentRound.Type = RoundType.NORMAL;
					}

					if (CurrentRound.Type != RoundType.NORMAL)
					{
						if (IsOvertime)
						{
							if (IsHalfMatch)
							{
								if (CurrentRound.EquipementValueTeam1 > CurrentRound.EquipementValueTeam2)
								{
									CurrentRound.TeamTrouble = Demo.Teams[0];
									CurrentRound.SideTrouble = Team.CounterTerrorist;
								}
								else
								{
									CurrentRound.TeamTrouble = Demo.Teams[1];
									CurrentRound.SideTrouble = Team.Terrorist;
								}
							}
							else
							{
								if (CurrentRound.EquipementValueTeam1 > CurrentRound.EquipementValueTeam2)
								{
									CurrentRound.TeamTrouble = Demo.Teams[1];
									CurrentRound.SideTrouble = Team.CounterTerrorist;
								}
								else
								{
									CurrentRound.TeamTrouble = Demo.Teams[0];
									CurrentRound.SideTrouble = Team.Terrorist;
								}
							}
						}
						else
						{
							if (IsHalfMatch)
							{
								if (CurrentRound.EquipementValueTeam1 > CurrentRound.EquipementValueTeam2)
								{
									CurrentRound.TeamTrouble = Demo.Teams[0];
									CurrentRound.SideTrouble = Team.Terrorist;
								}
								else
								{
									CurrentRound.TeamTrouble = Demo.Teams[1];
									CurrentRound.SideTrouble = Team.CounterTerrorist;
								}
							}
							else
							{
								if (CurrentRound.EquipementValueTeam1 > CurrentRound.EquipementValueTeam2)
								{
									CurrentRound.TeamTrouble = Demo.Teams[1];
									CurrentRound.SideTrouble = Team.Terrorist;
								}
								else
								{
									CurrentRound.TeamTrouble = Demo.Teams[0];
									CurrentRound.SideTrouble = Team.CounterTerrorist;
								}
							}
						}
					}
						
				}
			}

			if (AnalyzeHeatmapPoint || AnalyzePlayersPosition)
			{
				WeaponFire shoot = new WeaponFire(Parser.IngameTick)
				{
					Shooter = Demo.Players.FirstOrDefault(p => p.SteamId == e.Shooter.SteamID),
					Weapon = new Weapon(e.Weapon)
				};

				if (AnalyzeHeatmapPoint && shoot.Shooter != null)
				{
					shoot.Point = new HeatmapPoint
					{
						X = e.Shooter.Position.X,
						Y = e.Shooter.Position.Y,
						Round = CurrentRound,
						Player = shoot.Shooter,
						Team = e.Shooter.Team
					};
				}

				Demo.WeaponFired.Add(shoot);

				if (AnalyzePlayersPosition || AnalyzeHeatmapPoint && shoot.Shooter != null)
				{
					if (e.Shooter.SteamID == 0) return;

					switch (e.Weapon.Weapon)
					{
						case EquipmentElement.Incendiary:
						case EquipmentElement.Molotov:
							LastPlayersThrowedMolotov.Enqueue(Demo.Players.First(p => p.SteamId == e.Shooter.SteamID));
							if (AnalyzeHeatmapPoint) return;
							goto case EquipmentElement.Decoy;
						case EquipmentElement.Decoy:
						case EquipmentElement.Flash:
						case EquipmentElement.HE:
						case EquipmentElement.Smoke:
							PositionPoint positionPoint = new PositionPoint
							{
								X = e.Shooter.Position.X,
								Y = e.Shooter.Position.Y,
								Player = Demo.Players.First(p => p.SteamId == e.Shooter.SteamID),
								Team = e.Shooter.Team,
								Event = shoot,
								Round = CurrentRound
							};
							Demo.PositionsPoint.Add(positionPoint);
							break;
					}
				}
			}
			else
			{
				PlayerExtended shooter = Demo.Players.FirstOrDefault(p => p.SteamId == e.Shooter.SteamID);
				if (shooter == null) return;
				
				switch (e.Weapon.Weapon)
				{
					case EquipmentElement.Incendiary:
						shooter.IncendiaryThrowedCount++;
						break;
					case EquipmentElement.Molotov:
						shooter.MolotovThrowedCount++;
						break;
					case EquipmentElement.Decoy:
						shooter.DecoyThrowedCount++;
						break;
					case EquipmentElement.Flash:
						shooter.FlashbangThrowedCount++;
						break;
					case EquipmentElement.HE:
						shooter.HeGrenadeThrowedCount++;
						break;
					case EquipmentElement.Smoke:
						shooter.SMokeThrowedCount++;
						break;
				}
			}
		}
		/// <summary>
		/// Draw player's marker
		/// </summary>
		/// <param name="positionPoint"></param>
		public async void DrawPlayerMarker(PositionPoint positionPoint)
		{
			try
			{
				PlayerMarkerLayer.FillEllipseCentered((int)positionPoint.X, (int)positionPoint.Y, 5, 5, positionPoint.Color);

				Bitmap icon = null;
				if (positionPoint.Player.HasBomb)
				{
					icon = new Bitmap(Properties.Resources.bomb_overview);
					DrawIcon(PlayerMarkerLayer, icon, positionPoint);
				}

				await Task.Delay(200);

				PlayerMarkerLayer.FillEllipseCentered((int)positionPoint.X, (int)positionPoint.Y, 5, 5, Colors.Transparent);

				if (positionPoint.Player.HasBomb)
				{
					await Task.Delay(200);

					ClearIcon(PlayerMarkerLayer, icon, positionPoint);
					icon?.Dispose();
				}
			}
			catch (Exception e)
			{
				Logger.Instance.Log(e);
			}
		}
		protected void HandleFireNadeEnded(object sender, FireEventArgs e)
		{
			if (!AnalyzePlayersPosition || !IsMatchStarted) return;

			switch (e.NadeType)
			{
				case EquipmentElement.Incendiary:
				case EquipmentElement.Molotov:
					MolotovFireEndedEvent molotovEvent = new MolotovFireEndedEvent(Parser.IngameTick)
					{
						Point = new HeatmapPoint
						{
							X = e.Position.X,
							Y = e.Position.Y
						}
					};

					PlayerExtended thrower = null;

					// Thrower is not indicated every time
					if (e.ThrownBy != null)
					{
						thrower = Demo.Players.FirstOrDefault(player => player.SteamId == e.ThrownBy.SteamID);
					}

					if (LastPlayersFireStartedMolotov.Any())
					{
						LastPlayersFireEndedMolotov.Enqueue(LastPlayersFireStartedMolotov.Peek());
						// Remove the last player who started a fire
						thrower = LastPlayersFireStartedMolotov.Dequeue();
					}

					molotovEvent.Thrower = thrower;
					CurrentRound.MolotovsThrowed.Add(molotovEvent);

					PositionPoint positionPoint = new PositionPoint
					{
						X = e.Position.X,
						Y = e.Position.Y,
						Player = thrower,
						Team = thrower?.Team ?? Team.Spectate,
						Event = molotovEvent,
						Round = CurrentRound
					};
					Demo.PositionsPoint.Add(positionPoint);
					
					break;
			}
		}
		/// <summary>
		/// Draw successive icons to animate smoke started
		/// </summary>
		/// <param name="positionPoint"></param>
		public async void DrawSmokeStarted(PositionPoint positionPoint)
		{
			try
			{
				Bitmap icon = new Bitmap(Properties.Resources.smoke_start);
				DrawIcon(SmokeLayer, icon, positionPoint);

				await Task.Delay(1000);

				icon = new Bitmap(Properties.Resources.smoke);
				DrawIcon(SmokeLayer, icon, positionPoint);

				icon.Dispose();
			}
			catch (Exception e)
			{
				Logger.Instance.Log(e);
			}
		}
		protected void HandleExplosiveNadeExploded(object sender, GrenadeEventArgs e)
		{
			if (!AnalyzePlayersPosition && !AnalyzeHeatmapPoint || !IsMatchStarted || e.ThrownBy == null) return;

			ExplosiveNadeExplodedEvent explosiveEvent = new ExplosiveNadeExplodedEvent(Parser.IngameTick)
			{
				Thrower = Demo.Players.FirstOrDefault(player => player.SteamId == e.ThrownBy.SteamID)
			};

			if (AnalyzeHeatmapPoint && explosiveEvent.Thrower != null)
			{
				explosiveEvent.Point = new HeatmapPoint
				{
					X = e.Position.X,
					Y = e.Position.Y,
					Player = explosiveEvent.Thrower,
					Team = e.ThrownBy.Team,
					Round = CurrentRound
				};
			}

			CurrentRound.ExplosiveGrenadesExploded.Add(explosiveEvent);

			if (AnalyzePlayersPosition && explosiveEvent.Thrower != null)
			{
				PositionPoint positionPoint = new PositionPoint
				{
					X = e.Position.X,
					Y = e.Position.Y,
					Player = Demo.Players.First(p => p.SteamId == e.ThrownBy.SteamID),
					Team = e.ThrownBy.Team,
					Event = explosiveEvent,
					Round = CurrentRound
				};
				Demo.PositionsPoint.Add(positionPoint);
			}
		}
		/// <summary>
		/// Clear burn icon when a molotov is no more burning
		/// </summary>
		/// <param name="positionPoint"></param>
		public void DrawMolotovEnded(PositionPoint positionPoint)
		{
			try
			{
				Bitmap icon = new Bitmap(Properties.Resources.molotov_burning);
				ClearIcon(MolotovLayer, icon, positionPoint);
				icon.Dispose();
			}
			catch (Exception e)
			{
				Logger.Instance.Log(e);
			}
		}
		protected void HandleFlashNadeExploded(object sender, FlashEventArgs e)
		{
			if (!AnalyzePlayersPosition && !AnalyzeHeatmapPoint || !IsMatchStarted || e.ThrownBy == null) return;

			FlashbangExplodedEvent flashbangEvent = new FlashbangExplodedEvent(Parser.IngameTick)
			{
				Thrower = Demo.Players.FirstOrDefault(player => player.SteamId == e.ThrownBy.SteamID)
			};

			if (e.FlashedPlayers != null)
			{
				foreach (Player player in e.FlashedPlayers)
				{
					PlayerExtended playerExtended = Demo.Players.FirstOrDefault(p => p.SteamId == player.SteamID);
					if (playerExtended != null)
					{
						flashbangEvent.FlashedPlayers.Add(playerExtended);
					}
				}
			}

			if (AnalyzeHeatmapPoint && flashbangEvent.Thrower != null)
			{
				flashbangEvent.Point = new HeatmapPoint
				{
					X = e.Position.X,
					Y = e.Position.Y,
					Player = flashbangEvent.Thrower,
					Team = e.ThrownBy.Team,
					Round = CurrentRound
				};
			}

			CurrentRound.FlashbangsExploded.Add(flashbangEvent);

			if (AnalyzePlayersPosition && flashbangEvent.Thrower != null)
			{
				PositionPoint positionPoint = new PositionPoint
				{
					X = e.Position.X,
					Y = e.Position.Y,
					Player = flashbangEvent.Thrower,
					Team = e.ThrownBy.Team,
					Round = CurrentRound,
					Event = flashbangEvent
				};
				Demo.PositionsPoint.Add(positionPoint);
			}
		}
		/// <summary>
		/// Draw icon when a player has been killed
		/// </summary>
		/// <param name="positionPoint"></param>
		public async void DrawKill(PositionPoint positionPoint)
		{
			try
			{
				Bitmap icon = new Bitmap(Properties.Resources.kill);
				DrawIcon(KillLayer, icon, positionPoint);

				await Task.Delay(2000);

				ClearIcon(KillLayer, icon, positionPoint);

				icon.Dispose();
			}
			catch (Exception e)
			{
				Logger.Instance.Log(e);
			}
		}
		protected void HandleSmokeNadeStarted(object sender, SmokeEventArgs e)
		{
			if (!AnalyzePlayersPosition && !AnalyzeHeatmapPoint || !IsMatchStarted || e.ThrownBy == null) return;

			SmokeNadeStartedEvent smokeEvent = new SmokeNadeStartedEvent(Parser.IngameTick)
			{
				Thrower = Demo.Players.FirstOrDefault(player => player.SteamId == e.ThrownBy.SteamID)
			};

			if (AnalyzeHeatmapPoint && smokeEvent.Thrower != null)
			{
				smokeEvent.Point = new HeatmapPoint
				{
					X = e.Position.X,
					Y = e.Position.Y,
					Player = smokeEvent.Thrower,
					Team = e.ThrownBy.Team,
					Round = CurrentRound
				};
			}

			CurrentRound.SmokesStarted.Add(smokeEvent);

			if (AnalyzePlayersPosition && smokeEvent.Thrower != null)
			{
				PositionPoint positionPoint = new PositionPoint
				{
					X = e.Position.X,
					Y = e.Position.Y,
					Player = smokeEvent.Thrower,
					Team = e.ThrownBy.Team,
					Event = smokeEvent,
					Round = CurrentRound
				};
				Demo.PositionsPoint.Add(positionPoint);
			}
		}
		/// <summary>
		/// Draw icon when the bomb has been defused
		/// </summary>
		/// <param name="positionPoint"></param>
		public async void DrawBombDefused(PositionPoint positionPoint)
		{
			try
			{
				Bitmap icon = new Bitmap(Properties.Resources.bomb);

				ClearIcon(WeaponLayer, icon, positionPoint);

				icon = new Bitmap(Properties.Resources.defuser);
				DrawIcon(WeaponLayer, icon, positionPoint);

				await Task.Delay(3000);

				ClearIcon(WeaponLayer, icon, positionPoint);

				icon.Dispose();
			}
			catch (Exception e)
			{
				Logger.Instance.Log(e);
			}
		}
		protected void HandleDecoyNadeEnded(object sender, DecoyEventArgs e)
		{
			if (!AnalyzePlayersPosition || !IsMatchStarted) return;

			DecoyEndedEvent decoyEndedEvent = new DecoyEndedEvent(Parser.IngameTick)
			{
				Thrower = Demo.Players.FirstOrDefault(player => player.SteamId == e.ThrownBy.SteamID)
			};

			if (decoyEndedEvent.Thrower != null)
			{
				PositionPoint positionPoint = new PositionPoint
				{
					X = e.Position.X,
					Y = e.Position.Y,
					Player = Demo.Players.First(p => p.SteamId == e.ThrownBy.SteamID),
					Team = e.ThrownBy.Team,
					Event = decoyEndedEvent,
					Round = CurrentRound
				};
				Demo.PositionsPoint.Add(positionPoint);
			}
		}
		/// <summary>
		/// Undraw an icon when a decoy is over
		/// </summary>
		/// <param name="positionPoint"></param>
		public async void DrawDecoyEnded(PositionPoint positionPoint)
		{
			try
			{
				Bitmap icon = new Bitmap(Properties.Resources.decoy_screaming);
				ClearIcon(DecoyLayer, icon, positionPoint);

				icon = new Bitmap(Properties.Resources.decoy_exploded);
				DrawIcon(DecoyLayer, icon, positionPoint);

				await Task.Delay(1000);

				ClearIcon(DecoyLayer, icon, positionPoint);

				icon.Dispose();
			}
			catch (Exception e)
			{
				Logger.Instance.Log(e);
			}
		}
		protected override void HandlePlayerKilled(object sender, PlayerKilledEventArgs e)
		{
			if (!IsMatchStarted) return;
			if (e.Killer == null || e.Victim == null) return;

			KillEvent killEvent = new KillEvent(Parser.IngameTick)
			{
				Weapon = new Weapon(e.Weapon)
			};

			killEvent.DeathPerson = Demo.Players.FirstOrDefault(player => player.SteamId == e.Victim.SteamID);
			if (killEvent.DeathPerson != null)
			{
				killEvent.DeathPerson.IsAlive = false;
			}

			if (e.Assister != null)
			{
				killEvent.Assister = Demo.Players.FirstOrDefault(player => player.SteamId == e.Assister.SteamID);
			}

			// If the killer isn't a bot we can add a kill to the match
			killEvent.Killer = Demo.Players.FirstOrDefault(player => player.SteamId == e.Killer.SteamID);

			if (killEvent.Killer != null)
			{
				if (!KillsThisRound.ContainsKey(e.Killer))
				{
					KillsThisRound[e.Killer] = 0;
				}
				KillsThisRound[e.Killer]++;

				ProcessOpenAndEntryKills(killEvent);
			}

			if (killEvent.DeathPerson != null)
			{
				killEvent.DeathPerson.DeathCount++;

				// TK
				if (e.Killer.Team == e.Victim.Team)
				{
					if (killEvent.Killer != null && killEvent.DeathPerson != null)
					{
						PlayerExtended player = Demo.Players.FirstOrDefault(p => p.SteamId == e.Killer.SteamID);
						if (player != null) player.TeamKillCount++;
					}
				}
				else
				{
					if (killEvent.Killer != null)
					{
						killEvent.Killer.KillsCount++;
						if (e.Headshot)
						{
							killEvent.Killer.HeadshotCount++;
						}
					}
				}
			}

			if (killEvent.Assister != null)
			{
				killEvent.Assister.AssistCount++;
			}

			ProcessClutches();

			if (AnalyzeHeatmapPoint)
			{
				killEvent.Point = new HeatmapPoint
				{
					X = e.Victim.Position.X,
					Y = e.Victim.Position.Y,
					Round = CurrentRound,
					Player = killEvent.Killer,
					Team = e.Killer.Team
				};
			}

			Demo.Kills.Add(killEvent);
			CurrentRound.Kills.Add(killEvent);

			if (AnalyzePlayersPosition && killEvent.Killer != null)
			{
				PositionPoint positionPoint = new PositionPoint
				{
					X = e.Victim.Position.X,
					Y = e.Victim.Position.Y,
					Player = Demo.Players.First(p => p.SteamId == e.Killer.SteamID),
					Team = e.Killer.Team,
					Event = killEvent,
					Round = CurrentRound
				};
				Demo.PositionsPoint.Add(positionPoint);
			}
		}
		public void DrawEvent(PositionPoint positionPoint)
		{
			Type type = positionPoint.Event.GetType();
			if (type == typeof(WeaponFire))
			{
				DrawWeapon(positionPoint);
				WeaponFire e = (WeaponFire)positionPoint.Event;
				SoundService.PlayWeaponFired(positionPoint.Team, e);
			}
			else if (type == typeof(FlashbangExplodedEvent))
			{
				DrawFlashbangExploded(positionPoint);
				SoundService.PlayFlashbangExploded();
			}
			else if (type == typeof(SmokeNadeStartedEvent))
			{
				DrawSmokeStarted(positionPoint);
				SoundService.PlaySmokeDetonated();
			}
			else if (type == typeof(SmokeNadeEndedEvent))
			{
				DrawSmokeEnded(positionPoint);
			}
			else if (type == typeof(ExplosiveNadeExplodedEvent))
			{
				DrawExplosiveNadeExploded(positionPoint);
				SoundService.PlayHeExploded();
			}
			else if (type == typeof(MolotovFireStartedEvent))
			{
				DrawMolotovStarted(positionPoint);
				SoundService.PlayMolotovExploded();
			}
			else if (type == typeof(MolotovFireEndedEvent))
			{
				DrawMolotovEnded(positionPoint);
			}
			else if (type == typeof(KillEvent))
			{
				DrawKill(positionPoint);
				SoundService.PlayPlayerKilled(positionPoint.Team);
			}
			else if (type == typeof(DecoyStartedEvent))
			{
				DrawDecoyStarted(positionPoint);
			}
			else if (type == typeof(DecoyEndedEvent))
			{
				DrawDecoyEnded(positionPoint);
				SoundService.PlayDecoyExploded();
			}
			else if (type == typeof(BombPlantedEvent))
			{
				DrawBombPlanted(positionPoint);
				SoundService.PlayBombPlanted();
			}
			else if (type == typeof(BombExplodedEvent))
			{
				DrawBombExploded(positionPoint);
				SoundService.PlayBombExploded();
			}
			else if (type == typeof(BombDefusedEvent))
			{
				DrawBombDefused(positionPoint);
				SoundService.PlayBombDefused();
			}
		}
		/// <summary>
		/// killer == null => world
		/// killer.SteamID == 0 => BOT
		/// if a player is killed by bomb explosion, killer == planter
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		protected void HandlePlayerKilled(object sender, PlayerKilledEventArgs e)
		{
			if (!IsMatchStarted || e.Victim == null) return;

			PlayerExtended killed = Demo.Players.FirstOrDefault(player => player.SteamId == e.Victim.SteamID);
			if (killed == null) return;
			Weapon weapon = Weapon.WeaponList.FirstOrDefault(w => w.Element == e.Weapon.Weapon);
			if (weapon == null) return;
			PlayerExtended killer = null;

			KillEvent killEvent = new KillEvent(Parser.IngameTick, Parser.CurrentTime)
			{
				Weapon = weapon,
				KillerSteamId = e.Killer?.SteamID ?? 0,
				KillerName = e.Killer?.Name ?? string.Empty,
				KillerSide = e.Killer?.Team ?? Team.Spectate,
				KilledSide = e.Victim.Team,
				KilledSteamId = e.Victim.SteamID,
				KilledName = e.Victim.Name,
				KillerVelocityX = e.Killer?.Velocity.X ?? 0,
				KillerVelocityY = e.Killer?.Velocity.Y ?? 0,
				KillerVelocityZ = e.Killer?.Velocity.Z ?? 0,
				RoundNumber = CurrentRound.Number,
				IsKillerCrouching = e.Killer?.IsDucking ?? false
			};

			killed.IsAlive = false;
			killed.DeathCount++;
			if (e.Killer != null) killer = Demo.Players.FirstOrDefault(player => player.SteamId == e.Killer.SteamID);
			if (killer != null)
			{
				if (e.Killer.IsDucking) killer.CrouchKillCount++;
				if (e.Killer.Velocity.Z > 0) killer.JumpKillCount++;
			}

			if (e.Assister != null)
			{
				PlayerExtended assister = Demo.Players.FirstOrDefault(player => player.SteamId == e.Assister.SteamID);
				if (assister != null)
				{
					assister.AssistCount++;
					killEvent.AssisterSteamId = assister.SteamId;
					killEvent.AssisterName = assister.Name;
				}
			}

			if (e.Killer != null)
			{
				if (!KillsThisRound.ContainsKey(e.Killer))
				{
					KillsThisRound[e.Killer] = 0;
				}
				KillsThisRound[e.Killer]++;

				if (killer != null)
				{
					// TK
					if (e.Killer.Team == e.Victim.Team)
					{
						killer.KillsCount--;
						killer.TeamKillCount++;
					}
					else
					{
						killer.KillsCount++;
						if (e.Headshot) killer.HeadshotCount++;
					}
				}
			}

			ProcessOpenAndEntryKills(killEvent);
			ProcessClutches();
			ProcessPlayersRating();

			if (AnalyzeHeatmapPoint)
			{
				killEvent.Point = new KillHeatmapPoint
				{
					KillerX = e.Killer?.Position.X ?? 0,
					KillerY = e.Killer?.Position.Y ?? 0,
					VictimX = e.Victim.Position.X,
					VictimY = e.Victim.Position.Y,
					Round = CurrentRound,
					KillerSteamId = e.Killer?.SteamID ?? 0,
					KillerName = e.Killer?.Name ?? string.Empty,
					KillerTeam = e.Killer?.Team ?? Team.Spectate,
					VictimSteamId = e.Victim.SteamID,
					VictimName = e.Victim.Name,
					VictimTeam = e.Victim.Team
				};
			}

			Demo.Kills.Add(killEvent);
			CurrentRound.Kills.Add(killEvent);

			if (AnalyzePlayersPosition)
			{
				PositionPoint positionPoint = new PositionPoint
				{
					X = e.Victim.Position.X,
					Y = e.Victim.Position.Y,
					PlayerName = e.Killer?.Name ?? string.Empty,
					PlayerSteamId = e.Killer?.SteamID ?? 0,
					Team = e.Killer?.Team ?? Team.Spectate,
					Event = killEvent,
					RoundNumber = CurrentRound.Number
				};
				Demo.PositionsPoint.Add(positionPoint);
			}
		}