using AsbCloudDb.Model; using System; using System.Collections.Generic; using System.Linq; 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 int FragmentLength { get => fragmentLength; set => fragmentLength = value; } public int StepLength { get => stepLength; set => stepLength = value; } public FragmentDetector( Func detectStart, IFragmentDetector detector, params IFragmentDetector[] detectors) { this.detectStart = detectStart; this.detectors = JoinDetectors(detector, detectors); detectEnd = (f, i) => !detectStart(f,i); } public FragmentDetector( Func detectStart, Func detectEnd, IFragmentDetector detector, params IFragmentDetector[] detectors) { this.detectStart = detectStart; this.detectEnd = detectEnd; this.detectors = JoinDetectors(detector, detectors); } public FragmentDetector(Func detectStart, IOperationDetector operation) { this.detectStart = detectStart; detectors = new IOperationDetector[] { operation }; detectEnd = (f, i) => !detectStart(f, i); } public FragmentDetector(Func detectStart, Func detectEnd, IOperationDetector operation) { this.detectStart = detectStart; this.detectEnd = detectEnd; detectors = new IOperationDetector[] { operation }; } 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 && fragmentLength < telemetry.Length) data = telemetry[position..(position + fragmentLength)]; else data = telemetry; var line = new InterpolationLine(data.Select(d => (yGetter(d), (d.DateTime - telemetry[0].DateTime).TotalHours))); var result = interpolationValueCondition(line); return result; }; return detect; } public IFragmentDetector AddChildDetector(params IFragmentDetector[] detectors) { throw new NotImplementedException(); } public IDetector AddOperationDetector(IOperationDetector operation) { detectors = new IOperationDetector[] { operation}; return this; } public bool TryDetect(int idTelemetry, DetectableTelemetry[] telemetryFragment, out IEnumerable operations) { var positionStart = 0; var operationsList = new List(); // поиск начала соответствия критерию while (telemetryFragment.Length > positionStart + FragmentLength + stepLength) { if (detectStart(telemetryFragment, positionStart)) { // Поиск окончания соответствия критерию var positionEnd = positionStart + stepLength; while (telemetryFragment.Length > positionEnd + FragmentLength) { if (detectEnd(telemetryFragment, positionEnd)) { var innerFragment = telemetryFragment[positionStart..positionEnd]; var detectorEnumerator = detectors.GetEnumerator(); while(detectorEnumerator.MoveNext()) if (detectorEnumerator.Current.TryDetect(idTelemetry, innerFragment, out IEnumerable result)) operationsList.AddRange(result); break; } positionEnd += stepLength; } positionStart = positionEnd; } else { positionStart += stepLength; } } operations = operationsList; return operationsList.Any(); } } #nullable disable }