context: #region
  
  using System;
  using System.Collections.Generic;
  using System.Data.SqlTypes;
  using System.Linq;
  using System.Reflection.Emit;
  using System.Security.AccessControl;
  using LeagueSharp;
  using LeagueSharp.Common;
  using SharpDX;
  using Color = System.Drawing.Color;
  using EloBuddy;
  
  #endregion
  
  namespace Orianna
  {
      internal class Program
      {
          public const string ChampionName = "Orianna";
  
          public static Orbwalking.Orbwalker Orbwalker;
  
          public static Spell Q;
          public static Spell W;
          public static Spell E;
          public static Spell R;
  
          public static bool QIsReady;
          public static bool WIsReady;
          public static bool EIsReady;
          public static bool RIsReady;
  
          public static Menu Config;
  
          private static AIHeroClient Player;
  
          private static Dictionary<string, string> InitiatorsList = new Dictionary<string, string>
          {
              {"aatroxq", "Aatrox"},
              {"akalishadowdance", "Akali"},
              {"headbutt", "Alistar"},
              {"bandagetoss", "Amumu"},
              {"dianateleport", "Diana"},
              {"ekkoe", "ekko"},
              {"elisespidereinitial", "Elise"},
              {"crowstorm", "FiddleSticks"},
              {"fioraq", "Fiora"},
              {"gnare", "Gnar"},
              {"gnarbige", "Gnar"},
              {"gragase", "Gragas"},
              {"hecarimult", "Hecarim"},
              {"ireliagatotsu", "Irelia"},
              {"jarvanivdragonstrike", "JarvanIV"},
              {"jaxleapstrike", "Jax"},
              {"riftwalk", "Kassadin"},
              {"katarinae", "Katarina"},
              {"kennenlightningrush", "Kennen"},
              {"khazixe", "KhaZix"},
              {"khazixelong", "KhaZix"},
              {"blindmonkqtwo", "LeeSin"},
              {"leonazenithblademissle", "Leona"},
              {"lissandrae", "Lissandra"},
              {"ufslash", "Malphite"},
              {"maokaiunstablegrowth", "Maokai"},
              {"monkeykingnimbus", "MonkeyKing"},
              {"monkeykingspintowin", "MonkeyKing"},
              {"summonerflash", "MonkeyKing"},
              {"nocturneparanoia", "Nocturne"},
              {"olafragnarok", "Olaf"},
              {"poppyheroiccharge", "Poppy"},
              {"renektonsliceanddice", "Renekton"},
              {"rengarr", "Rengar"},
              {"reksaieburrowed", "RekSai"},
              {"sejuaniarcticassault", "Sejuani"},
              {"shenshadowdash", "Shen"},
              {"shyvanatransformcast", "Shyvana"},
              {"shyvanatransformleap", "Shyvana"},
              {"sionr", "Sion"},
              {"taloncutthroat", "Talon"},
              {"threshqleap", "Thresh"},
              {"slashcast", "Tryndamere"},
              {"udyrbearstance", "Udyr"},
              {"urgotswap2", "Urgot"},
              {"viq", "Vi"},
              {"vir", "Vi"},
              {"volibearq", "Volibear"},
              {"infiniteduress", "Warwick"},
              {"yasuorknockupcombow", "Yasuo"},
              {"zace", "Zac"}
          };
  
          public static void Game_OnGameLoad()
          {
              Player = ObjectManager.Player;
  
              if (Player.ChampionName != ChampionName) return;
  
              Q = new Spell(SpellSlot.Q, 825);
              W = new Spell(SpellSlot.W, 245);
              E = new Spell(SpellSlot.E, 1095);
              R = new Spell(SpellSlot.R, 380);
  
              Q.SetSkillshot(0f, 130f, 1400f, false, SkillshotType.SkillshotCircle);
              W.SetSkillshot(0.25f, 240f, float.MaxValue, false, SkillshotType.SkillshotCircle);
              E.SetSkillshot(0.25f, 80f, 1700f, false, SkillshotType.SkillshotLine);
              R.SetSkillshot(0.6f, 375f, float.MaxValue, false, SkillshotType.SkillshotCircle);
  
  
              Config = new Menu(ChampionName, ChampionName, true);
              TargetSelector.AddToMenu(Config.SubMenu("Target Selector"));
              Orbwalker = new Orbwalking.Orbwalker(Config.SubMenu("Orbwalking"));
  
              #region Combo
              Config.SubMenu("Combo").AddItem(new MenuItem("UseQCombo", "Use Q").SetValue(true));
              Config.SubMenu("Combo").AddItem(new MenuItem("UseWCombo", "Use W").SetValue(true));
              Config.SubMenu("Combo").AddItem(new MenuItem("UseECombo", "Use E").SetValue(true));
              Config.SubMenu("Combo").AddItem(new MenuItem("UseRCombo", "Use R").SetValue(true));
              Config.SubMenu("Combo").AddItem(new MenuItem("UseRNCombo", "Use R on at least").SetValue(new StringList(new string[]{"1 target", "2 target", "3 target", "4 target", "5 target"}, 0)));
              Config.SubMenu("Combo").AddItem(new MenuItem("UseRImportant", "-> Or if hero priority >=")).SetValue(new Slider(5, 1, 5)); // 5 for e.g adc's
              Config.SubMenu("Combo")
                  .AddItem(
                      new MenuItem("ComboActive", "Combo!").SetValue(
                          new KeyBind(Config.Item("Orbwalk").GetValue<KeyBind>().Key, KeyBindType.Press)));
              #endregion
  
              #region Misc
              Config.SubMenu("Misc").AddItem(new MenuItem("AutoW", "Auto W if it'll hit").SetValue(new StringList(new string[] { "No", ">=1 target", ">=2 target", ">=3 target", ">=4 target", ">=5 target" }, 2)));
              Config.SubMenu("Misc").AddItem(new MenuItem("AutoR", "Auto R if it'll hit").SetValue(new StringList(new string[] { "No", ">=1 target", ">=2 target", ">=3 target", ">=4 target", ">=5 target" }, 3)));
              Config.SubMenu("Misc").AddItem(new MenuItem("AutoEInitiators", "Auto E initiators").SetValue(true));
  
              HeroManager.Allies.ForEach(
                  delegate(AIHeroClient hero)
                  {
                      InitiatorsList.ToList().ForEach(
                          delegate(KeyValuePair<string, string> pair)
                          {
                              if (string.Equals(hero.ChampionName, pair.Value, StringComparison.InvariantCultureIgnoreCase))
                              {
                                  Config.SubMenu("Misc")
                                      .SubMenu("Initiator's List")
                                      .AddItem(new MenuItem(pair.Key, pair.Value + " - " + pair.Key).SetValue(true));
                              }
                          });
                  });
              
              Config.SubMenu("Misc").AddItem(new MenuItem("InterruptSpells", "Interrupt spells using R").SetValue(true));
              Config.SubMenu("Misc").AddItem(new MenuItem("BlockR", "Block R if it won't hit").SetValue(false));
              #endregion
  
              #region Harass
              //Harass menu:
              Config.SubMenu("Harass").AddItem(new MenuItem("UseQHarass", "Use Q").SetValue(true));
              Config.SubMenu("Harass").AddItem(new MenuItem("UseWHarass", "Use W").SetValue(false));
              Config.SubMenu("Harass").AddItem(new MenuItem("HarassManaCheck", "Don't harass if mana < %").SetValue(new Slider(0, 0, 100)));
              Config.SubMenu("Harass")
                  .AddItem(
                      new MenuItem("HarassActive", "Harass!").SetValue(
                          new KeyBind(Config.Item("Farm").GetValue<KeyBind>().Key, KeyBindType.Press)));
              Config.SubMenu("Harass")
                  .AddItem(
                      new MenuItem("HarassActiveT", "Harass (toggle)!").SetValue(new KeyBind("Y".ToCharArray()[0],
                          KeyBindType.Toggle)));
              #endregion
  
              #region Farming
              //Farming menu:
              Config.SubMenu("Farm").AddItem(new MenuItem("EnabledFarm", "Enable! (On/Off: Mouse Scroll)").SetValue(true));
              Config.SubMenu("Farm")
                  .AddItem(
                      new MenuItem("UseQFarm", "Use Q").SetValue(
                          new StringList(new[] { "Freeze", "LaneClear", "Both", "No" }, 2)));
              Config.SubMenu("Farm")
                  .AddItem(
                      new MenuItem("UseWFarm", "Use W").SetValue(
                          new StringList(new[] { "Freeze", "LaneClear", "Both", "No" }, 1)));
              Config.SubMenu("Farm")
                  .AddItem(
                      new MenuItem("UseEFarm", "Use E").SetValue(
                          new StringList(new[] { "Freeze", "LaneClear", "Both", "No" }, 1)));
              Config.SubMenu("Farm").AddItem(new MenuItem("LaneClearManaCheck", "Don't LaneClear if mana < %").SetValue(new Slider(0, 0, 100)));
              
              Config.SubMenu("Farm")
                  .AddItem(
                      new MenuItem("FreezeActive", "Freeze!").SetValue(
                          new KeyBind(Config.Item("Farm").GetValue<KeyBind>().Key, KeyBindType.Press)));
              Config.SubMenu("Farm")
                  .AddItem(
                      new MenuItem("LaneClearActive", "LaneClear!").SetValue(
                          new KeyBind(Config.Item("LaneClear").GetValue<KeyBind>().Key, KeyBindType.Press)));
  
              //JungleFarm menu:
              Config.AddSubMenu(new Menu("JungleFarm", "JungleFarm"));
              Config.SubMenu("JungleFarm").AddItem(new MenuItem("UseQJFarm", "Use Q").SetValue(true));
              Config.SubMenu("JungleFarm").AddItem(new MenuItem("UseWJFarm", "Use W").SetValue(true));
              Config.SubMenu("JungleFarm").AddItem(new MenuItem("UseEJFarm", "Use E").SetValue(true));
              Config.SubMenu("JungleFarm")
                  .AddItem(
                      new MenuItem("JungleFarmActive", "JungleFarm!").SetValue(
                          new KeyBind(Config.Item("LaneClear").GetValue<KeyBind>().Key, KeyBindType.Press)));
              #endregion
  
              #region Drawings
              //Damage after combo:
              var dmgAfterComboItem = new MenuItem("DamageAfterR", "Draw damage after combo").SetValue(true);
              //LeagueSharp.Common.Utility.HpBar//DamageIndicator.DamageToUnit += hero => GetComboDamage(hero);
              //LeagueSharp.Common.Utility.HpBar//DamageIndicator.Enabled = dmgAfterComboItem.GetValue<bool>();
              dmgAfterComboItem.ValueChanged += delegate(object sender, OnValueChangeEventArgs eventArgs)
              {
                  //LeagueSharp.Common.Utility.HpBar//DamageIndicator.Enabled = eventArgs.GetNewValue<bool>();
              };
  
              
              //Drawings menu:
              Config.SubMenu("Drawings")
                  .AddItem(
                      new MenuItem("QRange", "Q range").SetValue(new Circle(true, Color.FromArgb(150, Color.DodgerBlue))));
              Config.SubMenu("Drawings")
                  .AddItem(
                      new MenuItem("WRange", "W range").SetValue(new Circle(false, Color.FromArgb(150, Color.DodgerBlue))));
              Config.SubMenu("Drawings")
                  .AddItem(
                      new MenuItem("ERange", "E range").SetValue(new Circle(false, Color.FromArgb(150, Color.DodgerBlue))));
              Config.SubMenu("Drawings")
                  .AddItem(
                      new MenuItem("RRange", "R range").SetValue(new Circle(false, Color.FromArgb(150, Color.DodgerBlue))));
              Config.SubMenu("Drawings")
                  .AddItem(
                      new MenuItem("QOnBallRange", "Draw ball position").SetValue(new Circle(true, Color.FromArgb(150, Color.DodgerBlue))));
              Config.SubMenu("Drawings")
                  .AddItem(dmgAfterComboItem);
              Config.SubMenu("Drawings")
                  .AddItem(
                      new MenuItem("HarassActiveTPermashow", "Show harass permashow").SetValue(true)).ValueChanged += (s, ar) =>
                      {
                          if (ar.GetNewValue<bool>())
                          {
                              Config.Item("HarassActiveT").Permashow(true, "HarassActive");
                          }
                          else
                          {
                              Config.Item("HarassActiveT").Permashow(false);
                          }
                      };
  
              Config.Item("HarassActiveT").Permashow(Config.Item("HarassActiveTPermashow").GetValue<bool>(), "HarassActive");
  
              Config.SubMenu("Drawings")
                  .AddItem(
                      new MenuItem("EnabledFarmPermashow", "Show farm permashow").SetValue(true)).ValueChanged +=
                  (s, ar) =>
                  {
                      if (ar.GetNewValue<bool>())
                      {
                          Config.Item("EnabledFarm").Permashow(true, "Enabled Farm");
                      }
                      else
                      {
                          Config.Item("EnabledFarm").Permashow(false);
                      }
                  };
              Config.Item("EnabledFarm").Permashow(Config.Item("EnabledFarmPermashow").GetValue<bool>(), "Enabled Farm");
              
              #endregion
  
              Config.AddToMainMenu();
  
              AIHeroClient.OnSpellCast += AIHeroClient_OnProcessSpellCast;
              Game.OnUpdate += Game_OnGameUpdate;
              Game.OnWndProc += Game_OnWndProc;
              Drawing.OnDraw += Drawing_OnDraw;
              Spellbook.OnCastSpell += Spellbook_OnCastSpell;
              Interrupter2.OnInterruptableTarget += Interrupter2_OnInterruptableTarget;
          }
          
          private static void Game_OnWndProc(WndEventArgs args)
          {
              if (args.Msg != 0x20a)
                  return;
  
              Config.SubMenu("Farm")
                  .Item("EnabledFarm")
                  .SetValue(!Config.SubMenu("Farm").Item("EnabledFarm").GetValue<bool>());
          }
  
  
          static void Interrupter2_OnInterruptableTarget(AIHeroClient sender, Interrupter2.InterruptableTargetEventArgs args)
          {
              if (!Config.Item("InterruptSpells").GetValue<bool>())
              {
                  return;
              }
  
              if (args.DangerLevel <= Interrupter2.DangerLevel.Medium)
              {
                  return;
              }
  
              if (sender.IsAlly)
              {
                  return;
              }
  
              if (RIsReady)
              {
                  Q.Cast(sender, true);
                  if (BallManager.BallPosition.Distance(sender.ServerPosition, true) < R.Range * R.Range)
                  {
                      R.Cast(Player.ServerPosition, true);
                  }
              }
          }
  
          static void AIHeroClient_OnProcessSpellCast(Obj_AI_Base sender, GameObjectProcessSpellCastEventArgs args)
          {
              if (!(sender is AIHeroClient))
              {
                  return;
              }
  
              if (!Config.SubMenu("Misc").Item("AutoEInitiators").GetValue<bool>())
              {
                  return;
              }
  
              var spellName = args.SData.Name.ToLower();
              if (!InitiatorsList.ContainsKey(spellName))
              {
                  return;
              }
  
              var item = Config.SubMenu("Misc").SubMenu("Initiator's List").Item(spellName);
              if (item == null || !item.GetValue<bool>())
              {
                  return;
              }
  
              if (!EIsReady)
              {
                  return;
              }
  
              if (sender.IsAlly && Player.Distance(sender, true) < E.Range * E.Range)
              {
                  E.CastOnUnit(sender);
              }
          }
  
          static void Spellbook_OnCastSpell(Spellbook sender, SpellbookCastSpellEventArgs args)
          {
              if (!Config.Item("BlockR").GetValue<bool>())
              {
                  return;
              }
  
              if (args.Slot == SpellSlot.R && GetHits(R).Item1 == 0)
              {
                  args.Process = false;
              }
          }
  
          private static void Farm(bool laneClear)
          {
              if (!Config.Item("EnabledFarm").GetValue<bool>())
              {
                  return;
              }
  
              var allMinions = MinionManager.GetMinions(ObjectManager.Player.ServerPosition, Q.Range + W.Width,
                  MinionTypes.All);
              var rangedMinions = MinionManager.GetMinions(ObjectManager.Player.ServerPosition, Q.Range + W.Width,
                  MinionTypes.Ranged);
  
              var useQi = Config.Item("UseQFarm").GetValue<StringList>().SelectedIndex;
              var useWi = Config.Item("UseWFarm").GetValue<StringList>().SelectedIndex;
              var useEi = Config.Item("UseWFarm").GetValue<StringList>().SelectedIndex;
  
              var useQ = (laneClear && (useQi == 1 || useQi == 2)) || (!laneClear && (useQi == 0 || useQi == 2));
              var useW = (laneClear && (useWi == 1 || useWi == 2)) || (!laneClear && (useWi == 0 || useWi == 2));
              var useE = (laneClear && (useEi == 1 || useEi == 2)) || (!laneClear && (useEi == 0 || useEi == 2));
  
              if (useQ && QIsReady)
              {
                  if (useW)
                  {
                      var qLocation = Q.GetCircularFarmLocation(allMinions, W.Range);
                      var q2Location = Q.GetCircularFarmLocation(rangedMinions, W.Range);
                      var bestLocation = (qLocation.MinionsHit > q2Location.MinionsHit + 1) ? qLocation : q2Location;
  
                      if (bestLocation.MinionsHit > 0)
                      {
                          Q.Cast(bestLocation.Position, true);
                          return;
                      }
                  }
                  else
                  {
                      foreach (var minion in allMinions.FindAll(m => !Orbwalking.InAutoAttackRange(m)))
                      {
                          if (HealthPrediction.GetHealthPrediction(minion, Math.Max((int)(minion.ServerPosition.Distance(BallManager.BallPosition) / Q.Speed * 1000) - 100, 0)) < 50)
                          {
                              Q.Cast(minion.ServerPosition, true);
                              return;
                          }
                      }
                  }
              }
  
              if (useW && WIsReady)
              {
                  var n = 0;
                  var d = 0;
                  foreach (var m in allMinions)
                  {
                      if (m.Distance(BallManager.BallPosition) <= W.Range)
                      {
                          n++;
                          if (W.GetDamage(m) > m.Health)
                          {
                              d++;
                          }
                      }
                  }
                  if (n >= 3 || d >= 2)
                  {
                      W.Cast(Player.ServerPosition, true);
                      return;
                  }
              }
  
              if (useE && EIsReady)
              {
                  if (W.CountHits(allMinions, Player.ServerPosition) >= 3)
                  {
                      E.CastOnUnit(Player, true);
                      return;
                  }
              }
          }
  
          private static void JungleFarm()
          {
              var useQ = Config.Item("UseQJFarm").GetValue<bool>();
              var useW = Config.Item("UseWJFarm").GetValue<bool>();
              var useE = Config.Item("UseEJFarm").GetValue<bool>();
  
              var mobs = MinionManager.GetMinions(Player.ServerPosition, Q.Range, MinionTypes.All,
                  MinionTeam.Neutral, MinionOrderTypes.MaxHealth);
  
              if (mobs.Count > 0)
              {
                  var mob = mobs[0];
                  if (useW && WIsReady && W.WillHit(mob.ServerPosition, BallManager.BallPosition))
                  {
                      W.Cast(Player.ServerPosition, true);
                  }
                  else if (useQ && QIsReady)
                  {
                      Q.Cast(mob, true);
                  }
                  else if (useE && EIsReady && (!WIsReady || !useW))
                  {
                      var closestAlly = HeroManager.Allies
                          .Where(h =>  h.IsValidTarget(E.Range, false))
                          .MinOrDefault(h => h.Distance(mob));
                      if (closestAlly != null)
                      {
                          E.CastOnUnit(closestAlly, true);
                      }
                  }
              }
          }
  
          public static Tuple<int, Vector3> GetBestQLocation(AIHeroClient mainTarget)
          {
              var points = new List<Vector2>();
              var qPrediction = Q.GetPrediction(mainTarget);
              if (qPrediction.Hitchance < HitChance.VeryHigh)
              {
                  return new Tuple<int, Vector3>(1, Vector3.Zero);
              }
              points.Add(qPrediction.UnitPosition.To2D());
  
              foreach (var enemy in HeroManager.Enemies.Where(h => h.IsValidTarget(Q.Range + R.Range)))
              {
                  var prediction = Q.GetPrediction(enemy);
                  if (prediction.Hitchance >= HitChance.High)
                  {
                     points.Add(prediction.UnitPosition.To2D()); 
                  }
              }
  
              for (int j = 0; j < 5; j++)
              {
                  var mecResult = MEC.GetMec(points);
                  
                  if (mecResult.Radius < (R.Range - 75) && points.Count >= 3 && RIsReady)
                  {
                      return new Tuple<int, Vector3>(3, mecResult.Center.To3D());
                  }
  
                  if (mecResult.Radius < (W.Range - 75) && points.Count >= 2 && WIsReady)
                  {
                      return new Tuple<int, Vector3>(2, mecResult.Center.To3D());
                  }
  
                  if (points.Count == 1)
                  {
                      return new Tuple<int, Vector3>(1, mecResult.Center.To3D());
                  }
  
                  if (mecResult.Radius < Q.Width && points.Count == 2)
                  {
  
gt:                     return new Tuple<int, Vector3>(2, mecResult.Center.To3D());