public void UpgradeIniFile()

in Configurator/Core/Ini/IniTemplate.cs [675:822]


    public void UpgradeIniFile(bool skipExistingValues = false)
    {
      // Load the existing ini file into memory.
      IniFile oldIniFile = new IniFile(ConfigurationFile);

      // Replace the existing ini file with a fresh one created from the template.
      ProcessTemplate(true);

      // Load the refreshed file created from the template into memory.
      IniFile iniTemplateFile = new IniFile(ConfigurationFile);

      // Now, to produce a merged new ini file that contains everything we need, first we need to add new sections if any.
      var newIniFileSections = iniTemplateFile.Lines.FindAll(s => s.IniLineType == IniLineType.Section && !oldIniFile.SectionExists(s.Section));
      foreach (var newSection in newIniFileSections)
      {
        if (oldIniFile.SectionExists(newSection.Section))
        {
          continue;
        }

        oldIniFile.Lines.Add(new IniLineFullDetail(IniLineType.EmptyLine, false, oldIniFile.GetLastSection()));
        oldIniFile.Lines.Add(new IniLineFullDetail(IniLineType.Section, false, newSection.Section));
      }

      // We need to remove any deprecated Server variables, otherwise they will create conflicts with the new Server version.
      var deprecatedVariablesInSeries = DeprecatedVariablesForVersion;
      if (deprecatedVariablesInSeries != null)
      {
        var deprecatedLines = oldIniFile.Lines.FindAll(oldLine => deprecatedVariablesInSeries.Any(dv => dv.Name.Equals(oldLine.Key, StringComparison.OrdinalIgnoreCase)));
        foreach (var deprecatedLine in deprecatedLines)
        {

          // First we remove any comments related to the deprecated lines
          // and we keep inserting these comments on top of the key until we're done working with them.
          int previousLineIndex = oldIniFile.Lines.IndexOf(deprecatedLine) - 1;
          while (previousLineIndex >= 0
                 && oldIniFile.Lines[previousLineIndex].IniLineType != IniLineType.EmptyLine
                 && oldIniFile.Lines[previousLineIndex].IsCommented)
          {
            oldIniFile.Lines.RemoveAt(previousLineIndex);
            previousLineIndex--;
          }

          // Now we remove the deprecated line itself.
          oldIniFile.Lines.Remove(deprecatedLine);
        }
      }

      // Then we need to replace the old values for keys from the old ini file for the recalculated ones from the refreshed file.
      var recalculatedLines = iniTemplateFile.Lines.FindAll(newline =>
                                                              newline.IniLineType == IniLineType.KeyValuePair
                                                              | newline.IniLineType == IniLineType.Flag);
      foreach (var recalculatedLine in recalculatedLines)
      {
        // Find the index of correspondent variable from the refreshed file to old ini file.
        var index = oldIniFile.Lines.FindLastIndex(oldLine => oldLine.Key == recalculatedLine.Key && oldLine.Section == recalculatedLine.Section);

        if (index >= 0)
        {
          // Skip replacement of existing variables if flag is set to true.
          if (skipExistingValues)
          {
            continue;
          }

          // If found, replace the old value of the key with the recalculated one.
          oldIniFile.Lines[index].Value = recalculatedLine.Value;
          oldIniFile.Lines[index].IsCommented = recalculatedLine.IsCommented;
        }
        else
        {
          // If the key is new, we add it to the correspondent section on the old ini file.
          int indexForInsertOnOldFile = oldIniFile.GetLastIndexForSection(recalculatedLine.Section);
          bool collectionLimitReached = indexForInsertOnOldFile >= oldIniFile.Lines.Count;

          // We add a new line at the bottom of the section on the old file.
          if (collectionLimitReached)
          {
            //If it is found at the end of the file we need to use Add() instead of Insert() to avoid an out of bounds exception.
            oldIniFile.Lines.Add(new IniLineFullDetail(IniLineType.EmptyLine, false, oldIniFile.GetLastSection()));
            oldIniFile.Lines.Add(new IniLineFullDetail(IniLineType.KeyValuePair, recalculatedLine.IsCommented, oldIniFile.GetLastSection(), recalculatedLine.Key, recalculatedLine.Value));
          }
          else
          {
            oldIniFile.Lines.Insert(indexForInsertOnOldFile++, new IniLineFullDetail(IniLineType.EmptyLine, false, oldIniFile.GetLastSection()));
            oldIniFile.Lines.Insert(indexForInsertOnOldFile, new IniLineFullDetail(IniLineType.KeyValuePair, recalculatedLine.IsCommented, oldIniFile.GetLastSection(), recalculatedLine.Key, recalculatedLine.Value));
          }

          // Then we need to gather all previous comments in top of the key value pair and insert them after that empty space.
          int recalculatedLinePreviousIndex = iniTemplateFile.Lines.IndexOf(recalculatedLine) - 1;

          // And we keep inserting these comments on top of the key until we're done working with them.
          while (iniTemplateFile.Lines[recalculatedLinePreviousIndex].IniLineType != IniLineType.EmptyLine
                 && iniTemplateFile.Lines[recalculatedLinePreviousIndex].IsCommented)
          {
            oldIniFile.Lines.Insert(collectionLimitReached ? oldIniFile.Lines.Count - 1 : indexForInsertOnOldFile, iniTemplateFile.Lines[recalculatedLinePreviousIndex]);
            recalculatedLinePreviousIndex--;

            // We need to break the while circle if we had reached the top of the template file.
            if (recalculatedLinePreviousIndex < 0) break;
          }
        }
      }

      // Here we just write the merged line by line result into the ini file.
      var writer = new StreamWriter(ConfigurationFile);
      IniLineFullDetail previousLine = null;
      foreach (var line in oldIniFile.Lines)
      {
        if (previousLine != null
            && previousLine.IniLineType == IniLineType.EmptyLine
            && line.IniLineType == IniLineType.EmptyLine)
        {
          continue;
        }

        var sb = new StringBuilder();
        if (line.IsCommented)
        {
          sb.Append("# ");
        }

        switch (line.IniLineType)
        {
          case IniLineType.Comment:
            sb.Append(line.Key);
            break;

          case IniLineType.Section:
            sb.Append("[" + line.Section + "]");
            break;

          case IniLineType.KeyValuePair:
            sb.Append(line.Key + "=" + line.Value);
            break;

          case IniLineType.Flag:
            sb.Append(line.Key);
            break;
        }

        writer.WriteLine(sb.ToString());
        previousLine = line;
      }

      writer.Close();
      writer.Dispose();
    }