context: using System;
  using System.Collections.Generic;
  using System.Globalization;
  using System.Linq;
  using System.Windows.Forms;
  using System.Xml;
  using System.Xml.XPath;
  
  namespace Chummer.Backend.Equipment
  {
  	/// <summary>
  	/// Vehicle Modification.
  	/// </summary>
  	public class WeaponMount : INamedItemWithGuid
  	{
  		private Guid _guiID;
  		private decimal _decMarkup;
  		private string _strAvail = string.Empty;
  		private string _strSource = string.Empty;
  		private string _strPage = string.Empty;
  		private bool _blnIncludeInVehicle;
  		private bool _blnInstalled = true;
  		private List<Weapon> _weapons = new List<Weapon>();
  		private string _strNotes = string.Empty;
  		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 string _strName = string.Empty;
  		private string _strCategory = string.Empty;
  		private string _strLimit = string.Empty;
  		private int _intSlots = 0;
  		private string _strCost = string.Empty;
  
  		private readonly Vehicle _vehicle;
  	    private readonly Character _character;
  
  		#region Constructor, Create, Save, Load, and Print Methods
  		public WeaponMount(Character character, Vehicle vehicle)
  		{
  			// Create the GUID for the new VehicleMod.
  			_guiID = Guid.NewGuid();
  		    _character = character;
  			_vehicle = vehicle;
          }
  
          /// 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="objParent">Vehicle that the mod will be attached to.</param>
          /// <param name="decMarkup">Discount or markup that applies to the base cost of the mod.</param>
          public void Create(XmlNode objXmlMod, TreeNode objNode, 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.TryGetInt32FieldQuickly("slots", ref _intSlots);
              objXmlMod.TryGetStringFieldQuickly("weaponcategories", ref _strWeaponMountCategories);
              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 = _character.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);
  
              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("weaponmount");
  			objWriter.WriteElementString("guid", _guiID.ToString());
  			objWriter.WriteElementString("name", _strName);
  			objWriter.WriteElementString("category", _strCategory);
  			objWriter.WriteElementString("limit", _strLimit);
  			objWriter.WriteElementString("slots", _intSlots.ToString());
  			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("weaponmountcategories", _strWeaponMountCategories);
  			objWriter.WriteStartElement("weapons");
              foreach (Weapon w in _weapons)
              {
                  w.Save(objWriter);
              }
              objWriter.WriteEndElement();
              objWriter.WriteStartElement("weaponmountoptions");
              foreach (WeaponMountOption w in WeaponMountOptions)
              {
                  w.Save(objWriter);
              }
              objWriter.WriteEndElement();
              objWriter.WriteElementString("notes", _strNotes);
  			objWriter.WriteElementString("discountedcost", DiscountCost.ToString());
  			objWriter.WriteEndElement();
  			_character.SourceProcess(_strSource);
  		}
  
  		/// <summary>
  		/// Load the VehicleMod from the XmlNode.
  		/// </summary>
  		/// <param name="objNode">XmlNode to load.</param>
  		/// <param name="objVehicle">Vehicle that the mod is attached to.</param>
  		/// <param name="blnCopy">Indicates whether a new item will be created as a copy of this one.</param>
  		public void Load(XmlNode objNode, Vehicle objVehicle, 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.TryGetInt32FieldQuickly("slots", ref _intSlots);
  			objNode.TryGetStringFieldQuickly("weaponmountcategories", ref _strWeaponMountCategories);
  			objNode.TryGetStringFieldQuickly("page", ref _strPage);
  			objNode.TryGetStringFieldQuickly("avail", ref _strAvail);
  			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);
  			if (objNode["weapons"] != null)
  			{
                  foreach (XmlNode n in objNode.SelectNodes("weapons/weapon"))
                  {
                      Weapon w = new Weapon(_character);
                      w.Load(n, blnCopy);
                      _weapons.Add(w);
                  }
              }
              if (objNode["weaponmountoptions"] != null)
              {
                  foreach (XmlNode n in objNode.SelectNodes("weaponmountoptions/weaponmountoption"))
                  {
                      WeaponMountOption w = new WeaponMountOption(_character);
                      w.Load(n, _vehicle);
                      WeaponMountOptions.Add(w);
                  }
              }
              objNode.TryGetStringFieldQuickly("notes", ref _strNotes);
  			objNode.TryGetBoolFieldQuickly("discountedcost", ref _blnDiscountCost);
  			objNode.TryGetStringFieldQuickly("extra", ref _strExtra);
  
              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;
              }
          }
  
  		/// <summary>
  		/// Print the object's XML to the XmlWriter.
  		/// </summary>
  		/// <param name="objWriter">XmlTextWriter to write with.</param>
  		public void Print(XmlTextWriter objWriter, CultureInfo objCulture)
  		{
  			objWriter.WriteStartElement("mod");
  			objWriter.WriteElementString("name", DisplayNameShort);
  			objWriter.WriteElementString("category", DisplayCategory);
  			objWriter.WriteElementString("limit", _strLimit);
  			objWriter.WriteElementString("slots", _intSlots.ToString());
  			objWriter.WriteElementString("avail", TotalAvail);
  			objWriter.WriteElementString("cost", TotalCost.ToString());
  			objWriter.WriteElementString("owncost", OwnCost.ToString());
  			objWriter.WriteElementString("source", _character.Options.LanguageBookShort(_strSource));
  			objWriter.WriteElementString("page", Page);
  			objWriter.WriteElementString("included", _blnIncludeInVehicle.ToString());
              objWriter.WriteStartElement("weapons");
              foreach (Weapon w in _weapons)
              {
                  w.Print(objWriter, objCulture);
              }
              objWriter.WriteEndElement();
  			if (_character.Options.PrintNotes)
  				objWriter.WriteElementString("notes", _strNotes);
  			objWriter.WriteEndElement();
  		}
          /// <summary>
          /// Create a weapon mount using names instead of IDs, because user readability is important and untrustworthy. 
          /// </summary>
          /// <param name="n"></param>
          internal void CreateByName(XmlNode n, TreeNode t)
          {
  
gt:             XmlDocument doc = XmlManager.Load("vehicles.xml");