context: /*  This file is part of Chummer5a.
   *
   *  Chummer5a 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 3 of the License, or
   *  (at your option) any later version.
   *
   *  Chummer5a 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 Chummer5a.  If not, see <http://www.gnu.org/licenses/>.
   *
   *  You can obtain the full source code for Chummer5a at
   *  https://github.com/chummer5a/chummer5a
   */
  
  using System;
  using System.Collections.Generic;
  using System.Globalization;
  using System.Linq;
  using System.Text;
  using System.Threading.Tasks;
  using System.Windows.Forms;
  using System.Xml.XPath;
  
  namespace Chummer
  {
      public partial class SelectQuality : Form
      {
          private string _strSelectedQuality = string.Empty;
          private bool _blnAddAgain;
          private bool _blnLoading = true;
          private readonly Character _objCharacter;
  
          private readonly XPathNavigator _xmlBaseQualityDataNode;
          private readonly XPathNavigator _xmlMetatypeQualityRestrictionNode;
  
          private readonly List<ListItem> _lstCategory = Utils.ListItemListPool.Get();
  
          private static string _strSelectCategory = string.Empty;
  
          #region Control Events
  
          public SelectQuality(Character objCharacter)
          {
              InitializeComponent();
              this.UpdateLightDarkMode();
              this.TranslateWinForm();
              _objCharacter = objCharacter ?? throw new ArgumentNullException(nameof(objCharacter));
  
              // Load the Quality information.
              _xmlBaseQualityDataNode = _objCharacter.LoadDataXPath("qualities.xml").SelectSingleNodeAndCacheExpression("/chummer");
              _xmlMetatypeQualityRestrictionNode = _objCharacter.GetNodeXPath().SelectSingleNode("qualityrestriction");
          }
  
          private async void SelectQuality_Load(object sender, EventArgs e)
          {
              // Populate the Quality Category list.
              foreach (XPathNavigator objXmlCategory in await _xmlBaseQualityDataNode.SelectAndCacheExpressionAsync("categories/category"))
              {
                  string strInnerText = objXmlCategory.Value;
                  _lstCategory.Add(new ListItem(strInnerText, (await objXmlCategory.SelectSingleNodeAndCacheExpressionAsync("@translate"))?.Value ?? strInnerText));
              }
  
              if (_lstCategory.Count > 0)
              {
                  _lstCategory.Insert(0, new ListItem("Show All", await LanguageManager.GetStringAsync("String_ShowAll")));
              }
              
              await cboCategory.PopulateWithListItemsAsync(_lstCategory);
              // Select the first Category in the list.
              if (string.IsNullOrEmpty(_strSelectCategory))
                  cboCategory.SelectedIndex = 0;
              else
              {
                  cboCategory.SelectedValue = _strSelectCategory;
  
                  if (cboCategory.SelectedIndex == -1)
                      cboCategory.SelectedIndex = 0;
              }
              cboCategory.Enabled = _lstCategory.Count > 1;
  
              if (_objCharacter.MetagenicLimit == 0)
                  chkNotMetagenic.Checked = true;
  
              lblBPLabel.Text = await LanguageManager.GetStringAsync("Label_Karma");
              _blnLoading = false;
              await BuildQualityList();
          }
  
          private async void cboCategory_SelectedIndexChanged(object sender, EventArgs e)
          {
              await BuildQualityList();
          }
  
          private async void lstQualities_SelectedIndexChanged(object sender, EventArgs e)
          {
              if (_blnLoading)
                  return;
  
              _blnLoading = true;
  
              XPathNavigator xmlQuality = null;
              string strSelectedQuality = lstQualities.SelectedValue?.ToString();
              if (!string.IsNullOrEmpty(strSelectedQuality))
              {
                  xmlQuality = _xmlBaseQualityDataNode.SelectSingleNode("qualities/quality[id = " + strSelectedQuality.CleanXPath() + ']');
              }
  
              if (xmlQuality != null)
              {
                  nudRating.ValueAsInt = nudRating.MinimumAsInt;
                  int intMaxRating = int.MaxValue;
                  if (xmlQuality.TryGetInt32FieldQuickly("limit", ref intMaxRating) && xmlQuality.SelectSingleNode("nolevels") == null)
                  {
                      lblRatingNALabel.Visible = false;
                      nudRating.MaximumAsInt = intMaxRating;
                      nudRating.Visible = true;
                  }
                  else
                  {
                      lblRatingNALabel.Visible = true;
                      nudRating.MaximumAsInt = 1;
                      nudRating.ValueAsInt = 1;
                      nudRating.Visible = false;
                  }
  
                  await UpdateCostLabel(xmlQuality);
  
                  string strSource = xmlQuality.SelectSingleNode("source")?.Value ?? await LanguageManager.GetStringAsync("String_Unknown");
                  string strPage = (await xmlQuality.SelectSingleNodeAndCacheExpressionAsync("altpage"))?.Value ?? xmlQuality.SelectSingleNode("page")?.Value ?? await LanguageManager.GetStringAsync("String_Unknown");
                  SourceString objSource = await SourceString.GetSourceStringAsync(strSource, strPage, GlobalSettings.Language,
                      GlobalSettings.CultureInfo, _objCharacter);
                  lblSource.Text = objSource.ToString();
                  await lblSource.SetToolTipAsync(objSource.LanguageBookTooltip);
                  lblSourceLabel.Visible = lblSource.Visible = !string.IsNullOrEmpty(lblSource.Text);
                  tlpRight.Visible = true;
              }
              else
              {
                  tlpRight.Visible = false;
              }
  
              _blnLoading = false;
          }
  
          private async void cmdOK_Click(object sender, EventArgs e)
          {
              _blnAddAgain = false;
              await AcceptForm();
          }
  
          private async void cmdOKAdd_Click(object sender, EventArgs e)
          {
              _blnAddAgain = true;
              await AcceptForm();
          }
  
          private void cmdCancel_Click(object sender, EventArgs e)
          {
              DialogResult = DialogResult.Cancel;
          }
  
          private async void chkLimitList_CheckedChanged(object sender, EventArgs e)
          {
              await BuildQualityList();
          }
  
          private async void CostControl_Changed(object sender, EventArgs e)
          {
              if (_blnLoading)
                  return;
  
              _blnLoading = true;
  
              XPathNavigator xmlQuality = null;
              string strSelectedQuality = lstQualities.SelectedValue?.ToString();
              if (!string.IsNullOrEmpty(strSelectedQuality))
              {
                  xmlQuality = _xmlBaseQualityDataNode.SelectSingleNode("qualities/quality[id = " + strSelectedQuality.CleanXPath() + ']');
              }
  
              if (xmlQuality != null)
                  await UpdateCostLabel(xmlQuality);
  
              _blnLoading = false;
          }
  
          private async void chkMetagenic_CheckedChanged(object sender, EventArgs e)
          {
              if (chkMetagenic.Checked)
                  chkNotMetagenic.Checked = false;
              await BuildQualityList();
          }
  
          private async void chkNotMetagenic_CheckedChanged(object sender, EventArgs e)
          {
              if (chkNotMetagenic.Checked)
                  chkMetagenic.Checked = false;
              await BuildQualityList();
          }
  
          private async void txtSearch_TextChanged(object sender, EventArgs e)
          {
              await BuildQualityList();
          }
  
          private void txtSearch_KeyDown(object sender, KeyEventArgs e)
          {
              switch (e.KeyCode)
              {
                  case Keys.Down when lstQualities.SelectedIndex + 1 < lstQualities.Items.Count:
                      ++lstQualities.SelectedIndex;
                      break;
  
                  case Keys.Down:
                      {
                          if (lstQualities.Items.Count > 0)
                          {
                              lstQualities.SelectedIndex = 0;
                          }
  
                          break;
                      }
                  case Keys.Up when lstQualities.SelectedIndex - 1 >= 0:
                      --lstQualities.SelectedIndex;
                      break;
  
                  case Keys.Up:
                      {
                          if (lstQualities.Items.Count > 0)
                          {
  
gt:                             lstQualities.SelectedIndex = lstQualities.Items.Count - 1;