text: using System;
  using System.IO;
  using System.Linq;
  using System.Collections.Generic;
  using System.Text.RegularExpressions;
  using UnityEditor;
  using UnityEditor.IMGUI.Controls;
  using UnityEditor.VersionControl;
  using UnityEngine;
  using UObject = UnityEngine.Object;
  
  namespace UnityEngine.ProBuilder.AssetIdRemapUtility
  {
      sealed class AssetTreeItem : TreeViewItem
      {
          string m_RelativePath;
          string m_FullPath;
          bool m_IsEnabled;
          bool m_IsDirectory;
          bool m_IsMixedState;
  
          public AssetTreeItem(int id, string fullPath, string relativePath) : base(id, 0)
          {
              m_IsDirectory = Directory.Exists(fullPath);
              m_FullPath = fullPath;
              m_RelativePath = relativePath;
              m_IsEnabled = true;
              displayName = m_FullPath.Replace("\\", "/").Replace(Application.dataPath, "Assets/");
          }
  
          public bool enabled
          {
              get { return m_IsEnabled; }
              set { m_IsEnabled = value; }
          }
  
          public bool isDirectory
          {
              get { return m_IsDirectory; }
              set { m_IsDirectory = value; }
          }
  
          public string fullPath
          {
              get { return m_FullPath; }
          }
  
          public string relativePath
          {
              get { return m_RelativePath; }
          }
  
          public bool isMixedState { get { return m_IsMixedState; } }
  
          public void SetEnabled(bool isEnabled)
          {
              enabled = isEnabled;
  
              if (children != null)
              {
                  foreach (var child in children)
                  {
                      AssetTreeItem asset = child as AssetTreeItem;
  
                      if (asset != null)
                          asset.SetEnabled(isEnabled);
                  }
              }
  
              var upstream = parent;
  
              while (upstream != null)
              {
                  var up = upstream as AssetTreeItem;
  
                  if (up != null && up.children != null)
                  {
                      AssetTreeItem firstChild = up.children.FirstOrDefault() as AssetTreeItem;
  
                      if (firstChild != null)
                      {
                          up.m_IsMixedState = up.children.Any(x =>
                              {
                                  var y = x as AssetTreeItem;
                                  return y.enabled != firstChild.enabled;
                              });
  
                          if (!up.m_IsMixedState)
                              up.enabled = firstChild.enabled;
                      }
                      else
                      {
                          up.m_IsMixedState = false;
                      }
                  }
  
                  upstream = upstream.parent;
              }
          }
      }
  
      class AssetTreeView : TreeView
      {
          string m_RootDirectory = null;
          GUIContent m_TempContent = new GUIContent();
          Rect m_ToggleRect = new Rect(0, 0, 0, 0);
  
          public string directoryRoot
          {
              get { return m_RootDirectory; }
              set { m_RootDirectory = value; }
          }
  
          public AssetTreeItem GetRoot()
          {
              return rootItem.hasChildren
                  ? rootItem.children.First() as AssetTreeItem
                  : null;
          }
  
          IEnumerable<Regex> m_DirectoryIgnorePatterns;
          IEnumerable<Regex> m_FileIgnorePatterns;
  
          public void SetDirectoryIgnorePatterns(string[] regexStrings)
          {
              m_DirectoryIgnorePatterns = regexStrings.Select(x => new Regex(x));
          }
  
          public void SetFileIgnorePatterns(string[] regexStrings)
          {
              m_FileIgnorePatterns = regexStrings.Select(x => new Regex(x));
          }
  
          public AssetTreeView(TreeViewState state, MultiColumnHeader header) : base(state, header)
          {
              showBorder = true;
              columnIndexForTreeFoldouts = 0;
              rowHeight = 18f;
          }
  
          protected override TreeViewItem BuildRoot()
          {
              AssetTreeItem root = new AssetTreeItem(0, Application.dataPath, "")
              {
                  depth = -1,
                  enabled = false
              };
  
              if (string.IsNullOrEmpty(m_RootDirectory) || !Directory.Exists(m_RootDirectory))
              {
                  // if root has no children and you SetupDepthsFromParentsAndChildren nullrefs are thrown
                  var list = new List<TreeViewItem>() {};
                  SetupParentsAndChildrenFromDepths(root, list);
              }
              else
              {
                  int nodeIndex = 0;
                  PopulateAssetTree(m_RootDirectory, root, ref nodeIndex);
                  SetupDepthsFromParentsAndChildren(root);
                  ApplyEnabledFilters(root);
              }
  
              return root;
          }
  
          void PopulateAssetTree(string directory, AssetTreeItem parent, ref int nodeIdIndex)
          {
              string unixDirectory = directory.Replace("\\", "/");
  
              AssetTreeItem leaf = new AssetTreeItem(
                      nodeIdIndex++,
                      unixDirectory,
                      unixDirectory.Replace(parent.fullPath, "").Trim('/'))
              {
                  enabled = true
              };
  
              parent.AddChild(leaf);
  
              foreach (string path in Directory.GetFiles(directory, "*", SearchOption.TopDirectoryOnly))
              {
                  if (path.StartsWith(".") || path.EndsWith(".meta"))
                      continue;
  
                  string unixPath = path.Replace("\\", "/");
  
                  leaf.AddChild(new AssetTreeItem(
                          nodeIdIndex++,
                          unixPath,
                          unixPath.Replace(unixDirectory, "").Trim('/')) { enabled = true });
              }
  
              foreach (string dir in Directory.GetDirectories(directory, "*", SearchOption.TopDirectoryOnly))
                  PopulateAssetTree(dir, leaf, ref nodeIdIndex);
          }
  
          public void ApplyEnabledFilters(TreeViewItem root)
          {
              AssetTreeItem node = root as AssetTreeItem;
              AssetTreeItem parent = root.parent as AssetTreeItem;
  
              if (node != null)
              {
                  if (node.isDirectory)
                      node.SetEnabled(
                          (parent == null || parent.enabled) &&
                          (m_DirectoryIgnorePatterns == null || !m_DirectoryIgnorePatterns.Any(x => x.IsMatch(node.fullPath))));
                  else
                      node.SetEnabled(
                          (parent == null || parent.enabled) &&
                          (m_FileIgnorePatterns == null || !m_FileIgnorePatterns.Any(x => x.IsMatch(node.fullPath))));
              }
  
              if (root.children != null)
                  foreach (var child in root.children)
                      ApplyEnabledFilters(child);
          }
  
          protected override void AfterRowsGUI()
          {
              if (rootItem.hasChildren)
                  return;
  
              if (Event.current.type == EventType.Repaint)
              {
                  Rect r = new Rect(treeViewRect);
                  // not sure why there is a two row pad to the treeViewRect
                  r.y -= rowHeight * 2;
                  GUI.Label(r, "No Existing ProBuilder Install Found", EditorStyles.centeredGreyMiniLabel);
              }
          }
  
          protected override void RowGUI(RowGUIArgs args)
          {
              CenterRectUsingSingleLineHeight(ref args.rowRect);
              args.rowRect.xMin += GetContentIndent(args.item);
  
              AssetTreeItem item = args.item as AssetTreeItem;
              m_TempContent.text = item.relativePath;
              m_TempContent.tooltip = item.fullPath;
              m_ToggleRect.x = args.rowRect.xMin;
              m_ToggleRect.y = args.rowRect.yMin;
              m_ToggleRect.width = 16;
              m_ToggleRect.height = args.rowRect.height;
              args.rowRect.xMin += m_ToggleRect.width;
  
              EditorGUI.BeginChangeCheck();
              EditorGUI.showMixedValue = item.isMixedState;
              item.enabled = EditorGUI.Toggle(m_ToggleRect, "", item.enabled);
              EditorGUI.showMixedValue = false;
  
              if (EditorGUI.EndChangeCheck())
              {
                  if (GetSelection().Any(x => FindItem(x, rootItem) == item))
                  {
                      foreach (int id in GetSelection())
                      {
                          var sel = FindItem(id, rootItem) as AssetTreeItem;
  
                          if (sel != null)
                              sel.SetEnabled(item.enabled);
                      }
                  }
                  else
                  {
                      item.SetEnabled(item.enabled);
                  }
              }
  
              bool guiEnabled = GUI.enabled;
              GUI.enabled = item.enabled;
              GUI.Label(args.rowRect, m_TempContent);
              GUI.enabled = guiEnabled;
          }
  
          protected override void ContextClickedItem(int id)
          {
              var clicked = FindItem(id, rootItem) as AssetTreeItem;
              if (clicked != null)
              {
                  var menu = new GenericMenu();
                  menu.AddItem(new GUIContent("Show Asset"), false, () =>
                      {
                          EditorGUIUtility.PingObject(AssetDatabase.LoadAssetAtPath<UObject>(clicked.fullPath));
                      });
                  menu.ShowAsContext();
              }
          }
  
          public List<AssetTreeItem> GetAssetList()
          {
              List<AssetTreeItem> assets = new List<AssetTreeItem>();
              GatherTreeItems(rootItem as AssetTreeItem, assets);
              return assets;
          }
  
          void GatherTreeItems(AssetTreeItem node, List<AssetTreeItem> list)
          {
              if (node == null)
                  return;
  
              list.Add(node);
  
              if (node.children != null)
                  foreach (var child in node.children)
                      if (child is AssetTreeItem)
                          GatherTreeItems(child as AssetTreeItem, list);
          }
      }
  }
  