using System;
using System.Collections;
using System.Collections.Generic;
using Server.Mobiles;
using Server.Network;
using Server.Spells.Fifth;
using Server.Spells.Seventh;
using Server.Spells.Necromancy;
using Server.Spells.Ninjitsu;

namespace Server.Spells.Spellweaving
{
	public abstract class ArcaneForm : ArcanistSpell
	{
		public static void Initialize()
		{
			EventSink.Login += new LoginEventHandler( OnLogin );
		}

		public static void OnLogin( LoginEventArgs e )
		{
			ArcaneFormContext context = ArcaneForm.GetContext( e.Mobile );

			if( context != null && context.SpeedPenalty )
				e.Mobile.Send( /*SpeedBoost.Slower*/SpeedBoostSlower.p );
		}

		public abstract int Body { get; }
		public virtual int Hue { get { return 0; } }

		public virtual int PhysResistOffset { get { return 0; } }
		public virtual int FireResistOffset { get { return 0; } }
		public virtual int ColdResistOffset { get { return 0; } }
		public virtual int PoisResistOffset { get { return 0; } }
		public virtual int NrgyResistOffset { get { return 0; } }

		public virtual bool SpeedPenalty { get { return false; } }
		public virtual int SwingBonus { get { return 0; } }
		public virtual int SDIBonus { get { return 0; } }

		public ArcaneForm( Mobile caster, Item scroll, SpellInfo info )	: base( caster, scroll, info )
		{
		}

		public override bool CheckCast()
		{
			if( Factions.Sigil.ExistsOn( Caster ) )
			{
				Caster.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil.
				return false;
			}
			else if( !Caster.CanBeginAction( typeof( PolymorphSpell ) ) )
			{
				Caster.SendLocalizedMessage( 1061628 ); // You can't do that while polymorphed.
				return false;
			}
			else if( TransformationSpell.UnderTransformation( Caster ) )
			{
				Caster.SendLocalizedMessage( 1063218 ); // You cannot use that ability in this form.
				return false;
			}
			else if( AnimalForm.UnderTransformation( Caster ) )
			{
				Caster.SendLocalizedMessage( 1063218 ); // You cannot use that ability in this form.
				return false;
			}
			else if( UnderTransformation( Caster ) && !UnderTransformation( Caster, GetType() ) )
			{
				Caster.SendLocalizedMessage( 1063218 ); // You cannot use that ability in this form.
				return false;
			}

			return base.CheckCast();
		}

		public override void OnCast()
		{
			if( Factions.Sigil.ExistsOn( Caster ) )
			{
				Caster.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil.
			}
			else if( !Caster.CanBeginAction( typeof( PolymorphSpell ) ) )
			{
				Caster.SendLocalizedMessage( 1061628 ); // You can't do that while polymorphed.
			}
			else if( TransformationSpell.UnderTransformation( Caster ) )
			{
				Caster.SendLocalizedMessage( 1063218 ); // You cannot use that ability in this form.
			}
			else if( AnimalForm.UnderTransformation( Caster ) )
			{
				Caster.SendLocalizedMessage( 1063218 ); // You cannot use that ability in this form.
			}
			else if( !Caster.CanBeginAction( typeof( IncognitoSpell ) ) )
			{
				Caster.SendLocalizedMessage( 1061630 ); // You can't do that while incognito.
			}
			else if( UnderTransformation( Caster ) && !UnderTransformation( Caster, GetType() ) )
			{
				Caster.SendLocalizedMessage( 1063218 ); // You cannot use that ability in this form.
			}
			else if( !UnderTransformation( Caster ) && Caster.IsBodyMod )
			{
				DoFizzle();
			}
			else if( CheckSequence() )
			{
				if( GetContext( Caster ) != null )
				{
					RemoveContext( Caster, true );

					Caster.PlaySound( 0xFA );
				}
				else
				{
					List<ResistanceMod> mods = new List<ResistanceMod>();

					if( PhysResistOffset != 0 )
						mods.Add( new ResistanceMod( ResistanceType.Physical, PhysResistOffset ) );

					if( FireResistOffset != 0 )
						mods.Add( new ResistanceMod( ResistanceType.Fire, FireResistOffset ) );

					if( ColdResistOffset != 0 )
						mods.Add( new ResistanceMod( ResistanceType.Cold, ColdResistOffset ) );

					if( PoisResistOffset != 0 )
						mods.Add( new ResistanceMod( ResistanceType.Poison, PoisResistOffset ) );

					if( NrgyResistOffset != 0 )
						mods.Add( new ResistanceMod( ResistanceType.Energy, NrgyResistOffset ) );

					if( !( (Body)this.Body ).IsHuman )
					{
						IMount mt = Caster.Mount;

						if( mt != null )
							mt.Rider = null;
					}

					Caster.BodyMod = this.Body;
					Caster.HueMod = this.Hue;

					for( int i = 0; i < mods.Count; ++i )
						Caster.AddResistanceMod( mods[i] );

					PlayEffect( Caster );

					Timer timer = new ArcaneFormTimer( Caster, this );
					timer.Start();

					AddContext( Caster, new ArcaneFormContext( timer, mods, GetType(), SpeedPenalty, SwingBonus, SDIBonus ) );
				}
			}

			FinishSequence();
		}

