context: using Server.Commands;
  using Server.ContextMenus;
  using Server.Engines.Auction;
  using Server.Gumps;
  using Server.Items;
  using Server.Mobiles;
  using Server.Regions;
  using Server.Targeting;
  using System;
  using System.Collections.Generic;
  using System.IO;
  using System.Linq;
  using System.Text;
  
  namespace Server.Engines.VendorSearching
  {
      public class VendorSearch
      {
          public static string FilePath = Path.Combine("Saves/Misc", "VendorSearch.bin");
          public static Ultima.StringList StringList { get; private set; }
  
          public static List<SearchItem> DoSearchAuction(Mobile m, SearchCriteria criteria)
          {
              if (criteria == null || Auction.Auction.Auctions == null || Auction.Auction.Auctions.Count == 0)
              {
                  return null;
              }
  
              List<SearchItem> list = new List<SearchItem>();
              bool excludefel = criteria.Details.FirstOrDefault(d => d.Attribute is Misc && (Misc)d.Attribute == Misc.ExcludeFel) != null;
  
              foreach (Auction.Auction pv in Auction.Auction.Auctions.Where(pv => pv.AuctionItem != null &&
                                                                                  pv.AuctionItem.Map != Map.Internal &&
                                                                                 pv.AuctionItem.Map != null &&
                                                                                 pv.OnGoing &&
                                                                                 (!excludefel || pv.AuctionItem.Map != Map.Felucca)))
              {
                  list.Add(new SearchItem(pv.Safe, pv.AuctionItem, (int)pv.Buyout, false));
              }
  
              switch (criteria.SortBy)
              {
                  case SortBy.LowToHigh: list = list.OrderBy(vi => vi.Price).ToList(); break;
                  case SortBy.HighToLow: list = list.OrderBy(vi => -vi.Price).ToList(); break;
              }
  
              return list;
          }
  
          public static List<SearchItem> DoSearch(Mobile m, SearchCriteria criteria)
          {
              if (criteria == null || PlayerVendor.PlayerVendors == null || PlayerVendor.PlayerVendors.Count == 0)
                  return null;
  
              List<SearchItem> list = new List<SearchItem>();
              bool excludefel = criteria.Details.FirstOrDefault(d => d.Attribute is Misc && (Misc)d.Attribute == Misc.ExcludeFel) != null;
  
              foreach (PlayerVendor pv in PlayerVendor.PlayerVendors.Where(pv => pv.Map != Map.Internal &&
                                                                                 pv.Map != null &&
                                                                                 pv.Backpack != null &&
                                                                                 pv.VendorSearch &&
                                                                                 pv.Backpack.Items.Count > 0 &&
                                                                                 (!excludefel || pv.Map != Map.Felucca)))
              {
                  List<Item> items = GetItems(pv);
  
                  foreach (Item item in items)
                  {
                      VendorItem vendorItem = pv.GetVendorItem(item);
                      int price = 0;
                      bool isChild = false;
  
                      if (vendorItem != null)
                      {
                          price = vendorItem.Price;
                      }
                      else if (item.Parent is Container)
                      {
                          vendorItem = GetParentVendorItem(pv, (Container)item.Parent);
  
                          if (vendorItem != null)
                          {
                              isChild = true;
                              price = vendorItem.Price;
                          }
                      }
  
                      if (price > 0 && CheckMatch(item, price, criteria))
                      {
                          list.Add(new SearchItem(pv, item, price, isChild));
                      }
                  }
  
                  ColUtility.Free(items);
              }
  
              switch (criteria.SortBy)
              {
                  case SortBy.LowToHigh: list = list.OrderBy(vi => vi.Price).ToList(); break;
                  case SortBy.HighToLow: list = list.OrderBy(vi => -vi.Price).ToList(); break;
              }
  
              return list;
          }
  
          private static VendorItem GetParentVendorItem(PlayerVendor pv, Container parent)
          {
              VendorItem vendorItem = pv.GetVendorItem(parent);
  
              if (vendorItem == null)
              {
                  if (parent.Parent is Container)
                  {
                      return GetParentVendorItem(pv, (Container)parent.Parent);
                  }
              }
  
              return vendorItem;
          }
  
          public static bool CheckMatch(Item item, int price, SearchCriteria searchCriteria)
          {
              if (item is CommodityDeed && ((CommodityDeed)item).Commodity != null)
              {
                  item = ((CommodityDeed)item).Commodity;
              }
  
              if (searchCriteria.MinPrice > -1 && price < searchCriteria.MinPrice)
                  return false;
  
              if (searchCriteria.MaxPrice > -1 && price > searchCriteria.MaxPrice)
                  return false;
  
              if (!string.IsNullOrEmpty(searchCriteria.SearchName))
              {
                  string name;
  
                  if (item is CommodityDeed && ((CommodityDeed)item).Commodity is ICommodity)
                  {
                      ICommodity commodity = (ICommodity)((CommodityDeed)item).Commodity;
  
                      if (!string.IsNullOrEmpty(commodity.Description.String))
                      {
                          name = commodity.Description.String;
                      }
                      else
                      {
                          name = StringList.GetString(commodity.Description.Number);
                      }
                  }
                  else
                  {
                      name = GetItemName(item);
                  }
  
                  if (name == null)
                  {
                      return false; // TODO? REturn null names?
                  }
  
                  if (!CheckKeyword(searchCriteria.SearchName, item) && name.ToLower().IndexOf(searchCriteria.SearchName.ToLower()) < 0)
                  {
                      return false;
                  }
              }
  
              if (searchCriteria.SearchType != Layer.Invalid && searchCriteria.SearchType != item.Layer)
              {
                  return false;
              }
  
              if (searchCriteria.Details.Count == 0)
                  return true;
  
              foreach (SearchDetail detail in searchCriteria.Details)
              {
                  object o = detail.Attribute;
                  int value = detail.Value;
  
                  if (value == 0)
                      value = 1;
  
                  if (o is AosAttribute)
                  {
                      AosAttributes attrs = RunicReforging.GetAosAttributes(item);
  
                      if (attrs == null || attrs[(AosAttribute)o] < value)
                          return false;
                  }
                  else if (o is AosWeaponAttribute)
                  {
                      AosWeaponAttributes attrs = RunicReforging.GetAosWeaponAttributes(item);
  
                      if ((AosWeaponAttribute)o == AosWeaponAttribute.MageWeapon)
                      {
                          if (attrs == null || attrs[(AosWeaponAttribute)o] == 0 || attrs[(AosWeaponAttribute)o] > Math.Max(0, 30 - value))
                              return false;
                      }
                      else if (attrs == null || attrs[(AosWeaponAttribute)o] < value)
                          return false;
                  }
                  else if (o is SAAbsorptionAttribute)
                  {
                      SAAbsorptionAttributes attrs = RunicReforging.GetSAAbsorptionAttributes(item);
  
                      if (attrs == null || attrs[(SAAbsorptionAttribute)o] < value)
                          return false;
                  }
                  else if (o is AosArmorAttribute)
                  {
                      AosArmorAttributes attrs = RunicReforging.GetAosArmorAttributes(item);
  
                      if (attrs == null || attrs[(AosArmorAttribute)o] < value)
                          return false;
                  }
                  else if (o is SkillName)
                  {
                      if (detail.Category != Category.RequiredSkill)
                      {
                          AosSkillBonuses skillbonuses = RunicReforging.GetAosSkillBonuses(item);
  
                          if (skillbonuses != null)
                          {
                              bool hasSkill = false;
  
                              for (int i = 0; i < 5; i++)
                              {
                                  SkillName check;
                                  double bonus;
  
                                  if (skillbonuses.GetValues(i, out check, out bonus) && check == (SkillName)o && bonus >= value)
                                  {
                                      hasSkill = true;
                                      break;
                                  }
                              }
  
                              if (!hasSkill)
                                  return false;
                          }
                          else if (item is SpecialScroll && value >= 105)
                          {
                              if (((SpecialScroll)item).Skill != (SkillName)o || ((SpecialScroll)item).Value < value)
                                  return false;
                          }
                          else
                          {
                              return false;
                          }
                      }
                      else if (!(item is BaseWeapon) || ((BaseWeapon)item).DefSkill != (SkillName)o)
                      {
                          return false;
                      }
                  }
                  else if (!CheckSlayer(item, o))
                  {
                      return false;
                  }
                  else if (o is AosElementAttribute)
                  {
                      if (item is BaseWeapon)
                      {
                          BaseWeapon wep = item as BaseWeapon;
  
                          if (detail.Category == Category.DamageType)
                          {
                              int phys, fire, cold, pois, nrgy, chaos, direct;
                              wep.GetDamageTypes(null, out phys, out fire, out cold, out pois, out nrgy, out chaos, out direct);
  
                              switch ((AosElementAttribute)o)
                              {
                                  case AosElementAttribute.Physical: if (phys < value) return false; break;
                                  case AosElementAttribute.Fire: if (fire < value) return false; break;
                                  case AosElementAttribute.Cold: if (cold < value) return false; break;
                                  case AosElementAttribute.Poison: if (pois < value) return false; break;
                                  case AosElementAttribute.Energy: if (nrgy < value) return false; break;
                                  case AosElementAttribute.Chaos: if (chaos < value) return false; break;
                                  case AosElementAttribute.Direct: if (direct < value) return false; break;
                              }
                          }
                          else
                          {
                              switch ((AosElementAttribute)o)
                              {
                                  case AosElementAttribute.Physical:
                                      if (wep.WeaponAttributes.ResistPhysicalBonus < value) return false;
                                      break;
                                  case AosElementAttribute.Fire:
                                      if (wep.WeaponAttributes.ResistFireBonus < value) return false;
                                      break;
                                  case AosElementAttribute.Cold:
                                      if (wep.WeaponAttributes.ResistColdBonus < value) return false;
                                      break;
                                  case AosElementAttribute.Poison:
                                      if (wep.WeaponAttributes.ResistPoisonBonus < value) return false;
                                      break;
                                  case AosElementAttribute.Energy:
                                      if (wep.WeaponAttributes.ResistEnergyBonus < value) return false;
                                      break;
                              }
                          }
                      }
                      else if (item is BaseArmor && detail.Category == Category.Resists)
                      {
                          BaseArmor armor = item as BaseArmor;
  
                          switch ((AosElementAttribute)o)
                          {
                              case AosElementAttribute.Physical:
                                  if (armor.PhysicalResistance < value) return false;
                                  break;
                              case AosElementAttribute.Fire:
                                  if (armor.FireResistance < value) return false;
                                  break;
                              case AosElementAttribute.Cold:
                                  if (armor.ColdResistance < value) return false;
                                  break;
                              case AosElementAttribute.Poison:
                                  if (armor.PoisonResistance < value) return false;
                                  break;
                              case AosElementAttribute.Energy:
                                  if (armor.EnergyResistance < value) return false;
                                  break;
                          }
                      }
                      else if (detail.Category != Category.DamageType)
                      {
                          AosElementAttributes attrs = RunicReforging.GetElementalAttributes(item);
  
                          if (attrs == null || attrs[(AosElementAttribute)o] < value)
                          {
                              return false;
                          }
                      }
                      else
                      {
                          return false;
                      }
                  }
                  else if (o is Misc)
                  {
                      switch ((Misc)o)
                      {
                          case Misc.ExcludeFel: break;
                          case Misc.GargoyleOnly:
                              if (!IsGargoyle(item))
                                  return false;
                              break;
                          case Misc.NotGargoyleOnly:
                              if (IsGargoyle(item))
                                  return false;
                              break;
                          case Misc.ElvesOnly:
                              if (!IsElf(item))
                                  return false;
                              break;
                          case Misc.NotElvesOnly:
                              if (IsElf(item))
                                  return false;
                              break;
                          case Misc.FactionItem:
                              return false;
                          case Misc.PromotionalToken:
                              if (!(item is PromotionalToken))
                                  return false;
                              break;
                          case Misc.Cursed:
                              if (item.LootType != LootType.Cursed)
                                  return false;
                              break;
                          case Misc.NotCursed:
                              if (item.LootType == LootType.Cursed)
                                  return false;
                              break;
                          case Misc.CannotRepair:
                              if (CheckCanRepair(item))
                                  return false;
                              break;
                          case Misc.NotCannotBeRepaired:
                              if (!CheckCanRepair(item))
                                  return false;
                              break;
                          case Misc.Brittle:
                              NegativeAttributes neg2 = RunicReforging.GetNegativeAttributes(item);
                              if (neg2 == null || neg2.Brittle == 0)
                                  return false;
                              break;
                          case Misc.NotBrittle:
                              NegativeAttributes neg3 = RunicReforging.GetNegativeAttributes(item);
                              if (neg3 != null && neg3.Brittle > 0)
                                  return false;
                              break;
                          case Misc.Antique:
                              NegativeAttributes neg4 = RunicReforging.GetNegativeAttributes(item);
                              if (neg4 == null || neg4.Antique == 0)
                                  return false;
                              break;
                          case Misc.NotAntique:
                              NegativeAttributes neg5 = RunicReforging.GetNegativeAttributes(item);
                              if (neg5 != null && neg5.Antique > 0)
                                  return false;
                              break;
                      }
                  }
                  else if (o is string)
                  {
                      string str = o as string;
  
                      if (str == "WeaponVelocity" && (!(item is BaseRanged) || ((BaseRanged)item).Velocity < value))
                          return false;
  
                      if (str == "SearingWeapon" && (!(item is BaseWeapon) || !((BaseWeapon)item).SearingWeapon))
                          return false;
  
                      if (str == "ArtifactRarity" && (!(item is IArtifact) || ((IArtifact)item).ArtifactRarity < value))
                      {
                          return false;
                      }
                  }
              }
  
              return true;
          }
  
          private static bool CheckSlayer(Item item, object o)
          {
              if (o is TalismanSlayerName && (TalismanSlayerName)o == TalismanSlayerName.Undead)
              {
                  if (!(item is ISlayer) || ((((ISlayer)item).Slayer != SlayerName.Silver && ((ISlayer)item).Slayer2 != SlayerName.Silver)))
                  {
                      if (!(item is BaseTalisman) || ((BaseTalisman)item).Slayer != TalismanSlayerName.Undead)
                      {
                          return false;
                      }
                  }
              }
              else
              {
                  if (o is SlayerName && (!(item is ISlayer) || (((ISlayer)item).Slayer != (SlayerName)o && ((ISlayer)item).Slayer2 != (SlayerName)o)))
                  {
                      return false;
                  }
                  else if (o is TalismanSlayerName && (!(item is BaseTalisman) || ((BaseTalisman)item).Slayer != (TalismanSlayerName)o))
                  {
                      return false;
                  }
              }
  
              return true;
          }
  
          private static bool CheckCanRepair(Item item)
          {
              NegativeAttributes neg = RunicReforging.GetNegativeAttributes(item);
  
              return neg != null && neg.NoRepair != 0;
          }
  
          private static bool CheckKeyword(string searchstring, Item item)
          {
              if (item is CommodityDeed && ((CommodityDeed)item).Commodity != null)
              {
                  item = ((CommodityDeed)item).Commodity;
              }
  
              if (item is IResource)
              {
                  string resName = CraftResources.GetName(((IResource)item).Resource);
  
                  if (resName.ToLower().IndexOf(searchstring.ToLower()) >= 0)
                  {
                      return true;
                  }
              }
  
              if (item is ICommodity)
              {
                  ICommodity commodity = (ICommodity)item;
  
                  string name = commodity.Description.String;
  
                  if (string.IsNullOrEmpty(name) && commodity.Description.Number > 0)
                  {
                      name = StringList.GetString(commodity.Description.Number);
                  }
  
                  if (!string.IsNullOrEmpty(name) && name.ToLower().IndexOf(searchstring.ToLower()) >= 0)
                  {
                      return true;
                  }
              }
  
              return Keywords.ContainsKey(searchstring.ToLower()) && Keywords[searchstring.ToLower()] == item.GetType();
          }
  
          public static bool IsGargoyle(Item item)
          {
              if (item is BaseArmor)
              {
                  return ((BaseArmor)item).RequiredRace == Race.Gargoyle;
              }
              else if (item is BaseWeapon)
              {
                  return ((BaseWeapon)item).RequiredRace == Race.Gargoyle;
              }
              else if (item is BaseClothing)
              {
                  return ((BaseClothing)item).RequiredRace == Race.Gargoyle;
              }
              else if (item is BaseJewel)
              {
                  return ((BaseJewel)item).RequiredRace == Race.Gargoyle;
              }
  
              return false;
          }
  
          public static bool IsElf(Item item)
          {
              if (item is BaseArmor)
              {
                  return ((BaseArmor)item).RequiredRace == Race.Elf;
              }
              else if (item is BaseWeapon)
              {
                  return ((BaseWeapon)item).RequiredRace == Race.Elf;
              }
              else if (item is BaseClothing)
              {
  
gt:                 return ((BaseClothing)item).RequiredRace == Race.Elf;