private void Finished_ColumnStats(ColumnStatsRequest req, ColumnSetStats results)
        {
            _columns = results;
            ShowUsedColumnStats();

            DoSOM();
        }
        private void Exception_ColumnStats(ColumnStatsRequest req, Exception ex)
        {
            _columns = new ColumnSetStats(req.Names, ex.Message);
            pnlColumns.Children.Clear();

            DoSOM();
        }
        /// <summary>
        /// This looks at the current inputs, and starts a new SOM async
        /// </summary>
        private void DoSOM()
        {
            #region Init

            // Parse all the inputs
            QueryRequest queryReq = GetQueryRequest();

            if (queryReq.Columns.Length == 0)
            {
                lblErrorMessage.Text = "No columns specified";
                lblQueryStatus.Text = "";
                pnlColumns.Children.Clear();
                _queryResults = null;
                _columns = null;
                _result = null;
                return;
            }

            #endregion
            #region Query

            // Run query if changed
            if (_queryResults == null || _queryResults.ConnectionString != queryReq.ConnectionString || _queryResults.SQLStatement != queryReq.SQLStatement)
            {
                lblQueryStatus.Text = "Running query...";
                lblErrorMessage.Text = "";
                pnlColumns.Children.Clear();
                _columns = null;
                _result = null;

                _workerQuery.Start(queryReq);
                return;     //_workerQuery.finish will call this method again, and execution will flow past this if statement
            }

            lblQueryStatus.Text = "";

            if (!string.IsNullOrEmpty(_queryResults.Exception))
            {
                lblErrorMessage.Text = _queryResults.Exception;
                _result = null;
                return;
            }

            lblQueryStatus.Text = string.Format("{0} row{1}", _queryResults.Results.Length.ToString("N0"), _queryResults.Results.Length == 1 ? "" : "s");

            #endregion
            #region Columns

            if (_columns != null)
            {
                _columns = _columns.CloneIfSameNames(queryReq.Columns, _queryResults.ColumnNames);      //NOTE: This will still clone if it just holds an exception
            }

            if (_columns == null || !IsSame(queryReq.Columns, _columns.Names))
            {
                lblErrorMessage.Text = "";
                _result = null;
                _workerColumns.Start(new ColumnStatsRequest(queryReq.Columns, _queryResults));
                return;
            }

            if (_columns != null && !string.IsNullOrEmpty(_columns.Exception))
            {
                lblErrorMessage.Text = _columns.Exception;
                _result = null;
                return;
            }

            #endregion
            #region Do SOM

            if (_result == null)
            {
                RowInput[] inputs = GetSOMInputs(_columns.Columns, _queryResults, true);

                //TODO: Get these from the gui.  Add an option to randomize against their settings
                SOMRules rules = GetSOMRules_Rand();

                //TODO: Make an option for display1D.  Then do a SOM for each column and put the results in the column details dump
                _workerSOM.Start(new SOMRequest(inputs, rules));
                return;
            }

            #endregion
            #region Show Results

            var events = new SelfOrganizingMapsWPF.BlobEvents(Polygon_MouseMove, Polygon_MouseLeave, Polygon_Click);

            SelfOrganizingMapsWPF.ShowResults2D_Blobs(panelDisplay, _result, SelfOrganizingMapsWPF.GetNodeColor, events);

            #endregion
        }