context: using System;
  using System.Collections.Generic;
  using System.Drawing;
  using System.IO;
  using System.Text;
  using System.Threading;
  using System.Threading.Tasks;
  using System.Windows.Forms;
  using GitCommands.Statistics;
  using GitStatistics.PieChart;
  using GitUIPluginInterfaces;
  
  namespace GitStatistics
  {
      public partial class FormGitStatistics : Form
      {
          private readonly string _codeFilePattern;
  
          protected Color[] DecentColors =
              new[]
                  {
                      Color.Red,
                      Color.Yellow,
                      Color.DodgerBlue,
                      Color.LightGreen,
                      Color.Coral,
                      Color.Goldenrod,
                      Color.YellowGreen,
                      Color.MediumPurple,
                      Color.LightGray,
                      Color.Brown,
                      Color.Pink,
                      Color.DarkBlue,
                      Color.Purple
                  };
  
          public string DirectoriesToIgnore;
          public DirectoryInfo WorkingDir;
          private SynchronizationContext syncContext;
          private LineCounter lineCounter;
          private Task loadThread;
          private readonly IGitModule Module;
  
          public FormGitStatistics(IGitModule aModule, string codeFilePattern)
          {
              Module = aModule;
              _codeFilePattern = codeFilePattern;
              InitializeComponent();
  
              TotalLinesOfCode.Font = new Font(SystemFonts.MessageBoxFont.FontFamily, 9.75F, FontStyle.Bold, GraphicsUnit.Point);
              TotalLinesOfCode2.Font = TotalLinesOfCode.Font;
              TotalLinesOfTestCode.Font = TotalLinesOfCode.Font;
              TotalCommits.Font = TotalLinesOfCode.Font;
              LoadingLabel.Font = TotalLinesOfCode.Font;
  
              syncContext = SynchronizationContext.Current;
          }
  
          private void FormGitStatisticsSizeChanged(object sender, EventArgs e)
          {
              SetPieStyle(CommitCountPie);
              SetPieStyle(LinesOfCodeExtensionPie);
              SetPieStyle(LinesOfCodePie);
              SetPieStyle(TestCodePie);
          }
  
          public void Initialize()
          {
              InitializeCommitCount();
              InitializeLinesOfCode();
          }
  
          private void InitializeCommitCount()
          {
              Action<FormGitStatistics> a = sender =>
              {
                  var allCommitsByUser = CommitCounter.GroupAllCommitsByContributor(Module);
                  syncContext.Post(o =>
                  {
                      if (this.IsDisposed)
                          return;
                      var totalCommits = allCommitsByUser.Item2;
                      var commitsPerUser = allCommitsByUser.Item1;
  
                      TotalCommits.Text = totalCommits + " Commits";
  
                      var builder = new StringBuilder();
  
                      var commitCountValues = new Decimal[commitsPerUser.Count];
                      var commitCountLabels = new string[commitsPerUser.Count];
                      var n = 0;
                      foreach (var keyValuePair in commitsPerUser)
                      {
                          var user = keyValuePair.Key;
                          var commits = keyValuePair.Value;
  
                          builder.AppendLine(commits + " " + user);
  
                          commitCountValues[n] = commits;
                          commitCountLabels[n] = commits + " Commits by " + user;
                          n++;
                      }
                      CommitCountPie.SetValues(commitCountValues);
                      CommitCountPie.ToolTips = commitCountLabels;
  
                      CommitStatistics.Text = builder.ToString();
  
                  }, null);
              };
              a.BeginInvoke(null, null, this);
          }
  
          private void SetPieStyle(PieChartControl pie)
          {
              pie.SetLeftMargin(10);
              pie.SetRightMargin(10);
              pie.SetTopMargin(10);
              pie.SetBottomMargin(10);
              pie.SetFitChart(false);
              pie.SetEdgeColorType(EdgeColorType.DarkerThanSurface);
              pie.SetSliceRelativeHeight(0.20f);
              pie.SetColors(DecentColors);
              pie.SetShadowStyle(ShadowStyle.GradualShadow);
  
              if (pie.Parent.Width > pie.Parent.Height)
              {
                  pie.Height = pie.Parent.Height;
                  pie.Width = pie.Parent.Height;
              }
              else
              {
                  pie.Height = pie.Parent.Width;
                  pie.Width = pie.Parent.Width;
              }
          }
  
          bool initializeLinesOfCodeDone;
          private void InitializeLinesOfCode()
          {
              if (initializeLinesOfCodeDone)
                  return;
              
              initializeLinesOfCodeDone = true;
  
              lineCounter = new LineCounter(WorkingDir);
              lineCounter.LinesOfCodeUpdated += lineCounter_LinesOfCodeUpdated;
  
              loadThread = Task.Factory.StartNew(LoadLinesOfCode);
          }
          
          public void LoadLinesOfCode()
          {
              lineCounter.FindAndAnalyzeCodeFiles(_codeFilePattern, DirectoriesToIgnore);
          }
  
          void lineCounter_LinesOfCodeUpdated(object sender, EventArgs e)
          {
              LineCounter lineCounter = (LineCounter)sender;
  
              //Must do this synchronously because lineCounter.LinesOfCodePerExtension might change while we are iterating over it otherwise.
              var extensionValues = new Decimal[lineCounter.LinesOfCodePerExtension.Count];
              var extensionLabels = new string[lineCounter.LinesOfCodePerExtension.Count];
  
              List<KeyValuePair<string, int>> LinesOfCodePerExtension = new List<KeyValuePair<string, int>>(lineCounter.LinesOfCodePerExtension);
              LinesOfCodePerExtension.Sort((first, next) => -first.Value.CompareTo(next.Value));
  
              var n = 0;
              string linesOfCodePerLanguageText = "";
              foreach (var keyValuePair in LinesOfCodePerExtension)
              {
                  string percent = ((double)keyValuePair.Value / lineCounter.NumberCodeLines).ToString("P1");
                  linesOfCodePerLanguageText += keyValuePair.Value + " Lines of code in " + keyValuePair.Key + " files (" + percent + ")" + Environment.NewLine;
                  extensionValues[n] = keyValuePair.Value;
                  extensionLabels[n] = keyValuePair.Value + " Lines of code in " + keyValuePair.Key + " files (" + percent + ")";
                  n++;
              }
  
              //Sync rest to UI thread
              syncContext.Post(o => UpdateUI(lineCounter, linesOfCodePerLanguageText, extensionValues, extensionLabels), null);
          }
  
          private void UpdateUI(LineCounter lineCounter, string linesOfCodePerLanguageText, decimal[] extensionValues,
                                string[] extensionLabels)
          {
              TotalLinesOfTestCode.Text = lineCounter.NumberTestCodeLines + " Lines of test code";
  
              TestCodePie.SetValues(new Decimal[]
                  {
                      lineCounter.NumberTestCodeLines,
                      lineCounter.NumberCodeLines - lineCounter.NumberTestCodeLines
                  });
  
              string percent_t = ((double) lineCounter.NumberTestCodeLines/lineCounter.NumberCodeLines).ToString("P1");
              string percent_p =
                  ((double) (lineCounter.NumberCodeLines - lineCounter.NumberTestCodeLines)/lineCounter.NumberCodeLines).ToString(
                      "P1");
              TestCodePie.ToolTips =
                  new[]
                      {
                          lineCounter.NumberTestCodeLines + " Lines of testcode (" + percent_t + ")",
                          lineCounter.NumberCodeLines - lineCounter.NumberTestCodeLines +
                          " Lines of production code (" + percent_p + ")"
                      };
  
              TestCodeText.Text = lineCounter.NumberTestCodeLines + " Lines of testcode (" + percent_t + ")" + Environment.NewLine +
                                  (lineCounter.NumberCodeLines - lineCounter.NumberTestCodeLines) +
                                  " Lines of production code (" + percent_p + ")";
  
  
              string percent_blank = ((double) lineCounter.NumberBlankLines/lineCounter.NumberLines).ToString("P1");
              string percent_comments = ((double) lineCounter.NumberCommentsLines/lineCounter.NumberLines).ToString("P1");
              string percent_code = ((double) lineCounter.NumberCodeLines/lineCounter.NumberLines).ToString("P1");
              string percent_designer = ((double) lineCounter.NumberLinesInDesignerFiles/lineCounter.NumberLines).ToString("P1");
              LinesOfCodePie.SetValues(new Decimal[]
                  {
                      lineCounter.NumberBlankLines,
                      lineCounter.NumberCommentsLines,
                      lineCounter.NumberLines,
                      lineCounter.NumberLinesInDesignerFiles
                  });
              LinesOfCodePie.ToolTips =
                  new[]
                      {
                          lineCounter.NumberBlankLines + " Blank lines (" + percent_blank + ")",
                          lineCounter.NumberCommentsLines + " Comment lines (" + percent_comments + ")",
                          lineCounter.NumberCodeLines + " Lines of code (" + percent_code + ")",
                          lineCounter.NumberLinesInDesignerFiles + " Lines in designer files (" + percent_designer + ")"
                      };
  
              LinesOfCodePerTypeText.Text = LinesOfCodePie.ToolTips[0] + Environment.NewLine;
              LinesOfCodePerTypeText.Text += LinesOfCodePie.ToolTips[1] + Environment.NewLine;
              LinesOfCodePerTypeText.Text += LinesOfCodePie.ToolTips[2] + Environment.NewLine;
              LinesOfCodePerTypeText.Text += LinesOfCodePie.ToolTips[3] + Environment.NewLine;
  
              LinesOfCodePerLanguageText.Text = linesOfCodePerLanguageText;
  
              LinesOfCodeExtensionPie.SetValues(extensionValues);
              LinesOfCodeExtensionPie.ToolTips = extensionLabels;
  
              TotalLinesOfCode2.Text = TotalLinesOfCode.Text = lineCounter.NumberCodeLines + " Lines of code";
          }
  
          private void FormGitStatisticsShown(object sender, EventArgs e)
          {
              Initialize();
  
              Tabs.Visible = true;
              LoadingLabel.Visible = false;
  
  
              FormGitStatisticsSizeChanged(null, null);
  
gt:             SizeChanged += FormGitStatisticsSizeChanged;