using Server;
using System;
using Server.Mobiles;
using System.Collections.Generic;
using Server.Multis;
using Server.Regions;
using Server.Targeting;

namespace Server.Items
{
    public class CorgulAltar : Container
    {

        #region Statics
        private static TimeSpan ExpireTime = TimeSpan.FromMinutes(180);
        private static TimeSpan CompleteTime = TimeSpan.FromMinutes(15);

        private static readonly int m_RegionSize = 186;

        private static Rectangle2D[] m_WarpLocations = new Rectangle2D[]
        {
                new Rectangle2D(2885, 1373, 500, 800),
                new Rectangle2D(330,  2940, 400, 400),
                new Rectangle2D(4040, 2550, 500, 350), 
                new Rectangle2D(4040, 1755, 500, 250),
                new Rectangle2D(180,  180,  300, 300)
        };

        public static Rectangle2D[] WarpLocations { get { return m_WarpLocations; } }

        private static Rectangle2D m_BoatKickLocation = new Rectangle2D(2400, 2500, 500, 500);
        public static Rectangle2D BoatKickLocation { get { return m_BoatKickLocation; } }

        private static Rectangle2D m_LandKickLocation = new Rectangle2D(2125, 3090, 25, 30);
        public static Rectangle2D LandKickLocation { get { return m_LandKickLocation; } }

        private static Rectangle2D m_CorgulBounds = new Rectangle2D(6337, 1156, m_RegionSize, m_RegionSize);

        public static Rectangle2D CorgulBounds { get { return m_CorgulBounds; } }
        #endregion

        private bool m_Activated;
        private bool m_Active;
        private CorgulWarpRegion m_WarpRegion;
        private CorgulRegion m_BossRegion;
        private Point3D m_WarpPoint;
        private DateTime m_DeadLine;
        private Mobile m_Boss;
        private int m_KeyStage;
        private List<Item> m_IslandMaps = new List<Item>();

        [CommandProperty(AccessLevel.GameMaster)]
        public bool Activated {  get { return m_Activated; } }

        [CommandProperty(AccessLevel.GameMaster)]
        public bool Active 
        { 
            get { return m_Active; } 
            set 
            { 
                m_Active = value; 
                PublicOverheadMessage(Server.Network.MessageType.Regular, 25, false, String.Format("Corgul Altar for {0} has been {1}", this.Map, m_Active ? "activated" : "deactivated")); 
            } 
        }

        public CorgulWarpRegion WarpRegion { get { return m_WarpRegion; } }
        public CorgulRegion BossRegion { get { return m_BossRegion; } }

        private Type[] m_Keys = new Type[] { typeof(TreasureMap), typeof(WorldMap) };

        public static Point3D SpawnLoc = new Point3D(6431, 1236, 10);

        [CommandProperty(AccessLevel.GameMaster)]
        public DateTime DeadLine { get { return m_DeadLine; } }

        public int KeyStage { get { return m_KeyStage; } }

        public override int LabelNumber { get { return 1074818; } }

        public CorgulAltar()
            : base(13807)
        {
            Movable = false;
            Hue = 2075;
            m_Activated = false;
            m_Active = true;
            m_WarpRegion = null;
            m_WarpPoint = Point3D.Zero;
            m_KeyStage = 0;

            Timer.DelayCall(TimeSpan.FromSeconds(1.0), InitializeBossRegion);
        }

        public void InitializeBossRegion()
        {
            m_BossRegion = new CorgulRegion(m_CorgulBounds, this);
            m_BossRegion.Register();
        }

        public override void Delete()
        {
            Active = false;
            Reset();

            if (m_BossRegion != null)
            {
                m_BossRegion.Unregister();
                m_BossRegion = null;
            }

            if (m_WarpRegion != null)
            {
                m_WarpRegion.Unregister();
                m_WarpRegion = null;
            }

            base.Delete();
        }

        public override void OnMapChange()
        {
            if (m_BossRegion != null)
            {
                m_BossRegion.Unregister();
                InitializeBossRegion();
            }

            Reset();
        }

        private Point3D GetRandomWarpPoint()
        {
            Rectangle2D rec = m_WarpLocations[Utility.Random(m_WarpLocations.Length)];

            int x = Utility.Random(rec.X, rec.Width);
            int y = Utility.Random(rec.Y, rec.Height);

            return new Point3D(x, y, -5);
        }

