context: using System;
  using System.IO;
  using System.Xml;
  using System.Collections;
  using Server.Network;
  using Server.Mobiles;
  
  /*
  ** Modified from RunUO 1.0.0 CategorizedAddGump.cs
  ** by ArteGordon
  ** 2/5/05
  */
  namespace Server.Gumps
  {
  
  	public abstract class XmlAddCAGNode
  	{
  		public abstract string Caption{ get; }
  		public abstract void OnClick( Mobile from, int page, int index, Gump gump );
  	}
  
  	public class XmlAddCAGObject : XmlAddCAGNode
  	{
  		private Type m_Type;
  		private int m_ItemID;
  		private int m_Hue;
  		private XmlAddCAGCategory m_Parent;
  
  		public Type Type{ get{ return m_Type; } }
  		public int ItemID{ get{ return m_ItemID; } }
  		public int Hue{ get{ return m_Hue; } }
  		public XmlAddCAGCategory 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, int index, Gump gump )
  		{
  			if ( m_Type == null )
  			{
  				from.SendMessage( "That is an invalid type name." );
  			}
  			else
  			{
  				if(gump is XmlAddGump)
  				{
  					XmlAddGump xmladdgump = (XmlAddGump)gump;
  
  					//Commands.Handle( from, String.Format( "{0}Add {1}", Commands.CommandPrefix, m_Type.Name ) );
  					if(xmladdgump != null && xmladdgump.defs != null && xmladdgump.defs.NameList != null &&
  						index >= 0 && index < xmladdgump.defs.NameList.Length)
  					{
  
  						xmladdgump.defs.NameList[index] = m_Type.Name;
  						XmlAddGump.Refresh(from, true);
  					}
  					from.SendGump( new XmlCategorizedAddGump( from, m_Parent, page, index, xmladdgump ) );
  				} 
  				else
  					if(gump is XmlSpawnerGump)
  				{
  					XmlSpawner m_Spawner = ((XmlSpawnerGump)gump).m_Spawner;
  
  					if(m_Spawner != null)
  					{							
  						XmlSpawnerGump xg = m_Spawner.SpawnerGump; 
  
  						if(xg != null)
  						{
  
  							xg.Rentry = new XmlSpawnerGump.ReplacementEntry();
  							xg.Rentry.Typename = m_Type.Name;
  							xg.Rentry.Index = index;
  							xg.Rentry.Color = 0x1436;
  
  							Timer.DelayCall( TimeSpan.Zero, new TimerStateCallback( XmlSpawnerGump.Refresh_Callback ), new object[]{ from } );
  							//from.CloseGump(typeof(XmlSpawnerGump));
  							//from.SendGump( new XmlSpawnerGump(xg.m_Spawner, xg.X, xg.Y, xg.m_ShowGump, xg.xoffset, xg.page, xg.Rentry) );
  						}							
  					}
  				}
  			}
  		}
  
  		public XmlAddCAGObject( XmlAddCAGCategory 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 XmlAddCAGCategory : XmlAddCAGNode
  	{
  		private string m_Title;
  		private XmlAddCAGNode[] m_Nodes;
  		private XmlAddCAGCategory m_Parent;
  
  		public string Title{ get{ return m_Title; } }
  		public XmlAddCAGNode[] Nodes{ get{ return m_Nodes; } }
  		public XmlAddCAGCategory Parent{ get{ return m_Parent; } }
  
  		public override string Caption{ get{ return m_Title; } }
  
  		public override void OnClick( Mobile from, int page, int index, Gump gump )
  		{
  			from.SendGump( new XmlCategorizedAddGump( from, this, 0, index, gump ) );
  		}
  
  		private XmlAddCAGCategory()
  		{
  			m_Title = "no data";
  			m_Nodes = new XmlAddCAGNode[0];
  		}
  
  		public XmlAddCAGCategory( XmlAddCAGCategory parent, XmlTextReader xml )
  		{
  			m_Parent = parent;
  
  			if ( xml.MoveToAttribute( "title" ) )
  			{
                  if(xml.Value == "Add Menu")
                      m_Title = "XmlAdd Menu";
                  else
  				    m_Title = xml.Value;
  
  			}
  			else
  				m_Title = "empty";
  
  			if ( m_Title == "Docked" )
  				m_Title = "Docked 2";
  
  			if ( xml.IsEmptyElement )
  			{
  				m_Nodes = new XmlAddCAGNode[0];
  			}
  			else
  			{
  				ArrayList nodes = new ArrayList();
  
                  try{
  				while ( xml.Read() && xml.NodeType != XmlNodeType.EndElement )
  				{
  
  					if ( xml.NodeType == XmlNodeType.Element && xml.Name == "object" )
  						nodes.Add( new XmlAddCAGObject( this, xml ) );
                      else if (xml.NodeType == XmlNodeType.Element && xml.Name == "category")
                      {
                          if (!xml.IsEmptyElement)
                          {
  
                              nodes.Add(new XmlAddCAGCategory(this, xml));
                          }
                      }
                      else
                          xml.Skip();
  
  				}
  				} catch (Exception ex){
                      Console.WriteLine("XmlCategorizedAddGump: Corrupted Data/objects.xml file detected. Not all XmlCAG objects loaded. {0}", ex); 
                  }
  
  
  				m_Nodes = (XmlAddCAGNode[])nodes.ToArray( typeof( XmlAddCAGNode ) );
  
  			}
  		}
  
  		private static XmlAddCAGCategory m_Root;
  
  		public static XmlAddCAGCategory Root
  		{
  			get
  			{
  				if ( m_Root == null )
  					m_Root = Load( "Data/objects.xml" );
  
  				return m_Root;
  			}
  		}
  
  		public static XmlAddCAGCategory 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 )
  					{
  						XmlAddCAGCategory cat = new XmlAddCAGCategory( null, xml );
  
  						xml.Close();
  
  						return cat;
  					}
  				}
  			}
  
  			return new XmlAddCAGCategory();
  		}
  	}
  
  
  
  	public class XmlCategorizedAddGump : Gump
  	{
  		public static bool OldStyle = PropsConfig.OldStyle;
  
  		public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX;
  		public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY;
  
  		public static readonly int TextHue = PropsConfig.TextHue;
  		public static readonly int TextOffsetX = PropsConfig.TextOffsetX;
  
  		public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID;
  		public static readonly int HeaderGumpID = PropsConfig.HeaderGumpID;
  		public static readonly int EntryGumpID = PropsConfig.EntryGumpID;
  		public static readonly int BackGumpID = PropsConfig.BackGumpID;
  		public static readonly int SetGumpID = PropsConfig.SetGumpID;
  
  		public static readonly int SetWidth = PropsConfig.SetWidth;
  		public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY /*+ (((EntryHeight - 20) / 2) / 2)*/;
  		public static readonly int SetButtonID1 = PropsConfig.SetButtonID1;
  		public static readonly int SetButtonID2 = PropsConfig.SetButtonID2;
  
  		public static readonly int PrevWidth = PropsConfig.PrevWidth;
  		public static readonly int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY /*+ (((EntryHeight - 20) / 2) / 2)*/;
  		public static readonly int PrevButtonID1 = PropsConfig.PrevButtonID1;
  		public static readonly int PrevButtonID2 = PropsConfig.PrevButtonID2;
  
  		public static readonly int NextWidth = PropsConfig.NextWidth;
  		public static readonly int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY /*+ (((EntryHeight - 20) / 2) / 2)*/;
  		public static readonly int NextButtonID1 = PropsConfig.NextButtonID1;
  		public static readonly int NextButtonID2 = PropsConfig.NextButtonID2;
  
  		public static readonly int OffsetSize = PropsConfig.OffsetSize;
  
  		public static readonly int EntryHeight = 24;//PropsConfig.EntryHeight;
  		public static readonly int BorderSize = PropsConfig.BorderSize;
  
  		private static bool PrevLabel = false, NextLabel = false;
  
  		private static readonly int PrevLabelOffsetX = PrevWidth + 1;
  		private static readonly int PrevLabelOffsetY = 0;
  
  		private static readonly int NextLabelOffsetX = -29;
  		private static readonly int NextLabelOffsetY = 0;
  
  		private static readonly int EntryWidth = 180;
  		private static readonly int EntryCount = 15;
  
  		private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize;
  		private static readonly int TotalHeight = OffsetSize + ((EntryHeight + OffsetSize) * (EntryCount + 1));
  
  		private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize;
  		private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize;
  		private Mobile m_Owner;
  		private XmlAddCAGCategory m_Category;
  		private int m_Page;
  		
  		private int m_Index = -1;
  		private Gump m_Gump;
  		private XmlSpawner m_Spawner;
  
  		public XmlCategorizedAddGump( Mobile owner, int index, Gump gump ) : this( owner, XmlAddCAGCategory.Root, 0, index, gump )
  		{
  		}
  
  		public XmlCategorizedAddGump( Mobile owner, XmlAddCAGCategory category, int page, int index, Gump gump ) : base( GumpOffsetX, GumpOffsetY )
  		{
  			if (category == null)
  			{
  				category = XmlAddCAGCategory.Root;
  				page = 0;
  			}
  
  			owner.CloseGump( typeof( WhoGump ) );
  
  			m_Owner = owner;
  			m_Category = category;
  			
  			m_Index = index;
  			m_Gump = gump;
  			if(gump is XmlAddGump)
  			{
  				XmlAddGump xmladdgump = (XmlAddGump)gump;
  
  				if(xmladdgump != null && xmladdgump.defs != null)
  				{
  					xmladdgump.defs.CurrentCategory = category;
  					xmladdgump.defs.CurrentCategoryPage = page;
  				}
  			} 
  			else
  				if(gump is XmlSpawnerGump)
  			{
  				m_Spawner = ((XmlSpawnerGump)gump).m_Spawner;
  
  				
  			}
  
  			Initialize( page );
  		}
  
  		public void Initialize( int page )
  		{
  			m_Page = page;
  
  			XmlAddCAGNode[] nodes = m_Category.Nodes;
  
  
gt: 			int count = nodes.Length - (page * EntryCount);