context: #region License
  
  /*
   Copyright 2014 - 2015 Nikita Bernthaler
   Champion.cs is part of SFXKogMaw.
  
   SFXKogMaw is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.
  
   SFXKogMaw is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   GNU General Public License for more details.
  
   You should have received a copy of the GNU General Public License
   along with SFXKogMaw. If not, see <http://www.gnu.org/licenses/>.
  */
  
  #endregion License
  
  #region
  
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using LeagueSharp;
  using LeagueSharp.Common;
  using SFXKogMaw.Enumerations;
  using SFXKogMaw.Interfaces;
  using SFXKogMaw.Library.Logger;
  using SFXKogMaw.Managers;
  using SFXKogMaw.Menus;
  using MinionManager = SFXKogMaw.Library.MinionManager;
  using MinionOrderTypes = SFXKogMaw.Library.MinionOrderTypes;
  using MinionTeam = SFXKogMaw.Library.MinionTeam;
  using MinionTypes = SFXKogMaw.Library.MinionTypes;
  using Orbwalking = SFXKogMaw.SFXTargetSelector.Orbwalking;
  using Spell = SFXKogMaw.Wrappers.Spell;
  using TargetSelector = SFXKogMaw.SFXTargetSelector.TargetSelector;
  
  #endregion
  
  namespace SFXKogMaw.Abstracts
  {
      internal abstract class Champion : IChampion
      {
          private static float _minionSearchRange;
          protected readonly Obj_AI_Hero Player;
          private Obj_AI_Base _nearestMinion;
          private List<Spell> _spells;
          private bool _useMuramana;
          protected Spell E;
          protected Spell Q;
          protected Spell R;
          protected UltimateManager Ultimate;
          protected Spell W;
  
          protected Champion()
          {
              Player = ObjectManager.Player;
              Core.OnBoot += OnCoreBoot;
          }
  
          protected abstract ItemFlags ItemFlags { get; }
          protected abstract ItemUsageType ItemUsage { get; }
          public Menu SFXMenu { get; private set; }
  
          public List<Spell> Spells
          {
              get { return _spells ?? (_spells = new List<Spell> { Q, W, E, R }); }
          }
  
          public Menu Menu { get; private set; }
          public Orbwalking.Orbwalker Orbwalker { get; private set; }
  
          void IChampion.Combo()
          {
              try
              {
                  Combo();
              }
              catch (Exception ex)
              {
                  Global.Logger.AddItem(new LogItem(ex));
              }
          }
  
          void IChampion.Harass()
          {
              try
              {
                  Harass();
              }
              catch (Exception ex)
              {
                  Global.Logger.AddItem(new LogItem(ex));
              }
          }
  
          void IChampion.LaneClear()
          {
              try
              {
                  if (_nearestMinion == null || !_nearestMinion.IsValid || _nearestMinion.Team != Player.Team)
                  {
                      LaneClear();
                  }
              }
              catch (Exception ex)
              {
                  Global.Logger.AddItem(new LogItem(ex));
              }
          }
  
          void IChampion.JungleClear()
          {
              try
              {
                  if (_nearestMinion == null || !_nearestMinion.IsValid || _nearestMinion.Team == GameObjectTeam.Neutral)
                  {
                      JungleClear();
                  }
              }
              catch (Exception ex)
              {
                  Global.Logger.AddItem(new LogItem(ex));
              }
          }
  
          void IChampion.Flee()
          {
              try
              {
                  Orbwalker.SetAttack(false);
                  Orbwalking.MoveTo(Game.CursorPos, Orbwalker.HoldAreaRadius);
                  Flee();
                  Utility.DelayAction.Add(
                      750, delegate
                      {
                          if (Orbwalker.ActiveMode == Orbwalking.OrbwalkingMode.Flee)
                          {
                              ItemManager.UseFleeItems();
                          }
                      });
                  Utility.DelayAction.Add(
                      125, delegate
                      {
                          if (Orbwalker.ActiveMode != Orbwalking.OrbwalkingMode.Flee)
                          {
                              Orbwalker.SetAttack(true);
                          }
                      });
              }
              catch (Exception ex)
              {
                  Global.Logger.AddItem(new LogItem(ex));
              }
          }
  
          void IChampion.Killsteal()
          {
              try
              {
                  Killsteal();
                  KillstealManager.Killsteal();
              }
              catch (Exception ex)
              {
                  Global.Logger.AddItem(new LogItem(ex));
              }
          }
  
          protected virtual void OnCorePreUpdate(EventArgs args)
          {
              try
              {
                  if (Orbwalker.ActiveMode == Orbwalking.OrbwalkingMode.LaneClear)
                  {
                      _nearestMinion =
                          MinionManager.GetMinions(
                              _minionSearchRange, MinionTypes.All, MinionTeam.NotAlly, MinionOrderTypes.None)
                              .OrderBy(m => m.Distance(Player))
                              .FirstOrDefault();
                  }
                  if (!_useMuramana)
                  {
                      ItemManager.Muramana(null, false);
                  }
                  if (_useMuramana && Orbwalker.ActiveMode == Orbwalking.OrbwalkingMode.Combo)
                  {
                      ItemManager.Muramana(null, true, float.MaxValue);
                      Utility.DelayAction.Add(1000 + Game.Ping, () => _useMuramana = false);
                  }
                  OnPreUpdate();
              }
              catch (Exception ex)
              {
                  Global.Logger.AddItem(new LogItem(ex));
              }
          }
  
          protected virtual void OnCorePostUpdate(EventArgs args)
          {
              try
              {
                  OnPostUpdate();
              }
              catch (Exception ex)
              {
                  Global.Logger.AddItem(new LogItem(ex));
              }
          }
  
          protected void ItemsSummonersLogic(Obj_AI_Hero ultimateTarget, bool single = true)
          {
              try
              {
                  var range = Math.Max(
                      600,
                      Math.Max(
                          SummonerManager.SummonerSpells.Where(s => s.CastType == CastType.Target).Max(s => s.Range),
                          ItemManager.Items.Where(
                              i => i.EffectFlags.HasFlag(EffectFlags.Damage) && i.Flags.HasFlag(ItemFlags.Offensive))
                              .Max(i => i.Range)));
                  if (ultimateTarget == null || Ultimate == null || !ultimateTarget.IsValidTarget(range))
                  {
                      var target = TargetSelector.GetTarget(range);
                      if (target != null)
                      {
                          if (ItemManager.CalculateComboDamage(target) + SummonerManager.CalculateComboDamage(target) >
                              target.Health)
                          {
                              ItemManager.UseComboItems(target);
                              SummonerManager.UseComboSummoners(target);
                          }
                      }
                  }
                  else
                  {
                      if (Ultimate.GetDamage(ultimateTarget, UltimateModeType.Combo, single ? 1 : 5) >
                          ultimateTarget.Health)
                      {
                          ItemManager.UseComboItems(ultimateTarget);
                          SummonerManager.UseComboSummoners(ultimateTarget);
                      }
                  }
              }
              catch (Exception ex)
              {
                  Global.Logger.AddItem(new LogItem(ex));
              }
          }
  
          protected abstract void OnLoad();
          protected abstract void SetupSpells();
          protected abstract void AddToMenu();
          protected abstract void OnPreUpdate();
          protected abstract void OnPostUpdate();
          protected abstract void Combo();
          protected abstract void Harass();
          protected abstract void LaneClear();
          protected abstract void JungleClear();
          protected abstract void Flee();
          protected abstract void Killsteal();
  
          private void OnCoreBoot(EventArgs args)
          {
              try
              {
                  OnLoad();
                  SetupSpells();
                  SetupMenu();
  
                  _minionSearchRange = Math.Min(
                      2000,
                      Math.Max(
                          ObjectManager.Player.AttackRange + ObjectManager.Player.BoundingRadius * 2,
                          Spells.Select(spell => spell.IsChargedSpell ? spell.ChargedMaxRange : spell.Range)
                              .Concat(new[] { _minionSearchRange })
                              .Max()));
  
                  TargetSelector.Weights.Range = Math.Max(
                      TargetSelector.Weights.Range,
                      Spells.Select(e => e.Range).DefaultIfEmpty(Orbwalking.GetRealAutoAttackRange(null) * 1.2f).Max());
  
                  Core.OnPreUpdate += OnCorePreUpdate;
                  Core.OnPostUpdate += OnCorePostUpdate;
  
                  Orbwalking.BeforeAttack += OnOrbwalkingBeforeAttack;
                  Orbwalking.AfterAttack += OnOrbwalkingAfterAttack;
  
gt:                 Obj_AI_Base.OnProcessSpellCast += OnObjAiBaseProcessSpellCast;