context: using System;
  using System.Collections.Generic;
  using System.Globalization;
  using Server.Items;
  using Server.Gumps;
  using Server.Prompts;
  using Server.Targeting;
  using Server.Misc;
  using Server.Multis;
  using Server.ContextMenus;
  
  namespace Server.Mobiles
  {
      [AttributeUsage( AttributeTargets.Class )]
  	public class PlayerVendorTargetAttribute : Attribute
  	{
  		public PlayerVendorTargetAttribute()
  		{
  		}
  	}
  
  	public class VendorItem
  	{
  		private Item m_Item;
  		private int m_Price;
  		private string m_Description;
  		private DateTime m_Created;
  
  		private bool m_Valid;
  
  		public Item Item{ get{ return m_Item; } }
  		public int Price{ get{ return m_Price; } }
  
  		public string FormattedPrice
  		{
  			get
  			{
  				if ( Core.ML )
  					return m_Price.ToString( "N0", CultureInfo.GetCultureInfo( "en-US" ) );
  
  				return m_Price.ToString();
  			}
  		}
  
  		public string Description
  		{
  			get{ return m_Description; }
  			set
  			{
  				if ( value != null )
  					m_Description = value;
  				else
  					m_Description = "";
  
  				if ( Valid )
  					Item.InvalidateProperties();
  			}
  		}
  
  		public DateTime Created{ get{ return m_Created; } }
  
  		public bool IsForSale{ get{ return Price >= 0; } }
  		public bool IsForFree{ get{ return Price == 0; } }
  
  		public bool Valid{ get{ return m_Valid; } }
  
  		public VendorItem( Item item, int price, string description, DateTime created )
  		{
  			m_Item = item;
  			m_Price = price;
  
  			if ( description != null )
  				m_Description = description;
  			else
  				m_Description = "";
  
  			m_Created = created;
  
  			m_Valid = true;
  		}
  
  		public void Invalidate()
  		{
  			m_Valid = false;
  		}
  	}
  
  	public class VendorBackpack : Backpack
  	{
  		public VendorBackpack()
  		{
  			Layer = Layer.Backpack;
  			Weight = 1.0;
  		}
  
  		public override int DefaultMaxWeight{ get{ return 0; } }
  
  		public override bool CheckHold( Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight )
  		{
  			if ( !base.CheckHold( m, item, message, checkItems, plusItems, plusWeight ) )
  				return false;
  
  			if ( Ethics.Ethic.IsImbued( item, true ) )
  			{
  				if ( message )
  					m.SendMessage( "Imbued items may not be sold here." );
  
  				return false;
  			}
  
  			if ( !BaseHouse.NewVendorSystem && Parent is PlayerVendor )
  			{
  				BaseHouse house = ((PlayerVendor)Parent).House;
  
  				if ( house != null && house.IsAosRules && !house.CheckAosStorage( 1 + item.TotalItems + plusItems ) )
  				{
  					if ( message )
  						m.SendLocalizedMessage( 1061839 ); // This action would exceed the secure storage limit of the house.
  
  					return false;
  				}
  			}
  
  			return true;
  		}
  
  		public override bool IsAccessibleTo( Mobile m )
  		{
  			return true;
  		}
  
  		public override bool CheckItemUse( Mobile from, Item item )
  		{
  			if ( !base.CheckItemUse( from, item ) )
  				return false;
  
  			if ( item is Container || item is Engines.BulkOrders.BulkOrderBook )
  				return true;
  
  			from.SendLocalizedMessage( 500447 ); // That is not accessible.
  			return false;
  		}
  
  		public override bool CheckTarget( Mobile from, Target targ, object targeted )
  		{
  			if ( !base.CheckTarget( from, targ, targeted ) )
  				return false;
  
  			if ( from.AccessLevel >= AccessLevel.GameMaster )
  				return true;
  
  			return targ.GetType().IsDefined( typeof( PlayerVendorTargetAttribute ), false );
  		}
  
  		public override void GetChildContextMenuEntries( Mobile from, List<ContextMenuEntry> list, Item item )
  		{
  			base.GetChildContextMenuEntries( from, list, item );
  
  			PlayerVendor pv = RootParent as PlayerVendor;
  
  			if ( pv == null || pv.IsOwner( from ) )
  				return;
  
  			VendorItem vi = pv.GetVendorItem( item );
  
  			if ( vi != null )
  				list.Add( new BuyEntry( item ) );
  		}
  
  		private class BuyEntry : ContextMenuEntry
  		{
  			private Item m_Item;
  
  			public BuyEntry( Item item ) : base( 6103 )
  			{
  				m_Item = item;
  			}
  
  			public override bool NonLocalUse{ get{ return true; } }
  
  			public override void OnClick()
  			{
  				if ( m_Item.Deleted )
  					return;
  
  				PlayerVendor.TryToBuy( m_Item, Owner.From );
  			}
  		}
  
  		public override void GetChildNameProperties( ObjectPropertyList list, Item item )
  		{
  			base.GetChildNameProperties( list, item );
  
  			PlayerVendor pv = RootParent as PlayerVendor;
  
  			if ( pv == null )
  				return;
  
  			VendorItem vi = pv.GetVendorItem( item );
  
  			if ( vi == null )
  				return;
  
  			if ( !vi.IsForSale )
  				list.Add( 1043307 ); // Price: Not for sale.
  			else if ( vi.IsForFree )
  				list.Add( 1043306 ); // Price: FREE!
  			else
  				list.Add( 1043304, vi.FormattedPrice ); // Price: ~1_COST~
  		}
  
  		public override void GetChildProperties( ObjectPropertyList list, Item item )
  		{
  			base.GetChildProperties( list, item );
  
  			PlayerVendor pv = RootParent as PlayerVendor;
  
  			if ( pv == null )
  				return;
  
  			VendorItem vi = pv.GetVendorItem( item );
  
  			if ( vi != null && vi.Description != null && vi.Description.Length > 0 )
  				list.Add( 1043305, vi.Description ); // <br>Seller's Description:<br>"~1_DESC~"
  		}
  
  		public override void OnSingleClickContained( Mobile from, Item item )
  		{
  			if ( RootParent is PlayerVendor )
  			{
  				PlayerVendor vendor = (PlayerVendor)RootParent;
  
  				VendorItem vi = vendor.GetVendorItem( item );
  
  				if ( vi != null )
  				{
  					if ( !vi.IsForSale )
  						item.LabelTo( from, 1043307 ); // Price: Not for sale.
  					else if ( vi.IsForFree )
  						item.LabelTo( from, 1043306 ); // Price: FREE!
  					else
  						item.LabelTo( from, 1043304, vi.FormattedPrice ); // Price: ~1_COST~
  
  					if ( !String.IsNullOrEmpty( vi.Description ) )
  					{
  						// The localized message (1043305) is no longer valid - <br>Seller's Description:<br>"~1_DESC~"
  						item.LabelTo( from, "Description: {0}", vi.Description );
  					}
  				}
  			}
  
  			base.OnSingleClickContained( from, item );
  		}
  
  		public VendorBackpack( Serial serial ) : base( serial )
  		{
  		}
  
  		public override void Serialize( GenericWriter writer )
  		{
  			base.Serialize( writer );
  
  			writer.Write( (int) 0 ); // version
  		}
  
  		public override void Deserialize( GenericReader reader )
  		{
  			base.Deserialize( reader );
  
  			int version = reader.ReadInt();
  		}
  	}
  
  	public class PlayerVendor : Mobile
  	{
  		private Dictionary<Item, VendorItem> m_SellItems;
  
  		private Mobile m_Owner;
  		private BaseHouse m_House;
  
  		private int m_BankAccount;
  		private int m_HoldGold;
  
  		private string m_ShopName;
  
  		private Timer m_PayTimer;
  		private DateTime m_NextPayTime;
  
  		private PlayerVendorPlaceholder m_Placeholder;
  
  		public PlayerVendor( Mobile owner, BaseHouse house )
  		{
  			Owner = owner;
  			House = house;
  
  			if ( BaseHouse.NewVendorSystem )
  			{
  				m_BankAccount = 0;
  				m_HoldGold = 4;
  			}
  			else
  			{
  				m_BankAccount = 1000;
  				m_HoldGold = 0;
  			}
  
  			ShopName = "Shop Not Yet Named";
  
  			m_SellItems = new Dictionary<Item, VendorItem>();
  
  			CantWalk = true;
  
  			if ( !Core.AOS )
  				NameHue = 0x35;
  
  			InitStats( 100, 100, 25 );
  			InitBody();
  			InitOutfit();
  
  			TimeSpan delay = PayTimer.GetInterval();
  
  			m_PayTimer = new PayTimer( this, delay );
  			m_PayTimer.Start();
  
  			m_NextPayTime = DateTime.UtcNow + delay;
  		}
  
  		public PlayerVendor( Serial serial ) : base( serial )
  		{
  		}
  
  		public override void Serialize( GenericWriter writer )
  		{
  			base.Serialize( writer );
  
  			writer.Write( (int) 2 ); // version
  
  			writer.Write( (bool) BaseHouse.NewVendorSystem );
  			writer.Write( (string) m_ShopName );
  			writer.WriteDeltaTime( (DateTime) m_NextPayTime );
  			writer.Write( (Item) House );
  
  			writer.Write( (Mobile) m_Owner );
  			writer.Write( (int) m_BankAccount );
  			writer.Write( (int) m_HoldGold );
  
  			writer.Write( (int) m_SellItems.Count );
  			foreach ( VendorItem vi in m_SellItems.Values )
  			{
  				writer.Write( (Item) vi.Item );
  				writer.Write( (int) vi.Price );
  				writer.Write( (string) vi.Description );
  
  				writer.Write( (DateTime) vi.Created );
  			}
  		}
  
  		public override void Deserialize( GenericReader reader )
  		{
  			base.Deserialize( reader );
  
  			int version = reader.ReadInt();
  
  			bool newVendorSystem = false;
  
  			switch ( version )
  			{
  				case 2:
  				case 1:
  				{
  					newVendorSystem = reader.ReadBool();
  					m_ShopName = reader.ReadString();
  					m_NextPayTime = reader.ReadDeltaTime();
  					House = (BaseHouse) reader.ReadItem();
  
  					goto case 0;
  				}
  				case 0:
  				{
  					m_Owner = reader.ReadMobile();
  					m_BankAccount = reader.ReadInt();
  					m_HoldGold = reader.ReadInt();
  
  					int count = reader.ReadInt();
  
  					m_SellItems = new Dictionary<Item, VendorItem>(count);
  
  					for ( int i = 0; i < count; i++ )
  					{
  						Item item = reader.ReadItem();
  
  						int price = reader.ReadInt();
  						if ( price > 100000000 )
  							price = 100000000;
  
  						string description = reader.ReadString();
  
  						DateTime created = version < 1 ? DateTime.UtcNow : reader.ReadDateTime();
  
  						if ( item != null )
  						{
  							SetVendorItem( item, version < 1 && price <= 0 ? -1 : price, description, created );
  						}
  					}
  
  					break;	
  				}
  			}
  
  			bool newVendorSystemActivated = BaseHouse.NewVendorSystem && !newVendorSystem;
  
  			if ( version < 1 || newVendorSystemActivated )
  			{
  				if ( version < 1 )
  				{
  					m_ShopName = "Shop Not Yet Named";
  					Timer.DelayCall( TimeSpan.Zero, new TimerStateCallback( UpgradeFromVersion0 ), newVendorSystemActivated );
  				}
  				else
  				{
  					Timer.DelayCall( TimeSpan.Zero, new TimerCallback( FixDresswear ) );
  				}
  
  				m_NextPayTime = DateTime.UtcNow + PayTimer.GetInterval();
  
  				if ( newVendorSystemActivated )
  				{
  					m_HoldGold += m_BankAccount;
  					m_BankAccount = 0;
  				}
  			}
  
  			if ( version < 2 && RawStr == 75 && RawDex == 75 && RawInt == 75 )
  				InitStats( 100, 100, 25 );
  
  			TimeSpan delay = m_NextPayTime - DateTime.UtcNow;
  
  			m_PayTimer = new PayTimer( this, delay > TimeSpan.Zero ? delay : TimeSpan.Zero );
  			m_PayTimer.Start();
  
  			Blessed = false;
  
  			if ( Core.AOS && NameHue == 0x35 )
  				NameHue = -1;
  		}
  
  		private void UpgradeFromVersion0( object newVendorSystem )
  		{
  			List<Item> toRemove = new List<Item>();
  
  			foreach ( VendorItem vi in m_SellItems.Values )
  				if ( !CanBeVendorItem( vi.Item ) )
  					toRemove.Add( vi.Item );
  				else
  					vi.Description = Utility.FixHtml( vi.Description );
  
  			foreach ( Item item in toRemove )
  				RemoveVendorItem( item );
  
  			House = BaseHouse.FindHouseAt( this );
  
  			if ( (bool) newVendorSystem )
  				ActivateNewVendorSystem();
  		}
  
  		private void ActivateNewVendorSystem()
  		{
  			FixDresswear();
  
  			if ( House != null && !House.IsOwner( Owner ) )
  				Destroy( false );
  		}
  
  		public void InitBody()
  		{
  			Hue = Utility.RandomSkinHue();
  			SpeechHue = 0x3B2;
  
  			if ( !Core.AOS )
  				NameHue = 0x35;
  
  			if ( this.Female = Utility.RandomBool() )
  			{
  				this.Body = 0x191;
  				this.Name = NameList.RandomName( "female" );
  			}
  			else
  			{
  				this.Body = 0x190;
  				this.Name = NameList.RandomName( "male" );
  			}
  		}
  
  		public virtual void InitOutfit()
  		{
  			Item item = new FancyShirt( Utility.RandomNeutralHue() );
  			item.Layer = Layer.InnerTorso;
  			AddItem( item );
  			AddItem( new LongPants( Utility.RandomNeutralHue() ) );
  			AddItem( new BodySash( Utility.RandomNeutralHue() ) );
  			AddItem( new Boots( Utility.RandomNeutralHue() ) );
  			AddItem( new Cloak( Utility.RandomNeutralHue() ) );
  
  			Utility.AssignRandomHair( this );
  
  			Container pack = new VendorBackpack();
  			pack.Movable = false;
  			AddItem( pack );
  		}
  
  		[CommandProperty( AccessLevel.GameMaster )]
  		public Mobile Owner
  		{
  			get{ return m_Owner; }
  			set{ m_Owner = value; }
  		}
  
  		[CommandProperty( AccessLevel.GameMaster )]
  		public int BankAccount
  		{
  			get{ return m_BankAccount; }
  			set{ m_BankAccount = value; }
  		}
  
  		[CommandProperty( AccessLevel.GameMaster )]
  		public int HoldGold
  		{
  			get{ return m_HoldGold; }
  			set{ m_HoldGold = value; }
  		}
  
  		[CommandProperty( AccessLevel.GameMaster )]
  		public string ShopName
  		{
  			get{ return m_ShopName; }
  			set
  			{
  				if ( value == null )
  					m_ShopName = "";
  				else
  					m_ShopName = value;
  
  				InvalidateProperties();
  			}
  		}
  
  
gt: 		[CommandProperty( AccessLevel.GameMaster )]