using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using HeuristicLab.Core; using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace HeuristicLab.JsonInterface { /// /// Main data class for json interface. /// public class JsonItem { #region Private Fields private string name; private object value; private IEnumerable range; #endregion public string Name { get => name; set { name = value; Path = Name; UpdatePath(); } } public string Type { get; set; } public string Path { get; set; } public IList Parameters { get; set; } // -> für flachen aufbau -> childs? public IList Operators { get; set; } public object Value { get => value; set { this.value = value; CheckConstraints(); } } public IEnumerable Range { get => range; set { range = value; CheckConstraints(); } } public string ActualName { get; set; } #region JsonIgnore Properties [JsonIgnore] public JsonItem Reference { get; set; } [JsonIgnore] public bool IsConfigurable => (Value != null && Range != null); [JsonIgnore] public bool IsParameterizedItem => Parameters != null; #endregion #region Public Static Methods public static void Merge(JsonItem target, JsonItem from) { target.Name = from.Name ?? target.Name; target.Type = from.Type ?? target.Type; target.Range = from.Range ?? target.Range; target.Path = from.Path ?? target.Path; target.Value = from.Value ?? target.Value; target.Reference = from.Reference ?? target.Reference; target.ActualName = from.ActualName ?? target.ActualName; target.Parameters = from.Parameters ?? target.Parameters; target.Operators = from.Operators ?? target.Operators; } #endregion #region Public Methods public void UpdatePath() { if (Parameters != null) UpdatePathHelper(Parameters); if (Operators != null) UpdatePathHelper(Operators); if (Reference != null) UpdatePathHelper(Reference); } #endregion #region Helper private void UpdatePathHelper(params JsonItem[] items) => UpdatePathHelper((IEnumerable)items); private void UpdatePathHelper(IEnumerable items) { foreach (var item in items) { item.Path = $"{Path}.{item.Name}"; item.UpdatePath(); } } private void CheckConstraints() { if (Range != null && Value != null && !IsInRange()) throw new ArgumentOutOfRangeException(nameof(Value), $"{nameof(Value)} is not in range."); } private bool IsInRange() => IsInRangeList() || (Value.GetType().IsArray && ((object[])Value).All(x => IsInNumericRange(x))) || (!Value.GetType().IsArray && IsInNumericRange(Value)); private bool IsInRangeList() { foreach (var x in Range) if (x.Equals(Value)) return true; return false; } private bool IsInNumericRange(object value) => IsInNumericRange(value) || IsInNumericRange(value) || IsInNumericRange(value) || IsInNumericRange(value) || IsInNumericRange(value) || IsInNumericRange(value); private bool IsInNumericRange(object value) where T : IComparable { object min = Range.First(), max = Range.Last(); return value != null && min != null && max != null && value is T && min is T && max is T && (((T)min).CompareTo(value) == -1 || ((T)min).CompareTo(value) == 0) && (((T)max).CompareTo(value) == 1 || ((T)max).CompareTo(value) == 0); } #endregion #region BuildJsonItemMethods public static JsonItem BuildJsonItem(JObject obj, IDictionary typeList) { object val = obj[nameof(Value)]?.ToObject(); if (val is JContainer) val = ((JContainer)val).ToObject(); return new JsonItem() { Name = obj[nameof(Name)]?.ToString(), Path = obj[nameof(Path)]?.ToString(), Value = val, Range = obj[nameof(Range)]?.ToObject(), Type = GetType(obj[nameof(Path)]?.ToObject(), typeList), ActualName = obj[nameof(ActualName)]?.ToString(), Parameters = PopulateParameters(obj, typeList), Operators = PopulateOperators(obj, typeList) }; } private static string GetType(string path, IDictionary typeList) { if (!string.IsNullOrEmpty(path)) if (typeList.TryGetValue(path, out string value)) return value; return null; } private static IList PopulateParameters(JObject obj, IDictionary typeList) { IList list = new List(); // add staticParameters if (obj[Constants.StaticParameters] != null) foreach (JObject param in obj[Constants.StaticParameters]) list.Add(BuildJsonItem(param, typeList)); // merge staticParameter with freeParameter if (obj[Constants.FreeParameters] != null) { foreach (JObject param in obj[Constants.FreeParameters]) { JsonItem tmp = BuildJsonItem(param, typeList); // search staticParameter from list JsonItem comp = null; foreach (var p in list) if (p.Name == tmp.Name) comp = p; if (comp == null) throw new InvalidDataException($"Invalid {Constants.FreeParameters.Trim('s')}: '{tmp.Name}'!"); JsonItem.Merge(comp, tmp); } } return list; } private static IList PopulateOperators(JObject obj, IDictionary typeList) { IList list = new List(); JToken operators = obj[nameof(JsonItem.Operators)]; if (operators != null) foreach (JObject sp in operators) list.Add(BuildJsonItem(sp, typeList)); return list; } #endregion } }