using System;
using Server;
using System.Collections.Generic;
using Server.Mobiles;
using System.Linq;
using Server.Network;
using Server.Commands;

namespace Server.Items
{
    public class MyrmidexHill : Item
    {
        private Type[] _SpawnList =
        {
            typeof(MyrmidexLarvae), typeof(MyrmidexDrone), typeof(MyrmidexWarrior)
        };

        [CommandProperty(AccessLevel.GameMaster)]
        public DateTime NextSpawn { get; set; }

        public EodonTribeRegion Zone { get; set; }

        public List<BaseCreature> Spawn { get; set; }

        [CommandProperty(AccessLevel.GameMaster)]
        public Mobile Focus { get; set; }

        public int SpawnCount { get { return Utility.RandomMinMax(6, 9); } }

        public int HasSpawned { get; set; }

        public MyrmidexHill(EodonTribeRegion zone, Mobile focus)
            : base(8754)
        {
            Movable = false;

            Focus = focus;
            Zone = zone;
            Spawn = new List<BaseCreature>();
        }

        public override bool HandlesOnMovement { get { return NextSpawn < DateTime.UtcNow; } }
        public override void OnMovement(Mobile m, Point3D oldLocation)
        {
            if (m.InRange(this.Location, 7) && m.AccessLevel == AccessLevel.Player &&
                (m is PlayerMobile || (m is BaseCreature && ((BaseCreature)m).GetMaster() is PlayerMobile)))
            {
                Focus = m;
                DoSpawn();
            }
        }

        public void DoSpawn()
        {
            Map map = this.Map;

            if (Spawn == null)
                return;

            ColUtility.ForEach(Spawn.Where(bc => bc == null || !bc.Alive || bc.Deleted), bc => Spawn.Remove(bc));

            if (map != null && map != Map.Internal && !this.Deleted && Spawn.Count == 0 && HasSpawned < 3)
            {
                HasSpawned++;
                NextSpawn = DateTime.UtcNow + TimeSpan.FromMinutes(Utility.RandomMinMax(2, 5));

                int time = 333;
                for (int i = 0; i < SpawnCount - Spawn.Count; i++)
                {
                    Timer.DelayCall(TimeSpan.FromMilliseconds(time), () =>
                    {
                        Point3D p = this.Location;

                        for (int j = 0; j < 25; j++)
                        {
                            int x = Utility.RandomMinMax(this.X - 3, this.X + 3);
                            int y = Utility.RandomMinMax(this.Y - 3, this.Y + 3);
                            int z = map.GetAverageZ(x, y);

                            if (map.CanSpawnMobile(x, y, z) && this.InLOS(new Point3D(x, y, z)))
                            {
                                p = new Point3D(x, y, z);
                                break;
                            }
                        }

                        BaseCreature bc = Activator.CreateInstance(_SpawnList[Utility.Random(_SpawnList.Length)]) as BaseCreature;

                        if (bc != null)
                        {
                            Spawn.Add(bc);
                            bc.MoveToWorld(p, map);

                            Timer.DelayCall<BaseCreature>(creature => creature.Combatant = Focus, bc);
                        }
                    });

                    time += 333;
                }
            }
        }

        public void CheckSpawn()
        {
            if (Spawn == null)
                Delete();
            else
            {
                int count = 0;
                ColUtility.ForEach(Spawn.Where(bc => bc != null && bc.Alive), bc => count++);

                if (count == 0)
                    Delete();
            }

        }

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

            if (Spawn != null)
            {
                ColUtility.Free(Spawn);
                Spawn = null;
            }
        }

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

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

            writer.Write(HasSpawned);

            writer.Write(Spawn == null ? 0 : Spawn.Count);

            if (Spawn != null)
            {
                Spawn.ForEach(bc => writer.Write(bc));
            }

            Timer.DelayCall(TimeSpan.FromSeconds(30), CheckSpawn);
        }

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

            switch (version)
            {
                case 1:
                    HasSpawned = reader.ReadInt();
                    goto case 0;
                case 0:
                    int count = reader.ReadInt();
                    if (count > 0)
                    {
                        Spawn = new List<BaseCreature>();

                        for (int i = 0; i < count; i++)
                        {
                            BaseCreature bc = reader.ReadMobile() as BaseCreature;

                            if (bc != null)
                                Spawn.Add(bc);
                        }
                    }

                    break;
            }

            if (Spawn == null || Spawn.Count == 0)
                Delete();
            else
            {
                Timer.DelayCall(TimeSpan.FromSeconds(10), () =>
                {
                    EodonTribeRegion r = Region.Find(this.Location, this.Map) as EodonTribeRegion;

                    if (r != null)
                        Zone = r;
                });
            }
        }
    }

    public class EodonTribeRegion : Region
    {
        public static void Initialize()
        {
            _Zones[0] = new EodonTribeRegion(EodonTribe.Jukari, new Rectangle2D[] { new Rectangle2D(640, 2046, 115, 115) }, 6);
            _Zones[1] = new EodonTribeRegion(EodonTribe.Kurak, new Rectangle2D[] { new Rectangle2D(291, 1817, 125, 90) }, 6);
            _Zones[2] = new EodonTribeRegion(EodonTribe.Barrab, new Rectangle2D[] { new Rectangle2D(134, 1767, 33, 20), new Rectangle2D(142, 1786, 57, 80), new Rectangle2D(145, 1750, 20, 20) }, 5);
            _Zones[3] = new EodonTribeRegion(EodonTribe.Barako, new Rectangle2D[] { new Rectangle2D(620, 1677, 95, 100) }, 5);
            _Zones[4] = new EodonTribeRegion(EodonTribe.Urali, new Rectangle2D[] { new Rectangle2D(320, 1551, 160, 72) }, 5);
            _Zones[5] = new EodonTribeRegion(EodonTribe.Sakkhra, new Rectangle2D[] { new Rectangle2D(482, 1375, 200, 200) }, 8);
        }

        public static EodonTribeRegion[] _Zones = new EodonTribeRegion[6];

        public int MaxSpawns { get; private set; }
        public EodonTribe Tribe { get; set; }
        public int Spawns { get { return this.GetItemCount(i => i is MyrmidexHill); } }

        public EodonTribeRegion(EodonTribe tribe, Rectangle2D[] rec, int maxSpawns)
            : base(tribe.ToString() + " tribe", Map.TerMur, Region.DefaultPriority, rec)
        {
            Tribe = tribe;
            Register();

            MaxSpawns = maxSpawns;
        }

        public override void OnLocationChanged(Mobile m, Point3D oldLocation)
        {
            if (Tribe != EodonTribe.Barrab && Spawns < MaxSpawns)
            {
                double chance = Utility.RandomDouble();

                if (0.005 > chance && (m is PlayerMobile || (m is BaseCreature && ((BaseCreature)m).GetMaster() is PlayerMobile)) && m.AccessLevel == AccessLevel.Player)
                {
                    MyrmidexHill hill = new MyrmidexHill(this, m);
                    Point3D p = m.Location;

                    for (int i = 0; i < 10; i++)
                    {
                        int x = Utility.RandomMinMax(p.X - 5, p.X + 5);
                        int y = Utility.RandomMinMax(p.Y - 5, p.Y + 5);
                        int z = this.Map.GetAverageZ(x, y);

                        if (this.Map.CanFit(x, y, z, 16, false, false, true))
                        {
                            p = new Point3D(x, y, z);
                            break;
                        }
                    }

                    hill.MoveToWorld(p, this.Map);
                    hill.DoSpawn();
                }
            }
        }
    }
}