context: using System;
  using System.Collections.Generic;
  using Server;
  using Server.Commands;
  using Server.Engines.Craft;
  using Server.Network;
  using Server.Spells;
  using Server.Targeting;
  
  namespace Server.Items
  {
  	public enum SpellbookType
  	{
  		Invalid = -1,
  		Regular,
  		Necromancer,
  		Paladin,
  		Ninja,
  		Samurai,
  		Arcanist
  	}
  
  	public enum BookQuality
  	{
  		Regular,
  		Exceptional,
  	}
  
  	public class Spellbook : Item, ICraftable, ISlayer
  	{
  		private string m_EngravedText;
  		private BookQuality m_Quality;
  				
  		[CommandProperty( AccessLevel.GameMaster )]		
  		public string EngravedText
  		{
  			get{ return m_EngravedText; }
  			set{ m_EngravedText = value; InvalidateProperties(); }
  		}
  				
  		[CommandProperty( AccessLevel.GameMaster )]		
  		public BookQuality Quality
  		{
  			get{ return m_Quality; }
  			set{ m_Quality = value; InvalidateProperties(); }
  		}
  
  		public static void Initialize()
  		{
  			EventSink.OpenSpellbookRequest += new OpenSpellbookRequestEventHandler( EventSink_OpenSpellbookRequest );
  			EventSink.CastSpellRequest += new CastSpellRequestEventHandler( EventSink_CastSpellRequest );
  
  			CommandSystem.Register( "AllSpells", AccessLevel.GameMaster, new CommandEventHandler( AllSpells_OnCommand ) );
  		}
  
  		[Usage( "AllSpells" )]
  		[Description( "Completely fills a targeted spellbook with scrolls." )]
  		private static void AllSpells_OnCommand( CommandEventArgs e )
  		{
  			e.Mobile.BeginTarget( -1, false, TargetFlags.None, new TargetCallback( AllSpells_OnTarget ) );
  			e.Mobile.SendMessage( "Target the spellbook to fill." );
  		}
  
  		private static void AllSpells_OnTarget( Mobile from, object obj )
  		{
  			if ( obj is Spellbook )
  			{
  				Spellbook book = (Spellbook)obj;
  
  				if ( book.BookCount == 64 )
  					book.Content = ulong.MaxValue;
  				else
  					book.Content = (1ul << book.BookCount) - 1;
  
  				from.SendMessage( "The spellbook has been filled." );
  
  				CommandLogging.WriteLine( from, "{0} {1} filling spellbook {2}", from.AccessLevel, CommandLogging.Format( from ), CommandLogging.Format( book ) );
  			}
  			else
  			{
  				from.BeginTarget( -1, false, TargetFlags.None, new TargetCallback( AllSpells_OnTarget ) );
  				from.SendMessage( "That is not a spellbook. Try again." );
  			}
  		}
  
  		private static void EventSink_OpenSpellbookRequest( OpenSpellbookRequestEventArgs e )
  		{
  			Mobile from = e.Mobile;
  
  			if ( !Multis.DesignContext.Check( from ) )
  				return; // They are customizing
  
  			SpellbookType type;
  
  			switch ( e.Type )
  			{
  				default:
  				case 1: type = SpellbookType.Regular; break;
  				case 2: type = SpellbookType.Necromancer; break;
  				case 3: type = SpellbookType.Paladin; break;
  				case 4: type = SpellbookType.Ninja; break;
  				case 5: type = SpellbookType.Samurai; break;
  				case 6:	type = SpellbookType.Arcanist; break;
  			}
  
  			Spellbook book = Spellbook.Find( from, -1, type );
  
  			if ( book != null )
  				book.DisplayTo( from );
  		}
  
  		private static void EventSink_CastSpellRequest( CastSpellRequestEventArgs e )
  		{
  			Mobile from = e.Mobile;
  
  			if ( !Multis.DesignContext.Check( from ) )
  				return; // They are customizing
  
  			Spellbook book = e.Spellbook as Spellbook;
  			int spellID = e.SpellID;
  
  			if ( book == null || !book.HasSpell( spellID ) )
  				book = Find( from, spellID );
  
  			if ( book != null && book.HasSpell( spellID ) )
  			{
  				SpecialMove move = SpellRegistry.GetSpecialMove( spellID );
  
  				if ( move != null )
  				{
  					SpecialMove.SetCurrentMove( from, move );
  				}
  				else
  				{
  					Spell spell = SpellRegistry.NewSpell( spellID, from, null );
  	
  					if ( spell != null )
  						spell.Cast();
  					else
  						from.SendLocalizedMessage( 502345 ); // This spell has been temporarily disabled.
  				}
  			}
  			else
  			{
  				from.SendLocalizedMessage( 500015 ); // You do not have that spell!
  			}
  		}
  
  		private static Dictionary<Mobile, List<Spellbook>> m_Table = new Dictionary<Mobile, List<Spellbook>>();
  
  		public static SpellbookType GetTypeForSpell( int spellID )
  		{
  			if ( spellID >= 0 && spellID < 64 )
  				return SpellbookType.Regular;
  			else if ( spellID >= 100 && spellID < 117 )
  				return SpellbookType.Necromancer;
  			else if ( spellID >= 200 && spellID < 210 )
  				return SpellbookType.Paladin;
  			else if( spellID >= 400 && spellID < 406 )
  				return SpellbookType.Samurai;
  			else if( spellID >= 500 && spellID < 508 )
  				return SpellbookType.Ninja;
  			else if ( spellID >= 600 && spellID < 617 )
  				return SpellbookType.Arcanist;
  
  			return SpellbookType.Invalid;
  		}
  
  		public static Spellbook FindRegular( Mobile from )
  		{
  			return Find( from, -1, SpellbookType.Regular );
  		}
  
  		public static Spellbook FindNecromancer( Mobile from )
  		{
  			return Find( from, -1, SpellbookType.Necromancer );
  		}
  
  		public static Spellbook FindPaladin( Mobile from )
  		{
  			return Find( from, -1, SpellbookType.Paladin );
  		}
  
  		public static Spellbook FindSamurai( Mobile from )
  		{
  			return Find( from, -1, SpellbookType.Samurai );
  		}
  
  		public static Spellbook FindNinja( Mobile from )
  		{
  			return Find( from, -1, SpellbookType.Ninja );
  		}
  
  		public static Spellbook FindArcanist( Mobile from )
  		{
  			return Find( from, -1, SpellbookType.Arcanist );
  		}
  
  		public static Spellbook Find( Mobile from, int spellID )
  		{
  			return Find( from, spellID, GetTypeForSpell( spellID ) );
  		}
  
  		public static Spellbook Find( Mobile from, int spellID, SpellbookType type )
  		{
  			if ( from == null )
  				return null;
  
  			if ( from.Deleted )
  			{
  				m_Table.Remove( from );
  				return null;
  			}
  
  			List<Spellbook> list = null;
  
  			m_Table.TryGetValue( from, out list );
  
  			bool searchAgain = false;
  
  			if ( list == null )
  				m_Table[from] = list = FindAllSpellbooks( from );
  			else
  				searchAgain = true;
  
  			Spellbook book = FindSpellbookInList( list, from, spellID, type );
  
  			if ( book == null && searchAgain )
  			{
  				m_Table[from] = list = FindAllSpellbooks( from );
  
  				book = FindSpellbookInList( list, from, spellID, type );
  			}
  
  			return book;
  		}
  
  		public static Spellbook FindSpellbookInList( List<Spellbook> list, Mobile from, int spellID, SpellbookType type )
  		{
  			Container pack = from.Backpack;
  
  			for ( int i = list.Count - 1; i >= 0; --i )
  			{
  				if ( i >= list.Count )
  					continue;
  
  				Spellbook book = list[i];
  
  				if ( !book.Deleted && (book.Parent == from || (pack != null && book.Parent == pack)) && ValidateSpellbook( book, spellID, type ) )
  					return book;
  
  				list.RemoveAt( i );
  			}
  
  			return null;
  		}
  
  		public static List<Spellbook> FindAllSpellbooks( Mobile from )
  		{
  			List<Spellbook> list = new List<Spellbook>();
  
  			Item item = from.FindItemOnLayer( Layer.OneHanded );
  
  			if ( item is Spellbook )
  				list.Add( (Spellbook)item );
  
  			Container pack = from.Backpack;
  
  			if ( pack == null )
  				return list;
  
  			for ( int i = 0; i < pack.Items.Count; ++i )
  			{
  				item = pack.Items[i];
  
  				if ( item is Spellbook )
  					list.Add( (Spellbook)item );
  			}
  
  			return list;
  		}
  
  		public static Spellbook FindEquippedSpellbook( Mobile from )
  		{
  			return (from.FindItemOnLayer( Layer.OneHanded ) as Spellbook);
  		}
  
  		public static bool ValidateSpellbook( Spellbook book, int spellID, SpellbookType type )
  		{
  			return ( book.SpellbookType == type && ( spellID == -1 || book.HasSpell( spellID ) ) );
  		}
  
  		public override bool DisplayWeight { get { return false; } }
  
  		private AosAttributes m_AosAttributes;
  		private AosSkillBonuses m_AosSkillBonuses;
  
  		[CommandProperty( AccessLevel.GameMaster )]
  		public AosAttributes Attributes
  		{
  			get{ return m_AosAttributes; }
  			set{}
  		}
  
  		[CommandProperty( AccessLevel.GameMaster )]
  		public AosSkillBonuses SkillBonuses
  		{
  			get{ return m_AosSkillBonuses; }
  			set{}
  		}
  
  		public virtual SpellbookType SpellbookType{ get{ return SpellbookType.Regular; } }
  		public virtual int BookOffset{ get{ return 0; } }
  		public virtual int BookCount{ get{ return 64; } }
  
  		private ulong m_Content;
  		private int m_Count;
  
  		public override bool AllowSecureTrade( Mobile from, Mobile to, Mobile newOwner, bool accepted )
  		{
  			if ( !Ethics.Ethic.CheckTrade( from, to, newOwner, this ) )
  				return false;
  
  			return base.AllowSecureTrade( from, to, newOwner, accepted );
  		}
  
  		public override bool CanEquip( Mobile from )
  		{
  			if ( !Ethics.Ethic.CheckEquip( from, this ) )
  			{
  				return false;
  			}
  			else if ( !from.CanBeginAction( typeof( BaseWeapon ) ) )
  			{
  				return false;
  			}
  
  			return base.CanEquip( from );
  		}
  
  		public override bool AllowEquipedCast( Mobile from )
  		{
  			return true;
  		}
  
  		public override bool OnDragDrop( Mobile from, Item dropped )
  		{
  			if ( dropped is SpellScroll && dropped.Amount == 1 )
  			{
  				SpellScroll scroll = (SpellScroll)dropped;
  
  
gt: 				SpellbookType type = GetTypeForSpell( scroll.SpellID );