context: using System;
  using System.Collections.Generic;
  using System.ComponentModel;
  using System.Data;
  using System.Drawing;
  using System.Text;
  using System.Windows.Forms;
  using System.IO;
  using ManagedWinapi;
  using TreeSizeSharp.Core;
  using System.Diagnostics;
  
  namespace TreeSizeSharp.GUI
  {
      public partial class MainForm : Form, IFolderView
      {
          static Dictionary<string, Icon> extensionIcons = new Dictionary<string, Icon>();
          FolderQueue fqueue = new FolderQueue();
          SizeValue sizeValue = SizeValue.PHYSICAL;
          DisplayMode displayMode = DisplayMode.MIXED;
          readonly ToolStripMenuItem[] sizeValueMenuItems, displayModeMenuItems;
          bool firstone;
  
          public MainForm(bool firstone)
          {
              this.firstone = firstone;
              InitializeComponent();
              sizeValueMenuItems = new ToolStripMenuItem[] {
                  logicalSizeToolStripMenuItem,
                  physicalSizeToolStripMenuItem,
                  allocatedSpaceToolStripMenuItem,
                  spaceWastedToolStripMenuItem,
                  fileCountToolStripMenuItem,
                  folderCountToolStripMenuItem,
                  totalCountToolStripMenuItem
              };
              displayModeMenuItems = new ToolStripMenuItem[] {
                  kBOnlyToolStripMenuItem,
                  mBOnlyToolStripMenuItem,
                  gBOnlyToolStripMenuItem,
                  mixedToolStripMenuItem,
                  percentToolStripMenuItem, 
                  percentParentToolStripMenuItem
              };
          }
  
          private void MainForm_Load(object sender, EventArgs e)
          {
              new FolderScanner(fqueue, this);
              new FolderScanner(fqueue, this);
              new FolderScanner(fqueue, this);
              foreach (String drive in Directory.GetLogicalDrives())
              {
                  ToolStripMenuItem mi = new ToolStripMenuItem("&" + drive, Bitmap.FromHicon(ExtendedFileInfo.GetIconForFilename(drive, true).Handle));
                  mi.Tag = drive;
                  mi.Click += new EventHandler(driveMenuItem_Click);
                  scanToolStripMenuItem.DropDown.Items.Add(mi);
              }
              folderBrowser.SelectedPath = Directory.GetCurrentDirectory();
              ScanFolder();
          }
  
          void driveMenuItem_Click(object sender, EventArgs e)
          {
              folderBrowser.SelectedPath = ((ToolStripMenuItem)sender).Tag.ToString();
              RescanFolder();
          }
  
          public static Icon GetIconForExtension(string extension)
          {
              if (!extensionIcons.ContainsKey(extension))
              {
                  Icon ic = ExtendedFileInfo.GetExtensionIcon(extension, true);
                  if (ic == null) throw new NullReferenceException("Icon for extension: " + extension);
                  extensionIcons[extension] = ic;
              }
              return extensionIcons[extension];
          }
  
          private void ScanFolder()
          {
              filesByExtensionToolStripMenuItem.Checked = false;
              filesByExtensionToolStripMenuItem.Enabled = true;
              string directory = folderBrowser.SelectedPath;
              FolderInfo fi = new FolderInfo(null, directory, directory, 0);
              fi.State = ScanState.EXPANDQUEUED;
              SizeNode sn = new SizeNode(fi);
              nodeMap[fi] = sn;
              TreeNode tn = BuildTreeNode(sn);
              tree.Nodes.Add(tn);
              fqueue.AddFolder(fi, fqueue.Generation);
          }
  
          private TreeNode BuildTreeNode(SizeNode sn)
          {
              TreeNode tn = new TreeNode();
              updateTreeNode(tn, sn);
              BuildChildren(tn);
              return tn;
          }
  
          private void BuildChildren(TreeNode tn)
          {
              SizeNode sn = (SizeNode)tn.Tag;
              List<SizeNode> allKids = new List<SizeNode>();
              if (sn.Directories != null)
              {
                  if (filesByExtensionToolStripMenuItem.Checked)
                  {
                      allKids.AddRange(sn.FileTypeSummaries);
                  }
                  else
                  {
                      allKids.AddRange(sn.FileSummaries);
                  }
                  allKids.AddRange(sn.Directories);
              }
              else if (sn.DummyNode != null)
              {
                  allKids.Add(sn.DummyNode);
              }
              foreach (SizeNode kid in allKids)
              {
                  BuildChild(tn, kid);
              }
              SortNodes(sn, tn);
          }
  
          private void BuildChild(TreeNode tn, SizeNode kid)
          {
              TreeNode child = new TreeNode();
              updateTreeNode(child, kid);
              tn.Nodes.Add(child);
          }
  
          private void updateTreeNode(TreeNode tn, SizeNode sn)
          {
              tn.ContextMenuStrip = treeMenuStrip;
              sn.treeNode = tn;
              tn.Tag = sn;
              string iconName = sn.IconName;
              if (!treeIcons.Images.ContainsKey(iconName))
              {
                  treeIcons.Images.Add(iconName, sn.Icon);
              }
              tn.ImageKey = iconName;
              tn.SelectedImageKey = iconName;
              string s;
              if (tn.Parent == null)
              {
                  s = SizeString(sn, sn, sn);
              }
              else
              {
                  s = SizeString(sn, (SizeNode)tn.Parent.Tag, (SizeNode)tree.Nodes[0].Tag);
              }
              tn.Text = PadString(s);
              tn.Text = s + "  " + sn.DisplayName;
          }
  
          private Dictionary<string, string> paddedStrings = new Dictionary<string, string>();
  
          private string PadString(string str)
          {
              if (!paddedStrings.ContainsKey(str))
              {
                  string s = str;
                  Graphics g = this.CreateGraphics();
                  while (g.MeasureString(s, tree.Font).Width < 64) s = " " + s;
                  g.Dispose();
                  paddedStrings.Add(str, s);
              }
              return paddedStrings[str];
          }
  
          private static readonly string FORMAT = "#,##0";
  
          private string SizeString(SizeNode sn, SizeNode sizeParent, SizeNode sizeRoot)
          {
              FolderSize size = sn.Size;
              ScanState ss = sn.State;
              if (ss == ScanState.QUEUED) return "QUEUED";
              if (ss == ScanState.SCANNING) return "SCAN";
              if (size.fileCount == 0 && size.folderCount == 0 && size.childrenDenied) return "DENIED";
              string den = size.childrenDenied ? "?" : "";
              ulong dsize = displayValue(size);
              if (sizeValue >= SizeValue.ALLCOUNT)
              {
                  if (displayMode != DisplayMode.PERCENT && displayMode != DisplayMode.PERCENTPARENT)
                  {
                      return dsize.ToString(FORMAT) + den;
                  }
              }
              switch (displayMode)
              {
                  case DisplayMode.KB:
                      return RoundDiv(dsize, 1024).ToString(FORMAT) + " kb" + den;
                  case DisplayMode.MB:
                      return RoundDiv(dsize, 1024 * 1024).ToString(FORMAT) + " MB" + den;
                  case DisplayMode.GB:
                      return RoundDiv(dsize, 1024 * 1024 * 1024).ToString(FORMAT) + " GB" + den;
                  case DisplayMode.MIXED:
                      {
                          ulong kb = RoundDiv(dsize, 1024);
                          if (kb < 100 * 1024)
                              return kb.ToString(FORMAT) + " kb" + den;
                          else
                              return (kb / 1024).ToString(FORMAT) + " MB" + den;
                      }
                  case DisplayMode.PERCENT:
                      return MakePercent(dsize, sizeRoot) + den;
                  case DisplayMode.PERCENTPARENT:
                      return MakePercent(dsize, sizeParent) + den;
                  default:
                      throw new Exception();
              }
          }
  
          private ulong RoundDiv(ulong size, ulong unit)
          {
              ulong result = size / unit;
              if (result == 0 && size > 0) result = 1;
              return result;
          }
  
          private string MakePercent(ulong size, SizeNode sizeRef)
          {
              if (size == 0) return "0%";
              if (sizeRef.State != ScanState.DONE)
              {
                  return "WAIT";
              }
              ulong refval = displayValue(sizeRef.Size);
              uint percent = (uint)(size * 100 / refval);
              if (percent < 0) percent = 0;
              if (percent > 100) percent = 100;
              return percent + "%";
          }
  
          private void Form1_FormClosed(object sender, FormClosedEventArgs e)
          {
              fqueue.Close();
          }
  
          private void UpdateFolder0(TreeNode n)
          {
              UpdateFolder00(n);
          }
  
          private void UpdateFolder00(TreeNode n)
          {
              SizeNode sn = (SizeNode)n.Tag;
              sn.Update();
              updateTreeNode(n, sn);
              for (int i = 0; i < n.Nodes.Count; i++)
              {
                  TreeNode nn = n.Nodes[i];
                  SizeNode ssn = (SizeNode)nn.Tag;
                  if (ssn.DummyNode == ssn && sn.DummyNode == null)
                  {
                      n.Nodes.RemoveAt(i);
                  }
                  else
                  {
                      updateTreeNode(nn, ssn);
                  }
              }
              SortNodes((SizeNode)n.Tag, n);
          }
  
          private void SortNodes(SizeNode sn, TreeNode n)
          {
              if (n.Nodes.Count < 2) return;
              if (sn.State != ScanState.DONE) return;
              int cnt = n.Nodes.Count;
              TreeNode[] l = new TreeNode[cnt];
              for (int i = 0; i < cnt; i++)
              {
                  l[i] = n.Nodes[i];
              }
              Array.Sort<TreeNode>(l, new Comparison<TreeNode>(CompareNodes));
              n.Nodes.Clear();
  
gt:             for (int i = 0; i < cnt; i++)