using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Topten.JsonKit
{
///
/// Helper extensions for navigating dictionaries of string/object
///
public static class IDictionaryExtensions
{
///
/// Navigates a string/object dictionary following a path
///
/// The root dictionary
/// The path to follow
/// Whether to create nodes as walking the path
/// A callback invoked for each lead node. Return false to stop walk
/// Result of last leafCallback, or false if key not found and create parameter is false
public static bool WalkPath(
this IDictionary This,
string Path,
bool create,
Func,string, bool> leafCallback
)
{
// Walk the path
var parts = Path.Split('.');
for (int i = 0; i < parts.Length-1; i++)
{
object val;
if (!This.TryGetValue(parts[i], out val))
{
if (!create)
return false;
val = new Dictionary();
This[parts[i]] = val;
}
This = (IDictionary)val;
}
// Process the leaf
return leafCallback(This, parts[parts.Length-1]);
}
///
/// Check if a path exists in an string/object dictionary heirarchy
///
/// The root dictionary
/// The path to follow
/// True if the path exists
public static bool PathExists(this IDictionary This, string Path)
{
return This.WalkPath(Path, false, (dict, key) => dict.ContainsKey(key));
}
///
/// Gets the object at the specified path in an string/object dictionary heirarchy
///
/// The root dictionary
/// The expected returned object type
/// The path to follow
/// The default value if the value isn't found
///
public static object GetPath(this IDictionary This, Type type, string Path, object def)
{
This.WalkPath(Path, false, (dict, key) =>
{
object val;
if (dict.TryGetValue(key, out val))
{
if (val == null)
def = val;
else if (type.IsAssignableFrom(val.GetType()))
def = val;
else
def = Json.Reparse(type, val);
}
return true;
});
return def;
}
///
/// Gets an object of specified type at a path location in a string/object dictionaryt
///
/// The returned object type
/// The root dictionary
/// The path of the object to return
/// The object instance
public static T GetObjectAtPath(this IDictionary This, string Path) where T:class,new()
{
T retVal = null;
This.WalkPath(Path, true, (dict, key) =>
{
object val;
dict.TryGetValue(key, out val);
retVal = val as T;
if (retVal == null)
{
retVal = val == null ? new T() : Json.Reparse(val);
dict[key] = retVal;
}
return true;
});
return retVal;
}
///
/// Get a value at a path in a string/object dictionary heirarchy
///
/// The type of object to be returned
/// The root dictionary
/// The path of the entry to find
/// The default value to return if not found
/// The located value, or the default value if not found
public static T GetPath(this IDictionary This, string Path, T def = default(T))
{
return (T)This.GetPath(typeof(T), Path, def);
}
///
/// Set a value in a string/object dictionary heirarchy
///
/// The root dictionary
/// The path of the value to set
/// The value to set
public static void SetPath(this IDictionary This, string Path, object value)
{
This.WalkPath(Path, true, (dict, key) => { dict[key] = value; return true; });
}
}
}