#nullable enable
using System.Diagnostics.CodeAnalysis;
using T3.Core.Operator;
using T3.Editor.UiModel;
namespace T3.Editor.Gui.Windows.SymbolLib;
///
/// A nested container that can contain further instances of
/// Used to structure the .
///
internal sealed class NamespaceTreeNode
{
internal string Name { get; private set; }
internal List Children { get; } = new();
internal readonly int Id;
internal NamespaceTreeNode? Parent { get; }
internal string Namespace => GetAsString();
internal SymbolFolderTypes FolderType = SymbolFolderTypes.Undefined;
internal NamespaceTreeNode(string name, NamespaceTreeNode? parent = null)
{
Name = name;
Parent = parent;
Id = name.GetHashCode();
}
internal string GetAsString()
{
var list = new List();
var t = this;
while (t.Parent != null)
{
list.Insert(0, t.Name);
t = t.Parent;
}
return string.Join(".", list);
}
private void Clear()
{
Children.Clear();
Symbols.Clear();
}
private static readonly List _rootProjectNames = [
"Lib.",
"Types.",
"Examples.",
"t3.",
];
internal void PopulateCompleteTree()
{
PopulateCompleteTree(filterAction: null);
}
// Define an action delegate that takes a Symbol and returns a bool
internal void PopulateCompleteTree(Predicate? filterAction)
{
Name = RootNodeId;
Clear();
var ordered = EditorSymbolPackage.AllSymbolUis
.OrderBy(ui =>
{
var ns = ui.Symbol.Namespace ?? string.Empty;
// Find matching root index
var index = _rootProjectNames.FindIndex(p => ns.StartsWith(p, StringComparison.Ordinal));
if (index < 0)
index = int.MaxValue;
return (index, ns + ui.Symbol.Name);
});
foreach (var ui in ordered)
{
var keep = filterAction == null || filterAction(ui);
if (!keep)
continue;
SortInOperator(ui.Symbol);
}
}
internal enum SymbolFolderTypes
{
Undefined,
Root,
User,
UserSubNamespace,
Project,
ProjectSubNamespace,
}
private void SortInOperator(Symbol symbol)
{
if (symbol.Namespace == null)
{
return;
}
var symbolNamespaceParts = symbol.SymbolPackage.RootNamespace.Split('.');
var parts = symbol.Namespace.Split('.');
var currentNode = this;
var expandingSubTree = false;
foreach (var part in parts)
{
if (part == "")
continue;
if (!expandingSubTree)
{
if(currentNode.TryFindNodeDataByName(part, out var node))
{
currentNode = node;
}
else
{
expandingSubTree = true;
}
}
if (!expandingSubTree)
continue;
var newNode = new NamespaceTreeNode(part, currentNode);
var typeIndex = GetIndexInList(part, symbolNamespaceParts);
if (typeIndex == -1)
{
newNode.FolderType = SymbolFolderTypes.ProjectSubNamespace;
}
else if (typeIndex == symbolNamespaceParts.Length - 1)
{
newNode.FolderType = SymbolFolderTypes.Project;
}
else if (typeIndex == 0)
{
newNode.FolderType = SymbolFolderTypes.User;
}
else
{
newNode.FolderType = SymbolFolderTypes.UserSubNamespace;
}
currentNode.Children.Add(newNode);
currentNode = newNode;
}
currentNode.Symbols.Add(symbol);
}
private static int GetIndexInList(string part, string[] list)
{
var partIndex = -1;
foreach (var p in list)
{
partIndex++;
if (p.Equals(part, StringComparison.InvariantCultureIgnoreCase))
{
return partIndex;
}
}
return -1;
}
private bool TryFindNodeDataByName(string name, [NotNullWhen(true)]out NamespaceTreeNode? node)
{
node=Children.FirstOrDefault(n => n.Name == name);
return node != null;
}
internal readonly List Symbols = [];
internal const string RootNodeId = "root";
}