/// <summary>
 /// Method called by ThreadPool to kick off data collection
 /// </summary>
 /// <param name="objRunner"></param>
 private void ProcessThreadedHashCollection(object objRunner)
 {
     try
     {
         QueryCollectionRunner runner = (QueryCollectionRunner)objRunner;
         runner.CollectQueryData();
     }
     catch (Exception exe)
     {
         log.LogError($"Error with QueryCollectionRunner{Environment.NewLine}{exe.ToString()}");
     }
     finally
     {
         lock (QueryCollector.SyncObj)
         {
             QueryCollector.SyncObj.WorkingRunners--;
         }
     }
 }
        /// <summary>
        /// Main method that coordinates the collection of data from each target database
        /// </summary>
        /// <param name="bgWorker">BackgroundWorker object used to communicate progress back to the caller</param>
        /// <param name="fileName">Name of the ultimate report file</param>
        /// <param name="reportType">The report type that the user wants</param>
        /// <param name="query">The SQL query to execute across the databases.</param>
        /// <param name="scriptTimeout">SQL timeout per connection</param>
        public bool GetQueryResults(ref BackgroundWorker bgWorker, string fileName, ReportType reportType, string query, int scriptTimeout)
        {
            this.resultsFilePath = Path.Combine(Path.GetDirectoryName(fileName), Guid.NewGuid().ToString());

            try
            {
                DirectoryInfo inf = new DirectoryInfo(this.resultsFilePath);
                inf.Create();
                inf.Attributes = FileAttributes.Hidden;
            }
            catch (Exception exe)
            {
                string message = String.Format("Unable to create working temp directory at {0}: {1}", this.resultsFilePath, exe.Message);
                log.LogError(exe, message);
                if (bgWorker != null && bgWorker.WorkerReportsProgress)
                {
                    bgWorker.ReportProgress(-1, message);
                }
                return(false);
            }

            this.bgWorker = bgWorker;
            int    threadTotal = 0;
            string db;

            //bool baseLineSet = false;
            foreach (ServerData srv in multiDbData)
            {
                srv.OverrideSequence.Sort(); //sort so the sequence is in proper order.
                foreach (string sequenceKey in srv.OverrideSequence.Keys)
                {
                    foreach (DatabaseOverride ovr in srv.OverrideSequence[sequenceKey])
                    {
                        db = srv.ServerName + "." + ovr.OverrideDbTarget;

                        threadTotal++;
                        lock (QueryCollector.SyncObj)
                        {
                            QueryCollector.SyncObj.WorkingRunners++;
                        }
                        QueryCollectionRunner runner = new QueryCollectionRunner(srv.ServerName, ovr.OverrideDbTarget, query, ovr.QueryRowData, reportType, this.resultsFilePath, scriptTimeout, this.connData);
                        runner.QueryCollectionRunnerUpdate += new QueryCollectionRunner.QueryCollectionRunnerUpdateEventHandler(runner_HashCollectionRunnerUpdate);
                        runners.Add(runner);
                        System.Threading.ThreadPool.QueueUserWorkItem(ProcessThreadedHashCollection, runner);
                    }
                }
            }


            int counter = 0;

            while (QueryCollector.SyncObj.WorkingRunners > 0)
            {
                System.Threading.Thread.Sleep(1000);
                counter++;

                if (bgWorker != null && bgWorker.WorkerReportsProgress && (counter % 2 == 0))
                {
                    bgWorker.ReportProgress(QueryCollector.SyncObj.WorkingRunners, String.Format("Databases remaining: {0}", QueryCollector.SyncObj.WorkingRunners.ToString()));
                }
            }

            if (bgWorker != null && bgWorker.WorkerReportsProgress)
            {
                bgWorker.ReportProgress(0, "Collating Results...");
            }

            List <string> queryResultFiles = new List <string>();

            foreach (QueryCollectionRunner runner in runners)
            {
                queryResultFiles.Add(runner.ResultsTempFile);
            }


            if (bgWorker != null && bgWorker.WorkerReportsProgress)
            {
                bgWorker.ReportProgress(-1, "Generating combined data report...");
            }

            return(GenerateReport(fileName, reportType, queryResultFiles));
        }