        public override void OnDoubleClick(Mobile from)
        {
            if (!m_Active)
                from.SendMessage("This altar has been deactivated.");
            else if (!CheckCanUse(from))
                from.SendLocalizedMessage(1116791); // You must wait a few minutes before making your sacrifice.
            else if (from.InRange(this.Location, 3))
            {
                from.Target = new InternalTarget(this);

                if (m_KeyStage == 0)
                    from.SendLocalizedMessage(1116586); // Your offering will be consumed by the altar if the sacrifice is accepted. You will then have 30 seconds to re-use the shrine to mark your map and pay the blood cost.
            }

        }

        private bool CheckCanUse(Mobile from)
        {
            if (m_Activated)
            {
                if (this.Map == Map.Trammel)
                    return false;

                if (m_Boss == null || !m_Boss.Alive || m_Boss.Hits < m_Boss.HitsMax / 2)
                    return false;
            }

            return true;
        }

        private class InternalTarget : Target
        {
            private CorgulAltar m_Altar;

            public InternalTarget(CorgulAltar altar) : base(-1, false, TargetFlags.None)
            {
                m_Altar = altar;
            }

            protected override void OnTarget(Mobile from, object targeted)
            {
                if (targeted is Item && ((Item)targeted).IsChildOf(from.Backpack) && m_Altar.IsKey((Item)targeted, from))
                    m_Altar.OnSacraficedItem((Item)targeted, from);
            }
        }

        public void OnSacraficedItem(Item item, Mobile from)
        {
            if (m_KeyStage == 1)
            {
                if (!m_Activated)
                {
                    SpawnBoss(from);
                    m_DeadLineTimer = Timer.DelayCall(ExpireTime, new TimerCallback(OnDeadLine));
                    m_DeadLine = DateTime.UtcNow + ExpireTime;
                }

                from.Hits = 0;
                from.Mana = 0;
                from.Stam = 2;
                from.PlaySound(0x244);
                from.FixedParticles(0x3709, 1, 30, 9965, 5, 7, EffectLayer.Waist);
                from.FixedParticles(0x376A, 1, 30, 9502, 5, 3, EffectLayer.Waist);

                GiveMap(from);
                ResetKeys();
            }
            else
            {
                m_KeyStage = 1;
                from.SendLocalizedMessage(1116585); // Your offering has been accepted. The price of blood will be taken when your -world map- is marked with the secret location.

                m_KeyResetTimer = Timer.DelayCall(TimeSpan.FromSeconds(30), new TimerCallback(ResetKeys));
            }

            item.Delete();
        }

        private void ResetKeys()
        {
            m_KeyStage = 0;

            if (m_KeyResetTimer != null)
                m_KeyResetTimer.Stop();

            m_KeyResetTimer = null;
        }

        public bool IsKey(Item item, Mobile from)
        {
            Type type = item.GetType();

            if (m_KeyStage >= 0 && m_KeyStage < m_Keys.Length && type == m_Keys[m_KeyStage])
                return true;
            else if (m_KeyStage == 1 && item is PresetMap && item.LabelNumber == 1041204)
                return true;
            else if (m_KeyStage == 1 && item is TreasureMap)
                from.SendLocalizedMessage(1116360); // The island's location cannot be marked on a treasure map.
            else if (m_KeyStage == 1 && item is MapItem)
                from.SendLocalizedMessage(1116358); // The island's location cannot be marked on this map.
            else
                from.SendLocalizedMessage(1072682); // This is not the proper key.
            return false;
        }

        public void OnBossKilled()
        {
            m_ResetTimer = Timer.DelayCall(CompleteTime, new TimerCallback(Reset));

            EndDeadLineTimer();

            if (m_BossRegion == null)
                return;

            foreach (Mobile m in m_BossRegion.GetMobiles())
            {
                if (m is PlayerMobile)
                    m.SendLocalizedMessage(1072681); // The master of this realm has been slain! You may only stay here so long.
            }
        }

        public void OnDeadLine()
        {
            if (m_BossRegion == null)
                return;

            foreach (Mobile m in m_BossRegion.GetMobiles())
            {
                if (m is PlayerMobile)
                    m.SendMessage("You have failed to slay Corgul in time.");
            }
            Reset();
        }

        public void Reset()
        {
            m_Activated = false;

            m_WarpPoint = Point3D.Zero;

            if(m_BossRegion != null)
                m_BossRegion.RemovePlayers(false);

            EndResetTimer();
            EndDeadLineTimer();

            if (m_Boss != null && !m_Boss.Deleted)
                m_Boss.Delete();

            m_Boss = null;

            foreach (Item item in m_IslandMaps)
            {
                if (item != null && !item.Deleted)
                    item.Delete();
            }

            Timer.DelayCall(TimeSpan.FromSeconds(1), UnregisterWarpRegion);

            m_IslandMaps.Clear();
            ResetKeys();
        }

