context: using System;
  using System.Collections.Generic;
  using System.Globalization;
  using System.Linq;
  using System.Text;
  using System.Windows.Forms;
  using System.Xml;
  using System.Xml.XPath;
  
  namespace Chummer.Backend.Equipment
  {
      /// <summary>
      /// Vehicle Modification.
      /// </summary>
      public class VehicleMod : INamedItemWithGuidAndNode
      {
          private Guid _guiID;
          private string _strName = string.Empty;
          private string _strCategory = string.Empty;
          private string _strLimit = string.Empty;
          private string _strSlots = "0";
          private int _intRating;
          private string _strMaxRating = "0";
          private string _strCost = string.Empty;
          private decimal _decMarkup;
          private string _strAvail = string.Empty;
          private XmlNode _nodBonus;
          private XmlNode _nodWirelessBonus;
          private bool _blnWirelessOn = true;
          private string _strSource = string.Empty;
          private string _strPage = string.Empty;
          private bool _blnIncludeInVehicle;
          private bool _blnInstalled = true;
          private int _intResponse;
          private int _intSystem;
          private int _intFirewall;
          private int _intSignal;
          private int _intPilot;
          private int _intConditionMonitor;
          private readonly List<Weapon> _lstVehicleWeapons = new List<Weapon>();
          private string _strNotes = string.Empty;
          private string _strSubsystems = string.Empty;
          private readonly List<Cyberware> _lstCyberware = new List<Cyberware>();
          private string _strAltName = string.Empty;
          private string _strAltCategory = string.Empty;
          private string _strAltPage = string.Empty;
          private string _strExtra = string.Empty;
          private string _strWeaponMountCategories = string.Empty;
          private bool _blnDiscountCost;
          private bool _blnDowngrade;
          private string _strCapacity = string.Empty;
  
          private readonly Character _objCharacter;
  
          #region Constructor, Create, Save, Load, and Print Methods
          public VehicleMod(Character objCharacter)
          {
              // Create the GUID for the new VehicleMod.
              _guiID = Guid.NewGuid();
              _objCharacter = objCharacter;
          }
  
          /// Create a Vehicle Modification from an XmlNode and return the TreeNodes for it.
          /// <param name="objXmlMod">XmlNode to create the object from.</param>
          /// <param name="objNode">TreeNode to populate a TreeView.</param>
          /// <param name="intRating">Selected Rating for the Gear.</param>
          /// <param name="objParent">Vehicle that the mod will be attached to.</param>
          /// <param name="intMarkup">Discount or markup that applies to the base cost of the mod.</param>
          public void Create(XmlNode objXmlMod, TreeNode objNode, int intRating, Vehicle objParent, decimal decMarkup = 0)
          {
              if (objParent == null) throw new ArgumentNullException(nameof(objParent));
              Parent = objParent;
              if (objXmlMod == null) Utils.BreakIfDebug();
              objXmlMod.TryGetStringFieldQuickly("name", ref _strName);
              objXmlMod.TryGetStringFieldQuickly("category", ref _strCategory);
              objXmlMod.TryGetStringFieldQuickly("limit", ref _strLimit);
              objXmlMod.TryGetStringFieldQuickly("slots", ref _strSlots);
              _intRating = intRating;
              if (objXmlMod["downgrade"] != null)
              {
                  _blnDowngrade = true;
              }
  
              objXmlMod.TryGetStringFieldQuickly("capacity", ref _strCapacity);
              objXmlMod.TryGetStringFieldQuickly("rating", ref _strMaxRating);
              objXmlMod.TryGetInt32FieldQuickly("response", ref _intResponse);
              objXmlMod.TryGetInt32FieldQuickly("system", ref _intSystem);
              objXmlMod.TryGetInt32FieldQuickly("firewall", ref _intFirewall);
              objXmlMod.TryGetInt32FieldQuickly("signal", ref _intSignal);
              objXmlMod.TryGetInt32FieldQuickly("pilot", ref _intPilot);
              objXmlMod.TryGetInt32FieldQuickly("conditionmonitor", ref _intConditionMonitor);
              objXmlMod.TryGetStringFieldQuickly("weaponmountcategories", ref _strWeaponMountCategories);
              // Add Subsytem information if applicable.
              if (objXmlMod.InnerXml.Contains("subsystems"))
              {
                  StringBuilder objSubsystem = new StringBuilder();
                  foreach (XmlNode objXmlSubsystem in objXmlMod.SelectNodes("subsystems/subsystem"))
                  {
                      objSubsystem.Append(objXmlSubsystem.InnerText + ",");
                  }
                  // Remove last ","
                  if (objSubsystem.Length > 0)
                      objSubsystem.Length -= 1;
                  _strSubsystems = objSubsystem.ToString();
              }
              objXmlMod.TryGetStringFieldQuickly("avail", ref _strAvail);
              
              // Check for a Variable Cost.
              if (objXmlMod["cost"] != null)
              {
                  _strCost = objXmlMod["cost"].InnerText;
                  if (_strCost.StartsWith("Variable"))
                  {
                      decimal decMin = 0;
                      decimal decMax = decimal.MaxValue;
                      string strCost = _strCost.TrimStart("Variable", true).Trim("()".ToCharArray());
                      if (strCost.Contains('-'))
                      {
                          string[] strValues = strCost.Split('-');
                          decMin = Convert.ToDecimal(strValues[0], GlobalOptions.InvariantCultureInfo);
                          decMax = Convert.ToDecimal(strValues[1], GlobalOptions.InvariantCultureInfo);
                      }
                      else
                          decMin = Convert.ToDecimal(strCost.FastEscape('+'), GlobalOptions.InvariantCultureInfo);
  
                      if (decMin != 0 || decMax != decimal.MaxValue)
                      {
                          string strNuyenFormat = _objCharacter.Options.NuyenFormat;
                          int intDecimalPlaces = strNuyenFormat.IndexOf('.');
                          if (intDecimalPlaces == -1)
                              intDecimalPlaces = 0;
                          else
                              intDecimalPlaces = strNuyenFormat.Length - intDecimalPlaces - 1;
                          frmSelectNumber frmPickNumber = new frmSelectNumber(intDecimalPlaces);
                          if (decMax > 1000000)
                              decMax = 1000000;
                          frmPickNumber.Minimum = decMin;
                          frmPickNumber.Maximum = decMax;
                          frmPickNumber.Description = LanguageManager.GetString("String_SelectVariableCost").Replace("{0}", DisplayNameShort);
                          frmPickNumber.AllowCancel = false;
                          frmPickNumber.ShowDialog();
                          _strCost = frmPickNumber.SelectedValue.ToString();
                      }
                  }
              }
              _decMarkup = decMarkup;
  
              objXmlMod.TryGetStringFieldQuickly("source", ref _strSource);
              objXmlMod.TryGetStringFieldQuickly("page", ref _strPage);
              _nodBonus = objXmlMod["bonus"];
              _nodWirelessBonus = objXmlMod["wirelessbonus"];
              _blnWirelessOn = _nodWirelessBonus != null;
  
              if (GlobalOptions.Language != GlobalOptions.DefaultLanguage)
              {
                  
                  XmlNode objModNode = MyXmlNode;
                  if (objModNode != null)
                  {
                      objModNode.TryGetStringFieldQuickly("translate", ref _strAltName);
                      objModNode.TryGetStringFieldQuickly("altpage", ref _strAltPage);
                  }
  
                  XmlDocument objXmlDocument = XmlManager.Load("vehicles.xml");
                  objModNode = objXmlDocument.SelectSingleNode("/chummer/categories/category[. = \"" + _strCategory + "\"]");
                      _strAltCategory = objModNode?.Attributes?["translate"]?.InnerText;
              }
  
              objNode.Text = DisplayName;
              objNode.Tag = _guiID.ToString();
          }
  
          /// <summary>
          /// Save the object's XML to the XmlWriter.
          /// </summary>
          /// <param name="objWriter">XmlTextWriter to write with.</param>
          public void Save(XmlTextWriter objWriter)
          {
              objWriter.WriteStartElement("mod");
              objWriter.WriteElementString("guid", _guiID.ToString());
              objWriter.WriteElementString("name", _strName);
              objWriter.WriteElementString("category", _strCategory);
              objWriter.WriteElementString("limit", _strLimit);
              objWriter.WriteElementString("slots", _strSlots);
              objWriter.WriteElementString("capacity", _strCapacity);
              objWriter.WriteElementString("rating", _intRating.ToString(CultureInfo.InvariantCulture));
              objWriter.WriteElementString("maxrating", _strMaxRating);
              objWriter.WriteElementString("response", _intResponse.ToString(CultureInfo.InvariantCulture));
              objWriter.WriteElementString("system", _intSystem.ToString(CultureInfo.InvariantCulture));
              objWriter.WriteElementString("firewall", _intFirewall.ToString(CultureInfo.InvariantCulture));
              objWriter.WriteElementString("signal", _intSignal.ToString(CultureInfo.InvariantCulture));
              objWriter.WriteElementString("pilot", _intPilot.ToString(CultureInfo.InvariantCulture));
              objWriter.WriteElementString("conditionmonitor", _intConditionMonitor.ToString(CultureInfo.InvariantCulture));
              objWriter.WriteElementString("avail", _strAvail);
              objWriter.WriteElementString("cost", _strCost);
              objWriter.WriteElementString("markup", _decMarkup.ToString(CultureInfo.InvariantCulture));
              objWriter.WriteElementString("extra", _strExtra);
              objWriter.WriteElementString("source", _strSource);
              objWriter.WriteElementString("page", _strPage);
              objWriter.WriteElementString("included", _blnIncludeInVehicle.ToString());
              objWriter.WriteElementString("installed", _blnInstalled.ToString());
              objWriter.WriteElementString("wirelesson", _blnWirelessOn.ToString());
              objWriter.WriteElementString("subsystems", _strSubsystems);
              objWriter.WriteElementString("weaponmountcategories", _strWeaponMountCategories);
              objWriter.WriteStartElement("weapons");
              foreach (Weapon objWeapon in _lstVehicleWeapons)
                  objWeapon.Save(objWriter);
              objWriter.WriteEndElement();
              if (_lstCyberware.Count > 0)
              {
                  objWriter.WriteStartElement("cyberwares");
                  foreach (Cyberware objCyberware in _lstCyberware)
                      objCyberware.Save(objWriter);
                  objWriter.WriteEndElement();
              }
              if (_nodBonus != null)
                  objWriter.WriteRaw(_nodBonus.OuterXml);
              if (_nodWirelessBonus != null)
                  objWriter.WriteRaw(_nodWirelessBonus.OuterXml);
              objWriter.WriteElementString("notes", _strNotes);
              objWriter.WriteElementString("discountedcost", DiscountCost.ToString());
              objWriter.WriteEndElement();
              _objCharacter.SourceProcess(_strSource);
          }
  
          /// <summary>
          /// Load the VehicleMod from the XmlNode.
          /// </summary>
          /// <param name="objNode">XmlNode to load.</param>
          /// <param name="blnCopy">Indicates whether a new item will be created as a copy of this one.</param>
          public void Load(XmlNode objNode, bool blnCopy = false)
          {
              if (blnCopy)
              {
                  _guiID = Guid.NewGuid();
              }
              else
              {
                  objNode.TryGetField("guid", Guid.TryParse, out _guiID);
              }
              objNode.TryGetStringFieldQuickly("name", ref _strName);
              objNode.TryGetStringFieldQuickly("category", ref _strCategory);
              objNode.TryGetStringFieldQuickly("limit", ref _strLimit);
              objNode.TryGetStringFieldQuickly("slots", ref _strSlots);
              objNode.TryGetInt32FieldQuickly("rating", ref _intRating);
              objNode.TryGetStringFieldQuickly("maxrating", ref _strMaxRating);
              objNode.TryGetStringFieldQuickly("capacity", ref _strCapacity);
              objNode.TryGetStringFieldQuickly("weaponmountcategories", ref _strWeaponMountCategories);
              objNode.TryGetInt32FieldQuickly("response", ref _intResponse);
              objNode.TryGetInt32FieldQuickly("system", ref _intSystem);
              objNode.TryGetInt32FieldQuickly("firewall", ref _intFirewall);
              objNode.TryGetInt32FieldQuickly("signal", ref _intSignal);
              objNode.TryGetInt32FieldQuickly("pilot", ref _intPilot);
              objNode.TryGetStringFieldQuickly("page", ref _strPage);
              objNode.TryGetStringFieldQuickly("avail", ref _strAvail);
              objNode.TryGetInt32FieldQuickly("conditionmonitor", ref _intConditionMonitor);
              objNode.TryGetStringFieldQuickly("cost", ref _strCost);
              objNode.TryGetDecFieldQuickly("markup", ref _decMarkup);
              objNode.TryGetStringFieldQuickly("source", ref _strSource);
              objNode.TryGetBoolFieldQuickly("included", ref _blnIncludeInVehicle);
              objNode.TryGetBoolFieldQuickly("installed", ref _blnInstalled);
              objNode.TryGetStringFieldQuickly("subsystems", ref _strSubsystems);
              // Legacy Shims
              if (Name.StartsWith("Gecko Tips (Bod"))
              {
                  Name = "Gecko Tips";
                  XmlNode objNewNode = MyXmlNode;
                  if (objNewNode != null)
                  {
                      objNewNode.TryGetStringFieldQuickly("cost", ref _strCost);
                      objNewNode.TryGetStringFieldQuickly("slots", ref _strSlots);
                  }
              }
              if (Name.StartsWith("Gliding System (Bod"))
              {
                  Name = "Gliding System";
                  XmlNode objNewNode = MyXmlNode;
                  if (objNewNode != null)
                  {
                      objNewNode.TryGetStringFieldQuickly("cost", ref _strCost);
                      objNewNode.TryGetStringFieldQuickly("slots", ref _strSlots);
                      objNewNode.TryGetStringFieldQuickly("avail", ref _strAvail);
                  }
              }
  
              if (objNode.InnerXml.Contains("<weapons>"))
              {
                  XmlNodeList xmlNodeList = objNode.SelectNodes("weapons/weapon");
                  if (xmlNodeList != null)
                      foreach (XmlNode nodChild in xmlNodeList)
                      {
                          var objWeapon = new Weapon(_objCharacter);
                          objWeapon.Load(nodChild, blnCopy);
                          _lstVehicleWeapons.Add(objWeapon);
                      }
              }
              if (objNode.InnerXml.Contains("<cyberwares>"))
              {
                  XmlNodeList xmlNodeList = objNode.SelectNodes("cyberwares/cyberware");
                  if (xmlNodeList != null)
                      foreach (XmlNode nodChild in xmlNodeList)
                      {
                          Cyberware objCyberware = new Cyberware(_objCharacter);
                          objCyberware.Load(nodChild, blnCopy);
                          objCyberware.ParentVehicle = Parent;
                          _lstCyberware.Add(objCyberware);
                      }
              }
  
              _nodBonus = objNode["bonus"];
              _nodWirelessBonus = objNode["wirelessbonus"];
              if (!objNode.TryGetBoolFieldQuickly("wirelesson", ref _blnWirelessOn))
  
gt:                 _blnWirelessOn = _nodWirelessBonus != null;