using Server.Engines.XmlSpawner2;
using Server.Items;
using Server.Spells;
using System;
using System.Collections;

namespace Server.Mobiles
{
    //[CorpseName("a auberon dragon corpse")]
    public class DrakAuberon : BaseCreature
    {
        private Point3D m_Target;
        private bool m_IsBoss;

        [CommandProperty(AccessLevel.GameMaster)]
        public Point3D Target
        {
            get
            {
                return m_Target;
            }
            set
            {
                m_Target = value;
            }
        }

        [CommandProperty(AccessLevel.GameMaster)]
        public bool IsBoss
        {
            get
            {
                return m_IsBoss;
            }
            set
            {
                m_IsBoss = value;
            }
        }

        public override WeaponAbility GetWeaponAbility()
        {
            switch (Utility.Random(3))
            {
                default:
                case 0: return WeaponAbility.DoubleStrike;
                case 1: return WeaponAbility.WhirlwindAttack;
                case 2: return WeaponAbility.CrushingBlow;
            }
        }

        [Constructable]
        public DrakAuberon() : base(AIType.AI_Necromage, FightMode.Closest, 10, 1, 0.2, 0.4)
        {
            Name = "Lord Auberon";
            Title = "the Ancient Dragon";
            Body = 104;
            BaseSoundID = 0x488;
            Hue = 1161;

            SetStr(700, 720);
            SetDex(1000, 1100);
            SetInt(1000, 1200);

            SetHits(199000, 199000);
            SetMana(4000, 5000);
            SetStam(4000, 4000);

            SetDamage(55, 80);

            SetDamageType(ResistanceType.Physical, 0);
            SetDamageType(ResistanceType.Poison, 30);
            SetDamageType(ResistanceType.Fire, 70);

            SetResistance(ResistanceType.Physical, 95);
            SetResistance(ResistanceType.Fire, 100);
            SetResistance(ResistanceType.Cold, 90);
            SetResistance(ResistanceType.Poison, 100);
            SetResistance(ResistanceType.Energy, 100);

            SetSkill(SkillName.EvalInt, 77.6, 110.5);
            SetSkill(SkillName.Necromancy, 120.6, 130.5);
            SetSkill(SkillName.SpiritSpeak, 120.1, 150.5);
            SetSkill(SkillName.Magery, 150.1, 160.1);
            SetSkill(SkillName.Poisoning, 90.5);
            SetSkill(SkillName.Meditation, 110.0);
            SetSkill(SkillName.MagicResist, 80.1, 85.0);
            SetSkill(SkillName.Parry, 90.1, 100.1);
            SetSkill(SkillName.Tactics, 190.0);
            SetSkill(SkillName.Anatomy, 100.0);
            SetSkill(SkillName.Wrestling, 155.1, 160.0);
            SetSkill(SkillName.Swords, 115.1, 120.0);

            Fame = 25000;
            Karma = -25000;

            VirtualArmor = 70;
            Tamable = false;
            AddItem(new LightSource());
            PackItem((Item)Activator.CreateInstance(Teragon.TalentArtifacts[Utility.Random(Teragon.TalentArtifacts.Length)]));
            PackItem(new Xanthos.Evo.RaelisDragonDust(Utility.RandomMinMax(20000, 30000)));

            m_Target = new Point3D(2113, 1009, -28);
            m_FieldActive = CanUseField;
            m_IsBoss = true;
            m_IsClone = false;
        }

        public override bool BardImmune { get { return true; } }
        public override bool Unprovokable { get { return true; } }
        public override bool Uncalmable { get { return true; } }
        public override bool BleedImmune { get { return true; } }
        public override bool AutoDispel { get { return true; } }
        public override Poison PoisonImmune { get { return Poison.Lethal; } }
        public override Poison HitPoison { get { return Poison.Lethal; } }
        public override bool AlwaysMurderer { get { return true; } }

        public override int BreathFireDamage { get { return 300; } }
        public override double BreathDamageScalar { get { return 0.10; } }

        public override bool ReacquireOnMovement { get { return true; } }
        public override bool HasBreath { get { return true; } } // fire breath enabled
        public override bool IsNotScaredOfDeath { get { return true; } } //neutika pri malem poctu hp
        public override bool IsScaredOfScaryThings { get { return false; } }
        public override bool IsScaryToPets { get { return true; } }
        public override bool DeleteCorpseOnDeath { get { return true; } }

