context: using System.Collections.Generic;
  using System.ComponentModel;
  using System.Drawing;
  using System.Globalization;
  using System.IO;
  using System.Text;
  using System.Text.RegularExpressions;
  using System.Threading;
  #if FULL_PROFILE
  using System.Windows.Forms.Design;
  #endif
  using NetSpell.SpellChecker.Dictionary.Affix;
  using NetSpell.SpellChecker.Dictionary.Phonetic;
  
  namespace NetSpell.SpellChecker.Dictionary
  {
      using AffixRuleCollection = Dictionary<string, AffixRule>;
      using PhoneticRuleCollection = List<PhoneticRule>;
  
      /// <summary>
      /// The WordDictionary class contains all the logic for managing the word list.
      /// </summary>
      [ToolboxBitmap(typeof(WordDictionary), "Dictionary.bmp")]
      public class WordDictionary : Component
      {
          private string _dictionaryFile = Thread.CurrentThread.CurrentCulture.Name + ".dic";
          private Container _components;
  
          /// <summary>
          ///     Initializes a new instance of the class
          /// </summary>
          public WordDictionary()
          {
              InitializeComponent();
          }
  
          /// <summary>
          ///     Initializes a new instance of the class
          /// </summary>
          public WordDictionary(IContainer container)
          {
              container.Add(this);
              InitializeComponent();
          }
  
          /// <summary>
          ///     Loads the user dictionary file
          /// </summary>
          private void LoadUserFile()
          {
              // load user words
              UserWords.Clear();
  
              // quit if user file is disabled
              if (!EnableUserFile)
              {
                  return;
              }
  
              string userPath = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData), "NetSpell");
              string filePath = Path.Combine(userPath, UserFile);
  
              if (File.Exists(filePath))
              {
                  TraceWriter.TraceInfo("Loading User Dictionary:{0}", filePath);
  
                  FileStream fs = null;
                  try
                  {
                      fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
                      using (var sr = new StreamReader(fs, Encoding.UTF8))
                      {
                          fs = null;
  
                          // read line by line
                          while (sr.Peek() >= 0)
                          {
                              string tempLine = sr.ReadLine().Trim();
                              if (tempLine.Length > 0)
                              {
                                  UserWords.Add(tempLine, tempLine);
                              }
                          }
                      }
                  }
                  finally
                  {
                      fs?.Dispose();
                  }
  
                  TraceWriter.TraceInfo("Loaded User Dictionary; Words:{0}", UserWords.Count);
              }
          }
  
          /// <summary>
          ///     Saves the user dictionary file
          /// </summary>
          /// <remarks>
          ///     If the file does not exist, it will be created
          /// </remarks>
          private void SaveUserFile()
          {
              // quit if user file is disabled
              if (!EnableUserFile)
              {
                  return;
              }
  
              string userPath = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData), "NetSpell");
              if (!Directory.Exists(userPath))
              {
                  Directory.CreateDirectory(userPath);
              }
  
              string filePath = Path.Combine(userPath, UserFile);
  
              TraceWriter.TraceInfo("Saving User Dictionary:{0}", filePath);
  
              FileStream fs = null;
              try
              {
                  fs = new FileStream(filePath, FileMode.Create, FileAccess.Write);
                  using (var sw = new StreamWriter(fs, Encoding.UTF8))
                  {
                      fs = null;
                      sw.NewLine = "\n";
  
                      foreach (string tempWord in UserWords.Keys)
                      {
                          sw.WriteLine(tempWord);
                      }
                  }
              }
              finally
              {
                  fs?.Dispose();
              }
  
              TraceWriter.TraceInfo("Saved User Dictionary; Words:{0}", UserWords.Count);
          }
  
          /// <summary>
          ///     Verifies the base word has the affix key
          /// </summary>
          /// <param name="word" type="string">
          ///     <para>
          ///         Base word to check
          ///     </para>
          /// </param>
          /// <param name="affixKey" type="string">
          ///     <para>
          ///         Affix key to check
          ///     </para>
          /// </param>
          /// <returns>
          ///     True if word contains affix key
          /// </returns>
          private bool VerifyAffixKey(string word, char affixKey)
          {
              // make sure base word has this affix key
              Word baseWord = BaseWords[word];
              return baseWord.AffixKeys.IndexOf(affixKey) != -1;
          }
  
          /// <summary>
          ///     Adds a word to the user list
          /// </summary>
          /// <param name="word" type="string">
          ///     <para>
          ///         The word to add
          ///     </para>
          /// </param>
          /// <remarks>
          ///     This method is only affects the user word list
          /// </remarks>
          public void Add(string word)
          {
              UserWords.Add(word, word);
              SaveUserFile();
          }
  
          /// <summary>
          ///     Clears the user list of words
          /// </summary>
          /// <remarks>
          ///     This method is only affects the user word list
          /// </remarks>
          public void Clear()
          {
              UserWords.Clear();
              SaveUserFile();
          }
  
          /// <summary>
          ///     Searches all contained word lists for word
          /// </summary>
          /// <param name="word" type="string">
          ///     <para>
          ///         The word to search for
          ///     </para>
          /// </param>
          /// <returns>
          ///     Returns true if word is found
          /// </returns>
          public bool Contains(string word)
          {
              // clean up possible base word list
              PossibleBaseWords.Clear();
  
              // Step 1 Search UserWords
              if (UserWords.ContainsKey(word))
              {
                  TraceWriter.TraceVerbose("Word Found in User Dictionary: {0}", word);
                  return true;  // word found
              }
  
              // Step 2 Search BaseWords
              if (BaseWords.ContainsKey(word))
              {
                  TraceWriter.TraceVerbose("Word Found in Base Words: {0}", word);
                  return true; // word found
              }
  
              // Step 3 Remove suffix, Search BaseWords
  
              // save suffixed words for use when removing prefix
              var suffixWords = new List<string>();
  
              // Add word to suffix word list
              suffixWords.Add(word);
  
              foreach (AffixRule rule in SuffixRules.Values)
              {
                  foreach (AffixEntry entry in rule.AffixEntries)
                  {
                      string tempWord = AffixUtility.RemoveSuffix(word, entry);
                      if (tempWord != word)
                      {
                          if (BaseWords.ContainsKey(tempWord))
                          {
                              if (VerifyAffixKey(tempWord, rule.Name[0]))
                              {
                                  TraceWriter.TraceVerbose("Word Found With Base Words: {0}; Suffix Key: {1}", tempWord, rule.Name[0]);
                                  return true; // word found
                              }
                          }
  
                          if (rule.AllowCombine)
                          {
                              // saving word to check if it is a word after prefix is removed
                              suffixWords.Add(tempWord);
                          }
                          else
                          {
                              // saving possible base words for use in generating suggestions
                              PossibleBaseWords.Add(tempWord);
                          }
                      }
                  }
              }
  
              // saving possible base words for use in generating suggestions
              PossibleBaseWords.AddRange(suffixWords);
  
              // Step 4 Remove Prefix, Search BaseWords
              foreach (AffixRule rule in PrefixRules.Values)
              {
                  foreach (AffixEntry entry in rule.AffixEntries)
                  {
                      foreach (string suffixWord in suffixWords)
                      {
                          string tempWord = AffixUtility.RemovePrefix(suffixWord, entry);
                          if (tempWord != suffixWord)
                          {
                              if (BaseWords.ContainsKey(tempWord))
                              {
                                  if (VerifyAffixKey(tempWord, rule.Name[0]))
                                  {
                                      TraceWriter.TraceVerbose("Word Found With Base Words: {0}; Prefix Key: {1}", tempWord, rule.Name[0]);
                                      return true; // word found
                                  }
                              }
  
                              // saving possible base words for use in generating suggestions
                              PossibleBaseWords.Add(tempWord);
                          }
                      }
                  }
              }
  
              // word not found
              TraceWriter.TraceVerbose("Possible Base Words: {0}", PossibleBaseWords.Count);
              return false;
          }
  
          /// <summary>
          ///     Expands an affix compressed base word
          /// </summary>
          /// <param name="word" type="NetSpell.SpellChecker.Dictionary.Word">
          ///     <para>
          ///         The word to expand
          ///     </para>
          /// </param>
          /// <returns>
          ///     A System.Collections.Generic.List(of String) of words expanded from base word
          /// </returns>
          public List<string> ExpandWord(Word word)
          {
              var suffixWords = new List<string>();
  
gt:             var words = new List<string>();