private void ClassifierList_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Right && SelectedItem != null)
            {
                Classifier classifier = SelectedItem as Classifier;
                if (classifier == null)
                    throw new NullReferenceException("Failed to cast classifier item from list");

                string updateWindowTitle = "Updating " + classifier.GetType().Name + "...";

                if (classifier is LibLinear)
                {
                    LibLinear liblinear = classifier as LibLinear;
                    DynamicForm f = new DynamicForm("Set LibLinear parameters", DynamicForm.CloseButtons.OkCancel);
                    f.AddCheckBox("Run feature selection:", ContentAlignment.MiddleRight, liblinear.RunFeatureSelection, "run_feature_selection");
                    f.AddDropDown("Positive weighting:", Enum.GetValues(typeof(LibLinear.PositiveClassWeighting)), liblinear.Weighting, "positive_weighting", true);
                    if (f.ShowDialog() == DialogResult.OK)
                    {
                        liblinear.RunFeatureSelection = f.GetValue<bool>("run_feature_selection");
                        liblinear.Weighting = f.GetValue<LibLinear.PositiveClassWeighting>("positive_weighting");
                    }
                }
                else if (classifier is SvmRank)
                {
                    SvmRank svmRank = classifier as SvmRank;
                    DynamicForm f = new DynamicForm("Set SvmRank parameters", DynamicForm.CloseButtons.OkCancel);
                    f.AddNumericUpdown("c:", (decimal)svmRank.C, 3, decimal.MinValue, decimal.MaxValue, (decimal)0.01, "c");
                    if (f.ShowDialog() == DialogResult.OK)
                    {
                        try { svmRank.C = Convert.ToSingle(f.GetValue<decimal>("c")); }
                        catch (Exception ex) { MessageBox.Show("Invalid value for C:  " + ex.Message); }
                    }
                }
                else if (classifier is RandomForest)
                {
                    RandomForest randomForest = classifier as RandomForest;
                    DynamicForm f = new DynamicForm("Set RandomForest parameters", DynamicForm.CloseButtons.OkCancel);
                    f.AddNumericUpdown("Number of trees:", randomForest.NumTrees, 0, 1, decimal.MaxValue, 1, "ntree");
                    if (f.ShowDialog() == DialogResult.OK)
                    {
                        randomForest.NumTrees = Convert.ToInt32(f.GetValue<decimal>("ntree"));
                    }
                }
                else if (classifier is AdaBoost)
                {
                    AdaBoost adaBoost = classifier as AdaBoost;
                    DynamicForm f = new DynamicForm("Set AdaBoost parameters", DynamicForm.CloseButtons.OkCancel);
                    f.AddNumericUpdown("Number of iterations:", adaBoost.Iterations, 0, 1, decimal.MaxValue, 1, "iterations");
                    if (f.ShowDialog() == DialogResult.OK)
                    {
                        adaBoost.Iterations = Convert.ToInt32(f.GetValue<decimal>("iterations"));
                    }
                }
            }
        }
        private void run_Click(object sender, EventArgs e)
        {
            DiscreteChoiceModel m = SelectedModel;

            if (m == null)
                MessageBox.Show("Select a model to run.");
            else
            {
                string defaultPredictionName = m.Name + " (" + m.GetType().Name + ")" + (!perIncident.Checked ? " " + m.IncidentTypes.Concatenate("+") : "");
                DynamicForm f = new DynamicForm("Enter name for prediction" + (perIncident.Checked ? " (per-incident names will be added)" : "") + "...", DynamicForm.CloseButtons.OkCancel);
                f.AddTextBox("Prediction name:", defaultPredictionName, -1, "name");
                if (f.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    string predictionName = f.GetValue<string>("name").Trim();
                    if (predictionName != "")
                        Run(true, predictionName, null);
                }
            }
        }
        private void resetToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string[] candidateTables = DB.Tables;
            if (candidateTables.Length == 0)
            {
                MessageBox.Show("It appears as though the ATT system has not yet been initialized. This indicates an error somewhere in the configuration.");
                return;
            }

            DynamicForm f = new DynamicForm("Reset ATT System", DynamicForm.CloseButtons.OkCancel);
            f.AddListBox("Tables to KEEP:", candidateTables, null, SelectionMode.MultiExtended, "keep", true, "Select the tables that you wish to keep.");
            f.GetControl<ListBox>("keep").SelectedItem = null;
            if (f.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                Set<string> tablesToKeep = new Set<string>(f.GetValue<ListBox.SelectedObjectCollection>("keep").Cast<string>().ToArray());
                if (candidateTables.Where(t => !tablesToKeep.Contains(t)).Count() > 0 && MessageBox.Show("This will permanently delete data from the database. Proceed?", "WARNING", MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
                    try
                    {
                        ATT.Configuration.Reset(tablesToKeep);
                        _logWriter.Clear();
                        RefreshAll();
                    }
                    catch (Exception ex) { Console.Out.WriteLine("Error resetting the ATT system:  " + ex.Message); }
            }
        }
        private void parameterizeFeatureToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Feature feature = parameterizeFeatureToolStripMenuItem.Tag as Feature;
            DynamicForm f = new DynamicForm("Parameterize \"" + feature.Description + "\"...", DynamicForm.CloseButtons.OkCancel);
            foreach (Enum parameter in feature.Parameters.OrderBy(p => p))
                if (parameter.Equals(FeatureBasedDCM.GeometryAttributeParameter.AttributeColumn))
                    f.AddDropDown(parameter + ":", DB.Connection.GetColumnNames(new Shapefile(int.Parse(feature.TrainingResourceId)).GeometryTable).ToArray(), feature.Parameters.GetStringValue(parameter), parameter.ToString(), true, toolTipText: feature.Parameters.GetTip(parameter));
                else if (parameter.Equals(FeatureBasedDCM.GeometryAttributeParameter.AttributeType))
                    f.AddDropDown(parameter + ":", new string[] { "Numeric", "Nominal" }, feature.Parameters.GetStringValue(parameter), parameter.ToString(), true, toolTipText: feature.Parameters.GetTip(parameter));
                else
                    f.AddTextBox(parameter + ":", feature.Parameters.GetStringValue(parameter), 20, parameter.ToString(), toolTipText: feature.Parameters.GetTip(parameter));

            if (f.ShowDialog() == DialogResult.OK)
                foreach (Enum parameter in feature.Parameters.OrderBy(p => p))
                    feature.Parameters.Set(parameter, f.GetValue<string>(parameter.ToString()));
        }