        private static bool m_IsClone;
        public bool IsClone { get { return m_IsClone; } set { m_IsClone = value; } }
        private DateTime m_Delay = DateTime.Now;
        private DateTime m_FlameWaveDelay = DateTime.Now;
        private DateTime m_FieldDelay = DateTime.Now;
        private DateTime m_MeteorDelay = DateTime.Now;

        private bool m_FieldActive;
        public bool FieldActive { get { return m_FieldActive; } }
        public bool CanUseField { get { return Hits >= HitsMax / 2; } } // TODO: an OSI bug prevents to verify this

        public override void AlterMeleeDamageFrom(Mobile from, ref int damage)
        {
            if (m_FieldActive && !m_IsClone)
                damage = 0; // no melee damage when the field is up
        }

        public override void AlterSpellDamageFrom(Mobile from, ref int damage)
        {
            if (!m_FieldActive && !m_IsClone)
                damage = 0; // no spell damage when the field is down
        }

        public override void OnDamagedBySpell(Mobile from)
        {
            if (!InRange(from, 2) && Utility.RandomDouble() < 0.05)
            {
                FixedParticles(0x375A, 1, 17, 0x7DA, 0x960, 0x3, EffectLayer.Waist);
                MadSquirrel summon = new MadSquirrel(from, 1.0);
                summon.Name = "a hell cat";
                summon.Body = 0xC9;
                summon.BaseSoundID = 0x69;
                summon.Hue = this.Hue;
                summon.MoveToWorld(this.Location, this.Map);
            }

            if (m_IsClone)
            {
                base.OnDamagedBySpell(from);
                return;
            }

            if (!m_FieldActive)
            {
                // should there be an effect when spells nullifying is on?
                this.FixedParticles(0, 10, 0, 0x2522, EffectLayer.Waist);
            }
            else if (m_FieldActive && !CanUseField)
            {
                m_FieldActive = false;
                Hue = 2603;

                // TODO: message and effect when field turns down; cannot be verified on OSI due to a bug
                this.FixedParticles(0x3735, 1, 30, 0x251F, EffectLayer.Waist);

                DrakAuberon summon = new DrakAuberon();
                summon.IsBoss = false;
                summon.IsClone = true;
                summon.Hits = this.Hits;
                summon.Hue = this.Hue;
                summon.SetDamage(30, 40);
                summon.SetResistance(ResistanceType.Physical, 60);
                summon.SetResistance(ResistanceType.Fire, 100);
                summon.SetResistance(ResistanceType.Cold, 50);
                summon.SetResistance(ResistanceType.Poison, 60);
                summon.SetResistance(ResistanceType.Energy, 60);
                XmlAttach.AttachTo(summon, new XmlSpecial());
                summon.MoveToWorld(TavaraSewel.GetSpawnPosition(from.Location, from.Map, 5), this.Map);

                if (from.Player)
                    summon.Combatant = from;
            }

            base.OnDamagedBySpell(from);
        }

        public override void OnGotMeleeAttack(Mobile attacker)
        {
            base.OnGotMeleeAttack(attacker);

            if (m_FieldActive && !m_IsClone)
            {
                this.FixedParticles(0x376A, 20, 10, 0x2530, EffectLayer.Waist);
                PlaySound(0x2F4);
                AOS.Damage(attacker, this, 350, 30, 70, 0, 0, 0);

                //attacker.SendAsciiMessage("Muahahaha! Do you really think you could hurt me!");
            }

            if (attacker != null && attacker.Alive && attacker.Weapon is BaseRanged && ( 0.4 > Utility.RandomDouble() || MortalStrike.IsWounded(this)))
            {
                if (!InRange(attacker, 2) && Utility.RandomDouble() < 0.7)
                {
                    FixedParticles(0x375A, 1, 17, 0x7DA, 0x960, 0x3, EffectLayer.Waist);
                    MadSquirrel summon = new MadSquirrel(attacker, 1.0);
                    summon.Name = "a hell frog";
                    summon.Body = 0x51;
                    summon.BaseSoundID = 614;
                    summon.Hue = this.Hue;// Utility.RandomList(0x647, 0x650, 0x659, 0x662, 0x66B, 0x674);
                    summon.MoveToWorld(this.Location, this.Map);
                }
                else
                {
                    //AOS.Damage(attacker, this, 200, 30, 70, 0, 0, 0);
                    attacker.ApplyPoison(this, Poison.Lethal);
                    this.MovingParticles(attacker, 0x379F, 7, 0, false, true, 0xBE3, 0xFCB, 0x211);
                }
            }
        }

