context: using Server.Mobiles;
  using Server.Network;
  using System;
  using System.Collections;
  using System.IO;
  using System.Xml;
  
  /*
  ** 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 readonly Type m_Type;
          private readonly int m_ItemID;
          private readonly int m_Hue;
          private readonly XmlAddCAGCategory m_Parent;
  
          public Type Type => m_Type;
          public int ItemID => m_ItemID;
          public int Hue => m_Hue;
          public XmlAddCAGCategory Parent => m_Parent;
  
          public override string Caption => (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 readonly string m_Title;
          private readonly XmlAddCAGNode[] m_Nodes;
          private readonly XmlAddCAGCategory m_Parent;
  
          public string Title => m_Title;
          public XmlAddCAGNode[] Nodes => m_Nodes;
          public XmlAddCAGCategory Parent => m_Parent;
  
          public override string Caption => 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 readonly 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 readonly Mobile m_Owner;
          private readonly XmlAddCAGCategory m_Category;
          private int m_Page;
  
          private readonly int m_Index = -1;
          private readonly Gump m_Gump;
          private readonly 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;
  
              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);
  
  
gt:             if (m_Category.Parent != null)