// GuardKey (to be used with GuardSpawner)
// a RunUO ver 1.0 Script
// Written by David
// last edited 4/28/06

/* Version 1.1 */

using System;
using Server;
using System.Collections;
using System.Collections.Generic;
using Server.Network;
using Server.Targeting;
using Server.Prompts;
using Server.Mobiles;
using Server.Engines.PartySystem;

namespace Server.Items
{
    public class GuardKey : Item
    {
        private string i_Description;
        private uint i_KeyVal;
        private int i_Uses;
        private int i_Max;
        private TimeSpan i_Delay;
        private Timer m_Timer;
        private int m_Lifespan;

        [CommandProperty(AccessLevel.GameMaster)]
        public string Description
        {
            get { return i_Description; }
            set
            {
                i_Description = value;
                InvalidateProperties();
            }
        }

        [CommandProperty(AccessLevel.GameMaster)]
        public uint KeyValue
        {
            get { return i_KeyVal; }
            set
            {
                i_KeyVal = value;
                InvalidateProperties();
            }
        }

        [CommandProperty(AccessLevel.GameMaster)]
        public int Uses
        {
            get { return i_Uses; }
        }

        public int codeUses
        {
            get { return i_Uses; }
            set { i_Uses = value; InvalidateProperties(); }
        }

        [CommandProperty(AccessLevel.GameMaster)]
        public int MaxUses
        {
            get { return i_Max; }
            set { i_Max = value; InvalidateProperties(); }
        }

        [CommandProperty(AccessLevel.GameMaster)]
        public TimeSpan RelockDelay
        {
            get { return i_Delay; }
            set { i_Delay = value; }
        }

        [CommandProperty(AccessLevel.GameMaster)]
        public int Lifespan
        {
            get { return m_Lifespan; }
            set { m_Lifespan = value; InvalidateProperties(); }
        }

        [Constructable] // for GM testing, will need to be linked to door
        public GuardKey() : this(1, "Hlidacuv Klic", 1, 50, 3600) { }

        public GuardKey(uint KeyVal, string Desc, int MaxUsage, int DelayTime, int lifespan)
        : base(0x1013)
        {
            Weight = 1.0;
            LootType = LootType.Regular;

            i_KeyVal = KeyVal;
            i_Description = Desc;
            i_Max = MaxUsage;
            i_Delay = TimeSpan.FromSeconds(DelayTime);
            m_Lifespan = lifespan;
        }

        public override bool OnDragLift(Mobile from)
        {
            if (from is PlayerMobile && m_Lifespan > 0 && m_Timer == null)
                StartTimer();

            return true;
        }

        public override void OnDoubleClick(Mobile from)
        {
            if (this.Parent is XmlQuestHolder)
            {
                from.SendLocalizedMessage(1060640);//The item must be in your backpack to use it.
            }
            else if (!IsChildOf(from.Backpack))
            {
                from.SendLocalizedMessage(1060640);//The item must be in your backpack to use it.
            }
            else
            {
                from.SendLocalizedMessage(501662); // What shall I use this key on?
                from.Target = new UnlockTarget(this);
            }
        }

        public override void GetProperties(ObjectPropertyList list)
        {
            //base.GetProperties( list );
            list.Add(i_Description);
            list.Add(1060584, (i_Max - i_Uses).ToString()); // uses remaining: ~1_val~
            if (m_Lifespan > 0)
                list.Add(1072517, m_Lifespan.ToString()); // Lifespan: ~1_val~ seconds

            Server.Engines.XmlSpawner2.XmlAttach.AddAttachmentProperties(this, list);
        }

        public override void OnSingleClick(Mobile from)
        {
            LabelTo(from, i_Description);
        }

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

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

            writer.Write((int)m_Lifespan);

            writer.Write(i_Description);
            writer.Write(i_KeyVal);
            writer.Write(i_Uses);
            writer.Write(i_Max);
            writer.Write((string)i_Delay.ToString());
        }

        public override void Deserialize(GenericReader reader)
        {
            base.Deserialize(reader);

            int version = reader.ReadInt();

            switch (version)
            {
                case 1:
                    {
                        m_Lifespan = reader.ReadInt();
                        goto case 0;
                    }

                case 0:
                    {
                        i_Description = reader.ReadString();
                        i_KeyVal = reader.ReadUInt();
                        i_Uses = reader.ReadInt();
                        i_Max = reader.ReadInt();
                        i_Delay = TimeSpan.Parse(reader.ReadString());
                        break;
                    }
            }
        }

