using System;
using Server;
using Server.Spells;
using Server.Network;
using Server.Mobiles;
using Server.Gumps;
using System.Collections.Generic;
using Server.Items;

namespace Server.Spells.SkillMasteries
{
    public class BodyGuardSpell : SkillMasterySpell
    {
        private static SpellInfo m_Info = new SpellInfo(
                "Body Guard", "",
                -1,
                9002
            );
 
        public override int RequiredMana { get { return 40; } }
        public override int DisruptMessage { get { return 1156103; } } // Bodyguard has expired.
        public override bool BlocksMovement { get { return false; } }
        public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds(1.0); } }

        public override SkillName CastSkill { get { return SkillName.Parry; } }
 
		private double _Block;
 
        public BodyGuardSpell(Mobile caster, Item scroll)
            : base(caster, scroll, m_Info)
        {
        }
		
		public override bool CheckCast()
		{
            if (_Table != null && _Table.ContainsKey(Caster))
            {
                RemoveGumpTimer(_Table[Caster], Caster);
                return false;
            }

			BodyGuardSpell spell = GetSpell(Caster, this.GetType()) as BodyGuardSpell;
			
			if(spell != null)
			{
				spell.Expire(true);
				return false;
			}

            if (!HasShield())
                return false;
			
			return base.CheckCast();
		}
 
        public override void OnCast()
        {
            if (Caster is BaseCreature && ((BaseCreature)Caster).ControlMaster != null)
            {
                var master = ((BaseCreature)Caster).ControlMaster;

                if (Caster.CanSee(master) && Caster.InRange(master.Location, 8))
                {
                    SpellHelper.Turn(Caster, master);
                    OnTarget(master);
                }
            }
            else
            {
                Caster.BeginTarget(8, false, Server.Targeting.TargetFlags.None, (m, o) =>
                    {
                        if (!Caster.CanSee(o))
                        {
                            Caster.SendLocalizedMessage(500237); // Target can not be seen.
                        }
                        else
                        {
                            SpellHelper.Turn(Caster, o);
                            OnTarget(o);
                        }
                    });
            }
        }
		
		protected override void OnTarget(object o)
		{
            if (!HasShield())
                return;

            Mobile protectee = o as Mobile;
            Mobile master = null;

            if (protectee is BaseCreature && !((BaseCreature)protectee).Summoned && ((BaseCreature)protectee).GetMaster() is PlayerMobile)
                master = ((BaseCreature)protectee).GetMaster();

            if (protectee != null)
			{
                BodyGuardSpell spell = GetSpell(s => s.GetType() == typeof(BodyGuardSpell) && s.Target == protectee) as BodyGuardSpell;
				
				if(spell != null)
				{
					Caster.SendLocalizedMessage(1156094); // Your target is already under the effect of this ability.
				}
                if (!protectee.Alive)
				{
					Caster.SendLocalizedMessage( 501857 ); // This spell won't work on that!
				}
				else if ( !Caster.CanBeBeneficial( protectee, true ))
				{
                    Caster.SendLocalizedMessage(1001017); // You cannot perform beneficial acts on your target.
				}
                else if (protectee != Caster)
				{
                    Mobile responsible = master != null ? master : protectee;

                    Caster.FixedParticles( 0x376A, 9, 32, 5030, 1168, 0, EffectLayer.Waist, 0 );

                    if (Caster.Player)
                    {
                        Caster.PlaySound(Caster.Female ? 0x338 : 0x44A);
                    }
                    else if (Caster is BaseCreature)
                    {
                        Caster.PlaySound(((BaseCreature)Caster).GetAngerSound());
                    }

                    if (Caster is PlayerMobile)
                    {
                        protectee.SendGump(new AcceptBodyguardGump(Caster, protectee, this));
                        AddGumpTimer(responsible, Caster);
                    }
                    else
                    {
                        AcceptBodyGuard(responsible);
                    }
				}
			}
		}

		public void AcceptBodyGuard(Mobile toGuard)
		{
            RemoveGumpTimer(toGuard, Caster);

			if(CheckBSequence(toGuard))
			{
				_Block = ((Caster.Skills[CastSkill].Value + GetWeaponSkill() + (GetMasteryLevel() * 40)) / 3) / 2.4;
                Target = toGuard;

				Expires = DateTime.UtcNow + TimeSpan.FromSeconds(90);
				BeginTimer();

                Caster.SendLocalizedMessage(1049452, "\t" + toGuard.Name); // You are now protecting ~2_NAME~.
                toGuard.SendLocalizedMessage(1049451, Caster.Name); // You are now being protected by ~1_NAME~.

                BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.Bodyguard, 1155924, 1156061, TimeSpan.FromSeconds(90), Caster, String.Format("{0}\t{1}\t{2}\t{3}", Caster.Name, ((int)(_Block + 5)).ToString(), toGuard.Name, ((int)_Block).ToString())));
                BuffInfo.AddBuff(toGuard, new BuffInfo(BuffIcon.Bodyguard, 1155924, 1156061, TimeSpan.FromSeconds(90), toGuard, String.Format("{0}\t{1}\t{2}\t{3}", Caster.Name, ((int)(_Block + 5)).ToString(), toGuard.Name, ((int)_Block).ToString())));
                //~1_NAME~ receives ~2_DAMAGE~% of all damage dealt to ~3_NAME~. All damage dealt to ~3_NAME~ will be reduced by ~4_DAMAGE~%. Body guard must be within 2 tiles. 
			}

            FinishSequence();
		}

        private bool HasShield()
        {
            if (!Caster.Player)
                return true;

            BaseShield shield = Caster.FindItemOnLayer(Layer.TwoHanded) as BaseShield;

            if (shield == null)
            {
                Caster.SendLocalizedMessage(1156096); // You must be wielding a shield to use this ability!
                return false;
            }

            return true;
        }

        public override bool OnTick()
        {
            if (!HasShield())
            {
                Expire();
                return false;
            }

            return base.OnTick();
        }

        public override void EndEffects()
        {
            if (Target != null)
            {
                Target.SendLocalizedMessage(1156103); // Bodyguard has expired.
                BuffInfo.RemoveBuff(Target, BuffIcon.Bodyguard);
            }

            Caster.SendLocalizedMessage(1156103); // Bodyguard has expired.
            BuffInfo.RemoveBuff(Caster, BuffIcon.Bodyguard);
        }

        public void DeclineBodyGuard(Mobile protectee)
        {
            Caster.SendLocalizedMessage(1049454, "\t" + protectee.Name); // ~2_NAME~ has declined your protection.
            protectee.SendLocalizedMessage(1049453, Caster.Name); // You have declined protection from ~1_NAME~.

            RemoveGumpTimer(protectee, Caster);
            FinishSequence();
        }

        public override void OnTargetDamaged(Mobile attacker, Mobile defender, DamageType type, ref int damage)
		{
            if (defender == Target && Caster.InRange(defender, 2))
			{
				double mod = (double)PropertyBonus() / 100.0;
				
				damage = damage - (int)((double)damage * mod);
                int casterDamage = damage - (int)((double)damage * (mod - .05));

                if (type >= DamageType.Spell)
                    casterDamage /= 2;

                Caster.Damage(casterDamage, attacker);
			}
		}

        public static void RemoveGumpTimer(Mobile m, Mobile caster)
        {
            if (_Table != null && _Table.ContainsKey(caster))
                _Table.Remove(caster);

            if (m.HasGump(typeof(AcceptBodyguardGump)))
            {
                m.CloseGump(typeof(AcceptBodyguardGump));
                m.SendLocalizedMessage(1156103); // Bodyguard has expired.
                caster.SendLocalizedMessage(1156103); // Bodyguard has expired.
            }
        }

        public static void AddGumpTimer(Mobile m, Mobile caster)
        {
            if (_Table == null)
                _Table = new Dictionary<Mobile, Mobile>();

            _Table[caster] = m;

            Server.Timer.DelayCall(TimeSpan.FromSeconds(10), () =>
            {
                RemoveGumpTimer(m, caster);
            });
        }

        private static Dictionary<Mobile, Mobile> _Table;
		
		public override int PropertyBonus()
		{
			return (int)_Block;
		}
    }

    public class AcceptBodyguardGump : Gump
	{
		private Mobile m_Protector;
		private Mobile m_Protectee;
        private BodyGuardSpell m_Spell;

		public AcceptBodyguardGump( Mobile protector, Mobile protectee, BodyGuardSpell spell ) : base( 150, 50 )
		{
			m_Protector = protector;
			m_Protectee = protectee;
            m_Spell = spell;

			Closable = false;

			AddPage( 0 );

			AddBackground( 0, 0, 396, 218, 3600 );

			AddImageTiled( 15, 15, 365, 190, 2624 );
			AddAlphaRegion( 15, 15, 365, 190 );

			AddHtmlLocalized( 30, 20, 360, 25, 1156099, 0x7FFF, false, false ); // Another player is offering to bodyguard you:
			AddLabel( 90, 55, 1153, String.Format("{0} will body guard {1}", protector.Name, protectee.Name));

			AddImage( 50, 45, 9005 );
			AddImageTiled( 80, 80, 200, 1, 9107 );
			AddImageTiled( 95, 82, 200, 1, 9157 );

			AddRadio( 30, 110, 9727, 9730, true, 1 );
			AddHtmlLocalized( 65, 115, 300, 25, 1049444, 0x7FFF, false, false ); // Yes, I would like their protection.

			AddRadio( 30, 145, 9727, 9730, false, 0 );
			AddHtmlLocalized( 65, 148, 300, 25, 1049445, 0x7FFF, false, false ); // No thanks, I can take care of myself.

			AddButton( 160, 175, 247, 248, 2, GumpButtonType.Reply, 0 );

			AddImage( 215, 0, 50581 );

			AddImageTiled( 15, 14, 365, 1, 9107 );
			AddImageTiled( 380, 14, 1, 190, 9105 );
			AddImageTiled( 15, 205, 365, 1, 9107 );
			AddImageTiled( 15, 14, 1, 190, 9105 );
			AddImageTiled( 0, 0, 395, 1, 9157 );
			AddImageTiled( 394, 0, 1, 217, 9155 );
			AddImageTiled( 0, 216, 395, 1, 9157 );
			AddImageTiled( 0, 0, 1, 217, 9155 );
		}

		public override void OnResponse( Server.Network.NetState sender, RelayInfo info )
		{
			if ( info.ButtonID == 2 )
			{
				bool okay = info.IsSwitched( 1 );

                if(okay)
                    m_Spell.AcceptBodyGuard(m_Protectee);
                else
                    m_Spell.DeclineBodyGuard(m_Protectee);
			}
		}
	}
}
