using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RainmeterStudio.Core.Model;
namespace RainmeterStudio.Core.Utils
{
///
/// Extension methods for trees
///
public static class TreeExtensions
{
///
/// Tree traversal orders
///
public enum TreeTraversalOrder
{
BreadthFirst,
DepthFirst,
DepthFirstPreOrder = DepthFirst,
DepthFirstPostOrder
}
///
/// Traverses a tree
///
/// Tree data type
/// Root node of tree
/// Traversal order
/// An enumeration of the nodes in the specified traverse order
public static IEnumerable> Traverse(this Tree root, TreeTraversalOrder order = TreeTraversalOrder.BreadthFirst)
{
if (order == TreeTraversalOrder.BreadthFirst)
return TraverseBF(root);
else return TraverseDF(root, order);
}
private static IEnumerable> TraverseDF(this Tree root, TreeTraversalOrder order)
{
// Preorder - return root first
if (order == TreeTraversalOrder.DepthFirstPreOrder)
yield return root;
// Return children
foreach (var child in root.Children)
foreach (var node in TraverseDF(child, order))
yield return node;
// Postorder - return root last
if (order == TreeTraversalOrder.DepthFirstPostOrder)
yield return root;
}
private static IEnumerable> TraverseBF(this Tree root)
{
// Create a queue containing the root
Queue> queue = new Queue>();
queue.Enqueue(root);
// While there are elements in the queue
while (queue.Count > 0)
{
// Return next node in tree
var node = queue.Dequeue();
yield return node;
// Enqueue node's children
foreach (var child in node.Children)
queue.Enqueue(child);
}
}
///
/// Applies an action to every node of the tree
///
/// Tree data type
/// Root node of tree
/// Action to apply
/// Traversal order
public static void Apply(this Tree root, Action> action, TreeTraversalOrder order = TreeTraversalOrder.BreadthFirst)
{
// Safety check
if (action == null)
return;
// Apply action
foreach (var node in Traverse(root, order))
action(node);
}
///
/// Applies an action to every node of the tree
///
/// Tree data type
/// Root node of tree
/// Action to apply
/// Traversal order
public static void ApplyToData(this Tree root, Action action, TreeTraversalOrder order = TreeTraversalOrder.BreadthFirst)
where T : class
{
// Safety check
if (action == null)
return;
// Apply action
foreach (var node in Traverse(root, order))
action(node.Data);
}
///
/// Rebuilds the tree by applying the specified transform function
///
/// Data type of tree
/// Data type of rebuilt tree
/// The root node
/// The transform function
/// The transformed tree
public static Tree Transform(this Tree root, Func, Tree> transformFunction)
{
// Safety check
if (transformFunction == null)
throw new ArgumentNullException("Transform function cannot be null.");
// Build root
Tree resRoot = transformFunction(root);
// Add children
foreach (var node in root.Children)
resRoot.Children.Add(Transform(node, transformFunction));
// Return
return resRoot;
}
///
/// Rebuilds the tree by applying the specified transform function
///
/// Data type of tree
/// Data type of rebuilt tree
/// The root node
/// The transform function
/// The transformed tree
public static Tree TransformData(this Tree root, Func transformFunction)
{
// Safety check
if (transformFunction == null)
throw new ArgumentNullException("Transform function cannot be null.");
// Build root
Tree resRoot = new Tree(transformFunction(root.Data));
// Add children
foreach (var node in root.Children)
resRoot.Children.Add(TransformData(node, transformFunction));
// Return
return resRoot;
}
}
}