        public override void OnThink()
        {
            base.OnThink();

            // TODO: an OSI bug prevents to verify if the field can regenerate or not
            if (!m_FieldActive && !IsHurt())
            {
                m_FieldActive = true;
                Hue = 1161;
            }
            
            if (!Blessed && DateTime.Now > m_FieldDelay)
            {
                Effects.PlaySound(this.Location, this.Map, 0x208);
                new Ability.FireField(this, 90, 20, 35, Utility.RandomBool(), TavaraSewel.GetSpawnPosition(this.Location, this.Map, 10), this.Map);
                m_FieldDelay = DateTime.Now + TimeSpan.FromSeconds(40.0);
            }
        }

        public override void OnDamage(int amount, Mobile from, bool willKill, int typ)
        {
            base.OnDamage(amount, from, willKill, typ);

            if (from != null && from != this && typ < 1)
            {
                //MovingEffect(from, 0xECA, 10, 0, false, false, 0, 0);
                //PlaySound(0x491);

                if (0.09 > Utility.RandomDouble() && !m_IsClone)
                {
                    if (m_FieldActive)
                        Timer.DelayCall(TimeSpan.FromSeconds(1.0), new TimerStateCallback(CreateBones_Callback), from);
                    else if (DateTime.Now > m_Delay)
                    {
                        Effects.PlaySound(this.Location, this.Map, 0x491);
                        SkeletalDragon.ItemSummoningRing(6, this, typeof(UnholyBone), 0, null, Utility.Random(0xECA, 9));
                        m_Delay = DateTime.Now + TimeSpan.FromMinutes(2.0);
                    }
                }

                if (Utility.RandomDouble() < 0.1)
                    Utilitky.CorpseExplosion(from, this);

                if (0.05 > Utility.RandomDouble())
                {
                    BreathStallMovement();
                    BreathPlayAngerSound();
                    BreathPlayAngerAnimation();
                    this.Direction = this.GetDirectionTo(from);
                    Ability.JaggedLineEffect(this, 12, 300);
                    Ability.JaggedLineEffect(this, 12, 300);
                    Ability.JaggedLineEffect(this, 12, 300);
                }

                if (DateTime.Now > m_MeteorDelay)
                {
                    Ability.CrimsonMeteor(this, 25);
                    m_MeteorDelay = DateTime.Now + TimeSpan.FromSeconds(80.0);
                }

                if (Utility.RandomDouble() < 0.015 && this.Hits < (this.HitsMax * 70) / 100 && !m_IsClone)
                {
                    FlareVortex vortex = new FlareVortex();

                    vortex.ItemID = 13804;
                    vortex.Hue = 1078;
                    vortex.Name = "explosive crystal";
                    vortex.Light = LightType.Circle300;
                    vortex.MoveToWorld(TavaraSewel.GetSpawnPosition(from.Location, from.Map, 10), from.Map);
                }

                if (DateTime.Now > m_FlameWaveDelay && Utility.RandomDouble() < 0.1/* && !m_IsClone*/)
                {
                    m_FlameWaveDelay = DateTime.Now + TimeSpan.FromSeconds(60.0);
                    Regions.KhaldunRegion.DropHealthOrb(this);
                    Regions.KhaldunRegion.DropHealthOrb(this);
                    FlameWave(this);
                }

                from.Stam -= Utility.Random(5, 10);
                from.Mana -= Utility.Random(5, 10);
                Ability.TurnPet(from);

                // teleports player near
                if (from is PlayerMobile && !InRange(from.Location, 2) && Utility.RandomDouble() < 0.001)
                {
                    Combatant = from;
                    from.MoveToWorld(Location, Map);
                    from.FixedParticles(0x376A, 9, 32, 0x13AF, EffectLayer.Waist);
                    from.PlaySound(0x1FE);
                }
            }
        }

        public override void AlterMeleeDamageTo(Mobile to, ref int damage)
        {
            if (to is Xanthos.Interfaces.IEvoCreature)
                damage *= 5;
        }