        private Timer m_ResetTimer;
        private Timer m_DeadLineTimer;
        private Timer m_KeyResetTimer;

        public void EndResetTimer()
        {
            if (m_ResetTimer != null)
                m_ResetTimer.Stop();

            m_ResetTimer = null;
        }

        public void EndDeadLineTimer()
        {
            if (m_DeadLineTimer != null)
                m_DeadLineTimer.Stop();

            m_DeadLine = DateTime.MinValue;
            m_DeadLineTimer = null;
        }

        public void UnregisterWarpRegion()
        {
            if (m_WarpRegion != null)
            {
                m_WarpRegion.Unregister();
                m_WarpRegion = null;
            }
        }

        public void SpawnBoss(Mobile from)
        {
            //Spawn boss
            CorgulTheSoulBinder boss = new CorgulTheSoulBinder(this);
            boss.MoveToWorld(SpawnLoc, this.Map);
            boss.SpawnHelpers();
            m_Boss = boss;

            //create dummy spawn point and bounds for warp region
            m_WarpPoint = GetRandomWarpPoint();
            Rectangle2D bounds = GetRectangle(m_WarpPoint);

            //create region based on dummy spot and bounds
            m_WarpRegion = new CorgulWarpRegion(this, bounds);
            m_WarpRegion.Register();
            m_Activated = true;
        }

        private void GiveMap(Mobile from)
        {
            CorgulIslandMap map = new CorgulIslandMap(m_WarpPoint);
            from.AddToBackpack(map);

            m_IslandMaps.Add(map);

            from.SendLocalizedMessage(1116359); // The island's location has been marked on your map. You should make haste while the island is still afloat.
        }

        public static Point3D GetRandomPoint(Rectangle2D rec, Map map)
        {
            int x = Utility.Random(rec.X, rec.Width);
            int y = Utility.Random(rec.Y, rec.Height);
            int z = map.GetAverageZ(x, y);

            return new Point3D(x, y, z);
        }

        public Rectangle2D GetRectangle(Point3D pnt)
        {
            return new Rectangle2D(pnt.X - (m_RegionSize / 2), pnt.Y - (m_RegionSize / 2), m_RegionSize, m_RegionSize);
        }

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

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

            writer.Write(m_DeadLine);
            writer.Write(m_Boss);
            writer.Write(m_Activated);
            writer.Write(m_Active);
            writer.Write(m_WarpPoint);
            //writer.Write(m_IslandMap); Old version 0

            writer.Write(m_IslandMaps.Count);
            foreach (Item item in m_IslandMaps)
                writer.Write(item);
        }

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

            switch (version)
            {
                case 1:
                    {
                        m_DeadLine = reader.ReadDateTime();
                        m_Boss = reader.ReadMobile();
                        m_Activated = reader.ReadBool();
                        m_Active = reader.ReadBool();
                        m_WarpPoint = reader.ReadPoint3D();

                        int count = reader.ReadInt();
                        for (int i = 0; i < count; i++)
                        {
                            Item map = reader.ReadItem();

                            if (map != null && !map.Deleted && map is CorgulIslandMap)
                                m_IslandMaps.Add(map);
                        }

                        break;
                    }
                case 0:
                    {
                        m_DeadLine = reader.ReadDateTime();
                        m_Boss = reader.ReadMobile();
                        m_Activated = reader.ReadBool();
                        m_Active = reader.ReadBool();
                        m_WarpPoint = reader.ReadPoint3D();
                        //m_IslandMap = reader.ReadItem() as CorgulIslandMap;
                        Item item = reader.ReadItem();
                        break;
                    }
            }

            InitializeBossRegion();

            if (m_Active && m_Activated && m_WarpPoint != Point3D.Zero)
            {
                if (m_DeadLine < DateTime.UtcNow || m_Boss == null || m_Boss.Deleted)
                    Reset();
                else
                {
                    Rectangle2D bounds = GetRectangle(m_WarpPoint);
                    m_WarpRegion = new CorgulWarpRegion(this, bounds);
                    m_WarpRegion.Register();
                    TimeSpan ts = m_DeadLine - DateTime.UtcNow;
                    m_DeadLineTimer = Timer.DelayCall(ts, new TimerCallback(OnDeadLine));
                }
            }
        }
    }
}