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.
   *
   */
  /*
   * Credits go to:
   * - Echostorm's Mob Drop Loot System
   * - Roach's modifications to add loottemplate base mobdrops
   */
  using System;
  using System.Collections;
  using System.Collections.Generic;
  using System.Collections.Specialized;
  using System.Linq;
  using DOL.Database;
  using DOL.AI.Brain;
  using DOL.GS.Utils;
  
  namespace DOL.GS
  {
  	/// <summary>
  	/// TemplateLootGenerator
  	/// This implementation uses LootTemplates to relate loots to a specific mob type.
  	/// Used DB Tables:
  	///				MobxLootTemplate  (Relation between Mob and loottemplate
  	///				LootTemplate	(loottemplate containing possible loot items)
  	/// </summary>
  	public class LootGeneratorTemplate : LootGeneratorBase
  	{
  		private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
  
  		/// <summary>
  		/// Map holding a list of ItemTemplateIDs for each TemplateName
  		/// 1:n mapping between loottemplateName and loottemplate entries
  		/// </summary>
  		protected static Dictionary<string, Dictionary<string, LootTemplate>> m_lootTemplates = null;
  
  		/// <summary>
  		/// Map holding the corresponding LootTemplateName for each MobName
  		/// 1:n Mapping between Mob and LootTemplate
  		/// </summary>
  		protected static Dictionary<string, List<MobXLootTemplate>> m_mobXLootTemplates = null;
  
  		/// <summary>
  		/// Construct a new templategenerate and load its values from database.
  		/// </summary>
  		public LootGeneratorTemplate()
  		{
  			PreloadLootTemplates();
  		}
  
  		public static void ReloadLootTemplates()
  		{
  			m_lootTemplates = null;
  			m_mobXLootTemplates = null;
  			PreloadLootTemplates();
  		}
  
  		/// <summary>
  		/// Loads the loottemplates
  		/// </summary>
  		/// <returns></returns>
  		protected static bool PreloadLootTemplates()
  		{
  			if (m_lootTemplates == null)
  			{
  				m_lootTemplates = new Dictionary<string, Dictionary<string, LootTemplate>>();
  				Dictionary<string, ItemTemplate> itemtemplates = new Dictionary<string, ItemTemplate>();
  
  				lock (m_lootTemplates)
  				{
  					IList<LootTemplate> dbLootTemplates = null;
  
  					try
  					{
  						// TemplateName (typically the mob name), ItemTemplateID, Chance
  						dbLootTemplates = GameServer.Database.SelectAllObjects<LootTemplate>();
  						itemtemplates = GameServer.Database.SelectAllObjects<ItemTemplate>().ToDictionary(k => k.Id_nb.ToLower());
  					}
  					catch (Exception e)
  					{
  						if (log.IsErrorEnabled)
  						{
  							log.Error("LootGeneratorTemplate: LootTemplates could not be loaded:", e);
  						}
  						return false;
  					}
  
  					if (dbLootTemplates != null)
  					{
  						Dictionary<string, LootTemplate> loot = null;
  
  						foreach (LootTemplate dbTemplate in dbLootTemplates)
  						{
  							if (!m_lootTemplates.TryGetValue(dbTemplate.TemplateName.ToLower(), out loot))
  							{
  								loot = new Dictionary<string, LootTemplate>();
  								m_lootTemplates[dbTemplate.TemplateName.ToLower()] = loot;
  							}
  
  							ItemTemplate drop = null;
  							
  							if (itemtemplates.ContainsKey(dbTemplate.ItemTemplateID.ToLower()))
  								drop = itemtemplates[dbTemplate.ItemTemplateID.ToLower()];
  
  							if (drop == null)
  							{
  								if (log.IsErrorEnabled)
  									log.Error("ItemTemplate: " + dbTemplate.ItemTemplateID + " is not found, it is referenced from loottemplate: " + dbTemplate.TemplateName);
  							}
  							else
  							{
  								if (!loot.ContainsKey(dbTemplate.ItemTemplateID.ToLower()))
  									loot.Add(dbTemplate.ItemTemplateID.ToLower(), dbTemplate);
  							}
  						}
  					}
  				}
  
  				log.Info("LootTemplates pre-loaded.");
  			}
  
  			if (m_mobXLootTemplates == null)
  			{
  				m_mobXLootTemplates = new Dictionary<string, List<MobXLootTemplate>>();
  
  				lock (m_mobXLootTemplates)
  				{
  					IList<MobXLootTemplate> dbMobXLootTemplates = null;
  
  					try
  					{
  						// MobName, LootTemplateName, DropCount
  						dbMobXLootTemplates = GameServer.Database.SelectAllObjects<MobXLootTemplate>();
  					}
  					catch (Exception e)
  					{
  						if (log.IsErrorEnabled)
  						{
  							log.Error("LootGeneratorTemplate: MobXLootTemplates could not be loaded", e);
  						}
  						return false;
  					}
  
  					if (dbMobXLootTemplates != null)
  					{
  						foreach (MobXLootTemplate dbMobXTemplate in dbMobXLootTemplates)
  						{
  							// There can be multiple MobXLootTemplates for a mob, each pointing to a different loot template
  							List<MobXLootTemplate> mobxLootTemplates;
  							if (!m_mobXLootTemplates.TryGetValue(dbMobXTemplate.MobName.ToLower(), out mobxLootTemplates))
  							{
  								mobxLootTemplates = new List<MobXLootTemplate>();
  								m_mobXLootTemplates[dbMobXTemplate.MobName.ToLower()] = mobxLootTemplates;
  							}
  							mobxLootTemplates.Add(dbMobXTemplate);
  						}
  					}
  				}
  
  				log.Info("MobXLootTemplates pre-loaded.");
  			}
  
  			return true;
  		}
  
  		/// <summary>
  		/// Reload the loot templates for this mob
  		/// </summary>
  		/// <param name="mob"></param>
  		public override void Refresh(GameNPC mob)
  		{
  			if (mob == null)
  				return;
  
  			bool isDefaultLootTemplateRefreshed = false;
  
  			// First see if there are any MobXLootTemplates associated with this mob
  
  			var mxlts = DOLDB<MobXLootTemplate>.SelectObjects(DB.Column(nameof(MobXLootTemplate.MobName)).IsEqualTo(mob.Name));
  
  			if (mxlts != null)
  			{
  				lock (m_mobXLootTemplates)
  				{
  					foreach (MobXLootTemplate mxlt in mxlts)
  					{
  						List<MobXLootTemplate> mobxLootTemplates;
  						if (!m_mobXLootTemplates.TryGetValue(mxlt.MobName.ToLower(), out mobxLootTemplates))
  						{
  							mobxLootTemplates = new List<MobXLootTemplate>();
  							m_mobXLootTemplates[mxlt.MobName.ToLower()] = mobxLootTemplates;
  						}
  						mobxLootTemplates.Add(mxlt);
  
  						RefreshLootTemplate(mxlt.LootTemplateName);
  
  
  						if (mxlt.LootTemplateName.ToLower() == mob.Name.ToLower())
  							isDefaultLootTemplateRefreshed = true;
  					}
  				}
  			}
  
  			// now force a refresh of the mobs default loot template
  
  			if (isDefaultLootTemplateRefreshed == false)
  				RefreshLootTemplate(mob.Name);
  		}
  
  		protected void RefreshLootTemplate(string templateName)
  		{
  			lock (m_lootTemplates)
  			{
  				if (m_lootTemplates.ContainsKey(templateName.ToLower()))
  				{
  					m_lootTemplates.Remove(templateName.ToLower());
  				}
  			}
  
  			var lootTemplates = DOLDB<LootTemplate>.SelectObjects(DB.Column(nameof(LootTemplate.TemplateName)).IsEqualTo(templateName));
  
  			if (lootTemplates != null)
  			{
  				lock (m_lootTemplates)
  				{
  					if (m_lootTemplates.ContainsKey(templateName.ToLower()))
  					{
  						m_lootTemplates.Remove(templateName.ToLower());
  					}
  
  					Dictionary<string, LootTemplate> lootList = new Dictionary<string, LootTemplate>();
  
  					foreach (LootTemplate lt in lootTemplates)
  					{
  						if (lootList.ContainsKey(lt.ItemTemplateID.ToLower()) == false)
  						{
  							lootList.Add(lt.ItemTemplateID.ToLower(), lt);
  						}
  					}
  
  					m_lootTemplates.Add(templateName.ToLower(), lootList);
  				}
  			}
  		}
  
  		public override LootList GenerateLoot(GameNPC mob, GameObject killer)
  		{
  			LootList loot = base.GenerateLoot(mob, killer);
  
  			try
  			{
  				GamePlayer player = null;
  
  				if (killer is GamePlayer)
  				{
  					player = killer as GamePlayer;
  				}
  				else if (killer is GameNPC && (killer as GameNPC).Brain is IControlledBrain)
  				{
  					player = ((killer as GameNPC).Brain as ControlledNpcBrain).GetPlayerOwner();
  				}
  
  				// allow the leader to decide the loot realm
  				if (player != null && player.Group != null)
  				{
  					player = player.Group.Leader;
  				}
  
  				if (player != null)
  				{
  
gt: 					List<MobXLootTemplate> killedMobXLootTemplates = null;