Exemplo n.º 5
0
        public static void SetEncryptionKey(bool reset)
        {
            if (_encryptionKey != null && !reset)
            {
                return;
            }

            string passphraseHashPath = ".encryption_passphrase_hash";

            if (reset)
            {
                File.WriteAllText(passphraseHashPath, "");
            }

            string passphraseHash = "";

            if (File.Exists(passphraseHashPath))
            {
                passphraseHash = File.ReadAllText(passphraseHashPath);
            }

            string key = null;

            while (true)
            {
                DynamicForm f = new DynamicForm("Enter encryption passphrase", DynamicForm.CloseButtons.OkCancel);
                f.AddTextBox("Passphrase:", null, 20, "passphrase", '*', true);
                f.AddTextBox("Confirm passphrase:", null, 20, "confirmed", '*', true);

                if (f.ShowDialog() == DialogResult.Cancel)
                {
                    break;
                }

                string passphrase = f.GetValue <string>("passphrase").Trim();
                string confirmed  = f.GetValue <string>("confirmed").Trim();
                if (passphrase != confirmed)
                {
                    MessageBox.Show("Entries do not match.");
                }
                else if (passphrase.Length < 8)
                {
                    MessageBox.Show("Passphrase must be at least 8 characters.");
                }
                else
                {
                    key = passphrase;
                    break;
                }
            }

            if (key == null)
            {
                throw new Exception("Encryption not set up. No passphrase supplied.");
            }

            _encryptionKey = new byte[32];
            byte[] keyBytes = Encoding.Default.GetBytes(key);
            Array.Copy(keyBytes, _encryptionKey, keyBytes.Length);

            string hash;

            using (SHA256 sha2 = SHA256Managed.Create())
            {
                hash = sha2.ComputeHash(_encryptionKey).Select(b => b.ToString()).Concatenate("-");
            }

            if (passphraseHash == "")
            {
                File.WriteAllText(passphraseHashPath, hash);
            }
            else if (hash != passphraseHash)
            {
                _encryptionKey = null;
                throw new Exception("The given passphrase does not match the one previously established. Encryption will not function properly. To enable encryption, either enter the correct passphrase or reset the passphrase with File -> Reset encryption key.");
            }
        }
        public void importIncidentsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Import(ATT.Configuration.IncidentsImportDirectory,

                   new CompleteImporterFormDelegate(f =>
                       {
                           Area[] areas = Area.GetAll().ToArray();
                           if (areas.Length == 0)
                           {
                               MessageBox.Show("No areas available. Import one first.");
                               return null;
                           }

                           f.AddDropDown("Import into area:", areas, null, "area", true);
                           f.AddNumericUpdown("Incident hour offset:", 0, 0, decimal.MinValue, decimal.MaxValue, 1, "offset");

                           return f;
                       }),

                   new CreateImporterDelegate((name, path, sourceURI, importerForm) =>
                       {
                           Area importArea = importerForm.GetValue<Area>("area");
                           int hourOffset = Convert.ToInt32(importerForm.GetValue<decimal>("offset"));

                           string extension = Path.GetExtension(path).ToLower();
                           if (extension == ".xml")
                           {
                               DynamicForm f = new DynamicForm("Location SRID", DynamicForm.CloseButtons.OK);
                               f.AddNumericUpdown("Location SRID:", 0, 0, 0, decimal.MaxValue, 1, "source_srid");
                               f.ShowDialog();
                               int sourceSRID = Convert.ToInt32(f.GetValue<decimal>("source_srid"));

                               Type[] rowInserterTypes = Assembly.GetAssembly(typeof(XmlImporter.XmlRowInserter)).GetTypes().Where(type => !type.IsAbstract && (type == typeof(XmlImporter.IncidentXmlRowInserter) || type.IsSubclassOf(typeof(XmlImporter.IncidentXmlRowInserter)))).ToArray();
                               string[] databaseColumns = new string[] { Incident.Columns.NativeId, Incident.Columns.Time, Incident.Columns.Type, Incident.Columns.X(importArea), Incident.Columns.Y(importArea) };

                               return CreateXmlImporter(name, path, ATT.Configuration.IncidentsImportDirectory, PathRelativizationId.IncidentDirectory, sourceURI, rowInserterTypes, databaseColumns, databaseColumnInputColumn =>
                                                        {
                                                            return new XmlImporter.IncidentXmlRowInserter(databaseColumnInputColumn, importArea, hourOffset, sourceSRID);
                                                        });
                           }
                           else if (extension == ".shp")
                           {
                               int targetSRID = importArea.Shapefile.SRID;
                               ShapefileInfoRetriever shapefileInfoRetriever = new ShapefileInfoRetriever(name, 0, targetSRID);
                               return new IncidentShapefileImporter(name, path, RelativizePath(path, ATT.Configuration.IncidentsImportDirectory, PathRelativizationId.IncidentDirectory), sourceURI, 0, targetSRID, shapefileInfoRetriever, importArea, new IncidentTableShapefileTableMappingRetriever(), hourOffset);
                           }
                           else
                               throw new NotImplementedException("Unrecognized incident import file extension:  " + extension);
                       }),

                   ATT.Configuration.IncidentsImportDirectory,
                   "Incident files (*.shp;*.xml;*.zip)|*.shp;*.xml;*.zip",
                   new string[] { "*.xml", "*.shp" },
                   null);
        }
        public void comparePredictionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (TraversePredictionTree().Count(n => n.Checked) <= 1)
                MessageBox.Show("Select two or more predictions / groups to make a comparison.");
            else
            {
                EvaluateSelectedPredictions();

                List<List<Plot>> plotRows = new List<List<Plot>>();
                foreach (TreeNode node in TraversePredictionTree())
                    if (node.Checked)
                        if (node.Tag is PredictionGroup)
                            plotRows.Add(new List<Plot>(new Plot[] { (node.Tag as PredictionGroup).AggregatePlot }));
                        else if (node.Tag is Prediction)
                            plotRows.Add((node.Tag as Prediction).AssessmentPlots);
                        else
                            throw new Exception("Unexpected node tag:  " + node.Tag);

                PredictionComparisonForm comparisonForm = new PredictionComparisonForm(plotRows, Size);
                if (comparisonForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    StringBuilder comparisonTitle = new StringBuilder();
                    Dictionary<string, List<PointF>> seriesPoints = new Dictionary<string, List<PointF>>();
                    foreach (SurveillancePlot selectedPlot in comparisonForm.SelectedPlots)
                    {
                        string plotTitle = selectedPlot.Title.Replace(Environment.NewLine, " ").RemoveRepeatedWhitespace();
                        comparisonTitle.Append((comparisonTitle.Length == 0 ? "Comparison of " : ", ") + plotTitle);
                        foreach (string series in selectedPlot.SeriesPoints.Keys)
                            if (series != DiscreteChoiceModel.OptimalSeriesName)
                            {
                                string baseSeriesTitle = plotTitle;
                                if (series == DiscreteChoiceModel.OptimalSeriesName)
                                    baseSeriesTitle = DiscreteChoiceModel.OptimalSeriesName + " " + baseSeriesTitle;

                                string seriesTitle = baseSeriesTitle;
                                int dupNameNum = 2;
                                while (seriesPoints.Keys.Count(k => k == seriesTitle) > 0)
                                    seriesTitle = baseSeriesTitle + " " + dupNameNum++;

                                seriesPoints.Add(seriesTitle, selectedPlot.SeriesPoints[series]);
                            }
                    }

                    SurveillancePlot comparisonPlot = new SurveillancePlot(comparisonTitle.ToString(), -1, seriesPoints, 500, 500, Plot.Format.JPEG, 2);
                    DynamicForm f = new DynamicForm("Result comparison", DynamicForm.CloseButtons.OK);
                    f.AddPictureBox(comparisonPlot.Image);
                    f.ShowDialog();
                }
            }
        }
        public void addModelToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Type[] modelTypes = Assembly.GetAssembly(typeof(DiscreteChoiceModel)).GetTypes().Where(t => !t.IsAbstract && t.IsSubclassOf(typeof(DiscreteChoiceModel))).ToArray();
            if (modelTypes.Length == 0)
                MessageBox.Show("No model type are available.");
            else if (Area.GetAll().Count == 0)
                MessageBox.Show("No areas available to model. Import one first.");
            else
            {
                DynamicForm modelForm = new DynamicForm("Select model type...", DynamicForm.CloseButtons.OkCancel);
                modelForm.AddDropDown("Model type:", modelTypes, null, "model_type", false);
                if (modelForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    Type modelType = modelForm.GetValue<Type>("model_type");
                    DiscreteChoiceModel model = null;

                    if (modelType == typeof(KernelDensityDCM))
                    {
                        KernelDensityDcmForm f = new KernelDensityDcmForm();
                        if (f.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                            model = f.ResultingModel;
                    }
                    else if (modelType == typeof(FeatureBasedDCM))
                    {
                        FeatureBasedDcmForm f = new FeatureBasedDcmForm();
                        if (f.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                            model = f.ResultingModel;
                    }
                    else if (modelType == typeof(TimeSliceDCM))
                    {
                        TimeSliceDcmForm f = new TimeSliceDcmForm();
                        if (f.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                            model = f.ResultingModel;
                    }

                    if (model != null)
                        RefreshModels(model.Id);
                }
            }
        }
        private void deleteGeographicDataToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Shapefile[] shapefiles = Shapefile.GetAll().ToArray();
            if (shapefiles.Length == 0)
                MessageBox.Show("No geographic data available for deletion.");
            else
            {
                DynamicForm f = new DynamicForm("Select geographic data to delete...", DynamicForm.CloseButtons.OkCancel);
                f.AddListBox("Geographic data:", shapefiles, null, SelectionMode.MultiExtended, "shapefiles", true);
                if (f.ShowDialog() == DialogResult.OK)
                {
                    Shapefile[] selectedShapefiles = f.GetValue<System.Windows.Forms.ListBox.SelectedObjectCollection>("shapefiles").Cast<Shapefile>().ToArray();
                    if (selectedShapefiles.Length > 0 && MessageBox.Show("Are you sure you want to delete " + selectedShapefiles.Length + " shapefile(s)?", "Confirm delete", MessageBoxButtons.YesNo) == DialogResult.Yes)
                    {
                        int shapefilesDeleted = 0;
                        foreach (Shapefile shapefile in selectedShapefiles)
                        {
                            List<Area> areasForShapefile = Area.GetForShapefile(shapefile);
                            List<DiscreteChoiceModel> modelsForShapefile = areasForShapefile.SelectMany(a => DiscreteChoiceModel.GetForArea(a, false)).Union(DiscreteChoiceModel.GetAll(false).Where(m => m is IFeatureBasedDCM && (m as IFeatureBasedDCM).Features.Any(feat => feat.TrainingResourceId == shapefile.Id.ToString() || feat.PredictionResourceId == shapefile.Id.ToString()))).ToList();
                            List<Prediction> predictionsForShapefile = modelsForShapefile.SelectMany(m => Prediction.GetForModel(m, true)).ToList();
                            if (modelsForShapefile.Count > 0 || predictionsForShapefile.Count > 0)
                                if (MessageBox.Show("The shapefile \"" + shapefile + "\" is associated with " + modelsForShapefile.Count + " model(s) and " + predictionsForShapefile.Count + " prediction(s), which must be deleted before the shapefile can be deleted. Delete them now?", "Delete models and predictions?", MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
                                {
                                    foreach (Prediction prediction in predictionsForShapefile)
                                        prediction.Delete();

                                    foreach (DiscreteChoiceModel model in modelsForShapefile)
                                        model.Delete();
                                }
                                else
                                    continue;

                            try
                            {
                                shapefile.Delete();
                                ++shapefilesDeleted;
                            }
                            catch (Exception ex) { Console.Out.WriteLine("Error deleting shapefile \"" + shapefile.Name + "\":  " + ex.Message); }
                        }

                        Console.Out.WriteLine("Deleted " + shapefilesDeleted + " shapefile(s)");

                        if (shapefilesDeleted > 0)
                            RefreshAll();
                    }
                }
            }
        }
        private XmlImporter CreateXmlImporter(string name, string path, string relativePathBase, PathRelativizationId relativizationId, string sourceURI, Type[] rowInserterTypes, string[] databaseColumns, CreateXmlRowInserterDelegate createXmlRowInserter)
        {
            DynamicForm rowInserterForm = new DynamicForm("Define row inserter...", DynamicForm.CloseButtons.OkCancel);

            rowInserterForm.AddDropDown("Row inserter:", rowInserterTypes, null, "row_inserter", true);

            string[] inputColumns = XmlImporter.GetColumnNames(path, "row", "row");
            Array.Sort(inputColumns);
            foreach (string databaseColumn in databaseColumns)
                rowInserterForm.AddDropDown(databaseColumn + ":", inputColumns, null, databaseColumn, true);

            XmlImporter importer = null;
            if (rowInserterForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                Type rowInserterType = rowInserterForm.GetValue<Type>("row_inserter");

                Dictionary<string, string> databaseColumnInputColumn = new Dictionary<string, string>();
                foreach (string databaseColumn in databaseColumns)
                    databaseColumnInputColumn.Add(databaseColumn, rowInserterForm.GetValue<string>(databaseColumn));

                importer = new XmlImporter(name, path, RelativizePath(path, relativePathBase, relativizationId), sourceURI, createXmlRowInserter(databaseColumnInputColumn), "row", "row");
            }

            return importer;
        }
        private void copyPredictionToolStripMenuItem_Click(object sender, EventArgs e)
        {
            List<Prediction> selectedPredictions = SelectedPredictions;
            if (selectedPredictions.Count == 0)
                MessageBox.Show("Select one or more predictions to copy.");
            else if (selectedPredictions.Count == 1 || MessageBox.Show("Are you sure you want to copy " + selectedPredictions.Count + " prediction(s)?", "Confirm copy", MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
            {
                DynamicForm f = new DynamicForm("Set copy parameters", DynamicForm.CloseButtons.OkCancel);
                f.AddNumericUpdown("Number of copies of each prediction:  ", 1, 0, 1, decimal.MaxValue, 1, "copies");
                if (f.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    int numCopies;
                    try { numCopies = Convert.ToInt32(f.GetValue<decimal>("copies")); }
                    catch (Exception ex) { MessageBox.Show("Invalid number of copies:  " + ex.Message); return; }

                    Thread t = new Thread(new ThreadStart(delegate()
                        {
                            int predictionNum = 0;
                            foreach (Prediction selectedPrediction in selectedPredictions)
                            {
                                ++predictionNum;

                                for (int copyNum = 1; copyNum <= numCopies; ++copyNum)
                                {
                                    Console.Out.WriteLine("Creating copy " + copyNum + " (of " + numCopies + ") of prediction " + predictionNum + " (of " + selectedPredictions.Count + ")");
                                    try
                                    {
                                        Prediction copy = selectedPrediction.Copy("Copy " + copyNum + " of " + selectedPrediction.Name, predictionNum == 1 && copyNum == 1, false);
                                        Point.VacuumTable(copy);
                                        PointPrediction.VacuumTable(copy);
                                    }
                                    catch (Exception ex) { Console.Out.WriteLine("Error while copying prediction:  " + ex.Message); }
                                }
                            }

                            try { Prediction.VacuumTable(); }
                            catch (Exception ex) { Console.Out.WriteLine("Failed to vacuum " + Prediction.Table + ":  " + ex.Message); }

                            string msg = "Done copying predictions";
                            Console.Out.WriteLine(msg);
                            Notify(msg, "");

                            RefreshPredictions(selectedPredictions.ToArray());
                        }));

                    t.Start();
                }
            }
        }
        private void collapseIncidentTypesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DynamicForm f = new DynamicForm("Collapse incident types...", DynamicForm.CloseButtons.OkCancel);

            f.AddDropDown("Area:", Area.GetAll().ToArray(), null, "area", true, new Action<object, EventArgs>((o, args) =>
                {
                    ListBox typesList = f.GetControl<ListBox>("types");
                    if (typesList != null)
                    {
                        typesList.Items.Clear();

                        Area selectedArea = (o as ComboBox).SelectedItem as Area;
                        if (selectedArea != null)
                            foreach (string type in Incident.GetUniqueTypes(DateTime.MinValue, DateTime.MaxValue, selectedArea))
                                typesList.Items.Add(type);
                    }
                }));

            Area area = f.GetValue<Area>("area") as Area;
            if (area == null)
                MessageBox.Show("No areas available to collapse incidents for.");
            else
            {
                f.AddListBox("Types:", Incident.GetUniqueTypes(DateTime.MinValue, DateTime.MaxValue, area).ToArray(), null, SelectionMode.MultiExtended, "types", true);
                f.AddTextBox("Collapsed type:", null, 50, "collapsed");

                if (f.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    area = f.GetValue<Area>("area");

                    List<string> types = new List<string>();
                    foreach (string type in f.GetValue<System.Windows.Forms.ListBox.SelectedObjectCollection>("types"))
                        types.Add(type);

                    string collapsedType = f.GetValue<string>("collapsed").Trim();

                    if (area == null)
                        MessageBox.Show("Must select an area.");
                    else if (types.Count <= 1)
                        MessageBox.Show("Must select two or more types to collapse.");
                    else if (string.IsNullOrWhiteSpace(collapsedType))
                        MessageBox.Show("Must enter a collapsed type name.");
                    else if (MessageBox.Show("Are you sure you want to collapse these incident types?", "Collapse?", MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
                        Incident.Collapse(area, types, collapsedType);
                }
            }
        }
        public static void SetEncryptionKey(bool reset)
        {
            if (_encryptionKey != null && !reset)
                return;

            string passphraseHashPath = ".encryption_passphrase_hash";
            if (reset)
                File.WriteAllText(passphraseHashPath, "");

            string passphraseHash = "";
            if (File.Exists(passphraseHashPath))
                passphraseHash = File.ReadAllText(passphraseHashPath);

            string key = null;

            while (true)
            {
                DynamicForm f = new DynamicForm("Enter encryption passphrase", DynamicForm.CloseButtons.OkCancel);
                f.AddTextBox("Passphrase:", null, 20, "passphrase", '*', true);
                f.AddTextBox("Confirm passphrase:", null, 20, "confirmed", '*', true);

                if (f.ShowDialog() == DialogResult.Cancel)
                    break;

                string passphrase = f.GetValue<string>("passphrase").Trim();
                string confirmed = f.GetValue<string>("confirmed").Trim();
                if (passphrase != confirmed)
                    MessageBox.Show("Entries do not match.");
                else if (passphrase.Length < 8)
                    MessageBox.Show("Passphrase must be at least 8 characters.");
                else
                {
                    key = passphrase;
                    break;
                }
            }

            if (key == null)
                throw new Exception("Encryption not set up. No passphrase supplied.");

            _encryptionKey = new byte[32];
            byte[] keyBytes = Encoding.Default.GetBytes(key);
            Array.Copy(keyBytes, _encryptionKey, keyBytes.Length);

            string hash;
            using (SHA256 sha2 = SHA256Managed.Create())
            {
                hash = sha2.ComputeHash(_encryptionKey).Select(b => b.ToString()).Concatenate("-");
            }

            if (passphraseHash == "")
                File.WriteAllText(passphraseHashPath, hash);
            else if (hash != passphraseHash)
            {
                _encryptionKey = null;
                throw new Exception("The given passphrase does not match the one previously established. Encryption will not function properly. To enable encryption, either enter the correct passphrase or reset the passphrase with File -> Reset encryption key.");
            }
        }
        private void remapSelectedFeaturesDuringPredictionToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (Features.Count == 0)
                MessageBox.Show("Must select one or more features before remapping.");
            else
            {
                Area[] predictionAreas = Area.GetAll().ToArray();
                if (predictionAreas.Length == 0)
                    MessageBox.Show("No prediction areas available for remapping.");
                else
                {
                    DynamicForm df = new DynamicForm("Remapping features...", DynamicForm.CloseButtons.OkCancel);
                    df.AddDropDown("Prediction area:", predictionAreas, null, "prediction_area", true);
                    if (df.ShowDialog() == DialogResult.OK)
                    {
                        List<Feature> selectedFeatures = Features;
                        FeatureRemappingForm f = new FeatureRemappingForm(selectedFeatures, _getFeatures(df.GetValue<Area>("prediction_area")));
                        f.ShowDialog();

                        _featureRemapKeyTargetPredictionResource.Clear();
                        foreach (Feature feature in selectedFeatures)
                            if (feature.PredictionResourceId != feature.TrainingResourceId)
                                _featureRemapKeyTargetPredictionResource.Add(feature.RemapKey, feature.PredictionResourceId);

                        RefreshFeatures();

                        foreach (Feature feature in selectedFeatures)
                            features.SetSelected(features.Items.IndexOf(feature), true);
                    }
                }
            }
        }
        private void parameterizeSelectedFeaturesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DynamicForm f = new DynamicForm("Parameterize " + Features.Count + " features...", DynamicForm.CloseButtons.OkCancel);
            foreach (Enum parameter in Features.SelectMany(feature => feature.Parameters).Distinct().OrderBy(p => p.GetType().FullName + "." + p))
            {
                string currentValue = "";
                List<string> distinctValues = Features.Where(feature => feature.Parameters.Contains(parameter)).Select(feature => feature.Parameters.GetStringValue(parameter)).Distinct().ToList();
                if (distinctValues.Count == 1)
                    currentValue = distinctValues[0];

                string parameterId = parameter.GetType().FullName;
                parameterId = parameterId.Substring(parameterId.IndexOf('+') + 1) + "." + parameter;
                f.AddTextBox(parameterId + ":", currentValue, 20, parameterId, toolTipText: Features.Where(feature => feature.Parameters.Contains(parameter)).First().Parameters.GetTip(parameter));
            }

            if (f.ShowDialog() == DialogResult.OK)
                foreach (string parameterId in f.ValueIds)
                {
                    string[] enumTypeEnumValue = parameterId.Split('.');
                    string enumType = enumTypeEnumValue[0];
                    string enumValue = enumTypeEnumValue[1];
                    foreach (Feature feature in Features)
                        foreach (Enum parameter in feature.Parameters.ToArray())
                            if (parameter.GetType().FullName.EndsWith("+" + enumType) && parameter.ToString() == enumValue)
                                feature.Parameters.Set(parameter, f.GetValue<string>(parameterId));
                }
        }
            public Dictionary<string, string> MapIncidentColumnsToShapefileColumns(string shapefileGeometryTable, bool reusePrevious)
            {
                if (!reusePrevious)
                    _incidentColumnShapefileColumn = null;

                if (_incidentColumnShapefileColumn == null)
                {
                    _incidentColumnShapefileColumn = new Dictionary<string, string>();

                    string[] shapefileColumns = DB.Connection.GetColumnNames(shapefileGeometryTable).ToArray();
                    DynamicForm f = new DynamicForm("Supply column mapping from incident table to shapefile table...", DynamicForm.CloseButtons.OK);
                    string[] incidentColumns = new string[] { Incident.Columns.Location, Incident.Columns.NativeId, Incident.Columns.Time, Incident.Columns.Type };
                    foreach (string incidentColumn in incidentColumns)
                        f.AddDropDown(incidentColumn + ":", shapefileColumns, null, incidentColumn, true);

                    f.ShowDialog();

                    _incidentColumnShapefileColumn = new Dictionary<string, string>();
                    foreach (string incidentTableColumn in incidentColumns)
                        _incidentColumnShapefileColumn.Add(incidentTableColumn, f.GetValue<string>(incidentTableColumn));
                }

                return _incidentColumnShapefileColumn;
            }
            public void GetShapefileInfo(string shapefilePath, List<string> optionValuesToGet, Dictionary<string, string> optionValue)
            {
                DynamicForm df = new DynamicForm("Supply shapefile import options...", DynamicForm.CloseButtons.OK);
                foreach (string optionValueToGet in optionValuesToGet)
                {
                    string value = null;

                    if (optionValueToGet == "reprojection" && _sourceSRID > 0 && _targetSRID > 0)
                        value = _sourceSRID + ":" + _targetSRID;

                    if (optionValueToGet == "name" && !string.IsNullOrWhiteSpace(_name))
                        value = _name;

                    df.AddTextBox(optionValueToGet + ":", value, 50, optionValueToGet);

                    if (value != null)
                        optionValue.Add(optionValueToGet, value);
                }

                if (optionValuesToGet.Any(v => !optionValue.ContainsKey(v)))
                {
                    df.ShowDialog();

                    foreach (string optionValueToGet in optionValuesToGet)
                        if (!optionValue.ContainsKey(optionValueToGet))
                            optionValue.Add(optionValueToGet, df.GetValue<string>(optionValueToGet));
                }
            }
        private void editPredictionRunToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (SelectedPredictions.Count == 0)
                MessageBox.Show("Select one or more predictions to edit run number for.");
            else
            {
                DynamicForm f = new DynamicForm("", DynamicForm.CloseButtons.OkCancel);
                f.AddNumericUpdown("New run number for " + SelectedPredictions.Count + " prediction(s):", 1, 0, 1, int.MaxValue, 1, "run");
                if (f.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    int run = Convert.ToInt32(f.GetValue<decimal>("run"));
                    foreach (Prediction prediction in SelectedPredictions)
                        prediction.RunId = run;

                    RefreshPredictions(SelectedPredictions.ToArray());
                }
            }
        }
        public void aggregateAndEvaluateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (SelectedPredictions.Count < 2)
                MessageBox.Show("Select at least two predictions to run an aggregate evaluation.");
            else
            {
                try
                {
                    string title = "Aggregated";
                    if (TraversePredictionTree().Count(n => n.Checked) == 1)
                        title = TraversePredictionTree().Where(n => n.Checked).First().Text;

                    Tuple<SurveillancePlot, float> surveillancePlotAndCorrelation = DiscreteChoiceModel.GetAggregateSurveillancePlotAndCorrelation(SelectedPredictions, 500, 500, title, title);
                    DynamicForm f = new DynamicForm(title, DynamicForm.CloseButtons.OK);
                    f.AddPictureBox(surveillancePlotAndCorrelation.Item1.Image, "Correlation between threat and crime count:  " + surveillancePlotAndCorrelation.Item2);
                    f.ShowDialog();
                }
                catch (Exception ex) { MessageBox.Show("Error rendering aggregate plot:  " + ex.Message); }
            }
        }
        private void encryptTextToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string textToEncrypt = null;

            while (true)
            {
                DynamicForm f = new DynamicForm("Encrypt text...", DynamicForm.CloseButtons.OkCancel);
                f.AddTextBox("Text:", null, 20, "text", '*', true);
                f.AddTextBox("Confirm text:", null, 20, "confirmed", '*', true);

                if (f.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    textToEncrypt = f.GetValue<string>("text").Trim();
                    string confirmedText = f.GetValue<string>("confirmed").Trim();
                    if (textToEncrypt.Length == 0)
                        MessageBox.Show("Empty text is not allowed.");
                    else if (textToEncrypt != confirmedText)
                        MessageBox.Show("Entries do not match.");
                    else
                        break;
                }
                else
                    return;
            }

            try
            {
                DynamicForm showEncrypted = new DynamicForm("Encrypted text", DynamicForm.CloseButtons.OK);
                showEncrypted.AddTextBox("Result:", textToEncrypt.Encrypt(Configuration.EncryptionKey, Configuration.EncryptionInitialization).Select(b => b.ToString()).Concatenate("-"), -1, "encrypted");
                showEncrypted.ShowDialog();
            }
            catch (Exception ex) { MessageBox.Show("Error getting encrypted text:  " + ex.Message); }
        }
        public void editPredictionNameToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (SelectedPredictions.Count == 0)
                MessageBox.Show("Select one or more predictions to rename.");
            else
            {
                List<Prediction> selectedPredictions = SelectedPredictions;
                if (selectedPredictions.Count == 1)
                {
                    DynamicForm f = new DynamicForm("", DynamicForm.CloseButtons.OkCancel);
                    f.AddTextBox("New prediction name:", SelectedPrediction.Name, -1, "name");
                    if (f.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    {
                        string name = f.GetValue<string>("name").Trim();
                        if (name != "")
                            selectedPredictions[0].Name = name;
                    }
                }
                else if (selectedPredictions.Count > 1)
                {
                    DynamicForm f = new DynamicForm("", DynamicForm.CloseButtons.OkCancel);
                    f.AddTextBox("Common base name for " + selectedPredictions.Count + " predictions:", null, -1, "name");
                    if (f.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    {
                        string name = f.GetValue<string>("name").Trim();
                        if (name != "")
                            for (int i = 0; i < selectedPredictions.Count; ++i)
                                selectedPredictions[i].Name = name.Trim() + "-" + i;
                    }
                }
                else
                    return;

                Set<int> selectedIds = new Set<int>(selectedPredictions.Select(p => p.Id).ToArray());
                if (threatMap.DisplayedPrediction != null && selectedIds.Contains(threatMap.DisplayedPrediction.Id))
                {
                    List<Plot> newPlots = selectedPredictions.Where(p => p.Id == threatMap.DisplayedPrediction.Id).First().AssessmentPlots.ToList();
                    threatMap.DisplayedPrediction.AssessmentPlots.Clear();
                    threatMap.DisplayedPrediction.AssessmentPlots.AddRange(newPlots);
                    RefreshAssessments();
                }

                RefreshPredictions(selectedPredictions.ToArray());
            }
        }
        private void Import(string downloadDirectory,
            CompleteImporterFormDelegate completeImporterForm,
            CreateImporterDelegate createImporter,
            string initialBrowsingDirectory,
            string fileBrowserFilter,
            string[] importFileSearchPatterns,
            ImportCompletionDelegate completionCallback)
        {
            Thread t = new Thread(new ThreadStart(delegate()
            {
                try
                {
                    DynamicForm importerForm = new DynamicForm("Enter import information...", DynamicForm.CloseButtons.OkCancel);

                    importerForm.AddTextBox("Import name (descriptive):", null, 70, "name");
                    importerForm.AddTextBox("Path:", null, 200, "path", addFileBrowsingButtons: true, initialBrowsingDirectory: initialBrowsingDirectory, fileFilter: fileBrowserFilter, textChanged: (o, e) =>
                        {
                            TextBox pathTextBox = o as TextBox;
                            ComboBox fileTypeCombo = importerForm.GetControl<ComboBox>("file_type");
                            string path = pathTextBox.Text.Trim().ToLower();
                            string extension = Path.GetExtension(path);
                            bool pathIsDirectory = Directory.Exists(path);
                            if (!pathIsDirectory)
                                if (extension == ".zip")
                                    fileTypeCombo.SelectedItem = ImportFileType.Zip;
                                else
                                    fileTypeCombo.SelectedItem = ImportFileType.Plain;
                        });

                    importerForm.AddTextBox("Download XML URI:", null, 200, "uri");
                    importerForm.AddDropDown("File type:", Enum.GetValues(typeof(ImportFileType)), ImportFileType.Plain, "file_type", true);
                    importerForm.AddCheckBox("Delete imported file after import:", ContentAlignment.MiddleRight, false, "delete");
                    importerForm.AddCheckBox("Save importer(s):", ContentAlignment.MiddleRight, false, "save_importer");

                    if (completeImporterForm != null)
                        importerForm = completeImporterForm(importerForm);

                    if (importerForm == null)
                        return;

                    if (importerForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    {
                        string p = importerForm.GetValue<string>("path").Trim();
                        ImportFileType fileType = (ImportFileType)importerForm.GetValue<object>("file_type");
                        bool pathIsDirectory = Directory.Exists(p);

                        if (pathIsDirectory)
                            downloadDirectory = p;

                        #region download file if a URI is given -- some callbacks need the file in order to set up the importer
                        string sourceURI = importerForm.GetValue<string>("uri");
                        if (!string.IsNullOrWhiteSpace(sourceURI))
                        {
                            if (string.IsNullOrWhiteSpace(p) || pathIsDirectory)
                            {
                                p = Path.Combine(downloadDirectory, ReplaceInvalidFilenameCharacters("uri_download_" + DateTime.Now.ToShortDateString() + "_" + DateTime.Now.ToLongTimeString() + (fileType == ImportFileType.Zip ? ".zip" : "")));
                                pathIsDirectory = false;
                            }

                            try { LAIR.IO.Network.Download(sourceURI, p); }
                            catch (Exception ex)
                            {
                                try { File.Delete(p); }
                                catch (Exception ex2) { Console.Out.WriteLine("Failed to delete partially downloaded file \"" + p + "\":  " + ex2.Message); }

                                Console.Out.WriteLine("Error downloading file from URI:  " + ex.Message);

                                return;
                            }
                        }
                        #endregion

                        #region decompress zip files if the user is providing them
                        if (fileType == ImportFileType.Zip)
                        {
                            string[] pathsToUnzip = new string[] { p };
                            if (pathIsDirectory)
                                pathsToUnzip = Directory.GetFiles(p, "*.zip", SearchOption.AllDirectories);

                            foreach (string pathToUnzip in pathsToUnzip)
                            {
                                string destinationDirectory = Importer.GetImportUnzipDirectory(pathToUnzip);
                                Console.Out.WriteLine("Unzipping \"" + pathToUnzip + "\" to \"" + destinationDirectory + "\"...");
                                try { ZipFile.ExtractToDirectory(pathToUnzip, destinationDirectory); }
                                catch (Exception) { }
                                if (!pathIsDirectory)
                                    p = destinationDirectory;
                            }

                            pathIsDirectory = true;
                        }
                        #endregion

                        string[] paths = new string[] { p };
                        if (pathIsDirectory)
                            paths = importFileSearchPatterns == null ? Directory.GetFiles(p, "*", SearchOption.AllDirectories) : importFileSearchPatterns.SelectMany(pattern => Directory.GetFiles(p, pattern, SearchOption.AllDirectories)).ToArray();

                        foreach (string path in paths)
                            if (File.Exists(path))
                            {
                                string importName = importerForm.GetValue<string>("name");
                                if (paths.Length > 1)
                                    importName = "";

                                bool deleteImportedFileAfterImport = importerForm.GetValue<bool>("delete");
                                bool saveImporter = Convert.ToBoolean(importerForm.GetValue<bool>("save_importer"));

                                try
                                {
                                    Importer importer = createImporter(importName, path, sourceURI, importerForm);
                                    importer.Import();

                                    if (deleteImportedFileAfterImport)
                                        File.Delete(path);

                                    if (saveImporter)
                                        importer.Save(false);
                                }
                                catch (Exception ex)
                                {
                                    Console.Out.WriteLine("Error while importing from \"" + path + "\":  " + ex.Message);
                                }
                            }
                    }
                }
                catch (Exception ex)
                {
                    Console.Out.WriteLine(ex.Message);
                }

                if (completionCallback != null)
                    completionCallback();
            }));

            t.SetApartmentState(ApartmentState.STA);
            t.Start();
        }
        private void SmootherList_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Right)
            {
                int clickedIndex = IndexFromPoint(e.Location);
                if (clickedIndex >= 0)
                {
                    Smoother smoother = Items[clickedIndex] as Smoother;
                    if (smoother == null)
                        throw new NullReferenceException("Expected Smoother objects in Items");

                    string updateWindowTitle = "Updating " + smoother.GetType().Name + "...";

                    if (smoother is KdeSmoother)
                    {
                        KdeSmoother kdeSmoother = smoother as KdeSmoother;
                        DynamicForm f = new DynamicForm("Set KDE smoother parameters", DynamicForm.CloseButtons.OkCancel);
                        f.AddNumericUpdown("Sample size:", kdeSmoother.SampleSize, 0, 1, decimal.MaxValue, 1, "sample_size");
                        f.AddCheckBox("Normalize:", ContentAlignment.MiddleRight, kdeSmoother.Normalize, "normalize");
                        if (f.ShowDialog() == DialogResult.OK)
                        {
                            try { kdeSmoother.SampleSize = Convert.ToInt32(f.GetValue<decimal>("sample_size")); }
                            catch (Exception ex) { MessageBox.Show("Invalid value for sample size:  " + ex.Message); }

                            kdeSmoother.Normalize = f.GetValue<bool>("normalize");
                        }
                    }
                    else if (smoother is WeightedAverageSmoother)
                    {
                        WeightedAverageSmoother avgSmoother = smoother as WeightedAverageSmoother;
                        DynamicForm f = new DynamicForm("Set weighted average smoother parameters", DynamicForm.CloseButtons.OkCancel);
                        f.AddNumericUpdown("Minimum:", (decimal)avgSmoother.Minimum, 0, 0, decimal.MaxValue, 1, "minimum");
                        f.AddNumericUpdown("Maximum:", (decimal)avgSmoother.Maximum, 0, 0, decimal.MaxValue, 1, "maximum");
                        if (f.ShowDialog() == DialogResult.OK)
                        {
                            try { avgSmoother.Minimum = Convert.ToDouble(f.GetValue<decimal>("minimum")); }
                            catch (Exception ex) { MessageBox.Show("Invalid value for minimum:  " + ex.Message); }

                            try
                            {
                                double value = Convert.ToDouble(f.GetValue<decimal>("maximum"));
                                if (value < avgSmoother.Minimum)
                                {
                                    avgSmoother.Maximum = avgSmoother.Minimum + 500;
                                    throw new Exception("Maximum must be greater than or equal to minimum (" + avgSmoother.Minimum + "). Setting maximum to " + avgSmoother.Maximum + ".");
                                }

                                avgSmoother.Maximum = value;
                            }
                            catch (Exception ex) { MessageBox.Show("Invalid value for maximum:  " + ex.Message); }
                        }
                    }
                    else if (smoother is MarsSmoother)
                    {
                        MarsSmoother marsSmoother = smoother as MarsSmoother;
                        DynamicForm f = new DynamicForm("Set MARS smoother parameters", DynamicForm.CloseButtons.OkCancel);
                        f.AddNumericUpdown("Number of considered parent terms (-1 for all):", marsSmoother.ConsideredParentTerms, 0, -1, decimal.MaxValue, 1, "parent");
                        f.AddNumericUpdown("Degree of interaction:", marsSmoother.InteractionDegree, 0, 1, decimal.MaxValue, 1, "interaction");
                        f.AddNumericUpdown("Number of knots (-1 for auto):", marsSmoother.NumberOfKnots, 0, -1, decimal.MaxValue, 1, "knots");
                        if (f.ShowDialog() == DialogResult.OK)
                        {
                            try { marsSmoother.ConsideredParentTerms = Convert.ToInt32(f.GetValue<decimal>("parent")); }
                            catch (Exception ex) { MessageBox.Show("Invalid value for parent terms:  " + ex.Message); }

                            try { marsSmoother.InteractionDegree = Convert.ToInt32(f.GetValue<decimal>("interaction")); }
                            catch (Exception ex) { MessageBox.Show("Invalid value for interaction degree:  " + ex.Message); }

                            try { marsSmoother.NumberOfKnots = Convert.ToInt32(f.GetValue<decimal>("knots")); }
                            catch (Exception ex) { MessageBox.Show("Invalid value for number of knots:  " + ex.Message); }
                        }
                    }
                    else
                        throw new NotImplementedException("Unrecognized smoother type:  " + smoother.GetType().FullName);
                }
            }
        }
        private void manageStoredImportersToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Importer[] storedImporters = Importer.GetAll().ToArray();

            Thread t = new Thread(new ThreadStart(() =>
                {
                    DialogResult manageDialogResult = System.Windows.Forms.DialogResult.OK;
                    bool refreshStoredImporters = false;
                    while (manageDialogResult == System.Windows.Forms.DialogResult.OK)
                    {
                        if (refreshStoredImporters)
                        {
                            storedImporters = Importer.GetAll().ToArray();
                            refreshStoredImporters = false;
                        }

                        DynamicForm f = new DynamicForm("Stored importers...", DynamicForm.CloseButtons.OkClose);
                        f.AddListBox("Importers:", storedImporters, null, SelectionMode.MultiExtended, "importers", true);
                        f.AddDropDown("Action:", Enum.GetValues(typeof(ManageImporterAction)), null, "action", false);
                        if ((manageDialogResult = f.ShowDialog()) == System.Windows.Forms.DialogResult.OK)
                        {
                            ManageImporterAction action = f.GetValue<ManageImporterAction>("action");

                            if (action == ManageImporterAction.Load)
                            {
                                DynamicForm df = new DynamicForm("Select importer source...", DynamicForm.CloseButtons.OkCancel);
                                df.AddTextBox("Path:", ATT.Configuration.ImportersLoadDirectory, 75, "path", addFileBrowsingButtons: true, fileFilter: "ATT importers|*.attimp", initialBrowsingDirectory: ATT.Configuration.ImportersLoadDirectory);
                                if (df.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                                {
                                    string path = df.GetValue<string>("path");
                                    string[] importerPaths = null;
                                    if (Directory.Exists(path))
                                        importerPaths = Directory.GetFiles(path, "*.attimp", SearchOption.TopDirectoryOnly);
                                    else if (File.Exists(path))
                                        importerPaths = new string[] { path };

                                    if (importerPaths != null)
                                    {
                                        BinaryFormatter bf = new BinaryFormatter();
                                        foreach (string importerPath in importerPaths)
                                            using (FileStream fs = new FileStream(importerPath, FileMode.Open, FileAccess.Read))
                                            {
                                                try
                                                {
                                                    Importer importer = bf.Deserialize(fs) as Importer;

                                                    string absolutePath = importer.Path;
                                                    int relativizationIdEnd = importer.RelativePath.IndexOf('}');
                                                    string relativizationId = importer.RelativePath.Substring(0, relativizationIdEnd + 1).Trim('{', '}');
                                                    if (!string.IsNullOrWhiteSpace(relativizationId))
                                                    {
                                                        PathRelativizationId pathRelativizationId = (PathRelativizationId)Enum.Parse(typeof(PathRelativizationId), relativizationId);
                                                        string relativeTrailingPath = importer.RelativePath.Substring(relativizationIdEnd + 1).Trim(Path.DirectorySeparatorChar);
                                                        if (pathRelativizationId == PathRelativizationId.EventDirectory)
                                                            absolutePath = Path.Combine(ATT.Configuration.EventsImportDirectory, relativeTrailingPath);
                                                        else if (pathRelativizationId == PathRelativizationId.IncidentDirectory)
                                                            absolutePath = Path.Combine(ATT.Configuration.IncidentsImportDirectory, relativeTrailingPath);
                                                        else if (pathRelativizationId == PathRelativizationId.ShapefileDirectory)
                                                            absolutePath = Path.Combine(ATT.Configuration.PostGisShapefileDirectory, relativeTrailingPath);
                                                        else
                                                            throw new NotImplementedException("Unrecognized path relativization id:  " + pathRelativizationId);
                                                    }

                                                    importer.Path = absolutePath;
                                                    importer.Save(false);
                                                    fs.Close();
                                                    refreshStoredImporters = true;
                                                }
                                                catch (Exception ex)
                                                {
                                                    Console.Out.WriteLine("Importer import failed:  " + ex.Message);
                                                }
                                            }
                                    }
                                }
                            }
                            else
                            {
                                string exportDirectory = null;
                                foreach (Importer importer in f.GetValue<System.Windows.Forms.ListBox.SelectedObjectCollection>("importers"))
                                    if (action == ManageImporterAction.Delete)
                                    {
                                        importer.Delete();
                                        refreshStoredImporters = true;
                                    }
                                    else if (action == ManageImporterAction.Edit)
                                    {
                                        Dictionary<string, object> updateKeyValue = new Dictionary<string, object>();
                                        DynamicForm updateForm = new DynamicForm("Update importer \"" + importer + "\"...", DynamicForm.CloseButtons.OkCancel);
                                        importer.GetUpdateRequests(new Importer.UpdateRequestDelegate((itemName, currentValue, possibleValues, id) =>
                                            {
                                                itemName += ":";

                                                if (possibleValues != null)
                                                    updateForm.AddDropDown(itemName, possibleValues.ToArray(), currentValue, id, false);
                                                else if (currentValue is string)
                                                    updateForm.AddTextBox(itemName, currentValue as string, -1, id);
                                                else if (currentValue is int)
                                                    updateForm.AddNumericUpdown(itemName, (int)currentValue, 0, int.MinValue, int.MaxValue, 1, id);
                                                else if (currentValue != null)
                                                    throw new NotImplementedException("Cannot dynamically generate form for update request");

                                                updateKeyValue.Add(id, currentValue);
                                            }));

                                        if (updateForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                                        {
                                            foreach (string updateKey in updateKeyValue.Keys.ToArray())
                                                updateKeyValue[updateKey] = updateForm.GetValue<object>(updateKey);

                                            importer.Update(updateKeyValue);
                                            importer.Save(true);
                                            refreshStoredImporters = true;
                                        }
                                    }
                                    else if (action == ManageImporterAction.Store)
                                    {
                                        if (exportDirectory == null)
                                            exportDirectory = LAIR.IO.Directory.PromptForDirectory("Select export directory...", ATT.Configuration.ImportersLoadDirectory);

                                        if (Directory.Exists(exportDirectory))
                                        {
                                            try
                                            {
                                                BinaryFormatter bf = new BinaryFormatter();
                                                using (FileStream fs = new FileStream(Path.Combine(exportDirectory, ReplaceInvalidFilenameCharacters(importer.ToString() + ".attimp")), FileMode.Create, FileAccess.ReadWrite))
                                                {
                                                    bf.Serialize(fs, importer);
                                                    fs.Close();
                                                    Console.Out.WriteLine("Exported \"" + importer + "\".");
                                                }
                                            }
                                            catch (Exception ex)
                                            {
                                                Console.Out.WriteLine("Importer export failed:  " + ex.Message);
                                            }
                                        }
                                    }
                                    else if (action == ManageImporterAction.Run)
                                    {
                                        Console.Out.WriteLine("Running importer \"" + importer + "\"...");
                                        try { importer.Import(); }
                                        catch (Exception ex)
                                        {
                                            Console.Out.WriteLine("Import failed:  " + ex.Message);
                                        }
                                    }
                                    else
                                        MessageBox.Show("Unrecognized action:  " + action);
                            }
                        }
                    }

                    // might have imported/created an area
                    RefreshPredictionAreas();
                }));

            t.SetApartmentState(ApartmentState.STA);
            t.Start();
        }
        private void SmootherList_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Right)
            {
                int clickedIndex = IndexFromPoint(e.Location);
                if (clickedIndex >= 0)
                {
                    Smoother smoother = Items[clickedIndex] as Smoother;
                    if (smoother == null)
                    {
                        throw new NullReferenceException("Expected Smoother objects in Items");
                    }

                    string updateWindowTitle = "Updating " + smoother.GetType().Name + "...";

                    if (smoother is KdeSmoother)
                    {
                        KdeSmoother kdeSmoother = smoother as KdeSmoother;
                        DynamicForm f           = new DynamicForm("Set KDE smoother parameters", DynamicForm.CloseButtons.OkCancel);
                        f.AddNumericUpdown("Sample size:", kdeSmoother.SampleSize, 0, 1, decimal.MaxValue, 1, "sample_size");
                        f.AddCheckBox("Normalize:", ContentAlignment.MiddleRight, kdeSmoother.Normalize, "normalize");
                        if (f.ShowDialog() == DialogResult.OK)
                        {
                            try { kdeSmoother.SampleSize = Convert.ToInt32(f.GetValue <decimal>("sample_size")); }
                            catch (Exception ex) { MessageBox.Show("Invalid value for sample size:  " + ex.Message); }

                            kdeSmoother.Normalize = f.GetValue <bool>("normalize");
                        }
                    }
                    else if (smoother is WeightedAverageSmoother)
                    {
                        WeightedAverageSmoother avgSmoother = smoother as WeightedAverageSmoother;
                        DynamicForm             f           = new DynamicForm("Set weighted average smoother parameters", DynamicForm.CloseButtons.OkCancel);
                        f.AddNumericUpdown("Minimum:", (decimal)avgSmoother.Minimum, 0, 0, decimal.MaxValue, 1, "minimum");
                        f.AddNumericUpdown("Maximum:", (decimal)avgSmoother.Maximum, 0, 0, decimal.MaxValue, 1, "maximum");
                        if (f.ShowDialog() == DialogResult.OK)
                        {
                            try { avgSmoother.Minimum = Convert.ToDouble(f.GetValue <decimal>("minimum")); }
                            catch (Exception ex) { MessageBox.Show("Invalid value for minimum:  " + ex.Message); }

                            try
                            {
                                double value = Convert.ToDouble(f.GetValue <decimal>("maximum"));
                                if (value < avgSmoother.Minimum)
                                {
                                    avgSmoother.Maximum = avgSmoother.Minimum + 500;
                                    throw new Exception("Maximum must be greater than or equal to minimum (" + avgSmoother.Minimum + "). Setting maximum to " + avgSmoother.Maximum + ".");
                                }

                                avgSmoother.Maximum = value;
                            }
                            catch (Exception ex) { MessageBox.Show("Invalid value for maximum:  " + ex.Message); }
                        }
                    }
                    else if (smoother is MarsSmoother)
                    {
                        MarsSmoother marsSmoother = smoother as MarsSmoother;
                        DynamicForm  f            = new DynamicForm("Set MARS smoother parameters", DynamicForm.CloseButtons.OkCancel);
                        f.AddNumericUpdown("Number of considered parent terms (-1 for all):", marsSmoother.ConsideredParentTerms, 0, -1, decimal.MaxValue, 1, "parent");
                        f.AddNumericUpdown("Degree of interaction:", marsSmoother.InteractionDegree, 0, 1, decimal.MaxValue, 1, "interaction");
                        f.AddNumericUpdown("Number of knots (-1 for auto):", marsSmoother.NumberOfKnots, 0, -1, decimal.MaxValue, 1, "knots");
                        if (f.ShowDialog() == DialogResult.OK)
                        {
                            try { marsSmoother.ConsideredParentTerms = Convert.ToInt32(f.GetValue <decimal>("parent")); }
                            catch (Exception ex) { MessageBox.Show("Invalid value for parent terms:  " + ex.Message); }

                            try { marsSmoother.InteractionDegree = Convert.ToInt32(f.GetValue <decimal>("interaction")); }
                            catch (Exception ex) { MessageBox.Show("Invalid value for interaction degree:  " + ex.Message); }

                            try { marsSmoother.NumberOfKnots = Convert.ToInt32(f.GetValue <decimal>("knots")); }
                            catch (Exception ex) { MessageBox.Show("Invalid value for number of knots:  " + ex.Message); }
                        }
                    }
                    else
                    {
                        throw new NotImplementedException("Unrecognized smoother type:  " + smoother.GetType().FullName);
                    }
                }
            }
        }
        private Area PromptForArea(string prompt)
        {
            Area[] areas = Area.GetAll().ToArray();
            if (areas.Length == 0)
            {
                MessageBox.Show("No areas available.");
                return null;
            }

            DynamicForm f = new DynamicForm(prompt, DynamicForm.CloseButtons.OkCancel);
            f.AddDropDown("Areas:", areas, null, "area", true);
            Area importArea = null;
            if (f.ShowDialog() == DialogResult.OK)
                importArea = f.GetValue<Area>("area");

            return importArea;
        }