using System.Collections; using LibCameraSharp; namespace GSS2.Core.Helpers; public static class ControlValueHelper { private static readonly Dictionary> _parsers = new() { { typeof(bool ), (obj, _) => Parse(obj, bool .TryParse) }, { typeof(byte ), (obj, _) => Parse(obj, byte .TryParse) }, { typeof(float ), (obj, _) => Parse(obj, float .TryParse) }, { typeof(long ), (obj, _) => Parse(obj, long .TryParse) }, { typeof(ushort ), (obj, _) => Parse(obj, ushort.TryParse) }, { typeof(uint ), (obj, _) => Parse(obj, uint .TryParse) }, { typeof(int ), ParseInt }, // int - особый случай потому что он может использовать ControlId.Enumerators для прообразования стокового "enum" в значение { typeof(Rectangle), ParseRectangle }, { typeof(Size ), ParseSize }, { typeof(Point ), ParsePoint } }; private delegate bool ParseValueDelegate(string s, out T value); private static object? Parse(object obj, ParseValueDelegate parser) where T : struct { if (obj is T value) return value; if (obj is string str && parser(str, out var parsed)) return parsed; return null; } private static object? ParseInt(object obj, ControlId id) { if (obj is int value) return value; if (obj is string str) { if (int.TryParse(str, out value)) return value; var match = id.Enumerators.FirstOrDefault(e => e.Value == str); if (!match.Equals(default(KeyValuePair))) return match.Key; } return null; } private static object? ParseRectangle(object obj, ControlId id) { if (obj is Rectangle value) return value; if (obj is IEnumerable enumerable) { var list = enumerable.Cast(); if (list.Count() != 4) return null; if (!int.TryParse(list.Skip(0).First(), out var x)) return null; if (!int.TryParse(list.Skip(1).First(), out var y)) return null; if (!uint.TryParse(list.Skip(2).First(), out var width)) return null; if (!uint.TryParse(list.Skip(3).First(), out var height)) return null; return new Rectangle(x, y, width, height); } return null; } private static object? ParseSize(object obj, ControlId id) { if (obj is Size value) return value; if (obj is IEnumerable enumerable) { var list = enumerable.Cast(); if (list.Count() != 2) return null; if (!uint.TryParse(list.Skip(0).First(), out var width)) return null; if (!uint.TryParse(list.Skip(1).First(), out var height)) return null; return new Size(width, height); } return null; } private static object? ParsePoint(object obj, ControlId id) { if (obj is Point value) return value; if (obj is IEnumerable enumerable) { var list = enumerable.Cast(); if (list.Count() != 4) return null; if (!int.TryParse(list.Skip(0).First(), out var x)) return null; if (!int.TryParse(list.Skip(1).First(), out var y)) return null; return new Point(x, y); } return null; } private static T ConvertValue(object obj, ControlId id) { if (!_parsers.TryGetValue(typeof(T), out var parser)) throw new Exception(); var parsed = parser(obj, id); if (parsed is null || parsed is not T typed) throw new Exception(); return typed; } private static IEnumerable ConvertArray(object obj, ControlId id) { if (obj is not IEnumerable enumerable) throw new Exception(); var list = enumerable.Cast().ToList(); if ((ulong)list.Count() != id.Size) throw new Exception(); var array = new T[list.Count()]; for (int i = 0; i < list.Count(); i++) array[i] = ConvertValue(list.Skip(i).First(), id); return array.AsEnumerable(); } private static ControlValue ConvertControlValue(object obj, ControlId id, ControlInfo info) { if (!ControlValue.ValueTypes.TryGetValue(id.Type, out var valueType)) throw new InvalidOperationException(); var convertValue = typeof(ControlValueHelper) .GetMethod(nameof(ConvertValue), System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static)? .MakeGenericMethod([valueType]); if (convertValue is null) throw new Exception(); var value = convertValue.Invoke(null, [obj, id]); var controlValueType = AppDomain.CurrentDomain .GetAssemblies() .SelectMany(a => a.GetTypes()) .FirstOrDefault(t => !t.IsAbstract && t.BaseType is { IsGenericType: true } baseType && baseType.GetGenericTypeDefinition() == typeof(ControlValue<>) && baseType.GetGenericArguments()[0] == valueType); if (controlValueType is null) throw new Exception(); var constructor = controlValueType.GetConstructor([valueType]); if (constructor is null) throw new Exception(); var controlValue = constructor.Invoke([value]); if (controlValue is null || controlValue is not ControlValue typed) throw new Exception(); return typed; } private static ControlValue ConvertControlArray(object obj, ControlId id, ControlInfo info) { if (!ControlValue.ArrayTypes.TryGetValue(id.Type, out var arrayType)) throw new Exception(); if (!ControlValue.ValueTypes.TryGetValue(id.Type, out var valueType)) throw new InvalidOperationException(); var convertArray = typeof(ControlValueHelper) .GetMethod(nameof(ConvertArray), System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static)? .MakeGenericMethod([valueType]); if (convertArray is null) throw new Exception(); var value = convertArray.Invoke(null, [obj, id]); var controlValueType = AppDomain.CurrentDomain .GetAssemblies() .SelectMany(a => a.GetTypes()) .FirstOrDefault(t => !t.IsAbstract && t.BaseType is { IsGenericType: true } baseType && baseType.GetGenericTypeDefinition() == typeof(ControlValue<>) && baseType.GetGenericArguments()[0] == arrayType); if (controlValueType is null) throw new Exception(); var constructor = controlValueType.GetConstructor([arrayType]); if (constructor is null) throw new Exception(); var controlValue = constructor.Invoke([value]); if (controlValue is null || controlValue is not ControlValue typed) throw new Exception(); return typed; } public static ControlValue Convert(object obj, ControlId id, ControlInfo info) { if (!id.IsArray) return ConvertControlValue(obj, id, info); return ConvertControlArray(obj, id, info); } }