        public override bool OnBeforeDeath()
        {
            Container pack = this.Backpack;
            if (pack != null && !m_IsClone)
            {
                pack.Movable = true;
                pack.Hue = this.Hue;
                //pack.DropItem((Item)Activator.CreateInstance(Teragon.TalentArtifacts[Utility.Random(Teragon.TalentArtifacts.Length)]));
                pack.MoveToWorld(Location, Map);
                SkeletalDragon.ItemSummoningRing(5, this, typeof(ArcaneDust), 2167, "arcane dust", 3983);
            }

            Effects.SendLocationEffect(Location, Map, 0x376A, 10, 1);
            Regions.KhaldunRegion.DropHealthOrb(this);
            Regions.KhaldunRegion.DropHealthOrb(this);

            if (m_IsBoss)
            {
                this.MoveToWorld(new Point3D(2114, 1028, -28), Map.Auberon); //Umisteni za barieru
                this.FixedParticles(0x376A, 9, 32, 0x13AF, EffectLayer.Waist);
                this.PlaySound(0x1FE);
                this.Hue = 1157;
                this.Blessed = true;
                this.Hits = this.HitsMax;

                World.Broadcast(37, true, "Zly drak Auberon byl porazen a znovu uveznen za magickou barierou. Doufame ze v nasem svete opet zavladne mir.");

                //Gate
                AuberonEndGate gate = new AuberonEndGate();
                gate.MoveToWorld(m_Target, this.Map);
                return false;
            }

            return true;
        }

        public virtual void CreateBones_Callback(object state)
        {
            Mobile from = (Mobile)state;
            Map map = from.Map;

            if (map == null)
                return;

            int count = Utility.RandomMinMax(1, 3);

            for (int i = 0; i < count; ++i)
            {
                int x = from.X + Utility.RandomMinMax(-1, 1);
                int y = from.Y + Utility.RandomMinMax(-1, 1);
                int z = from.Z;

                if (!map.CanFit(x, y, z, 16, false, true))
                {
                    z = map.GetAverageZ(x, y);

                    if (z == from.Z || !map.CanFit(x, y, z, 16, false, true))
                        continue;
                }

                UnholyBone bone = new UnholyBone();

                bone.Hue = 0;
                bone.Name = "unholy bones";
                bone.ItemID = Utility.Random(0xECA, 9);

                bone.MoveToWorld(new Point3D(x, y, z), map);
            }
        }

        #region FlameWave
        public static void FlameWave(Mobile from)
        {
            if (from.Player)
                return;

            from.CantWalk = true;
            from.PublicOverheadMessage(Network.MessageType.Regular, 193, true, "*Vas Grav Consume !*");

            Timer.DelayCall(TimeSpan.FromSeconds(4.0), new TimerStateCallback(TriggerFlameWave), new object[] { from });
        }

        private static void TriggerFlameWave(object state)
        {
            object[] args = (object[])state;
            Mobile mob = (Mobile)args[0];

            if (mob == null || mob.Deleted || !mob.Alive)
                return;

            new FlameWaveTimer(mob).Start();
            mob.CantWalk = false;
        }

        internal class FlameWaveTimer : Timer
        {
            private Mobile m_From;
            private Point3D m_StartingLocation;
            private Map m_Map;
            private int m_Count;
            private Point3D m_Point;

            public FlameWaveTimer(Mobile from)
                : base(TimeSpan.FromMilliseconds(300.0), TimeSpan.FromMilliseconds(300.0))
            {
                this.m_From = from;
                this.m_StartingLocation = from.Location;
                this.m_Map = from.Map;
                this.m_Count = 0;
                this.m_Point = new Point3D();
                this.SetupDamage(from);
            }

            protected override void OnTick()
            {
                if (this.m_From == null || this.m_From.Deleted)
                {
                    this.Stop();
                    return;
                }

                double dist = 0.0;
                Point3D fromEye = m_StartingLocation;
                fromEye.Z += 14;

                for (int i = -this.m_Count; i < this.m_Count + 1; i++)
                {
                    for (int j = -this.m_Count; j < this.m_Count + 1; j++)
                    {
                        this.m_Point.X = this.m_StartingLocation.X + i;
                        this.m_Point.Y = this.m_StartingLocation.Y + j;
                        this.m_Point.Z = this.m_Map.GetAverageZ(this.m_Point.X, this.m_Point.Y);
                        dist = this.GetDist(this.m_StartingLocation, this.m_Point);
                        if (dist < ((double)this.m_Count + 0.1) && dist > ((double)this.m_Count - 3.1) && m_Map.LineOfSight(fromEye, m_Point))
                        {
                            Effects.SendLocationParticles(EffectItem.Create(this.m_Point, this.m_Map, EffectItem.DefaultDuration), 0x3709, 10, 30, 5052);
                        }
                    }
                }

                this.m_Count += 3;

                if (this.m_Count > 15)
                    this.Stop();
            }

