using System; using System.Collections.Generic; using System.Linq; using System.Xml.Serialization; namespace OpenTap.Plugins.BasicSteps { public class SweepParam { internal SweepLoop Step; public string Name => Member?.Name; object[] _values = Array.Empty(); public object[] Values { get => _values; set => _values = value; } object _defaultValue; [XmlIgnore] public object DefaultValue { get => cloneObject(_defaultValue); set => _defaultValue = value; } [XmlIgnore] public ITypeData Type => Member?.TypeDescriptor; public string[] MemberNames { get; set; } internal static string GetMemberName(IMemberData member) => member.DeclaringType.Name + "." + member.Name; IMemberData[] members = Array.Empty(); [XmlIgnore] public IMemberData[] Members { get => members; set { members = value; MemberNames = value.Select(GetMemberName).ToArray(); Step?.parametersChanged(); } } /// /// The property from where attributes are pulled. /// public IMemberData Member => Members?.FirstOrDefault(); /// /// Default constructor. Used by serializer. /// public SweepParam() { } /// /// Initializes a new instance of the SweepParam class. For use when programatically creating a /// /// Property to sweep. This should be one of the properties on one of the childsteps of the . public SweepParam(IEnumerable props) : this() { Members = props.Distinct().ToArray(); if (Members.Length == 0) throw new ArgumentException("Must contain at least one member", nameof(props)); if (!Members.All(p => Equals(p.TypeDescriptor, Type))) throw new ArgumentException("All members must be of the same type", nameof(props)); } public SweepParam(IEnumerable members, params object[] values):this(members) { Resize(values.Length); for(int i = 0; i < values.Length; i++) { Values[i] = values[i]; } } public override string ToString() { return string.Format("{0} : {1}", Name, Type.Name); } TapSerializer serializer = null; object cloneObject(object newValue) { if (newValue == null) return null; if (StringConvertProvider.TryGetString(newValue, out string str)) { if (StringConvertProvider.TryFromString(str, TypeData.GetTypeData(newValue), this.Step, out object result)) { newValue = result; } } else { string serialized = null; serializer = new TapSerializer(); try { serialized = serializer.SerializeToString(newValue); newValue = serializer.DeserializeFromString(serialized, TypeData.GetTypeData(newValue)); } catch { } } return newValue; } public void Resize(int newCount) { int oldCount = Values.Length; if (oldCount == newCount) return; var oldValues = Values; Array.Resize(ref _values, newCount); for (int i = oldCount; i < newCount; i++) { object newValue = null; if (i == 0) newValue = DefaultValue; else newValue = _values.GetValue(i - 1); newValue = cloneObject(newValue); _values.SetValue(newValue, i); } var copyAmount = Math.Min(newCount, oldValues.Length); Array.Copy(oldValues, Values, copyAmount); Step?.parametersChanged(); } } }