context: using System;
  using Server;
  using Server.Items;
  using Server.Network;
  using Server.Mobiles;
  using System.Collections;
  using Server.Gumps;
  using System.Text;
  using Server.Targeting;
  using Server.Commands;
  using Server.Commands.Generic;
  using Server.FeaturesConfiguration;
  
  namespace Server.Engines.XmlSpawner2
  {
  
  	public class XmlSockets : XmlAttachment
  	{
  		// if CanSocketByDefault is set to true, then any object can be socketed using the default settings.  If the XmlSocketable attachment is present, it
  		// will override these defaults regardless of the CanSocketByDefault setting.  
  		// If this is set to false, then ONLY objects with the XmlSocketable attachment can be socketed.
  		public static bool CanSocketByDefault = false;
  
  		// The following default settings will be applied when CanSocketByDefault is true
  		//
  		// DefaultMaxSockets determines the default maximum number of sockets and item can have.
  		// A value of -1 means that any item can have an unlimited number of sockets.  
  		// To set it up so that items by default cannot have sockets added to them set this to zero.  
  		// That way, only items that have the XmlSocketLimit attachment will be allowed to be socketed.  This is the same as setting CanSocketByDefault to false.
  		// You can also assign any other value here to set the default number of sockets allowed when no XmlSocketLimit attachment is present.
  		public static int DefaultMaxSockets = -1;
  
  		// DefaultSocketDifficulty is the default minimum skill required to socket.
  		// This can be overridden with the XmlSocketLimit attachment on specific items (100 by default)
  		public static double DefaultSocketDifficulty = 100.0;
          
  		public static SkillName DefaultSocketSkill = SkillName.Blacksmith;
  
  		public static Type DefaultSocketResource = typeof(ValoriteIngot);
  
  		public static int DefaultSocketResourceQuantity = 50;
  
  		// DefaultDestructionProbability is the percent chance that failure to socket will result in destruction of the the item (10% by default)
  		public static double DefaultDestructionProbability = 0.1;
          
  		public static int MaxAugmentDistance = 2;   // if socketed object isnt in pack, then this is the max distance away from it you can be and still augment
          
  		public static int MaxSocketDistance = 2;   // if socketable object isnt in pack, then this is the max distance away from it you can be and still socket
  
  		private ArrayList m_SocketOccupants;
          
  		private bool m_MustAugmentInPack = true;         // determines whether the socketed object must be in the players pack in order to augment
  
  		public class SocketOccupant
  		{
  			public Type OccupantType;
  			public int OccupantID;
  			public int AugmentationVersion;
  			public string Description;
  			public int IconXOffset;
  			public int IconYOffset;
  			public int IconHue;
  			public bool UseGumpArt;
              
  			public SocketOccupant(Type t, int version, int id, int xoffset, int yoffset, int hue, bool usegumpart, string description)
  			{
  				OccupantType = t;
  				AugmentationVersion = version;
  				OccupantID = id;
  				IconXOffset = xoffset;
  				IconYOffset = yoffset;
  				IconHue = hue;
  				UseGumpArt = usegumpart;
  				Description = description;
  			}
              
  			public SocketOccupant(Type t, int nsockets, int version, int id)
  			{
  				OccupantType = t;
  				AugmentationVersion = version;
  				OccupantID = id;
  			}
  		}
  
  		public ArrayList SocketOccupants { get{ return m_SocketOccupants; } set { m_SocketOccupants = value;} }
  
  		[CommandProperty( AccessLevel.GameMaster )]
  		public bool MustAugmentInPack 
  		{
  			get
  			{ 
  				return m_MustAugmentInPack;
  			}
  			set 
  			{
  				m_MustAugmentInPack = value;
  			}
  		}
  
  		[CommandProperty( AccessLevel.GameMaster )]
  		public int NSockets 
  		{ 
  			get
  			{ 
  				if(m_SocketOccupants == null)
  				{
  					return 0;
  				}
  				else
  				{
  					return  m_SocketOccupants.Count;
  				}
  			}
  		}
  
  		[CommandProperty( AccessLevel.GameMaster )]
  		public int NFree 
  		{ 
  			get
  			{
  				if(m_SocketOccupants == null)
  				{
  					return 0;
  				}
  				else
  				{
  					int count = 0;
  					for(int i = 0; i < m_SocketOccupants.Count; i++)
  					{
  						if(m_SocketOccupants[i] != null) count++;
  					}
  					return  m_SocketOccupants.Count - count;
  				}
  			}
  		}
          
  		public static new void Initialize()
  		{
              if (FeaturesConfig.XMLAddSocketEnabled)
              {
                  CommandSystem.Register("AddSocket", AccessLevel.Player, new CommandEventHandler(AddSocket_OnCommand));
                  TargetCommands.Register(new UpgradeAugmentCommand());
                  TargetCommands.Register(new LimitSocketsCommand());
              }
  		}
  
  		public class LimitSocketsCommand : BaseCommand
  		{
  			int m_maxsockets;
  
  			public LimitSocketsCommand()
  			{
  				AccessLevel = AccessLevel.Administrator;
  				Supports = CommandSupport.Area | CommandSupport.Region | CommandSupport.Global | CommandSupport.Multi | CommandSupport.Single;
  				Commands = new string[]{ "LimitSockets" };
  				ObjectTypes = ObjectTypes.All;
  				Usage = "LimitSockets <maxsockets>";
  				Description = "Finds XmlSocket attachments with more than maxsockets, recovers their augmentations and reduces the socket number";
  				ListOptimized = true;
  			}
  			
  			public override void ExecuteList( CommandEventArgs e, ArrayList list )
  			{
  				
  			
  				int nobjects = 0;
  
  				for ( int i = 0; i < list.Count; ++i )
  				{
  
  					object targetobject = list[i];
  
  					// get any socket attachments
  					// first see if the target has any existing sockets
  					XmlSockets s = XmlAttach.FindAttachment(targetobject,typeof(XmlSockets)) as XmlSockets;
  
  					bool found = true;
  
  					if(s != null && s.SocketOccupants != null && s.SocketOccupants.Count > m_maxsockets)
  					{
  						int maxsock = s.NSockets;
  						int nchange = 0;
  						while(found && nchange <= maxsock)
  						{
  							found = false;
  						
  							// recover all of the augments
  							for(int j = 0; j < s.SocketOccupants.Count; j++)
  							{
  								SocketOccupant so =s.SocketOccupants[j] as SocketOccupant;
  								if(so != null )
  								{
  									nchange++;
  
  									// recover the old version of the augment
  									BaseSocketAugmentation augment = s.RecoverAugmentation(null, targetobject, j);
  
  									if(augment != null)
  									{
  
  										// give it back to the owner
  										if(targetobject is Item)
  										{
  											// is the parent a container?
  											if(((Item)targetobject).Parent is Container)
  											{
  												// add the augment to the container
  												((Container)((Item)targetobject).Parent).DropItem(augment);
  
  											} 
  											else
  												if(((Item)targetobject).Parent is Mobile)
  											{
  												// drop it on the ground
  												augment.MoveToWorld(((Mobile)((Item)targetobject).Parent).Location);
  											} 
  											else
  												if(((Item)targetobject).Parent == null)
  											{
  												// drop it on the ground
  												augment.MoveToWorld(((Item)targetobject).Location);
  											}
  										} 
  										else
  											if(targetobject is Mobile)
  										{
  											// drop it on the ground
  											augment.MoveToWorld(((Mobile)targetobject).Location);
  										}
  										
  										found = true;
  
  										break;
  									}
  								}
  							}
  						}
  						if(nchange > 0)
  							nobjects ++;
  
  						e.Mobile.SendMessage("Modified object {0}",targetobject);
  
  						// limit the sockets
  						s.SocketOccupants = new ArrayList(m_maxsockets);
  
  						for(int k =0;k<m_maxsockets;k++) 
  						{
  							s.SocketOccupants.Add(null);
  						}
  					}
  				}
  				
  				AddResponse( String.Format( "{0} objects adjusted.",nobjects) );
  
  			}
  			
  			public override bool ValidateArgs( BaseCommandImplementor impl, CommandEventArgs e )
  			{
  				if ( e.Arguments.Length >= 1 )
  				{
  					try
  					{
  						m_maxsockets = int.Parse(e.GetString( 0 ));
  					} 
  					catch { e.Mobile.SendMessage( "Usage: " + Usage ); return false; }
  
  					return true;
  
  					
  				}
  				
  				e.Mobile.SendMessage( "Usage: " + Usage );
  				return false;
  			}
  		}
  
  		public class UpgradeAugmentCommand : BaseCommand
  		{
  			int m_oldversion;
  			Type m_augmenttype;
  
  			public UpgradeAugmentCommand()
  			{
  				AccessLevel = AccessLevel.Administrator;
  				Supports = CommandSupport.Area | CommandSupport.Region | CommandSupport.Global | CommandSupport.Multi | CommandSupport.Single;
  				Commands = new string[]{ "UpgradeAugment" };
  				ObjectTypes = ObjectTypes.All;
  				Usage = "UpgradeAugment <augmenttype> <oldversion>";
  				Description = "Upgrades the specified augmentation on objects from the oldversion number to the newversion number.";
  				ListOptimized = true;
  			}
  			
  			public override void ExecuteList( CommandEventArgs e, ArrayList list )
  			{
  				
  			
  				int naugments = 0;
  				int nobjects = 0;
  				int nfailures = 0;
  
  				for ( int i = 0; i < list.Count; ++i )
  				{
  
  					object targetobject = list[i];
  
  					// get any socket attachments
  					// first see if the target has any existing sockets
  					XmlSockets s = XmlAttach.FindAttachment(targetobject,typeof(XmlSockets)) as XmlSockets;
  
  					bool found = true;
  
  					if(s != null && s.SocketOccupants != null)
  					{
  						int maxsock = s.NSockets;
  						int nchange = 0;
  						while(found && nchange <= maxsock)
  						{
  							found = false;
  						
  							// find the specified augment type
  							for(int j = 0; j < s.SocketOccupants.Count; j++)
  							{
  								SocketOccupant so =s.SocketOccupants[j] as SocketOccupant;
  								if(so != null && so.OccupantType == m_augmenttype && so.AugmentationVersion == m_oldversion)
  								{
  
  									// recover the old version of the augment
  									BaseSocketAugmentation augment = s.RecoverAugmentation(null, targetobject, j);
  
  									if(augment != null)
  									{
  
  										// augment with the new version
  										if(!Augment( null, targetobject, s, j, augment))
  										{
  											e.Mobile.SendMessage("failed to replace augment on {0}",targetobject);
  											nfailures++;
  										} 
  										else 
  										{
  
  											naugments++;
  										}
  
  										nchange++;
  
  										found = true;
  
  										break;
  									}
  								}
  							}
  						}
  						if(nchange > 0)
  							nobjects ++;
  					}
  				}
  				
  				AddResponse( String.Format( "{0} {1} augmentations upgraded on {2} objects. {3} failures.", naugments, m_augmenttype.Name, nobjects, nfailures ) );
  
  			}
  			
  			public override bool ValidateArgs( BaseCommandImplementor impl, CommandEventArgs e )
  			{
  				if ( e.Arguments.Length >= 2 )
  				{
  					m_augmenttype = SpawnerType.GetType(e.GetString( 0 ));
  
  					if(m_augmenttype == null)
  					{
  						e.Mobile.SendMessage( "Unknown augment type: " + e.GetString( 0 ));
  						return false;
  					}
  
  					m_oldversion = -1;
  					try
  					{
  						m_oldversion = int.Parse(e.GetString( 1 ));
  					} 
  					catch{}
  
  					if(m_oldversion != -1)
  					{
  						return true;
  					}
  				}
  				
  				e.Mobile.SendMessage( "Usage: " + Usage );
  				return false;
  			}
  		}
  
  		// These are the various ways in which the message attachment can be constructed.  
  		// These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword.
  		// Other overloads could be defined to handle other types of arguments
  
  		// a serial constructor is REQUIRED
  		public XmlSockets(ASerial serial) : base(serial)
  		{
  		}
  
  		[Attachable]
  		public XmlSockets(int nsockets)
  		{
  			m_SocketOccupants = new ArrayList(nsockets);
  
  			for(int i =0;i<nsockets;i++) 
  			{
  				m_SocketOccupants.Add(null);
  			}
  
  			InvalidateParentProperties();
  		}
          
  		[Attachable]
  		public XmlSockets(int nsockets, bool mustaugmentinpack)
  		{
  			m_SocketOccupants = new ArrayList(nsockets);
  
  			for(int i =0;i<nsockets;i++) 
  			{
  				m_SocketOccupants.Add(null);
  			}
              
  			MustAugmentInPack = mustaugmentinpack;
  
  			InvalidateParentProperties();
  		}
  
  		public override void Serialize( GenericWriter writer )
  		{
  			base.Serialize(writer);
  
  			writer.Write( (int) 2 );
  
  			// version 1
  			writer.Write(m_MustAugmentInPack);
  
  			// version 0
  			if(m_SocketOccupants == null)
  			{
  				writer.Write((int)0);
  			}
  			else
  			{
  				writer.Write(m_SocketOccupants.Count);
  
  				for(int i = 0;i< m_SocketOccupants.Count;i++)
  				{
  					SocketOccupant s = (SocketOccupant)m_SocketOccupants[i];
  					if(s != null)
  					{
  						string typename = s.OccupantType.ToString();
  
  						writer.Write(typename);
  
  						if( typename != null)
  						{
  							writer.Write(s.AugmentationVersion);  // added in version 2
  							writer.Write(s.OccupantID);
  							writer.Write(s.Description);
  							writer.Write(s.IconXOffset);
  							writer.Write(s.IconYOffset);
  							writer.Write(s.IconHue);
  							writer.Write(s.UseGumpArt);
  						}
  
  					} 
  					else
  					{
  						writer.Write((string)null);
  					}
  				}
  			}
  		}
  
  		public override void Deserialize(GenericReader reader)
  		{
  			base.Deserialize(reader);
  
  			int version = reader.ReadInt();
  
  			if(version > 0)
  			{
  				// version 1
  
gt: 				m_MustAugmentInPack = reader.ReadBool();