using System; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; namespace AsbCloudInfrastructure.Services.DetectOperations.Detectors { #nullable enable internal class FragmentDetector : IFragmentDetector { private int fragmentLength = 12; private int stepLength = 3; protected IEnumerable detectors = Enumerable.Empty(); protected Func detectStart; protected Func detectEnd; public string Name { get; set; } public int FragmentLength { get => fragmentLength; set => fragmentLength = value; } public int StepLength { get => stepLength; set => stepLength = value; } public FragmentDetector( string name, Func detectStart, IFragmentDetector detector, params IFragmentDetector[] detectors) { this.detectStart = detectStart; this.detectors = JoinDetectors(detector, detectors); detectEnd = (f, i) => !detectStart(f, i); Name = name; } public FragmentDetector( string name, Func detectStart, Func detectEnd, IFragmentDetector detector, params IFragmentDetector[] detectors) { this.detectStart = detectStart; this.detectEnd = detectEnd; this.detectors = JoinDetectors(detector, detectors); Name = name; } public FragmentDetector( string name, Func detectStart, IOperationDetector operation) { this.detectStart = detectStart; detectors = new IOperationDetector[] { operation }; detectEnd = (f, i) => !detectStart(f, i); Name = name; } public FragmentDetector( string name, Func detectStart, Func detectEnd, IOperationDetector operation) { this.detectStart = detectStart; this.detectEnd = detectEnd; detectors = new IOperationDetector[] { operation }; Name = name; } private static IEnumerable JoinDetectors(IFragmentDetector detector, params IFragmentDetector[] detectors) { var joined = new IFragmentDetector[1 + detectors.Length]; joined[0] = detector; if (detectors.Length > 0) detectors.CopyTo(joined, 1); return joined; } public static Func MakeInstantDelegate( Func instantValueCondition ) { var detect = (DetectableTelemetry[] telemetry, int position) => { var firstItem = telemetry[position]; var result = instantValueCondition(firstItem); return result; }; return detect; } public static Func MakeInterpolationDelegate( Func yGetter, Func interpolationValueCondition, int fragmentLength) { var detect = (DetectableTelemetry[] telemetry, int position) => { DetectableTelemetry[] data; if (fragmentLength > 0 && (position + fragmentLength) < telemetry.Length) data = telemetry[position..(position + fragmentLength)]; else data = telemetry[position..]; var line = new InterpolationLine(data.Select(d => (yGetter(d), (d.DateTime - telemetry[0].DateTime).TotalHours))); var result = interpolationValueCondition(line); return result; }; return detect; } public bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetry, int begin, int end, out IEnumerable results) { List? totaltResultList = null; var positionBegin = begin; // Поиск начала соответствия критерию начала операции while (end > positionBegin + fragmentLength + stepLength) { if (detectStart(telemetry, positionBegin)) { // Поиск окончания соответствия критерию var positionEnd = positionBegin; while (positionEnd < end) { positionEnd += stepLength; if ((positionEnd > end)) positionEnd = end; if ((positionEnd == end) || detectEnd(telemetry, positionEnd)) { totaltResultList = totaltResultList ?? new List(); var detectorsEnumerator = detectors.GetEnumerator(); while (detectorsEnumerator.MoveNext()) if (detectorsEnumerator.Current.TryDetect(idTelemetry, telemetry, positionBegin, positionEnd, out IEnumerable innerResult)) totaltResultList.AddRange(innerResult); break; } } positionBegin = positionEnd; } else { positionBegin += stepLength; } } if(totaltResultList?.Any() == true) { results = totaltResultList!; return true; } else { results = Enumerable.Empty(); return false; } } public override string ToString() => $"frame detector {Name}"; } #nullable disable }