using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
namespace InABox.Core
{
public interface ISubObject
{
BaseObject GetLinkedParent();
void SetLinkedParent(BaseObject obj);
string GetLinkedPath();
void SetLinkedPath(string path);
}
public class SubObjectOriginalValues : IOriginalValues
{
private ISubObject Object { get; set; }
private IOriginalValues? _rootDictionary;
private IOriginalValues RootDictionary
{
get
{
_rootDictionary ??= LinkedProperties.GetParent(Object).OriginalValueList;
return _rootDictionary;
}
}
private string? _rootPath;
///
/// Path of this sub object according to the root, suffixed with a "."
///
private string RootPath
{
get
{
_rootPath ??= $"{LinkedProperties.GetPath(Object)}.";
return _rootPath;
}
}
public SubObjectOriginalValues(ISubObject obj)
{
Object = obj;
}
private string ChangeKey(string key) => $"{RootPath}{key}";
public bool ContainsKey(string key)
{
return RootDictionary.ContainsKey(ChangeKey(key));
}
public void Clear()
{
foreach(var (k, v) in RootDictionary)
{
if (k.StartsWith(RootPath))
{
RootDictionary.Remove(k);
}
}
}
public void Remove(string key)
{
RootDictionary.Remove(ChangeKey(key));
}
public bool TryAdd(string key, object? value)
{
return RootDictionary.TryAdd(ChangeKey(key), value);
}
public bool TryGetValue(string key, out object? value)
{
return RootDictionary.TryGetValue(ChangeKey(key), out value);
}
public IEnumerator> GetEnumerator()
{
return RootDictionary.Where(x => x.Key.StartsWith(RootPath)).Select(x => new KeyValuePair(x.Key[RootPath.Length..], x.Value)).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public object? this[string key]
{
get => RootDictionary[ChangeKey(key)];
set => RootDictionary[ChangeKey(key)] = value;
}
}
public class SubObjectLoadedColumns : ILoadedColumns
{
private ISubObject Object { get; set; }
private ILoadedColumns? _rootSet;
private ILoadedColumns RootSet
{
get
{
_rootSet ??= LinkedProperties.GetParent(Object).LoadedColumns;
return _rootSet;
}
}
private string? _rootPath;
///
/// Path of this sub object according to the root, suffixed with a "."
///
private string RootPath
{
get
{
_rootPath ??= $"{LinkedProperties.GetPath(Object)}.";
return _rootPath;
}
}
public SubObjectLoadedColumns(ISubObject obj)
{
Object = obj;
}
private string ChangeKey(string key) => $"{RootPath}{key}";
public bool Add(string key)
{
return RootSet.Add(ChangeKey(key));
}
public bool Contains(string key)
{
return RootSet.Contains(ChangeKey(key));
}
public IEnumerator GetEnumerator()
{
return RootSet.Where(x => x.StartsWith(RootPath)).Select(x => x[RootPath.Length..]).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
public static class LinkedProperties
{
private static readonly Dictionary> _LinkedProperties = new Dictionary>();
public static void Register(Expression> path, Expression> source,
Expression> target, Func>? func = null)
where TLinkedEntity : class
where TEntityLink : class
{
var map = new LinkedProperty(path, source, target, func);
if(!_LinkedProperties.TryGetValue(map.Type, out var props))
{
props = new List();
_LinkedProperties[map.Type] = props;
}
if(!props.Any(x => x.Equals(map)))
{
props.Add(map);
}
}
/*public static IEnumerable Find(object parent, object path)
{
var all = _LinkedProperties.Where(x => x.Type == parent.GetType());
var filtered = all.Where(x => CoreUtils.GetPropertyValue(parent,x.Path)?.GetType() == path?.GetType());
return filtered;
}*/
public static BaseObject GetParent(ISubObject link)
{
while (true)
{
var parent = link.GetLinkedParent();
if(parent is ISubObject parentLink)
{
link = parentLink;
}
else
{
return parent;
}
}
}
public static string GetPath(ISubObject link)
{
var path = link.GetLinkedPath();
while (true)
{
var parent = link.GetLinkedParent();
if (parent is ISubObject parentLink)
{
link = parentLink;
path = $"{link.GetLinkedPath()}.{path}";
}
else
{
return path;
}
}
}
public static IEnumerable FindAll(Type parent)
{
if (_LinkedProperties.TryGetValue(parent, out var props))
{
return props;
}
return Enumerable.Empty();
}
public static IEnumerable Find(ISubObject subObject, out BaseObject parent)
{
parent = GetParent(subObject);
if (!_LinkedProperties.TryGetValue(parent.GetType(), out var props))
{
return Enumerable.Empty();
}
var path = GetPath(subObject);
return props.Where(x => x.Path == path);
}
public static bool Find(ISubObject subObject, string name, [NotNullWhen(true)] out ILinkedProperty? property, out BaseObject parent)
{
property = null;
parent = GetParent(subObject);
if (parent == null)
return false;
if(!_LinkedProperties.TryGetValue(parent.GetType(), out var props))
return false;
var path = GetPath(subObject);
property = props.FirstOrDefault(x => string.Equals(
$"{x.Path}{(x.Path.IsNullOrWhiteSpace() ? "" : ".")}{x.Source}",
$"{path}{(path.IsNullOrWhiteSpace() ? "" : ".")}{name}"));
return property != null;
}
}
}