context: /*
   * DAWN OF LIGHT - The first free open source DAoC server emulator
   * 
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
   * as published by the Free Software Foundation; either version 2
   * of the License, or (at your option) any later version.
   * 
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   * 
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   *
   */
  using System;
  using System.Collections;
  using System.Reflection;
  using System.Threading;
  using DOL.AI.Brain;
  using DOL.Database;
  using DOL.Language;
  using DOL.GS.Movement;
  using DOL.GS.PacketHandler;
  using log4net;
  
  namespace DOL.GS
  {
  	/// <summary>
  	/// Represents an in-game merchant
  	/// </summary>
  	public class GameMerchant : GameNPC
  	{
  		/// <summary>
  		/// Constructor
  		/// </summary>
  		public GameMerchant()
  			: base()
  		{
          }
          
          #region GetExamineMessages / Interact
  
          /// <summary>
  		/// Adds messages to ArrayList which are sent when object is targeted
  		/// </summary>
  		/// <param name="player">GamePlayer that is examining this object</param>
  		/// <returns>list with string messages</returns>
  		public override IList GetExamineMessages(GamePlayer player)
  		{
  			IList list = base.GetExamineMessages(player);
  			list.RemoveAt(list.Count - 1);
              list.Add(LanguageMgr.GetTranslation(player.Client.Account.Language, "GameMerchant.GetExamineMessages.YouExamine", 
                                                  GetName(0, false, player.Client.Account.Language, this), GetPronoun(0, true, player.Client.Account.Language),
                                                  GetAggroLevelString(player, false)));
  			list.Add(LanguageMgr.GetTranslation(player.Client.Account.Language, "GameMerchant.GetExamineMessages.RightClick")); 
  			return list;
  		}
  
  		/// <summary>
  		/// Called when a player right clicks on the merchant
  		/// </summary>
  		/// <param name="player">Player that interacted with the merchant</param>
  		/// <returns>True if succeeded</returns>
  		public override bool Interact(GamePlayer player)
  		{
  			if (!base.Interact(player))
  				return false;
  			TurnTo(player, 10000);
  			SendMerchantWindow(player);
  			return true;
  		}
  
  		/// <summary>
  		/// send the merchants item offer window to a player
  		/// </summary>
  		/// <param name="player"></param>
  		public virtual void SendMerchantWindow(GamePlayer player)
  		{
  			ThreadPool.QueueUserWorkItem(new WaitCallback(SendMerchantWindowCallback), player);
  		}
  
  		/// <summary>
  		/// Sends merchant window from threadpool thread
  		/// </summary>
  		/// <param name="state">The game player to send to</param>
  		protected virtual void SendMerchantWindowCallback(object state)
  		{
  			((GamePlayer)state).Out.SendMerchantWindow(m_tradeItems, eMerchantWindowType.Normal);
  		}
  		#endregion
  
  		#region Items List
  
  		/// <summary>
  		/// Items available for sale
  		/// </summary>
  		protected MerchantTradeItems m_tradeItems;
  
  		/// <summary>
  		/// Gets the items available from this merchant
  		/// </summary>
  		public MerchantTradeItems TradeItems
  		{
  			get { return m_tradeItems; }
  			set { m_tradeItems = value; }
  		}
  
  		#endregion
  
  		#region Buy / Sell / Apparaise
  
  		/// <summary>
  		/// Called when a player buys an item
  		/// </summary>
  		/// <param name="player">The player making the purchase</param>
  		/// <param name="item_slot">slot of the item to be bought</param>
  		/// <param name="number">Number to be bought</param>
  		/// <returns>true if buying is allowed, false if buying should be prevented</returns>
  		public virtual void OnPlayerBuy(GamePlayer player, int item_slot, int number)
  		{
  			//Get the template
  			int pagenumber = item_slot / MerchantTradeItems.MAX_ITEM_IN_TRADEWINDOWS;
  			int slotnumber = item_slot % MerchantTradeItems.MAX_ITEM_IN_TRADEWINDOWS;
  
  			ItemTemplate template = this.TradeItems.GetItem(pagenumber, (eMerchantWindowSlot)slotnumber);
  			if (template == null) return;
  
  			//Calculate the amout of items
  			int amountToBuy = number;
  			if (template.PackSize > 0)
  				amountToBuy *= template.PackSize;
  
  			if (amountToBuy <= 0) return;
  
  			//Calculate the value of items
  			long totalValue = number * template.Price;
  
  			lock (player.Inventory)
  			{
  
  				if (player.GetCurrentMoney() < totalValue)
  				{
  					player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client.Account.Language, "GameMerchant.OnPlayerBuy.YouNeed", Money.GetString(totalValue)), eChatType.CT_System, eChatLoc.CL_SystemWindow);
  					return;
  				}
  
  				if (!player.Inventory.AddTemplate(GameInventoryItem.Create(template), amountToBuy, eInventorySlot.FirstBackpack, eInventorySlot.LastBackpack))
  				{
  					player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client.Account.Language, "GameMerchant.OnPlayerBuy.NotInventorySpace"), eChatType.CT_System, eChatLoc.CL_SystemWindow);
  					return;
  				}
  				InventoryLogging.LogInventoryAction(this, player, eInventoryActionType.Merchant, template, amountToBuy);
  				//Generate the buy message
  				string message;
  				if (amountToBuy > 1)
  					message = LanguageMgr.GetTranslation(player.Client.Account.Language, "GameMerchant.OnPlayerBuy.BoughtPieces", amountToBuy, template.GetName(1, false), Money.GetString(totalValue));
  				else
  					message = LanguageMgr.GetTranslation(player.Client.Account.Language, "GameMerchant.OnPlayerBuy.Bought", template.GetName(1, false), Money.GetString(totalValue));
  
  				// Check if player has enough money and subtract the money
  				if (!player.RemoveMoney(totalValue, message, eChatType.CT_Merchant, eChatLoc.CL_SystemWindow))
  				{
  					throw new Exception("Money amount changed while adding items.");
  				}
  				InventoryLogging.LogInventoryAction(player, this, eInventoryActionType.Merchant, totalValue);
  			}
  		}
  
  
  		/// <summary>
  		/// Called when a player buys an item
  		/// </summary>
  		/// <param name="player">The player making the purchase</param>
  		/// <param name="item_slot">slot of the item to be bought</param>
  		/// <param name="number">Number to be bought</param>
  		/// <param name="TradeItems"></param>
  		/// <returns>true if buying is allowed, false if buying should be prevented</returns>
  		public static void OnPlayerBuy(GamePlayer player, int item_slot, int number, MerchantTradeItems TradeItems)
  		{
  			//Get the template
  			int pagenumber = item_slot / MerchantTradeItems.MAX_ITEM_IN_TRADEWINDOWS;
  			int slotnumber = item_slot % MerchantTradeItems.MAX_ITEM_IN_TRADEWINDOWS;
  
  			ItemTemplate template = TradeItems.GetItem(pagenumber, (eMerchantWindowSlot)slotnumber);
  			if (template == null) return;
  
  			//Calculate the amout of items
  			int amountToBuy = number;
  			if (template.PackSize > 0)
  				amountToBuy *= template.PackSize;
  
  			if (amountToBuy <= 0) return;
  
  			//Calculate the value of items
  			long totalValue = number * template.Price;
  
  			lock (player.Inventory)
  			{
  
  				if (player.GetCurrentMoney() < totalValue)
  				{
  					player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client.Account.Language, "GameMerchant.OnPlayerBuy.YouNeed", Money.GetString(totalValue)), eChatType.CT_System, eChatLoc.CL_SystemWindow);
  					return;
  				}
  
  				if (!player.Inventory.AddTemplate(GameInventoryItem.Create(template), amountToBuy, eInventorySlot.FirstBackpack, eInventorySlot.LastBackpack))
  				{
  					player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client.Account.Language, "GameMerchant.OnPlayerBuy.NotInventorySpace"), eChatType.CT_System, eChatLoc.CL_SystemWindow);
  					return;
  				}
  				InventoryLogging.LogInventoryAction("(TRADEITEMS;" + TradeItems.ItemsListID + ")", player, eInventoryActionType.Merchant, template, amountToBuy);
  				//Generate the buy message
  				string message;
  				if (amountToBuy > 1)
  					message = LanguageMgr.GetTranslation(player.Client.Account.Language, "GameMerchant.OnPlayerBuy.BoughtPieces", amountToBuy, template.GetName(1, false), Money.GetString(totalValue));
  				else
  					message = LanguageMgr.GetTranslation(player.Client.Account.Language, "GameMerchant.OnPlayerBuy.Bought", template.GetName(1, false), Money.GetString(totalValue));
  
  				// Check if player has enough money and subtract the money
  				if (!player.RemoveMoney(totalValue, message, eChatType.CT_Merchant, eChatLoc.CL_SystemWindow))
  				{
  					throw new Exception("Money amount changed while adding items.");
  				}
  				InventoryLogging.LogInventoryAction(player, "(TRADEITEMS;" + TradeItems.ItemsListID + ")", eInventoryActionType.Merchant, totalValue);
  			}
  		}
  		
  		/// <summary>
  		/// Called when a player sells something
  		/// </summary>
  		/// <param name="player">Player making the sale</param>
  		/// <param name="item">The InventoryItem to be sold</param>
  		/// <returns>true if selling is allowed, false if it should be prevented</returns>
  		public virtual void OnPlayerSell(GamePlayer player, InventoryItem item)
  		{
  			if(item==null || player==null) return;
  			if (!item.IsDropable)
  			{
  				player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client.Account.Language, "GameMerchant.OnPlayerSell.CantBeSold"), eChatType.CT_Merchant, eChatLoc.CL_SystemWindow);
  				return;
  			}
  
  			if (!this.IsWithinRadius(player, GS.ServerProperties.Properties.WORLD_PICKUP_DISTANCE)) // tested
  			{
  				player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client.Account.Language, "GameMerchant.OnPlayerSell.TooFarAway", GetName(0, true)), eChatType.CT_Merchant, eChatLoc.CL_SystemWindow);
  				return;
  			}
  
  			long itemValue = OnPlayerAppraise(player, item, true);
  
  			if (itemValue == 0)
  			{
  				player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client.Account.Language, "GameMerchant.OnPlayerSell.IsntInterested", GetName(0, true), item.GetName(0, false)), eChatType.CT_Merchant, eChatLoc.CL_SystemWindow);
  				return;
  			}
  
  			if (player.Inventory.RemoveItem(item))
  			{
  				string message = LanguageMgr.GetTranslation(player.Client.Account.Language, "GameMerchant.OnPlayerSell.GivesYou", GetName(0, true), Money.GetString(itemValue), item.GetName(0, false));
  				player.AddMoney(itemValue, message, eChatType.CT_Merchant, eChatLoc.CL_SystemWindow);
  				InventoryLogging.LogInventoryAction(player, this, eInventoryActionType.Merchant, item.Template, item.Count);
  				InventoryLogging.LogInventoryAction(this, player, eInventoryActionType.Merchant, itemValue);
  				return;
  			}
  			else
  				player.Out.SendMessage(LanguageMgr.GetTranslation(player.Client.Account.Language, "GameMerchant.OnPlayerSell.CantBeSold"), eChatType.CT_Merchant, eChatLoc.CL_SystemWindow);
  		}
  
  		/// <summary>
  		/// Called to appraise the value of an item
  		/// </summary>
  		/// <param name="player">The player whose item needs appraising</param>
  		/// <param name="item">The item to be appraised</param>
  		/// <param name="silent"></param>
  		/// <returns>The price this merchant will pay for the offered items</returns>
  		public virtual long OnPlayerAppraise(GamePlayer player, InventoryItem item, bool silent)
  		{
  			if (item == null)
  				return 0;
  
  
gt: 			int itemCount = Math.Max(1, item.Count);