context: using System;
  using System.IO;
  using System.Xml;
  using System.Collections;
  using Server.Network;
  
  namespace Server.Gumps
  {
  	public abstract class CAGNode
  	{
  		public abstract string Caption{ get; }
  		public abstract void OnClick( Mobile from, int page );
  	}
  
  	public class CAGObject : CAGNode
  	{
  		private Type m_Type;
  		private int m_ItemID;
  		private int m_Hue;
  		private CAGCategory m_Parent;
  
  		public Type Type{ get{ return m_Type; } }
  		public int ItemID{ get{ return m_ItemID; } }
  		public int Hue{ get{ return m_Hue; } }
  		public CAGCategory Parent{ get{ return m_Parent; } }
  
  		public override string Caption{ get{ return ( m_Type == null ? "bad type" : m_Type.Name ); } }
  
  		public override void OnClick( Mobile from, int page )
  		{
  			if ( m_Type == null )
  			{
  				from.SendMessage( "That is an invalid type name." );
  			}
  			else
  			{
  				Commands.Handle( from, String.Format( "{0}Add {1}", Commands.CommandPrefix, m_Type.Name ) );
  
  				from.SendGump( new CategorizedAddGump( from, m_Parent, page ) );
  			}
  		}
  
  		public CAGObject( CAGCategory parent, XmlTextReader xml )
  		{
  			m_Parent = parent;
  
  			if ( xml.MoveToAttribute( "type" ) )
  				m_Type = ScriptCompiler.FindTypeByFullName( xml.Value, false );
  
  			if ( xml.MoveToAttribute( "gfx" ) )
  				m_ItemID = XmlConvert.ToInt32( xml.Value );
  
  			if ( xml.MoveToAttribute( "hue" ) )
  				m_Hue = XmlConvert.ToInt32( xml.Value );
  		}
  	}
  
  	public class CAGCategory : CAGNode
  	{
  		private string m_Title;
  		private CAGNode[] m_Nodes;
  		private CAGCategory m_Parent;
  
  		public string Title{ get{ return m_Title; } }
  		public CAGNode[] Nodes{ get{ return m_Nodes; } }
  		public CAGCategory Parent{ get{ return m_Parent; } }
  
  		public override string Caption{ get{ return m_Title; } }
  
  		public override void OnClick( Mobile from, int page )
  		{
  			from.SendGump( new CategorizedAddGump( from, this, 0 ) );
  		}
  
  		private CAGCategory()
  		{
  			m_Title = "no data";
  			m_Nodes = new CAGNode[0];
  		}
  
  		public CAGCategory( CAGCategory parent, XmlTextReader xml )
  		{
  			m_Parent = parent;
  
  			if ( xml.MoveToAttribute( "title" ) )
  				m_Title = xml.Value;
  			else
  				m_Title = "empty";
  
  			if ( m_Title == "Docked" )
  				m_Title = "Docked 2";
  
  			if ( xml.IsEmptyElement )
  			{
  				m_Nodes = new CAGNode[0];
  			}
  			else
  			{
  				ArrayList nodes = new ArrayList();
  
  				while ( xml.Read() && xml.NodeType != XmlNodeType.EndElement )
  				{
  					if ( xml.NodeType == XmlNodeType.Element && xml.Name == "object" )
  						nodes.Add( new CAGObject( this, xml ) );
  					else if ( xml.NodeType == XmlNodeType.Element && xml.Name == "category" )
  						nodes.Add( new CAGCategory( this, xml ) );
  					else
  						xml.Skip();
  				}
  
  				m_Nodes = (CAGNode[])nodes.ToArray( typeof( CAGNode ) );
  			}
  		}
  
  		private static CAGCategory m_Root;
  
  		public static CAGCategory Root
  		{
  			get
  			{
  				if ( m_Root == null )
  					m_Root = Load(Path.Combine(Core.Config.ConfigDirectory, "objects.xml"));
  
  				return m_Root;
  			}
  		}
  
  		public static CAGCategory Load( string path )
  		{
  			if ( File.Exists( path ) )
  			{
  				XmlTextReader xml = new XmlTextReader( path );
  
  				xml.WhitespaceHandling = WhitespaceHandling.None;
  
  				while ( xml.Read() )
  				{
  					if ( xml.Name == "category" && xml.NodeType == XmlNodeType.Element )
  					{
  						CAGCategory cat = new CAGCategory( null, xml );
  
  						xml.Close();
  
  						return cat;
  					}
  				}
  			}
  
  			return new CAGCategory();
  		}
  	}
  
  	public class CategorizedAddGump : Gump
  	{
  		public static bool OldStyle = PropsConfig.OldStyle;
  
  		public const int GumpOffsetX = PropsConfig.GumpOffsetX;
  		public const int GumpOffsetY = PropsConfig.GumpOffsetY;
  
  		public const int TextHue = PropsConfig.TextHue;
  		public const int TextOffsetX = PropsConfig.TextOffsetX;
  
  		public const int OffsetGumpID = PropsConfig.OffsetGumpID;
  		public const int HeaderGumpID = PropsConfig.HeaderGumpID;
  		public const int  EntryGumpID = PropsConfig.EntryGumpID;
  		public const int   BackGumpID = PropsConfig.BackGumpID;
  		public const int    SetGumpID = PropsConfig.SetGumpID;
  
  		public const int SetWidth = PropsConfig.SetWidth;
  		public const int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY + (((EntryHeight - 20) / 2) / 2);
  		public const int SetButtonID1 = PropsConfig.SetButtonID1;
  		public const int SetButtonID2 = PropsConfig.SetButtonID2;
  
  		public const int PrevWidth = PropsConfig.PrevWidth;
  		public const int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY + (((EntryHeight - 20) / 2) / 2);
  		public const int PrevButtonID1 = PropsConfig.PrevButtonID1;
  		public const int PrevButtonID2 = PropsConfig.PrevButtonID2;
  
  		public const int NextWidth = PropsConfig.NextWidth;
  		public const int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY + (((EntryHeight - 20) / 2) / 2);
  		public const int NextButtonID1 = PropsConfig.NextButtonID1;
  		public const int NextButtonID2 = PropsConfig.NextButtonID2;
  
  		public const int OffsetSize = PropsConfig.OffsetSize;
  
  		public const int EntryHeight = 24;//PropsConfig.EntryHeight;
  		public const int BorderSize = PropsConfig.BorderSize;
  
  		private static bool PrevLabel = false, NextLabel = false;
  
  		private const int PrevLabelOffsetX = PrevWidth + 1;
  		private const int PrevLabelOffsetY = 0;
  
  		private const int NextLabelOffsetX = -29;
  		private const int NextLabelOffsetY = 0;
  
  		private const int EntryWidth = 180;
  		private const int EntryCount = 15;
  
  		private const int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize;
  		private const int TotalHeight = OffsetSize + ((EntryHeight + OffsetSize) * (EntryCount + 1));
  
  		private const int BackWidth = BorderSize + TotalWidth + BorderSize;
  		private const int BackHeight = BorderSize + TotalHeight + BorderSize;
  
  		private Mobile m_Owner;
  		private CAGCategory m_Category;
  		private int m_Page;
  
  		public CategorizedAddGump( Mobile owner ) : this( owner, CAGCategory.Root, 0 )
  		{
  		}
  
  		public CategorizedAddGump( Mobile owner, CAGCategory category, int page ) : base( GumpOffsetX, GumpOffsetY )
  		{
  			owner.CloseGump( typeof( WhoGump ) );
  
  			m_Owner = owner;
  			m_Category = category;
  
  			Initialize( page );
  		}
  
  		public void Initialize( int page )
  		{
  			m_Page = page;
  
  			CAGNode[] nodes = m_Category.Nodes;
  
  			int count = nodes.Length - (page * EntryCount);
  
  			if ( count < 0 )
  				count = 0;
  			else if ( count > EntryCount )
  				count = EntryCount;
  
  			int totalHeight = OffsetSize + ((EntryHeight + OffsetSize) * (count + 1));
  
  			AddPage( 0 );
  
  			AddBackground( 0, 0, BackWidth, BorderSize + totalHeight + BorderSize, BackGumpID );
  			AddImageTiled( BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), totalHeight, OffsetGumpID );
  
  			int x = BorderSize + OffsetSize;
  			int y = BorderSize + OffsetSize;
  
  			if ( OldStyle )
  				AddImageTiled( x, y, TotalWidth - (OffsetSize * 3) - SetWidth, EntryHeight, HeaderGumpID );
  			else
  				AddImageTiled( x, y, PrevWidth, EntryHeight, HeaderGumpID );
  
  			if ( m_Category.Parent != null )
  			{
  				AddButton( x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, 1, GumpButtonType.Reply, 0 );
  
  				if ( PrevLabel )
  					AddLabel( x + PrevLabelOffsetX, y + PrevLabelOffsetY, TextHue, "Previous" );
  			}
  
  			x += PrevWidth + OffsetSize;
  
  			int emptyWidth = TotalWidth - (PrevWidth * 2) - NextWidth - (OffsetSize * 5) - (OldStyle ? SetWidth + OffsetSize : 0);
  
  			if ( !OldStyle )
  				AddImageTiled( x - (OldStyle ? OffsetSize : 0), y, emptyWidth + (OldStyle ? OffsetSize * 2 : 0), EntryHeight, EntryGumpID );
  
  			AddHtml( x + TextOffsetX, y + ((EntryHeight - 20) / 2), emptyWidth - TextOffsetX, EntryHeight, String.Format( "<center>{0}</center>", m_Category.Caption ), false, false );
  
  
gt: 			x += emptyWidth + OffsetSize;