            private void SetupDamage(Mobile from)
            {
                ArrayList targets = Utilitky.GetTargets(from, 15, false);

                for (int i = 0; i < targets.Count; ++i)
                {
                    Mobile m = (Mobile)targets[i];

                    if (m == null || m.Deleted)
                        continue;

                    Timer.DelayCall(TimeSpan.FromMilliseconds(300 * (this.GetDist(this.m_StartingLocation, m.Location) / 3)), new TimerStateCallback(Hurt), m);
                }
            }

            public void Hurt(object o)
            {
                Mobile m = o as Mobile;

                if (this.m_From == null || m == null || m.Deleted)
                    return;

                //AOS.Damage(m, this.m_From, 200, 0, 100, 0, 0, 0);

                ExpireTimer timer = (ExpireTimer)m_Table[m];

                if (timer == null)
                {
                    m_From.PlaySound(1002);
                    timer = new ExpireTimer(m, m_From);
                    timer.Start();
                    m_Table[m] = timer;
                    m.SendMessage("You are being burnt alive by the seering heat!");
                }
            }

            private double GetDist(Point3D start, Point3D end)
            {
                int xdiff = start.X - end.X;
                int ydiff = start.Y - end.Y;
                return Math.Sqrt((xdiff * xdiff) + (ydiff * ydiff));
            }
        }

        private static Hashtable m_Table = new Hashtable();

        private class ExpireTimer : Timer
        {
            private Mobile m_Mobile;
            private Mobile m_From;
            private int m_Count;

            public ExpireTimer(Mobile m, Mobile from)
            : base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(5.0))
            {
                m_Mobile = m;
                m_From = from;
                Priority = TimerPriority.OneSecond;
            }

            public void DoExpire()
            {
                Stop();
                m_Table.Remove(m_Mobile);
                m_Mobile.SendMessage("Incinerate faded");
            }

            public void DrainLife()
            {
                if (m_Mobile != null && m_Mobile.Alive && !m_Mobile.Blessed && !m_Mobile.Deleted && m_From != null)
                {
                    m_Mobile.FixedParticles(6581, 10, 180, 0x2543, 0, 0, EffectLayer.Head);
                    m_Mobile.PlaySound(0x5CF);
                    m_Mobile.PlaySound(477);
                    m_Mobile.RevealingAction();

                    if ((m_Count % 2) == 0)
                    {
                        FireFury summon = new FireFury();
                        TimeSpan duration = TimeSpan.FromSeconds(240.0);
                        new UnsummonTimer(m_From, summon, duration).Start();
                        summon.SummonEnd = DateTime.Now + duration;
                        summon.MoveToWorld(TavaraSewel.GetSpawnPosition(m_Mobile.Location, m_Mobile.Map, 3), m_Mobile.Map);
                        summon.Combatant = m_Mobile;
                    }

                    int damage = XmlSpecial.PercentualDamage(Utility.RandomMinMax(25, 35), m_Mobile);

                    m_Mobile.Hits -= damage;
                    ISTile5.SendDmgPacket(m_Mobile, damage);

                    if (m_Mobile.Hits < 2)
                        m_Mobile.Kill();
                }
                else
                    DoExpire();
            }

            protected override void OnTick()
            {
                DrainLife();

                if (++m_Count >= 8)
                {
                    DoExpire();
                }
            }
        }
        #endregion

        public DrakAuberon(Serial serial) : base(serial)
        {
        }

        public override void Serialize(GenericWriter writer)
        {
            base.Serialize(writer);
            writer.Write((int)0);

            writer.Write((Point3D)m_Target);
        }

        public override void Deserialize(GenericReader reader)
        {
            base.Deserialize(reader);
            int version = reader.ReadInt();

            m_Target = reader.ReadPoint3D();
        }
    }
}
