using System;
using System.Text;
using Server.Items;
using Server.Mobiles;

namespace Server.Spells.Spellweaving
{
	public abstract class ArcanistSpell : Spell
	{
		public abstract double RequiredSkill { get; }
		public abstract int RequiredMana { get; }

		public override SkillName CastSkill { get { return SkillName.Spellweaving; } }
		public override SkillName DamageSkill { get { return SkillName.Spellweaving; } }

		public override bool ClearHandsOnCast { get { return false; } }

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

		public int GetFocusLevel()
		{
			return GetFocusLevel( Caster );
		}

		public static int GetFocusLevel( Mobile from )
		{
			ArcaneFocus focus = GetFocus( from );

			if( focus == null || focus.Deleted )
				return 0;

			return focus.Level;
		}

		public static ArcaneFocus GetFocus( Mobile from )
		{
			if( from == null || from.Deleted || from.Backpack == null || from.Backpack.Deleted )
				return null;

			return from.Backpack.FindItemByType( typeof( ArcaneFocus ) ) as ArcaneFocus;
		}

		public static bool CheckExpansion( Mobile from )
		{
			if( !( from is PlayerMobile ) )
				return true;

			if( from.NetState == null )
				return false;

			return from.NetState.SupportsExpansion( Expansion.ML );
		}

		public override bool CheckCast()
		{
			if( !CheckExpansion( Caster ) )
			{
				Caster.SendLocalizedMessage( 1072176 ); // You must upgrade to the Mondain's Legacy Expansion Pack before using that ability
				return false;
			}

			int mana = ScaleMana( RequiredMana );

			if( Caster.Mana < mana )
			{
				Caster.SendLocalizedMessage( 1060174, mana.ToString() ); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability.
				return false;
			}
			else if( Caster.Skills[CastSkill].Value < RequiredSkill )
			{
				Caster.SendLocalizedMessage( 1063013, String.Format( "{0}\t{1}", RequiredSkill.ToString( "F1" ), "#1044114" ) ); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability.
				return false;
			}

			return base.CheckCast();
		}

		public override void GetCastSkills( out double min, out double max )
		{
			min = RequiredSkill;
			max = RequiredSkill + 40.0;
		}
		
		public override bool ConsumeReagents()
		{
			if ( !( this is GiftOfLifeSpell ) )
				return true;
         
         if ( /*Caster.Map == Map.Trammel || */Scroll != null )
            return true;
            
         int tith = 2500;
         
         if ( Guilds.Guild.GetLevel( Caster ) > 10 )
            tith -= AOS.Scale( tith, Math.Min( 25, Guilds.Guild.GetLevel( Caster ) - 10 ) );
         
         if ( Caster.TithingPoints >= tith )
         {
            Caster.TithingPoints -= tith;
            return true;
         }
         else
            return false;
		}

		public override int GetMana()
		{
			return RequiredMana;
		}

		public override void DoFizzle()
		{
			Caster.PlaySound( 0x1D6 );
			Caster.NextSpellTime = DateTime.Now;
		}

		public override void DoHurtFizzle()
		{
			Caster.PlaySound( 0x1D6 );
		}

		public override void OnDisturb( DisturbType type, bool message )
		{
			base.OnDisturb( type, message );

			if( message )
				Caster.PlaySound( 0x1D6 );
		}

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

			SendCastEffect();
		}

		public virtual void SendCastEffect()
		{
			/* Tested in Osi.
             * 
             * Test values:
			 * 
             * Gift Of Life (4s), FC 2:  98
			 * Gift Of Life (4s), FC 1: 105
			 * Gift Of Life (4s), FC 0: 112
			 * 
			 * FC2 14/4 = 3.50 * x =  98	x=28
			 * FC1 15/4 = 3.75 * x = 105	x=28
			 * FC0 16/4 = 4.00 * x = 112	x=28
			 */
			Caster.FixedEffect( 0x37C4, 10, (int)( GetCastDelay().TotalSeconds * 28 ), 4, 3 );
		}

		public virtual string ToTicksString( int n )
		{
			StringBuilder sb = new StringBuilder( 5 );

			int intN = n >> 2;

			sb.Append( intN );

			switch( ( n & ~( intN << 2 ) ) )
			{
				case 1: sb.Append( ".25" ); break;
				case 2: sb.Append( ".5"  ); break;
				case 3: sb.Append( ".75" ); break;
			}

			return sb.ToString();
		}

		public bool Locked { get { return !Caster.CanBeginAction( GetType() ); } }

		public void Lock()
		{
			Lock( Caster );
		}

		public void Lock( Mobile from )
		{
			Lock( from, TimeSpan.FromMinutes( 3.0 ) );
		}

		public void Lock( TimeSpan delay )
		{
			Lock( Caster, delay );
		}

		public void Lock( Mobile from, TimeSpan delay )
		{
			from.BeginAction( GetType() );
			Timer.DelayCall( delay, new TimerStateCallback( Unlock ), from );
		}

		private void Unlock( object state )
		{
			Unlock( state as Mobile );
		}

		public void Unlock( Mobile from )
		{
			from.EndAction( GetType() );
		}
	}
}