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

namespace Server.Engines.XmlSpawner2
{
	public class XmlEnchant : XmlAttachment
	{
		private DateTime lasteffect;
		private int m_EItemID = 14202;  // 0 = disable, 14202 = sparkle, 6251 = round stone, 7885 = light pyramid
		private int m_Duration = 70;
		private Point3D m_Offset = new Point3D(0,0,0); // 20 overhead
		private int m_EHue = 90; // 68 = green, 90 = blue

		[CommandProperty( AccessLevel.GameMaster )]
		public int EItemID {
			get{ return m_EItemID; }
			set {
				m_EItemID = value;
			}
		}

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

		[CommandProperty( AccessLevel.GameMaster )]
		public int EDuration
		{
			get{ return m_Duration; }
			set
			{
				m_Duration = value;
			}
		}

		[CommandProperty( AccessLevel.GameMaster )]
		public int EHue
		{
			get{ return m_EHue; }
			set
			{
				m_EHue = value;
			}
		}
		
		public static void DisplayHighlight( Mobile pm )
		{
			if( pm != null )
			{
				Item inhand; 
            
            if ( pm.Weapon is BaseWeapon && !( pm.Weapon is Fists ) )
               inhand = (Item) pm.Weapon;
            else
               inhand = (Item) Spellbook.FindEquippedSpellbook( pm );
               
            if ( inhand == null )
               return;            
            
            XmlEnchant att = (XmlEnchant)XmlAttach.FindAttachment( inhand, typeof(XmlEnchant) );
				
				if ( att == null || att.EItemID < 1 || HasEffectActive( pm ) )
               return;
				
				ExpireTimer timer = new ExpireTimer( pm, att );
				
				timer.Start();
				m_Table[ pm ] = timer;
			}
		}
		
		#region timer
		private static Hashtable m_Table = new Hashtable();

		private class ExpireTimer : Timer
		{
			private Mobile m_Mobile;
			private int m_Count;
			private XmlEnchant att;

			public ExpireTimer( Mobile m, XmlEnchant a )
				: base( TimeSpan.FromSeconds( 0.75 ), TimeSpan.FromSeconds( 0.75 ) )
			{
				m_Mobile = m;
				att = a;
				Priority = TimerPriority.TwoFiftyMS;
			}

			public void DoExpire()
			{
				Stop();
				m_Table.Remove( m_Mobile );
			}

			public void DoEffect()
			{
				if( !m_Mobile.Deleted && m_Mobile.Alive && att != null )
				{
					Effects.SendLocationEffect(new Point3D( m_Mobile.Location.X + att.EOffset.X, m_Mobile.Location.Y + att.EOffset.Y, m_Mobile.Location.Z + att.EOffset.Z), m_Mobile.Map, att.EItemID, att.EDuration, att.EHue, 0);
				}
				else
					DoExpire();
			}

			protected override void OnTick()
			{
				DoEffect();

				if( ++m_Count >= 40 )
				{
					DoExpire();
				}
			}
		}
		
		public static bool HasEffectActive( Mobile mobile )
		{
			ExpireTimer timer = (ExpireTimer)m_Table[mobile];
			
			if ( timer == null )
				return false;
			
			return true;
		}
		#endregion

		// a serial constructor is REQUIRED
		public XmlEnchant(ASerial serial) :  base(serial)
		{
		}

		[Attachable]
		public XmlEnchant()
		{
		}

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

			writer.Write( (int) 0 );
			
			writer.Write( m_EItemID);
			writer.Write( m_Duration);
			writer.Write( m_Offset);
			writer.Write( m_EHue);

		}

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

