context: using System;
  using System.Collections.Generic;
  using System.Linq;
  using LeagueSharp;
  using LeagueSharp.Common;
  using Viktor.Extensions;
  using SharpDX;
  using Utilities = Viktor.Extensions.Utilities;
  
  using EloBuddy; 
  using LeagueSharp.Common; 
   namespace Viktor.Champions
  {
      internal class Viktor : VSpells
      {
          public Viktor()
          {
              LoadViktor();
          }
  
          private static void LoadViktor()
          {
              Game.OnWndProc += OnWndProc;
              Menus.InitializeMenu();
              Game.OnUpdate += Game_OnUpdate;
              Drawing.OnDraw += DrawingOnDraw;
              AntiGapcloser.OnEnemyGapcloser += OnAntiGapCloser;
              Orbwalking.OnNonKillableMinion += Orbwalking_OnNonKillableMinion;
              Interrupter2.OnInterruptableTarget += OnInterruptableTarget;
              //Orbwalking.BeforeAttack += OrbwalkingOnBeforeAttack;
          }
  
          private static void Game_OnUpdate(EventArgs args)
          {
              switch (Menus.Orbwalker.ActiveMode)
              {
                  case Orbwalking.OrbwalkingMode.Combo:
                      OnCombo();
                      UberMode();
                      break;
                  case Orbwalking.OrbwalkingMode.Mixed:
                      OnHarass();
                      break;
                  case Orbwalking.OrbwalkingMode.LaneClear:
                      OnLaneClear();
                      OnJungleClear();
                      break;
                  case Orbwalking.OrbwalkingMode.LastHit:
                      break;
              }
  
              if (spells[Spells.R].Instance.Name != "ViktorChaosStorm" && Utilities.IsEnabled("r.follow"))
              {
                  foreach (var enemy in HeroManager.Enemies.Where(x => x.IsValidTarget(spells[Spells.R].Range + 500)))
                  {
                      LeagueSharp.Common.Utility.DelayAction.Add(200, () => spells[Spells.R].Cast(enemy.ServerPosition));
                  }
              }
  
              W_OnCCandImmobile();
          }
  
          private static void OnWndProc(WndEventArgs args)
          {
              if (args.Msg == 0x20a)
              {
                  Menus.menuCfg.Item("e.clear").SetValue(!Menus.menuCfg.Item("e.clear").GetValue<bool>());
              }
          }
  
          private static void Orbwalking_OnNonKillableMinion(AttackableUnit minion)
          {
              CastQUnkillabeMinion();
          }
  
          /*private static void OrbwalkingOnBeforeAttack(Orbwalking.BeforeAttackEventArgs args)
          {
              if (Utilities.IsEnabled("q.misc"))
              {
                  switch (Menus.Orbwalker.ActiveMode)
                  {
                      case Orbwalking.OrbwalkingMode.Combo:
                          if (args.Target.Type == GameObjectType.AIHeroClient && Utilities.Player.HasBuff("viktorpowertransferreturn"))
                          {
                              args.Process = true;
                          }
                          else
                          {
                              args.Process = false;
                          }
                          break;
                      default:
                          return;
                  }
              
              }
          }*/
  
          public static void OnCombo()
          {
              if (spells[Spells.Q].IsReady() && Utilities.IsEnabled("q.combo"))
              {
                  foreach (var enemy in HeroManager.Enemies.Where(x => x.IsValidTarget(spells[Spells.Q].Range)))
                  {
                      spells[Spells.Q].Cast(enemy);
                  }
              }
  
              if (spells[Spells.W].IsReady() && Utilities.IsEnabled("w.combo"))
              {
                  foreach (var enemy in HeroManager.Enemies.Where(x => x.IsValidTarget(spells[Spells.W].Range)))
                  {
                      spells[Spells.W].PredictionCast(enemy, Utilities.TheHitChance("sel.hitchance.w"), "sel.predict.w", Menus.menuCfg);
                  }
              }
  
              if (spells[Spells.E].IsReady() && Utilities.IsEnabled("e.combo"))
              {
                  foreach (var enemy in HeroManager.Enemies.Where(x=> x.IsValidTarget(ERange + spells[Spells.E].Range)))
                  {
                      HitEnemy_E(enemy, Utilities.TheHitChance("sel.hitchance.e"));
                  }
              }
  
              if (spells[Spells.R].IsReady() && Utilities.IsEnabled("r.combo"))
              {
                  foreach (var enemy in HeroManager.Enemies.Where(x => x.IsValidTarget(spells[Spells.R].Range)
                       && spells[Spells.R].GetPrediction(x, true).Hitchance >= Utilities.TheHitChance("sel.hitchance.r")))
                  {
                      if (enemy.Health < CalculateDamage(enemy) && enemy.HealthPercent > 10)
                      {
                          if (Utilities.IsEnabled("r.champ.whitelist" + enemy.ChampionName))
                          {
                              spells[Spells.R].Cast(enemy);
                          }
                      }
                      if (Utilities.Player.CountEnemiesInRange(spells[Spells.R].Range) >= Utilities.SliderValue("r.min.hit"))
                      {
                          if (Utilities.IsEnabled("r.champ.whitelist" + enemy.ChampionName))
                          {
                              spells[Spells.R].CastIfWillHit(enemy, Utilities.SliderValue("r.min.hit"));
                          }
                      }
                  }
              }
          }
  
          public static void OnHarass()
          {
              if (spells[Spells.Q].IsReady() && Utilities.IsEnabled("q.harass"))
              {
                  foreach (var enemy in HeroManager.Enemies.Where(x => x.IsValidTarget(Utilities.Player.AttackRange)))
                  {
                      spells[Spells.Q].Cast(enemy);
                  }
              }
  
              if (spells[Spells.W].IsReady() && Utilities.IsEnabled("w.harass"))
              {
                  foreach (var enemy in HeroManager.Enemies.Where(x => x.IsValidTarget(spells[Spells.W].Range)))
                  {
                      spells[Spells.W].PredictionCast(enemy, Utilities.TheHitChance("sel.hitchance.w"), "sel.predict.w", Menus.menuCfg);
                  }
              }
  
              if (spells[Spells.E].IsReady() && Utilities.IsEnabled("e.combo"))
              {
                  foreach (var enemy in HeroManager.Enemies.Where(x => x.IsValidTarget(ERange + spells[Spells.E].Range)))
                  {
                      HitEnemy_E(enemy, Utilities.TheHitChance("sel.hitchance.e"));
                  }
              }
          }
  
          public static void OnLaneClear()
          {
              if (spells[Spells.E].IsReady() && Utilities.IsEnabled("e.clear"))
              {
                  PredictionCastEOnMinion();
              }
          }
  
          public static void OnJungleClear()
          {
              if (spells[Spells.Q].IsReady())
              {
                  foreach (var minion in MinionManager.GetMinions(Utilities.Player.Position, Utilities.Player.AttackRange, MinionTypes.All, MinionTeam.Neutral, MinionOrderTypes.MaxHealth))
                  {
                      spells[Spells.Q].Cast(minion);
                  }
              }
              if (spells[Spells.E].IsReady() && Utilities.IsEnabled("e.clear"))
              {
                  PredictionCastEOnJungle();
              }
          }
  
          private static void OnAntiGapCloser(ActiveGapcloser gGapCloser)
          {
              switch (gGapCloser.Sender.ChampionName)
              {
                  case "LeBlanc":
                      if (Utilities.IsEnabled("w.gapcloser")
                          && gGapCloser.Sender.IsEnemy
                          && gGapCloser.Sender.HasBuff("LeblancSlide")
                          && gGapCloser.Start.Distance(Utilities.Player.Position) < Orbwalking.GetRealAutoAttackRange(Utilities.Player)
                          && spells[Spells.W].IsReady())
                      {
                          spells[Spells.W].Cast(gGapCloser.Start);
                      }
                      break;
                  default:
                      if (Utilities.IsEnabled("w.gapcloser")
                          && gGapCloser.Sender.IsEnemy
                          && gGapCloser.End.Distance(Utilities.Player.Position) < Orbwalking.GetRealAutoAttackRange(Utilities.Player)
                          && spells[Spells.W].IsReady())
                      {
                          spells[Spells.W].Cast(gGapCloser.End);
                      }
                      break;
              }
          }
  
          public static void W_OnCCandImmobile()
          {
              if (spells[Spells.W].IsReady() && Utilities.IsEnabled("w.misc"))
              {
                  foreach (var enemy in HeroManager.Enemies.Where(x => x.IsValidTarget(spells[Spells.W].Range) && x.IsEnemyImmobile()))
                  {
                      spells[Spells.W].PredictionCast(enemy, Utilities.TheHitChance("sel.hitchance.w"), "sel.predict.w", Menus.menuCfg);
                  }
              }
          }
  
          private static void CastQUnkillabeMinion()
          {
              if (!Utilities.IsEnabled("q.lasthit"))
                  return;
  
              var MinionQ = MinionManager.GetMinions(spells[Spells.Q].Range, MinionTypes.All, MinionTeam.Enemy, MinionOrderTypes.Health);
  
              if (!Utilities.Player.CanAttack || Utilities.Player.Spellbook.IsAutoAttacking)
              {
                  foreach (var minion in MinionQ)
                  {
                      if (minion.Health <= spells[Spells.Q].GetDamage(minion) && spells[Spells.Q].IsReady())
                      {
                          spells[Spells.Q].Cast();
                          Utilities.Orbwalker.ForceTarget(minion);
                      }
                  }
              }
          }
  
          private static void HitEnemy_E(Obj_AI_Base enemy, HitChance hHitChance)
          {
  
              if (Utilities.Player.ServerPosition.Distance(enemy.ServerPosition) < ERange)
              {
                  spells[Spells.E].UpdateSourcePosition(enemy.ServerPosition, enemy.ServerPosition);
                  var prediction = spells[Spells.E].GetPrediction(enemy, true);
                  if (prediction.Hitchance >= hHitChance)
                  {
                      spells[Spells.E].Cast(enemy.ServerPosition, prediction.CastPosition);
                  }
              }
              else if (Utilities.Player.ServerPosition.Distance(enemy.ServerPosition) < spells[Spells.E].Range + ERange)
              {
                  var castStartPos = Utilities.Player.ServerPosition.Extend(enemy.ServerPosition, ERange);
                  spells[Spells.E].UpdateSourcePosition(castStartPos, castStartPos);
                  var prediction = spells[Spells.E].GetPrediction(enemy, true);
                  if (prediction.Hitchance >= hHitChance)
                  {
                      spells[Spells.E].Cast(castStartPos, prediction.CastPosition);
                  }
              }
          }
  
          private static void OnInterruptableTarget(AIHeroClient sender, Interrupter2.InterruptableTargetEventArgs args)
          {
              if (args.DangerLevel >= Interrupter2.DangerLevel.High)
              {
                  if (Utilities.IsEnabled("r.interrupt") && sender.IsValidTarget(spells[Spells.R].Range) && spells[Spells.R].Instance.Name == "ViktorChaosStorm")
                  {
                      spells[Spells.R].Cast(sender);
                  }
              }
          }
  
          public static float CalculateDamage(Obj_AI_Base enemy)
          {
              var QAADamage = new double[] { 20, 40, 60, 80, 100 };
              double damage = 0;
  
              if (Utilities.IsEnabled("q.combo") && spells[Spells.Q].IsReady())
              {
                  damage += spells[Spells.Q].GetDamage(enemy);
              }
  
              if (spells[Spells.Q].IsReady() || Utilities.Player.HasBuff("viktorpowertransferreturn") && Utilities.IsEnabled("q.combo"))
              {
                  damage += (float)Utilities.Player.CalcDamage(enemy, Damage.DamageType.Magical,
                      QAADamage[Utilities.Player.Level >= 18 ? 18 - 1 : Utilities.Player.Level - 1] +
                      (Utilities.Player.TotalMagicalDamage * .5) /*+ Utilities.Player.TotalAttackDamage()*/);
              }
  
              if (spells[Spells.E].IsReady() && Utilities.IsEnabled("e.combo"))
              {
                  if (Utilities.Player.HasBuff("viktoreaug") || Utilities.Player.HasBuff("viktorqeaug") || Utilities.Player.HasBuff("viktorqweaug"))
                  {
                      damage += spells[Spells.E].GetDamage(enemy, 1);
                  }
                  else
                  {
                      damage += spells[Spells.E].GetDamage(enemy, 0);
                  }
              }
  
              if (spells[Spells.R].IsReady() && Utilities.IsEnabled("r.combo"))
              {
                  damage += spells[Spells.R].GetDamage(enemy);
                  damage += spells[Spells.R].GetDamage(enemy, 2);
              }
  
              // Ludens Echo
              if (Items.HasItem(3285))
                  damage += Utilities.Player.CalcDamage(enemy, Damage.DamageType.Magical, 100 + Utilities.Player.FlatMagicDamageMod * 0.1);
  
              // Sheen
              if (Items.HasItem(3057))
                  damage += Utilities.Player.CalcDamage(enemy, Damage.DamageType.Physical, 0.5 * Utilities.Player.BaseAttackDamage);
  
              //Lich Bane
              if (Items.HasItem(3100))
                  damage += Utilities.Player.CalcDamage(enemy, Damage.DamageType.Magical, 0.5 * Utilities.Player.FlatMagicDamageMod + 0.75 * Utilities.Player.BaseAttackDamage);
  
              return (float)damage;
          }
  
          public static FarmLocation GetBestLaserFarmLocation(bool jungle)
          {
  
gt:             var bestEndPos = new Vector2();