private async Task StartBatchModeProcessAsync()
        {
            try
            {
                detectingAnomalyBtn.IsEnabled = false;

                string timestampFormat = curScenario.ScenarioType == AnomalyDetectionScenarioType.Telecom ? ShortDateFormat : ShortDateWithTimeFormat;
                double dataRange       = curScenario.MaxValue - curScenario.MinValue;
                double yScale          = (resultGrid.ActualHeight / dataRange);
                double yZeroLine       = yScale * curScenario.MinValue;

                for (int i = 0; i < dataPolyline.Points.Count; i++)
                {
                    progressIndicator.Offset = new Vector3(float.Parse(dataPolyline.Points[i].X.ToString()), float.Parse(resultGrid.ActualHeight.ToString()), resultGrid.CenterPoint.Z);

                    progressLine.X1 = dataPolyline.Points[i].X;
                    progressLine.X2 = dataPolyline.Points[i].X;

                    if (anomalyEntireDetectResult != null)
                    {
                        Point newUpperPoint = new Point(dataPolyline.Points[i].X, yZeroLine + resultGrid.ActualHeight - (yScale * (anomalyEntireDetectResult.ExpectedValues[i] + anomalyEntireDetectResult.UpperMargins[i])));
                        Point newLowerPoint = new Point(dataPolyline.Points[i].X, yZeroLine + resultGrid.ActualHeight - (yScale * (anomalyEntireDetectResult.ExpectedValues[i] - anomalyEntireDetectResult.LowerMargins[i])));

                        if (anomalyEntireDetectResult.IsAnomaly[i])
                        {
                            SpriteVisual   anomalyIndicator = GetNewAnomalyIndicator(dataPolyline.Points[i]);
                            TimeSeriesData timeSeriesData   = curScenario.AllData[i];
                            AnomalyInfo    anomalyInfo      = new AnomalyInfo
                            {
                                Text          = Util.StringToDateFormat(timeSeriesData.Timestamp, timestampFormat),
                                Value         = timeSeriesData.Value.ToString("F2"),
                                ExpectedValue = anomalyEntireDetectResult.ExpectedValues[i].ToString("F2")
                            };

                            containerRoot.Children.InsertAtTop(anomalyIndicator);
                            allAnomalyIndicators.Add(new Tuple <SpriteVisual, AnomalyInfo>(anomalyIndicator, anomalyInfo));
                        }

                        int endOfUpper = progressPolyline.Points.Count / 2;
                        int endOfLower = progressPolyline.Points.Count / 2 + 1;

                        progressPolyline.Points.Insert(endOfUpper, newUpperPoint);
                        progressPolyline.Points.Insert(endOfLower, newLowerPoint);
                    }
                }
            }
            catch (Exception ex)
            {
                await Util.GenericApiCallExceptionHandler(ex, "Failure during batch detection.");
            }
            finally
            {
                detectingAnomalyBtn.IsEnabled = true;
            }
        }
        private void OnChartPointer(object sender, PointerRoutedEventArgs e)
        {
            Point point   = e.GetCurrentPoint(resultGrid).Position;
            var   anomaly = allAnomalyIndicators.FirstOrDefault(x => Util.IsPointInsideVisualElement(x.Item1, point) &&
                                                                (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Mouse || e.Pointer.IsInContact)); // test for touch exit event);

            if (anomaly != null)
            {
                Visual      visualElement = anomaly.Item1;
                AnomalyInfo anomalyInfo   = anomaly.Item2;

                double popupWidth  = this.tooltipPopup.ActualWidth;
                double popupHeight = this.tooltipPopup.ActualHeight;

                Point  absolutePoint = e.GetCurrentPoint(Window.Current.Content).Position;
                double pageWidth     = ((AppShell)Window.Current.Content)?.ActualWidth ?? 0;

                double xOffset = absolutePoint.X + popupWidth / 2.0 >= pageWidth ? visualElement.Offset.X - popupWidth : visualElement.Offset.X - popupWidth / 2.0;
                double yOffset = visualElement.Offset.Y - popupHeight - TooltipBottomMargin;

                // set tooltip offset
                this.tooltipPopup.HorizontalOffset = xOffset;
                this.tooltipPopup.VerticalOffset   = yOffset;

                // set tooltip data
                this.timestampTextBlock.Text  = anomalyInfo.Text;
                this.delayValueTextBlock.Text = anomalyInfo.Value;
                this.expectedTextBlock.Text   = anomalyInfo.ExpectedValue;

                // show tooltip
                this.tooltipPopup.IsOpen = true;
            }
            else
            {
                // hide tooltip
                this.tooltipPopup.IsOpen = false;
            }
        }
        private void DrawProgressByDetectionResult(Point detectionPoint, AnomalyLastDetectResult detectionResult, AnomalyInfo anomalyInfo, double yScale, double yZeroLine = 0)
        {
            double upperMarginOnUI        = detectionResult.ExpectedValue + detectionResult.UpperMargin;
            double lowerMarginOnUI        = detectionResult.ExpectedValue - detectionResult.LowerMargin;
            double offsetY1               = yScale * upperMarginOnUI;
            double offsetY2               = lowerMarginOnUI > 0 ? yScale * lowerMarginOnUI : 0;
            int    indexOfFirstValidPoint = curScenario.MinIndexOfRequiredPoints;

            Point newUpperPoint = new Point(detectionPoint.X, (yZeroLine + resultGrid.ActualHeight - offsetY1) > 0 ? (yZeroLine + resultGrid.ActualHeight - offsetY1) : 0);
            Point newLowerPoint = new Point(detectionPoint.X, yZeroLine + resultGrid.ActualHeight - offsetY2);

            if (detectionResult.IsAnomaly)
            {
                SpriteVisual anomalyIndicator = GetNewAnomalyIndicator(detectionPoint);
                containerRoot.Children.InsertAtTop(anomalyIndicator);
                allAnomalyIndicators.Add(new Tuple <SpriteVisual, AnomalyInfo>(anomalyIndicator, anomalyInfo));
            }

            int endOfUpper = progressPolyline.Points.Count / 2;
            int endOfLower = progressPolyline.Points.Count / 2 + 1;

            progressPolyline.Points.Insert(endOfUpper, newUpperPoint);
            progressPolyline.Points.Insert(endOfLower, newLowerPoint);

            detectWindowPolyline.Points.Insert((detectWindowPolyline.Points.Count / 2), new Point(detectionPoint.X, 0));
            detectWindowPolyline.Points.Insert((detectWindowPolyline.Points.Count / 2 + 1), new Point(detectionPoint.X, resultGrid.ActualHeight));
            if ((detectWindowPolyline.Points.Count / 2) >= indexOfFirstValidPoint)
            {
                detectWindowPolyline.Points.RemoveAt(0);
                detectWindowPolyline.Points.RemoveAt(detectWindowPolyline.Points.Count - 1);
            }

            progressIndicator.Offset = new Vector3((float)(detectionPoint.X), (float)(resultGrid.ActualHeight), resultGrid.CenterPoint.Z);

            progressLine.X1 = detectionPoint.X;
            progressLine.X2 = detectionPoint.X;
        }
        private async Task StartStreamingModeProcessAsync()
        {
            try
            {
                if (dataPolyline.Points != null)
                {
                    dataPolyline.Points.Clear();
                }
                else
                {
                    dataPolyline.Points = new PointCollection();
                }

                double dataRange = curScenario.MaxValue - curScenario.MinValue;
                double yScale    = resultGrid.ActualHeight / dataRange;
                double xOffset   = resultGrid.ActualWidth / (curScenario.AllData.Count - 1);
                double yZeroLine = yScale * curScenario.MinValue;

                string timestampFormat = curScenario.ScenarioType == AnomalyDetectionScenarioType.Telecom ? ShortDateFormat : ShortDateWithTimeFormat;
                int    startIndex      = curScenario.MinIndexOfRequiredPoints;

                for (int i = 0; i < startIndex; i++)
                {
                    Point point = new Point(xOffset * i, yZeroLine + resultGrid.ActualHeight - (yScale * curScenario.AllData[i].Value));
                    dataPolyline.Points.Add(point);

                    Point newUpperPoint = new Point(dataPolyline.Points[i].X, 0);
                    Point newLowerPoint = new Point(dataPolyline.Points[i].X, resultGrid.ActualHeight);

                    int endOfUpper = detectWindowPolyline.Points.Count / 2;
                    int endOfLower = detectWindowPolyline.Points.Count / 2 + 1;

                    detectWindowPolyline.Points.Insert(endOfUpper, newUpperPoint);
                    detectWindowPolyline.Points.Insert(endOfLower, newLowerPoint);
                }

                for (int i = startIndex; i < curScenario.AllData.Count; i++)
                {
                    if (shouldStopCurrentRun)
                    {
                        break;
                    }

                    AnomalyLastDetectResult result = await GetStreamingAnomalyDetectionResultAsync(i);

                    Point point = new Point(xOffset * i, yZeroLine + resultGrid.ActualHeight - (yScale * curScenario.AllData[i].Value));
                    dataPolyline.Points.Add(point);

                    if (result != null)
                    {
                        TimeSeriesData timeSeriesData = curScenario.AllData[i];
                        AnomalyInfo    anomalyInfo    = new AnomalyInfo
                        {
                            Text          = Util.StringToDateFormat(timeSeriesData.Timestamp, timestampFormat),
                            Value         = timeSeriesData.Value.ToString("F2"),
                            ExpectedValue = result.ExpectedValue.ToString("F2")
                        };

                        DrawProgressByDetectionResult(dataPolyline.Points[i], result, anomalyInfo, yScale, yZeroLine);
                    }
                }
            }
            catch (Exception ex)
            {
                await Util.GenericApiCallExceptionHandler(ex, "Failure during streaming detection.");
            }
        }
        private async Task StartLiveDemoProcessAsync()
        {
            try
            {
                double yScale  = resultGrid.ActualHeight / MaxVolumeValue;
                double xOffset = resultGrid.ActualWidth / DefaultDurationOfLiveDemoInSecond;

                DateTime currentTime = DateTime.Now;
                DateTime startTime   = currentTime.AddMinutes((double)DefaultDurationOfLiveDemoInSecond * -1);

                progressLine.X1 = progressIndicator.CenterPoint.X;
                progressLine.X2 = progressIndicator.CenterPoint.X;

                dataPolyline.Points.Clear();

                int startIndex = AnomalyDetectionScenario.DefaultRequiredPoints;
                for (int i = 0; i < startIndex; i++)
                {
                    float volume = GetCurrentVolumeValue();

                    curScenario.AllData.Insert(i, new TimeSeriesData(startTime.ToString(), volume));
                    startTime = startTime.AddMinutes(AnomalyDetectorScenarioLoader.GetTimeOffsetInMinute(curScenario.Granularity));

                    double yOffset = yScale * (curScenario.AllData[i].Value - BaseVolume);
                    Point  point   = new Point(xOffset * i, resultGrid.ActualHeight - yOffset);
                    dataPolyline.Points.Add(point);

                    Point newUpperPoint = new Point(dataPolyline.Points[i].X, 0);
                    Point newLowerPoint = new Point(dataPolyline.Points[i].X, resultGrid.ActualHeight);

                    int endOfUpper = detectWindowPolyline.Points.Count / 2;
                    int endOfLower = detectWindowPolyline.Points.Count / 2 + 1;

                    detectWindowPolyline.Points.Insert(endOfUpper, newUpperPoint);
                    detectWindowPolyline.Points.Insert(endOfLower, newLowerPoint);
                }

                for (int i = startIndex; i < DefaultDurationOfLiveDemoInSecond; i++)
                {
                    if (shouldStopCurrentRun)
                    {
                        break;
                    }

                    float volume = GetCurrentVolumeValue();

                    curScenario.AllData.Insert(i, new TimeSeriesData(startTime.ToString(), volume));
                    startTime = startTime.AddMinutes(AnomalyDetectorScenarioLoader.GetTimeOffsetInMinute(curScenario.Granularity));

                    double yOffset = yScale * (curScenario.AllData[i].Value - BaseVolume);
                    Point  point   = new Point(xOffset * i, resultGrid.ActualHeight - yOffset);
                    dataPolyline.Points.Add(point);

                    AnomalyLastDetectResult result = await GetLiveDemoAnomalyDetectionResultAsync(i);

                    if (result != null)
                    {
                        result.ExpectedValue -= BaseVolume;
                        AnomalyInfo anomalyInfo = new AnomalyInfo
                        {
                            Text          = i.ToString(),
                            Value         = (volume - BaseVolume).ToString("F2"),
                            ExpectedValue = result.ExpectedValue.ToString("F2")
                        };
                        DrawProgressByDetectionResult(dataPolyline.Points[i], result, anomalyInfo, yScale);
                    }
                }

                this.StopLiveAudio?.Invoke(this, EventArgs.Empty);
            }
            catch (Exception ex)
            {
                await Util.GenericApiCallExceptionHandler(ex, "Failure during streaming detection.");
            }
        }