			int version = reader.ReadInt();
			switch(version)
			{
					// 				case 1:
					// 					// version 1
					// 					Range = reader.ReadInt();
					// 					goto case 0;
				case 0:
					// version 0
					m_EItemID = reader.ReadInt();
					m_Duration = reader.ReadInt();
					m_Offset = reader.ReadPoint3D();
					m_EHue = reader.ReadInt();
					break;
			}
		}
	}
	
	//=========================
	public class XmlEnchantWeaponDamage : XmlEnchant
	{
		private int m_Bonus = 5;
		private int m_Original;
		private TimeSpan m_Refractory = TimeSpan.Zero;
		private DateTime m_EndTime;

		[CommandProperty( AccessLevel.GameMaster )]
		public int Bonus { get{ return m_Bonus; } set { m_Bonus = Math.Max( value, 1 ); } }
		
		public int Original { get{ return m_Original; } set { m_Original = Math.Max( value, 1 ); } }

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

		public XmlEnchantWeaponDamage(ASerial serial) :  base(serial)
		{
		}

		[Attachable]
		public XmlEnchantWeaponDamage(int b)
		{
			m_Bonus = b;
		}

		[Attachable]
		public XmlEnchantWeaponDamage(int b, double expiresin)
		{
			m_Bonus = b;
			Expiration = TimeSpan.FromMinutes(expiresin);
		}
		
		[Attachable]
		public XmlEnchantWeaponDamage(int b, double refractory, double expiresin)
		{
			m_Bonus = b;
			Expiration = TimeSpan.FromMinutes(expiresin);
			Refractory = TimeSpan.FromSeconds(refractory);
		}


		// note that this method will be called when attached to either a mobile or a weapon
		// when attached to a weapon, only that weapon will do additional damage
		// when attached to a mobile, any weapon the mobile wields will do additional damage
		public override void OnWeaponHit(Mobile attacker, Mobile defender, BaseWeapon weapon, int damageGiven)
		{
			if( attacker == null || m_Original != ((BaseWeapon)AttachedTo).MaxDamage ) return;
			
			if ( m_Refractory > TimeSpan.Zero && DateTime.Now < m_EndTime ) return; //jeste nelze znovu
			
			attacker.FixedParticles( 0x375A, 10, 15, 5037, EffectLayer.Waist );

			((BaseWeapon)AttachedTo).MaxDamage += m_Bonus;
			
			if ( m_Refractory > TimeSpan.Zero )
			{
            Timer.DelayCall( TimeSpan.FromSeconds( 20.0 ), new TimerStateCallback( ReturnOriginal ), new object[]{ AttachedTo } );
			   m_EndTime = DateTime.Now + Refractory;
         }
		}
		
		public override void OnDelete()
		{
			base.OnDelete();

			if( AttachedTo is BaseWeapon )
			{
				((BaseWeapon)AttachedTo).MaxDamage = m_Original;
			}
		}
		
		public override void OnAttach()
		{
         base.OnAttach();

			if( AttachedTo is BaseWeapon )
			{
            BaseWeapon weap = (BaseWeapon) AttachedTo;
               
            m_Original = weap.MaxDamage;
            
            if ( m_Refractory == TimeSpan.Zero )
               weap.MaxDamage  += m_Bonus;
               
            EItemID = 4435;
			   EDuration = 25;
				EHue = 1934;
         }
         else
				Delete();
				
		}

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

			writer.Write( (int) 0 );

			writer.Write(m_Bonus);
			writer.Write(m_Original);
			writer.Write(m_Refractory);
			writer.Write(m_EndTime - DateTime.Now);

		}

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

			int version = reader.ReadInt();
			switch(version)
			{
					// 				case 1:
					// 					// version 1
					// 					Range = reader.ReadInt();
					// 					goto case 0;
				case 0:
					// version 0

					m_Bonus = reader.ReadInt();
					m_Original = reader.ReadInt();
					Refractory = reader.ReadTimeSpan();
					TimeSpan remaining = reader.ReadTimeSpan();
					m_EndTime = DateTime.Now + remaining;
					
					if(remaining > TimeSpan.Zero && m_Refractory > TimeSpan.Zero )
						Timer.DelayCall( remaining, new TimerStateCallback( ReturnOriginal ), new object[]{ AttachedTo } );
					break;
			}
		}
		
		private void ReturnOriginal( object state )
		{
			object[] args = (object[])state;
			BaseWeapon weap = (BaseWeapon) args[0];
			
			if ( weap != null && m_Original != weap.MaxDamage )
				weap.MaxDamage -= m_Bonus;
		}

		public override string OnIdentify(Mobile from)
		{
			string msg = null;

			if(Expiration > TimeSpan.Zero)
			{
				msg = String.Format( "+{0} base max damage on hit\n{1:F1} hours left", m_Bonus, Expiration.TotalHours );
			}
			else
			{
				msg = String.Format( "+{0} base max damage on hit", m_Bonus );
			}

            
			if(Refractory > TimeSpan.Zero)
			{
				return String.Format( "{0}\n{1} secs between uses", msg, Refractory.TotalSeconds );
			}
			else
				return msg;
		}
	}
	
	//=========================
	public class XmlEnchantConsecrateSpell : XmlEnchant
	{
		public XmlEnchantConsecrateSpell(ASerial serial) :  base(serial)
		{
		}
	
		[Attachable]
		public XmlEnchantConsecrateSpell( double expiresin )
		{
			Expiration = TimeSpan.FromMinutes(expiresin);
		}
		
		public override void OnAttach()
		{
			base.OnAttach();

			if( !( AttachedTo is Spellbook ) )
				Delete();
		}
      
		public override void Serialize( GenericWriter writer )
		{
			base.Serialize(writer);

			writer.Write( (int) 0 );
		}

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

			int version = reader.ReadInt();
			switch(version)
			{
					// 				case 1:
					// 					// version 1
					// 					Range = reader.ReadInt();
					// 					goto case 0;
				case 0:
					// version 0
					break;
			}
		}
		
		public override string OnIdentify(Mobile from)
		{
			string msg = null;

			if(Expiration > TimeSpan.Zero)
			{
				msg = String.Format( "Consecrated spells\n{0:F1} hours left", Expiration.TotalHours );
			}
			else
			{
				msg = "Consecrated spells";
			}

			return msg;
		}
	}
}
