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 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 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);
                }
            }
        }