public void Run(AFTimeRange timeRange)
        {
            if (!TryValidate())
            {
                Console.WriteLine("Failed to evaluate '{0}' due to configuration errors.", _analysis.GetPath());
                return;
            }

            var eventProvider = GetEventProvider();
            var state         = new AFAnalysisRuleState(_configuration);
            var outputHandler = new OutputHandler(_configuration);

            foreach (var time in eventProvider.GetEvents(timeRange))
            {
                Console.WriteLine("Evaluating for {0}", time);
                state.Reset();
                state.SetExecutionTimeAndPopulateInputs(time);
                _analysis.AnalysisRule.Run(state);

                Exception evaluationError = state.EvaluationError;
                if (!ReferenceEquals(evaluationError, null))
                {
                    AFAnalysisException analysisException = evaluationError as AFAnalysisException;
                    if (ReferenceEquals(analysisException, null) || analysisException.Severity == AFAnalysisErrorSeverity.Error)
                    {
                        // This is something for which Analysis service would stop running the analysis
                        Console.WriteLine("Fatal error: {0}", state.EvaluationError.Message);
                        break;
                    }
                    else
                    {
                        // Non-fatal error with severity < Error; analysis would continue to run
                        Console.WriteLine("Warning: {0}", state.EvaluationError.Message);
                    }
                }
                else
                {
                    outputHandler.ProcessOutputs(state);
                    foreach (var output in _configuration.ResolvedOutputs.Zip(state.Outputs, Tuple.Create))
                    {
                        Console.WriteLine("\t{0} = {1}", output.Item1.DisplayName, output.Item2);
                    }
                }
            }

            outputHandler.Flush();
        }
        /// <summary>
        /// Run calculations for specific time stamps.
        /// </summary>
        /// inspired from:
        /// <see cref="https://pisquare.osisoft.com/message/28537#28537"/>
        /// <param name="analysis">Analysis that needs to be evaluated</param>
        /// <param name="times">List of times</param>
        /// <param name="evaluationTime">output, contains the time taken to execute all the calculations</param>
        /// <param name="evaluationsErrorsCount">output, contains the number of evaluations in error.</param>
        /// <returns></returns>
        public List <AFValue> Run(AFAnalysis analysis, IEnumerable <AFTime> times, out TimeSpan evaluationTime, out int evaluationsErrorsCount)
        {
            evaluationsErrorsCount = 0;
            var results   = new List <AFValue>();
            var stopwatch = Stopwatch.StartNew();


            var analysisConfiguration = analysis.AnalysisRule.GetConfiguration();
            var state = new AFAnalysisRuleState(analysisConfiguration);

            foreach (var time in times)
            {
                //  Console.WriteLine("Evaluating for {0}", time);
                state.Reset();
                state.SetExecutionTimeAndPopulateInputs(time);
                analysis.AnalysisRule.Run(state);

                if (state.EvaluationError != null)
                {
                    if (_debug)
                    {
                        _logger.ErrorFormat("Analyse in error at time: {3:s}  - {0} - at {1}, Error: {2}", analysis.Name, analysis.GetPath(), state.EvaluationError, time);
                    }

                    evaluationsErrorsCount += 1;
                }


                // this merges the state (results) with the configuration so its easier to loop with both...
                var resultSet = analysisConfiguration.ResolvedOutputs.Zip(state.Outputs, Tuple.Create);

                foreach (var result in resultSet)
                {
                    // for more clarty, we take out our data into clearer variables
                    AFAnalysisRuleResolvedOutput analysisRow = result.Item1;
                    var calcRes = (AFValue)result.Item2;

                    // we filter to get only the results that have an output attribute ( an AFValue )
                    if (analysisRow.Attribute != null)
                    {
                        // add new AF Value into the results table
                        results.Add(new AFValue((AFAttribute)analysisRow.Attribute, calcRes.Value,
                                                calcRes.Timestamp));
                    }
                }
            }

            stopwatch.Stop();
            evaluationTime = stopwatch.Elapsed;
            return(results);
        }