		public virtual void PlayEffect( Mobile m )
		{
		}

		private static Hashtable m_Table = new Hashtable();

		public static void AddContext( Mobile m, ArcaneFormContext context )
		{
			m_Table[m] = context;

			if( context.SpeedPenalty )
				m.Send( /*SpeedBoost.Slower*/SpeedBoostSlower.p );
		}

		public static void RemoveContext( Mobile m, bool resetGraphics )
		{
			ArcaneFormContext context = GetContext( m );

			if( context != null )
				RemoveContext( m, context, resetGraphics );
		}

		public static void RemoveContext( Mobile m, ArcaneFormContext context, bool resetGraphics )
		{
			m_Table.Remove( m );

			List<ResistanceMod> mods = context.Mods;

			for( int i = 0; i < mods.Count; ++i )
				m.RemoveResistanceMod( mods[i] );

			if( resetGraphics )
			{
				m.HueMod = -1;
				m.BodyMod = 0;
			}

			if( context.SpeedPenalty )
				m.Send( SpeedBoost.Disabled );

			context.Timer.Stop();
		}

		public static ArcaneFormContext GetContext( Mobile m )
		{
			return ( m_Table[m] as ArcaneFormContext );
		}

		public static bool UnderTransformation( Mobile m )
		{
			return ( GetContext( m ) != null );
		}

		public static bool UnderTransformation( Mobile m, Type type )
		{
			ArcaneFormContext context = GetContext( m );

			return ( context != null && context.Type == type );
		}
	}

	public class ArcaneFormContext
	{
		private Timer m_Timer;
		private List<ResistanceMod> m_Mods;
		private Type m_Type;
		private bool m_SpeedPenalty;
		private int m_SwingBonus;
		private int m_SDIBonus;

		public Timer Timer { get { return m_Timer; } }
		public List<ResistanceMod> Mods { get { return m_Mods; } }
		public Type Type { get { return m_Type; } }
		public bool SpeedPenalty { get { return m_SpeedPenalty; } }
		public int SwingBonus { get { return m_SwingBonus; } }
		public int SDIBonus { get { return m_SDIBonus; } }

		public ArcaneFormContext( Timer timer, List<ResistanceMod> mods, Type type, bool speedPenalty, int swingBonus, int sdiBonus )
		{
			m_Timer = timer;
			m_Mods = mods;
			m_Type = type;
			m_SpeedPenalty = speedPenalty;
			m_SwingBonus = swingBonus;
			m_SDIBonus = sdiBonus;
		}
	}

	public class ArcaneFormTimer : Timer
	{
		private Mobile m_Mobile;
		private ArcaneForm m_Spell;

		public ArcaneFormTimer( Mobile from, ArcaneForm spell ) : base( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ) )
		{
			m_Mobile = from;
			m_Spell = spell;

			Priority = TimerPriority.TwoFiftyMS;
		}

		protected override void OnTick()
		{
			if( m_Mobile.Deleted || !m_Mobile.Alive || m_Mobile.Body != m_Spell.Body || m_Mobile.Hue != m_Spell.Hue )
			{
				ArcaneForm.RemoveContext( m_Mobile, true );
				Stop();
			}
		}
	}

	/* //Changed SpeedBoost class in Network/Packets.cs core file.
	public sealed class SpeedBoost : Packet
	{
		public static readonly Packet Enabled = Packet.SetStatic( new SpeedBoost( true ) );
		public static readonly Packet Disabled = Packet.SetStatic( new SpeedBoost( false ) );
		public static readonly Packet Slower = Packet.SetStatic( new SpeedBoost( 2 ) );

		public static Packet Instantiate( bool enable )
		{
			return ( enable ? Enabled : Disabled );
		}

		public static Packet Instantiate( byte speed )
		{
			return ( speed == 2 ? Slower : Instantiate( speed == 1 ) );
		}

		public SpeedBoost( bool enable )
			: this( (byte)( enable ? 1 : 0 ) )
		{
		}

		public SpeedBoost( byte speed )
			: base( 0xBF )
		{
			EnsureCapacity( 3 );

			m_Stream.Write( (short)0x26 );

			/* 0 for normal
			 * 1 for faster
			 * 2 for slower

			m_Stream.Write( speed );
		}
	}*/

	public sealed class SpeedBoostSlower : Packet
	{
		public static readonly Packet p = Packet.SetStatic( new SpeedBoostSlower() );

		public SpeedBoostSlower() : base( 0xBF )
		{
			EnsureCapacity( 3 );

			m_Stream.Write( (short)0x26 );

			/* 0 for normal
			 * 1 for faster
			 * 2 for slower
			 */
			m_Stream.Write( 2 );
		}
	}
}