        #region Target
        private class UnlockTarget : Target
        {
            private GuardKey m_Key;

            public UnlockTarget(GuardKey key)
            : base(3, false, TargetFlags.None)
            {
                m_Key = key;
                CheckLOS = false;
            }

            protected override void OnTarget(Mobile from, object targeted)
            {
                int number;

                if (targeted is ILockable)
                {
                    number = -1;

                    ILockable o = (ILockable)targeted;

                    if (o.KeyValue == m_Key.KeyValue)
                    {
                        if (o is BaseDoor && !((BaseDoor)o).UseLocks())
                        {
                            number = 501668; // This key doesn't seem to unlock that.
                        }
                        else
                        {
                            if (!o.Locked)
                                o.Locked = true;

                            if (o.Locked)
                            {
                                o.Locked = false;

                                if (o is BaseDoor && ((BaseDoor)o).Link != null)
                                {
                                    BaseDoor link = ((BaseDoor)o).Link;

                                    if (link != null)
                                        link.Locked = false;
                                }

                                if (targeted is Item)
                                {
                                    Item item = (Item)targeted;
                                    item.SendLocalizedMessageTo(from, 1048001); // or 1048000

                                    Engines.XmlSpawner2.XmlExpy att = (Engines.XmlSpawner2.XmlExpy)Engines.XmlSpawner2.XmlAttach.FindAttachment(item, typeof(Engines.XmlSpawner2.XmlExpy));

                                    if (att != null)
                                    {
                                        att.Count++;
                                        item.InvalidateProperties();
                                        Party party = Party.Get(from);

                                        if (party != null)
                                        {
                                            foreach (PartyMemberInfo info in party.Members)
                                            {
                                                PlayerMobile pm = (PlayerMobile)info.Mobile;

                                                if (pm != null && pm.InRange(from.Location, 25))
                                                {
                                                    Guilds.Guild.GiveXp(pm, att.Xp);
                                                    GiveExp(pm, att.Xp);

                                                    if (att.Body > 0)
                                                    {
                                                        pm.Expy += att.Body;
                                                        pm.SendMessage("Ziskavas {0} bodu.", att.Body);
                                                        pm.SendMessage("Celkem mas {0} bodu.", pm.Expy);
                                                    }
                                                }
                                            }
                                        }
                                        else
                                        {
                                            if (from is PlayerMobile)
                                            {
                                                Guilds.Guild.GiveXp(from, att.Xp);
                                                GiveExp((PlayerMobile)from, att.Xp);

                                                if (att.Body > 0)
                                                {
                                                    ((PlayerMobile)from).Expy += att.Body;
                                                    from.SendMessage("Ziskavas {0} bodu.", att.Body);
                                                    from.SendMessage("Celkem mas {0} bodu.", ((PlayerMobile)from).Expy);
                                                }
                                            }
                                        }

                                        if (item is BaseContainer) //Respawn spawneru uvnitr truhly po odemceni (pokud je attachment)
                                        {
                                            List<Item> items = item.Items;

                                            if (items.Count > 0)
                                            {
                                                for (int i = items.Count - 1; i >= 0; --i)
                                                {
                                                    if (i >= items.Count)
                                                        continue;

                                                    if (items[i] is XmlSpawner)
                                                    {
                                                        XmlSpawner spawner = (XmlSpawner)items[i];

                                                        if (spawner.MinDelay > TimeSpan.Zero)
                                                            continue;

                                                        spawner.DoReset = true;
                                                        spawner.TriggerMob = from;
                                                        spawner.DoRespawn = true;
                                                        spawner.Running = false;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }

                                // counter
                                int remain = m_Key.MaxUses - ++m_Key.codeUses;
                                switch (remain)
                                {
                                    default:
                                        {
                                            from.SendMessage(30, "{0} jsi zamek klicem", (from.Female) ? "Otevrela" : "Otevrel");
                                            break;
                                        }

                                    case 2:
                                        {
                                            from.SendMessage(30, "Pri otvirani se klic ohnul, ale zamek se podarilo otevrit");
                                            break;
                                        }

                                    case 1:
                                        {
                                            from.SendMessage(30, "Zamek se otevrel, ale klic je jiz silne nalomeny");
                                            break;
                                        }

                                    case 0:
                                        {
                                            from.SendMessage(30, "Zamek se podarilo otevrit, ale klic se zlomil");
                                            if (m_Key != null)
                                                m_Key.Delete();
                                            break;
                                        }
                                }

                                m_Key.InvalidateProperties();
                                // lock door
                                new RelockTimer(from, o, m_Key.RelockDelay).Start();
                                from.PlaySound(1000);
                            }
                        }
                    }
                    else
                    {
                        number = 501668; // This key doesn't seem to unlock that.
                    }
                }
                else
                {
                    number = 501666; // You can't unlock that!
                }

                if (number != -1)
                {
                    from.SendLocalizedMessage(number);
                }
            }
        }

        public static void GiveExp(PlayerMobile from, int body)
        {
            if (DateTime.Now > new DateTime(2018, 1, 6) || from == null || body < 1)
            {
                return;
            }

            int xp = Math.Max( 1, body / 1000);

            if (from.GameTime.Days < 100)
            {
                xp *= 2;
            }

            from.Expy += xp;
            from.SendMessage(0x35, "Pocet ziskanych bodu: {0}", xp);
            from.SendMessage(0x35, "Aktualni pocet tvych bodu: {0}", from.Expy);
        }
        #endregion

        #region Timer
        public class RelockTimer : Timer
        {
            private ILockable o_obj;
            private Mobile m_from;

            public RelockTimer(Mobile from, ILockable o, TimeSpan delay)
            : base(delay)
            {
                Priority = TimerPriority.TwoFiftyMS;
                m_from = from;
                o_obj = o;
            }

            protected override void OnTick()
            {
                if (o_obj != null)
                {
                    if (o_obj is BaseDoor && ((BaseDoor)o_obj).UseLocks())
                    {
                        ((BaseDoor)o_obj).Locked = true;

                        if (((BaseDoor)o_obj).Link != null)
                        {
                            BaseDoor link = ((BaseDoor)o_obj).Link;

                            if (link != null)
                                link.Locked = true;
                        }
                    }
                    else if (o_obj is LockableContainer)
                    {
                        ((LockableContainer)o_obj).Locked = true;
                    }

                    ((Item)o_obj).PublicOverheadMessage(MessageType.Regular, 0x3B2, false, "Zapadka znovu zaskocila a zamek se uzamknul");
                    Effects.PlaySound(((Item)o_obj).Location, ((Item)o_obj).Map, 998);
                    Stop();
                }
            }
        }

        #endregion

        public override void OnAfterDelete()
        {
            StopTimer();
            base.OnAfterDelete();
        }

        #region lifespan
        public virtual void StartTimer()
        {
            if (m_Timer != null)
                return;

            m_Lifespan = Lifespan;
            m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(10), new TimerCallback(Slice));
            m_Timer.Priority = TimerPriority.OneSecond;
        }

        public virtual void StopTimer()
        {
            if (m_Timer != null)
                m_Timer.Stop();

            m_Timer = null;
        }

        public virtual void Slice()
        {
            m_Lifespan -= 10;

            InvalidateProperties();

            if (m_Lifespan <= 0)
                Decay();
        }

        public virtual void Decay()
        {
            if (RootParent is Mobile)
            {
                Mobile parent = (Mobile)RootParent;

                if (Name == null)
                    parent.SendLocalizedMessage(1072515, "#" + LabelNumber); // The ~1_name~ expired...
                else
                    parent.SendLocalizedMessage(1072515, Name); // The ~1_name~ expired...

                Effects.SendLocationParticles(EffectItem.Create(parent.Location, parent.Map, EffectItem.DefaultDuration), 0x3728, 8, 20, 5042);
                Effects.PlaySound(parent.Location, parent.Map, 0x201);
            }
            else
            {
                Effects.SendLocationParticles(EffectItem.Create(Location, Map, EffectItem.DefaultDuration), 0x3728, 8, 20, 5042);
                Effects.PlaySound(Location, Map, 0x201);
            }

            StopTimer();
            Delete();
        }

        #endregion
    }
}