private void ButtMultiAnalyzeDiffClick(object sender, RoutedEventArgs e)
        {
            try
            {
                var layerNames = new List<string>();
                var allFieldNames = new List<string>();
                foreach (string s in this.lbChangeLayers.SelectedItems)
                {
                    if (!layerNames.Contains(s))
                    {
                        layerNames.Add(s);
                    }
                }
                if (this.lbChangeLayers.SelectedItems.Count < 2)
                {
                    MessageBox.Show("Please select at least two layers");
                    return;
                }
                var colsMappingForMsgBox = new Dictionary<string, string>();
                var uniqueFieldNames = new Dictionary<string, string>();
                var multiResult = new PivotTable();
                var analyzer = new PivotTableAnalyzer(this.UpdatePBar, this.SetPBarProperties);

                for (var i = 0; i < layerNames.Count; i++)
                {
                    for (var x = i + 1; x < layerNames.Count; x++)
                    {
                        var layerA = layerNames[i];
                        var layerB = layerNames[x];
                        colsMappingForMsgBox.Add("L" + i + "_" + x + "L", layerA + " --> " + layerB);

                        if (layerA == null || layerB == null)
                        {
                            MessageBox.Show("no layers available");
                        }

                        var layers = this.GetFeatureLayersFromToc(this.GetActiveViewFromArcMap(ArcMap.Application));
                        //  getSelectedFeatureFromLayerByName(layers, "somename");
                        var flayerA = this.GetLayerByName(layers, layerA);
                        var flayerB = this.GetLayerByName(layers, layerB);
                        this.pbarChangeDet.Value = 0;

                        this.UpdateStatusLabel("Preparing " + layerA);
                        Application.DoEvents();
                        var ignoreCols = new List<string> { "OBJECTID", "SHAPE", "SHAPE_Length", "SHAPE_Area" };
                        var ptA = this.FeatureLayerToPivotTable(flayerA, "GeoHash", ignoreCols);
                        this.UpdateStatusLabel("Preparing " + layerB);
                        Application.DoEvents();
                        var ptB = this.FeatureLayerToPivotTable(flayerB, "GeoHash", ignoreCols);
                        this.UpdateStatusLabel("Calculating change");
                        Application.DoEvents();

                        var res = analyzer.DetectChange(ptA, ptB, "L" + i + "_" + x + "L", false);

                        foreach (var entry in res)
                        {
                            if (!entry.Data.ContainsKey("layerAIndex"))
                            {
                                entry.Data.Add("layerAIndex", i);
                            }
                            if (!entry.Data.ContainsKey("layerBIndex"))
                            {
                                entry.Data.Add("layerBIndex", i);
                            }

                            entry.Label = "L" + i + "_" + x + "L";

                            foreach (var name in entry.Data.Keys)
                            {
                                if (!allFieldNames.Contains(name))
                                {
                                    allFieldNames.Add(name);
                                }

                                if (!uniqueFieldNames.ContainsKey(name))
                                {
                                    uniqueFieldNames.Add(name, name);
                                }
                            }
                            break;
                        }
                        multiResult.AddRange(res);
                    }
                }
                var flat = analyzer.flattenAndSimplify(multiResult, "percent_change");
                uniqueFieldNames = new Dictionary<string, string>();
                foreach (var pte in flat)
                {
                    var vals = new List<double>();
                    foreach (var field in pte.Data.Keys)
                    {
                        vals.Add(pte.Data[field]);
                    }
                    pte.Data.Add("stdev_", analyzer.stdev(vals));
                    pte.Data.Add("avg_", analyzer.avg(vals));
                    pte.Data.Add("min_", analyzer.min(vals));
                    pte.Data.Add("max_", analyzer.max(vals));

                    foreach (var field in pte.Data.Keys)
                    {
                        if (!uniqueFieldNames.ContainsKey(field))
                        {
                            uniqueFieldNames.Add(field, field);
                        }
                    }
                }
                var ws = Jarvis.OpenWorkspace(Settings.Default.geoDatabase);
                var fcName = "multi_change_" + DateTime.Now.Millisecond;
                //  uniqueFieldNames.Add("context_str", "context_str");
                var featureClass = Jarvis.CreateStandaloneFeatureClass(ws, fcName, uniqueFieldNames, false, 0);

                var insertCur = featureClass.Insert(true);
                this.UpdateStatusLabel("Loading Output Feature Class");
                Application.DoEvents();

                this.InsertPivoTableRowsToFeatureClass(featureClass, flat, uniqueFieldNames);
                this.AddLayerToArcMap(fcName);
                this.pbarChangeDet.Value = 0;

                this.lblPbarStatus.Content = "Done";
                var message = "FYI:\n";
                foreach (var colName in colsMappingForMsgBox.Keys)
                {
                    message += "Column " + colName + " represents change for " + colsMappingForMsgBox[colName] + "\n";
                }
                message += "\n*This is required because of field length limitations";
                MessageBox.Show(message);

                Application.DoEvents();
                // now I need to create a feature class and feature layer from this object
            }
            catch (Exception ex)
            {
                MessageBox.Show("An error occured calculating change" + ex.Message);
            }
        }
        private void ButRunSignatureClick(object sender, RoutedEventArgs e)
        {
            try
            {
                if (this.cbFocusLayer.Text == null || this.cbFocusLayer.Text == "")
                {
                    MessageBox.Show("You must select a layer");
                    return;
                }
                var layers = this.GetFeatureLayersFromToc(this.GetActiveViewFromArcMap(ArcMap.Application));
                var layerWithSelection = this.GetLayerByName(layers, this.cbFocusLayer.Text);
                if (layerWithSelection == null)
                {
                    MessageBox.Show("Layer does not exist");
                    return;
                }
                this.pbarChangeDet.Minimum = 0;
                this.pbarChangeDet.Maximum = layerWithSelection.FeatureClass.FeatureCount(null);
                this.pbarChangeDet.Value = 0;
                Application.DoEvents();

                var outPut = this.GetSelectedFeatureFromLayerByName(layers, this.cbFocusLayer.Text);
                var cols = new List<string>();
                var outputCols = new Dictionary<string, string>();
                if (outPut.Count == 0)
                {
                    MessageBox.Show("No features in focus layer are selected. Make a selection");
                    return;
                }

                var signature = this.FeaturesToPivotTable(outPut, "GeoHash", null);
                var ignoreCols = new List<string> { "OBJECTID", "SHAPE", "SHAPE_Length", "SHAPE_Area" };

                var analyzer = new PivotTableAnalyzer(this.UpdatePBar, this.SetPBarProperties);
                this.UpdateStatusLabel("Preparing and caching AOI layer");
                Application.DoEvents();

                var aoiPivotTable = this.FeatureLayerToPivotTable(layerWithSelection, "GeoHash", null);

                this.UpdateStatusLabel("Processing Signature");

                Application.DoEvents();

                if (signature.Count > 1)
                {
                    var res =
                        MessageBox.Show(
                            "You have multiple cells selected. Would you like to use an average of the selected features as the signature? If NO is selected, a new layer will be generated for every selected cell. If YES is selected an average will be generated as the signature, one layer will be generated, and typically the resulting similarity distribution may be narrower. Also, diff columns are based on the averages.",
                            "Multiple Selected Cells",
                            MessageBoxButtons.YesNo);
                    if (res == DialogResult.Yes)
                    {
                        var graph = analyzer.GetSimilarityGraph(signature);

                        foreach (var key in graph.Keys)
                        {
                            var formattedGraph = "Graph for rowkey: " + key + "\n";
                            foreach (var innerKey in graph[key].Keys)
                            {
                                var sim = graph[key][innerKey];
                                formattedGraph += "\t" + innerKey + " :: " + sim + "\n";
                            }
                            var box = new ScrollableMessageBox();
                            box.Show(formattedGraph);
                        }
                        var resGraph = MessageBox.Show("Continue?", "Graph", MessageBoxButtons.YesNoCancel);
                        if (resGraph == DialogResult.No || resGraph == DialogResult.Cancel)
                        {
                            this.UpdatePBar(0);
                            this.UpdateStatusLabel("Status");
                            return;
                        }
                        signature = analyzer.GenerateAverageVector(signature);
                    }
                }

                foreach (var entry in signature)
                {
                    var res = analyzer.GetSparseSimilarites(entry, aoiPivotTable, true, false);
                    foreach (var colName in res[0].Data.Keys)
                    {
                        if (!outputCols.ContainsKey(colName))
                        {
                            if (!ignoreCols.Contains(colName))
                            {
                                outputCols.Add(colName, colName);
                            }
                        }
                    }
                    var ws = Jarvis.OpenWorkspace(Settings.Default.geoDatabase);

                    var fcName = "mlt_" + entry.RowKey + "_" + DateTime.Now.Millisecond;
                    var featureClass = Jarvis.CreateStandaloneFeatureClass(ws, fcName, outputCols, false, 0);
                    this.UpdateStatusLabel("Loading Feature Class");
                    Application.DoEvents();

                    this.InsertPivoTableRowsToFeatureClass(featureClass, res, outputCols);
                    this.AddLayerToArcMap(fcName);

                    this.lblPbarStatus.Content = "Done";
                    this.pbarChangeDet.Value = 0;
                    Application.DoEvents();
                }
            }
            catch (Exception ex)
            {
                Jarvis.Logger.Error(ex);
                MessageBox.Show("An unhandled exception occurred");
            }
        }
        private void ButtAnalyzeDiffClick(object sender, RoutedEventArgs e)
        {
            try
            {
                var diffs = this.cbCalcDiffs.IsChecked.Value;
                var layerA = (string)this.cbAggLayerA.SelectedValue;
                var layerB = this.cbAggLayerB.Text;
                if (layerA == null || layerB == null)
                {
                    MessageBox.Show("no layers available");
                }
                var layers = this.GetFeatureLayersFromToc(this.GetActiveViewFromArcMap(ArcMap.Application));
                //  getSelectedFeatureFromLayerByName(layers, "somename");
                var flayerA = this.GetLayerByName(layers, layerA);
                var flayerB = this.GetLayerByName(layers, layerB);
                this.pbarChangeDet.Value = 0;

                this.UpdateStatusLabel("formatting and Caching Layer A");
                Application.DoEvents();
                var ignoreCols = new List<string> { "OBJECTID", "SHAPE", "SHAPE_Length", "SHAPE_Area" };
                var ptA = this.FeatureLayerToPivotTable(flayerA, "GeoHash", ignoreCols);
                this.UpdateStatusLabel("Preparing " + layerA);
                Application.DoEvents();
                var ptB = this.FeatureLayerToPivotTable(flayerB, "GeoHash", ignoreCols);
                this.UpdateStatusLabel("Preparing " + layerB);
                Application.DoEvents();
                var uniqueFieldNames = new Dictionary<string, string>();

                var analyzer = new PivotTableAnalyzer(this.UpdatePBar, this.SetPBarProperties);
                var res = analyzer.DetectChange(ptA, ptB, layerA + "," + layerB, diffs);
                foreach (var entry in res)
                {
                    foreach (var name in entry.Data.Keys)
                    {
                        if (!uniqueFieldNames.ContainsKey(name))
                        {
                            uniqueFieldNames.Add(name, name);
                        }
                    }
                    break;
                }
                var ws = Jarvis.OpenWorkspace(Settings.Default.geoDatabase);
                var fcName = "change_" + layerA + "_" + layerB + "_" + DateTime.Now.Millisecond;
                var featureClass = Jarvis.CreateStandaloneFeatureClass(ws, fcName, uniqueFieldNames, false, 0);
                this.UpdateStatusLabel("Loading Output Feature Class");
                Application.DoEvents();

                this.InsertPivoTableRowsToFeatureClass(featureClass, res, uniqueFieldNames);
                this.AddLayerToArcMap(fcName);
                this.pbarChangeDet.Value = 0;

                this.lblPbarStatus.Content = "Done";

                Application.DoEvents();
                // now I need to create a feature class and feature layer from this object
            }
            catch (Exception ex)
            {
                MessageBox.Show("An error occured calculating change\n" + ex.Message);
            }
        }
        private void ChangeDetection()
        {
            try
            {
                var diffs = this.includeDiffCheckbox.Checked;
                var layerA = this.aggLayerAComboBox.Text;
                var layerB = this.aggLayerBComboBox.Text;
                if (layerA == null || layerB == null)
                {
                    MessageBox.Show("No layers available");
                    return;
                }
                var layers = GetFeatureLayersFromToc(ArcMap.Document.ActiveView);
                var flayerA = this.GetLayerByName(layers, layerA);
                var flayerB = this.GetLayerByName(layers, layerB);
                this.analysisProgressBar.Value = 0;

                this.statusLabel.Text = StatusLabelPrefix + "formatting and caching Layer A";

                Application.DoEvents();

                var ignoreCols = new List<string> { "OBJECTID", "SHAPE", "SHAPE_Length", "SHAPE_Area" };

                var ptA = this.FeatureLayerToPivotTable(flayerA, "GeoHash", ignoreCols);

                this.statusLabel.Text = StatusLabelPrefix + "Preparing " + layerA;

                Application.DoEvents();

                var ptB = this.FeatureLayerToPivotTable(flayerB, "GeoHash", ignoreCols);

                this.statusLabel.Text = StatusLabelPrefix + "Preparing " + layerB;

                Application.DoEvents();
                var uniqueFieldNames = new Dictionary<string, string>();

                var analyzer = new PivotTableAnalyzer(this.UpdatePBar, this.SetPBarProperties);
                var res = analyzer.DetectChange(ptA, ptB, layerA + "," + layerB, diffs);
                foreach (var entry in res)
                {
                    foreach (var name in entry.Data.Keys)
                    {
                        if (!uniqueFieldNames.ContainsKey(name))
                        {
                            uniqueFieldNames.Add(name, name);
                        }
                    }
                    break;
                }
                var ws = Jarvis.OpenWorkspace(Settings.Default.geoDatabase);
                var fcName = "change_" + layerA + "_" + layerB + "_" + DateTime.Now.Millisecond;
                var featureClass = Jarvis.CreateStandaloneFeatureClass(ws, fcName, uniqueFieldNames, false, 0);
                this.statusLabel.Text = StatusLabelPrefix + "Loading output feature class";
                Application.DoEvents();

                this.InsertPivoTableRowsToFeatureClass(featureClass, res, uniqueFieldNames);
                this.AddLayerToArcMap(fcName);
                this.analysisProgressBar.Value = 0;

                this.statusLabel.Text = StatusLabelPrefix + "Done";
                Application.DoEvents();
            }
            catch (Exception ex)
            {
                MessageBox.Show("An error occured calculating change\n" + ex.Message);
            }
        }