diff --git a/DynamicBibleUtility/DynamicBibleUtility/DynamicBibleUtility.csproj b/DynamicBibleUtility/DynamicBibleUtility/DynamicBibleUtility.csproj
index 1a040158..e26bb595 100644
--- a/DynamicBibleUtility/DynamicBibleUtility/DynamicBibleUtility.csproj
+++ b/DynamicBibleUtility/DynamicBibleUtility/DynamicBibleUtility.csproj
@@ -63,6 +63,12 @@
frmMain.cs
+
+
+
+
+
+
diff --git a/DynamicBibleUtility/DynamicBibleUtility/Geolocation/BibleBook.cs b/DynamicBibleUtility/DynamicBibleUtility/Geolocation/BibleBook.cs
new file mode 100644
index 00000000..f6b68f88
--- /dev/null
+++ b/DynamicBibleUtility/DynamicBibleUtility/Geolocation/BibleBook.cs
@@ -0,0 +1,177 @@
+using System.Collections.Generic;
+
+namespace DynamicBibleUtility.Geolocation
+{
+ ///
+ /// An enum for uniquely identifying a book of the Bible.
+ /// An "invalid" enum value is first so that the numeric
+ /// value for actual books starts at 1, which helps maintain
+ /// consistency with how verse references are used in other
+ /// data for the app.
+ ///
+ public enum BibleBookId
+ {
+ INVALID,
+ GENESIS,
+ EXODUS,
+ LEVITICUS,
+ NUMBERS,
+ DEUTERONOMY,
+ JOSHUA,
+ JUDGES,
+ RUTH,
+ FIRST_SAMUEL,
+ SECOND_SAMUEL,
+ FIRST_KINGS,
+ SECOND_KINGS,
+ FIRST_CHRONICLES,
+ SECOND_CHRONICLES,
+ EZRA,
+ NEHEMIAH,
+ ESTHER,
+ JOB,
+ PSALMS,
+ PROVERBS,
+ ECCLESIASTES,
+ SONG_OF_SOLOMON,
+ ISAIAH,
+ JEREMIAH,
+ LAMENTATIONS,
+ EZEKIEL,
+ DANIEL,
+ HOSEA,
+ JOEL,
+ AMOS,
+ OBADIAH,
+ JONAH,
+ MICAH,
+ NAHUM,
+ HABAKKUK,
+ ZEPHANIAH,
+ HAGGAI,
+ ZECHARIAH,
+ MALACHI,
+ MATTHEW,
+ MARK,
+ LUKE,
+ JOHN,
+ ACTS,
+ ROMANS,
+ FIRST_CORINTHIANS,
+ SECOND_CORINTHIANS,
+ GALATIANS,
+ EPHESIANS,
+ PHILIPPIANS,
+ COLOSSIANS,
+ FIRST_THESSALONIANS,
+ SECOND_THESSALONIANS,
+ FIRST_TIMOTHY,
+ SECOND_TIMOTHY,
+ TITUS,
+ PHILEMON,
+ HEBREWS,
+ JAMES,
+ FIRST_PETER,
+ SECOND_PETER,
+ FIRST_JOHN,
+ SECOND_JOHN,
+ THIRD_JOHN,
+ JUDE,
+ REVELATION
+ };
+
+ ///
+ /// A book of the Bible.
+ ///
+ public class BibleBook
+ {
+ /// The unique ID of book.
+ public BibleBookId Id = BibleBookId.INVALID;
+
+ ///
+ /// Constructs a book by parsing a string.
+ ///
+ /// A string representation of the book.
+ /// Thrown if a parsing error occurs.
+ public BibleBook(string book_string)
+ {
+ // DEFINE A MAPPING OF BOOK STRINGS TO BOOK IDs.
+ // This code currently only handles parsing a subset of book strings as
+ // needed for geolocation parsing. If needed, it could be made more
+ // generic later and moved out of this namespace, but the structure
+ // of this logic would need to be altered.
+ var string_to_book_id_lookup = new Dictionary
+ {
+ { "Gen", BibleBookId.GENESIS },
+ { "Ex", BibleBookId.EXODUS },
+ { "Lev", BibleBookId.LEVITICUS },
+ { "Num", BibleBookId.NUMBERS },
+ { "Deut", BibleBookId.DEUTERONOMY },
+ { "Josh", BibleBookId.JOSHUA },
+ { "Judg", BibleBookId.JUDGES },
+ { "Ruth", BibleBookId.RUTH },
+ { "1 Sam", BibleBookId.FIRST_SAMUEL },
+ { "2 Sam", BibleBookId.SECOND_SAMUEL },
+ { "1 Kgs", BibleBookId.FIRST_KINGS },
+ { "2 Kgs", BibleBookId.SECOND_KINGS },
+ { "1 Chr", BibleBookId.FIRST_CHRONICLES },
+ { "2 Chr", BibleBookId.SECOND_CHRONICLES },
+ { "Ezra", BibleBookId.EZRA },
+ { "Neh", BibleBookId.NEHEMIAH },
+ { "Est", BibleBookId.ESTHER },
+ { "Job", BibleBookId.JOB },
+ { "Ps", BibleBookId.PSALMS },
+ // No locations exist for Proverbs. { "", BibleBookId.PROVERBS },
+ { "Eccl", BibleBookId.ECCLESIASTES },
+ { "Sng", BibleBookId.SONG_OF_SOLOMON },
+ { "Isa", BibleBookId.ISAIAH },
+ { "Jer", BibleBookId.JEREMIAH },
+ { "Lam", BibleBookId.LAMENTATIONS },
+ { "Ezek", BibleBookId.EZEKIEL },
+ { "Dan", BibleBookId.DANIEL },
+ { "Hos", BibleBookId.HOSEA },
+ { "Joel", BibleBookId.JOEL },
+ { "Amos", BibleBookId.AMOS },
+ { "Obad", BibleBookId.OBADIAH },
+ { "Jonah", BibleBookId.JONAH },
+ { "Mic", BibleBookId.MICAH },
+ { "Nahum", BibleBookId.NAHUM },
+ { "Hab", BibleBookId.HABAKKUK },
+ { "Zeph", BibleBookId.ZEPHANIAH },
+ { "Hag", BibleBookId.HAGGAI },
+ { "Zech", BibleBookId.ZECHARIAH },
+ { "Mal", BibleBookId.MALACHI },
+ { "Matt", BibleBookId.MATTHEW },
+ { "Mark", BibleBookId.MARK },
+ { "Luke", BibleBookId.LUKE },
+ { "John", BibleBookId.JOHN },
+ { "Acts", BibleBookId.ACTS },
+ { "Rom", BibleBookId.ROMANS },
+ { "1 Cor", BibleBookId.FIRST_CORINTHIANS },
+ { "2 Cor", BibleBookId.SECOND_CORINTHIANS },
+ { "Gal", BibleBookId.GALATIANS },
+ { "Eph", BibleBookId.EPHESIANS },
+ { "Phil", BibleBookId.PHILIPPIANS },
+ { "Col", BibleBookId.COLOSSIANS },
+ { "1 Thes", BibleBookId.FIRST_THESSALONIANS },
+ { "2 Thes", BibleBookId.SECOND_THESSALONIANS },
+ { "1 Tim", BibleBookId.FIRST_TIMOTHY },
+ { "2 Tim", BibleBookId.SECOND_TIMOTHY },
+ { "Titus", BibleBookId.TITUS },
+ // No locations exist for Philemon. { "", BibleBookId.PHILEMON },
+ { "Heb", BibleBookId.HEBREWS },
+ // No locations exist for James. { "", BibleBookId.JAMES },
+ { "1 Pet", BibleBookId.FIRST_PETER },
+ { "2 Pet", BibleBookId.SECOND_PETER },
+ // No locations exist for 1 John. { "", BibleBookId.FIRST_JOHN },
+ // No locations exist for 2 John. { "", BibleBookId.SECOND_JOHN },
+ // No locations exist for 3 John. { "", BibleBookId.THIRD_JOHN },
+ { "Jude", BibleBookId.JUDE },
+ { "Rev", BibleBookId.REVELATION }
+ };
+
+ // GET THE BOOK ID FROM THE STRING.
+ this.Id = string_to_book_id_lookup[book_string];
+ }
+ }
+}
diff --git a/DynamicBibleUtility/DynamicBibleUtility/Geolocation/BibleLocationIndexByName.cs b/DynamicBibleUtility/DynamicBibleUtility/Geolocation/BibleLocationIndexByName.cs
new file mode 100644
index 00000000..f9f4d1c9
--- /dev/null
+++ b/DynamicBibleUtility/DynamicBibleUtility/Geolocation/BibleLocationIndexByName.cs
@@ -0,0 +1,32 @@
+using System.Collections.Generic;
+
+namespace DynamicBibleUtility.Geolocation
+{
+ ///
+ /// An index of Bible location data by location name.
+ ///
+ public class BibleLocationIndexByName
+ {
+ /// A mapping of location names to full location data.
+ public IDictionary NameToLocationLookup = new Dictionary();
+
+ ///
+ /// Creates the index from the provided locations.
+ ///
+ /// The locations to put in the index.
+ /// Thrown if the locations are null.
+ public BibleLocationIndexByName(IEnumerable locations)
+ {
+ // INDEX THE LOCATIONS BY NAME.
+ foreach (var location in locations)
+ {
+ // ONLY INDEX THE LOCATION IF IT HAS GEOGRAPHIC COORDINATES.
+ // The information currently isn't useful without these coordinates.
+ if (location.HasGeographicCoordinates)
+ {
+ NameToLocationLookup[location.Name] = location;
+ }
+ }
+ }
+ }
+}
diff --git a/DynamicBibleUtility/DynamicBibleUtility/Geolocation/BibleLocationIndexByVerse.cs b/DynamicBibleUtility/DynamicBibleUtility/Geolocation/BibleLocationIndexByVerse.cs
new file mode 100644
index 00000000..382e3376
--- /dev/null
+++ b/DynamicBibleUtility/DynamicBibleUtility/Geolocation/BibleLocationIndexByVerse.cs
@@ -0,0 +1,52 @@
+using System.Collections.Generic;
+
+namespace DynamicBibleUtility.Geolocation
+{
+ ///
+ /// An index of Bible location data by verse reference.
+ ///
+ public class BibleLocationIndexByVerse
+ {
+ ///
+ /// A mapping of verse references to location names.
+ /// The verse reference keys are stored using their short string form in order
+ /// to simplify hashing (no custom hash code implementation) and to simplify
+ /// JSON serialization (so that the short string form is only serialized).
+ /// Only the location name, rather than the full location data, is stored
+ /// since the name can be used in a parallel lookup in the .
+ ///
+ public IDictionary> VerseToLocationNameLookup = new Dictionary>();
+
+ ///
+ /// Creates the index from the provided locations.
+ ///
+ /// The locations to put in the index.
+ /// Thrown if the locations are null.
+ public BibleLocationIndexByVerse(IEnumerable locations)
+ {
+ // INDEX THE LOCATIONS BY VERSE REFERENCE.
+ foreach (var location in locations)
+ {
+ // ONLY INDEX THE LOCATION IF IT HAS GEOGRAPHIC COORDINATES.
+ // The information currently isn't useful without these coordinates.
+ if (location.HasGeographicCoordinates)
+ {
+ // INDEX THE LOCATION NAME BY ALL ITS VERSE REFERENCES.
+ foreach (var verse_reference in location.VerseReferences)
+ {
+ // MAKE SURE THE VERSE HAS AN EXISTING COLLECTION FOR LOCATION DATA.
+ string verse_reference_string = verse_reference.ToString();
+ bool verse_reference_exists_in_index = VerseToLocationNameLookup.ContainsKey(verse_reference_string);
+ if (!verse_reference_exists_in_index)
+ {
+ VerseToLocationNameLookup[verse_reference_string] = new List();
+ }
+
+ // ADD THE LOCATION NAME FOR THE VERSE.
+ VerseToLocationNameLookup[verse_reference_string].Add(location.Name);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/DynamicBibleUtility/DynamicBibleUtility/Geolocation/BibleLocationReference.cs b/DynamicBibleUtility/DynamicBibleUtility/Geolocation/BibleLocationReference.cs
new file mode 100644
index 00000000..b0a4b222
--- /dev/null
+++ b/DynamicBibleUtility/DynamicBibleUtility/Geolocation/BibleLocationReference.cs
@@ -0,0 +1,61 @@
+using System.Collections.Generic;
+using System.Linq;
+using Newtonsoft.Json;
+
+namespace DynamicBibleUtility.Geolocation
+{
+ ///
+ /// A location mentioned in the Bible, with geographic coordinates and verse references.
+ ///
+ /// Attributes are used to control serialization to minimize the amount of JSON that
+ /// gets serialized.
+ ///
+ public class BibleLocationReference
+ {
+ ///
+ /// The name of the location.
+ /// Ignored for serialization since the name is more useful separately
+ /// as a key for a property in a JavaScript object, rather than
+ /// being duplicated again in the serialized data.
+ ///
+ [JsonIgnore]
+ public string Name = "";
+ /// The latitude of the location, if available.
+ [JsonProperty("lat")]
+ public double? Latitude = null;
+ /// The longitude of the location, if available.
+ [JsonProperty("lon")]
+ public double? Longitude = null;
+ /// References to verses that mention the location.
+ [JsonIgnore]
+ public IEnumerable VerseReferences = new List();
+
+ ///
+ /// Gets references to verses that mention the location, in their short string form
+ /// as used by the Dynamic Bible app.
+ ///
+ [JsonProperty("vss")]
+ public IEnumerable VerseReferenceStrings
+ {
+ get
+ {
+ var verse_reference_strings = VerseReferences.Select(verse_reference => verse_reference.ToString());
+ return verse_reference_strings;
+ }
+ }
+
+ ///
+ /// True if this location information has full geographic coordinates; false otherwise.
+ /// Marked such that it doesn't get serialized to JSON.
+ ///
+ [JsonIgnore]
+ public bool HasGeographicCoordinates
+ {
+ get
+ {
+ bool has_geographic_coordinates = Latitude.HasValue && Longitude.HasValue;
+ return has_geographic_coordinates;
+ }
+ }
+ }
+}
diff --git a/DynamicBibleUtility/DynamicBibleUtility/Geolocation/BibleVerseReference.cs b/DynamicBibleUtility/DynamicBibleUtility/Geolocation/BibleVerseReference.cs
new file mode 100644
index 00000000..2e8f0a9e
--- /dev/null
+++ b/DynamicBibleUtility/DynamicBibleUtility/Geolocation/BibleVerseReference.cs
@@ -0,0 +1,31 @@
+using System;
+using Newtonsoft.Json;
+
+namespace DynamicBibleUtility.Geolocation
+{
+ ///
+ /// A reference to a Bible verse including a book, chapter, and verse.
+ ///
+ public class BibleVerseReference
+ {
+ /// The book of the Bible.
+ public BibleBook Book = null;
+ /// The chapter number within the book.
+ public int Chapter = 0;
+ /// The verse number within the book.
+ public int Verse = 0;
+
+ ///
+ /// Converts the verse reference to the canonical string form
+ /// for the Dynamic Bible app. This form has the numeric book,
+ /// chapter, and verse in a single colon-separated string.
+ ///
+ /// The canonical short string form of the verse reference.
+ public override string ToString()
+ {
+ int book_number = Convert.ToInt32(Book.Id);
+ string short_reference_string = $"{book_number}:{Chapter}:{Verse}";
+ return short_reference_string;
+ }
+ }
+}
diff --git a/DynamicBibleUtility/DynamicBibleUtility/Geolocation/OpenBibleDotInfoLocationParser.cs b/DynamicBibleUtility/DynamicBibleUtility/Geolocation/OpenBibleDotInfoLocationParser.cs
new file mode 100644
index 00000000..20c98415
--- /dev/null
+++ b/DynamicBibleUtility/DynamicBibleUtility/Geolocation/OpenBibleDotInfoLocationParser.cs
@@ -0,0 +1,187 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+///
+/// A namespace for code related to geolocation data for the Dynamic Bible app.
+///
+namespace DynamicBibleUtility.Geolocation
+{
+ ///
+ /// A parser for Biblical location information from openbible.info.
+ ///
+ /// Specifically, this class only handles parsing the tab-delimited
+ /// file from https://www.openbible.info/geo/data/merged.txt.
+ /// Parsing this specific file was chosen over the KMZ/KML files
+ /// because it was a much simpler way to get the relevant data.
+ /// The "merged" version of the raw data was chosen over the
+ /// "unmerged" version because it seemed to contain more data.
+ ///
+ /// The data parsed by this parser is licensed under the
+ /// Creative Commons Attribution license (see
+ /// https://www.openbible.info/geo/ and
+ /// https://creativecommons.org/licenses/by/4.0/).
+ ///
+ public class OpenBibleDotInfoLocationParser
+ {
+ ///
+ /// Parses Biblical location information from the specified file.
+ ///
+ /// The relative or absolute path to the file to parse.
+ /// Location references parsed from the file; never null.
+ /// Thrown if a parsing error occurs.
+ public static IEnumerable Parse(string filepath)
+ {
+ // READ THE ENTIRE GEOLOCATION DATA FILE.
+ // It is small enough to store completely in memory.
+ string[] geolocation_input_file_lines = File.ReadAllLines(filepath);
+
+ // PARSE EACH LINE OF GEOLOCATION DATA.
+ // The first line contains a comment and the second line contains a header,
+ // so those two lines can be skipped.
+ const int FIRST_GEOLOCATION_LINE_INDEX = 2;
+ var locations = new List();
+ for (int line_index = FIRST_GEOLOCATION_LINE_INDEX; line_index < geolocation_input_file_lines.Length; ++line_index)
+ {
+ // SPLIT THE LINE INTO SEPARATE FIELDS.
+ // Since empty fields sometimes exist in the actual data, empty entries are still included
+ // from the string splitting operation to make indexing into known fields simpler.
+ const char FIELD_SEPARATOR = '\t';
+ string current_geolocation_line = geolocation_input_file_lines[line_index];
+ string[] current_line_fields = current_geolocation_line.Split(
+ new char[] { FIELD_SEPARATOR },
+ StringSplitOptions.None);
+
+ // PARSE THE LOCATION INFORMATION FROM CURRENT LINE.
+ BibleLocationReference location = new BibleLocationReference();
+
+ // The name is converted to lowercase to make it easier to do
+ // case insensitive lookups.
+ const int BIBLE_LOCATION_NAME_FIELD_INDEX = 0;
+ location.Name = current_line_fields[BIBLE_LOCATION_NAME_FIELD_INDEX];
+ location.Name = location.Name.ToLower();
+
+ // The file contains both the name of the location as mentioned in the Bible (parsed above)
+ // and this second name for the actual location that the geographic coordinates reference.
+ // Since the geographics coordinates are expected to be close enough to the Biblical name
+ // and the primary purpose of this data is to cross-reference the Biblical text,
+ // this second name is silently ignored but could be added later if desired.
+ const int GEO_COORDINATE_LOCATION_NAME_FIELD_INDEX = 1;
+ string geo_coordinate_location_name = current_line_fields[GEO_COORDINATE_LOCATION_NAME_FIELD_INDEX];
+
+ const int LATITUDE_INDEX = 2;
+ string latitude_string = current_line_fields[LATITUDE_INDEX];
+ location.Latitude = ParseGeographicCoordinate(latitude_string);
+
+ const int LONGITUDE_INDEX = 3;
+ string longitude_string = current_line_fields[LONGITUDE_INDEX];
+ location.Longitude = ParseGeographicCoordinate(longitude_string);
+
+ const int VERSE_REFERENCES_INDEX = 4;
+ string verse_references_csv_list = current_line_fields[VERSE_REFERENCES_INDEX];
+ location.VerseReferences = ParseVerseReferences(verse_references_csv_list);
+
+ // ADD THE LOCATION INFORMATION FOR RETURNING.
+ locations.Add(location);
+ }
+
+ return locations;
+ }
+
+ ///
+ /// Attempts to parse a geographic coordinate from the specified string.
+ /// This method is necessary because not all coordinate values in the file
+ /// are necessarily completely numeric.
+ ///
+ /// The coordinate string to parse.
+ ///
+ /// The geographic coordinate, if successfully parsed.
+ /// Null only if no geographic coordinate exists (an exception is thrown
+ /// if an unexpected parsing error occurs in order to provide easier visibilty
+ /// into such errors).
+ ///
+ /// Thrown if a parsing error occurs.
+ private static double? ParseGeographicCoordinate(string coordinate_string)
+ {
+ // REMOVE ANY KNOWN NON-NUMERIC CHARACTERS FROM THE STRING.
+ // These characters are used to mark cases where the location isn't known
+ // or the location may not be exact. That exactness isn't super important
+ // in this context, so the "marker" characters are ignored.
+ string numeric_coordinate_string = coordinate_string.Trim('?', '~', '<', '>');
+
+ // A '-' is used sometimes to indicate no location. Since a '-' could also
+ // be used for a negative geographic coordinate, it can only be safely
+ // trimmed from the end.
+ numeric_coordinate_string = numeric_coordinate_string.TrimEnd('-');
+
+ // CHECK IF A COORDINATE EXISTS.
+ bool coordinate_exists = !string.IsNullOrWhiteSpace(numeric_coordinate_string);
+ if (!coordinate_exists)
+ {
+ // Not all locations in this file may have geographic coordinates.
+ return null;
+ }
+
+ // PARSE THE NUMERIC COORDINATE.
+ double coordinate = double.Parse(numeric_coordinate_string);
+ return coordinate;
+ }
+
+ ///
+ /// Attempts to parse Bible verse references from a CSV list.
+ ///
+ /// A CSV list of Bible verse references.
+ /// Each reference is expected to be separated by a comma OR a comma and single space.
+ /// The verse references from the string; an empty list if no verse references exist in the string.
+ /// Thrown if a parsing error occurs.
+ private static IEnumerable ParseVerseReferences(string verse_references_csv_list)
+ {
+ // GET THE INDIVIDUAL VERSE REFERENCE STRINGS FROM THE LIST.
+ string[] verse_reference_strings = verse_references_csv_list.Split(
+ new string[] { ", ", "," },
+ StringSplitOptions.RemoveEmptyEntries);
+
+ // PARSE EACH VERSE REFERENCE.
+ var verse_references = new List();
+ foreach (string verse_reference_string in verse_reference_strings)
+ {
+ // PARSE THE BOOK.
+ // A single space separates the book from the chapter and verse numbers.
+ // Since there might be an additional space before that separator
+ // for books with numbers at the start, a split can't be used directly.
+ const int BOOK_START_INDEX = 0;
+ int index_of_space_after_book = verse_reference_string.LastIndexOf(' ');
+ int book_string_length_in_characters = index_of_space_after_book;
+ string book_string = verse_reference_string.Substring(BOOK_START_INDEX, book_string_length_in_characters);
+ BibleBook book = new BibleBook(book_string);
+
+ // PARSE THE CHAPTER.
+ // A single colon separates the chapter and verse numbers.
+ int chapter_start_index = index_of_space_after_book + 1;
+ string chapter_and_verse_string = verse_reference_string.Substring(chapter_start_index);
+ string[] chapter_and_verse_numbers = chapter_and_verse_string.Split(
+ new char[] { ':' },
+ StringSplitOptions.RemoveEmptyEntries);
+ const int CHAPTER_INDEX = 0;
+ string chapter_string = chapter_and_verse_numbers[CHAPTER_INDEX];
+ int chapter = int.Parse(chapter_string);
+
+ // PARSE THE VERSE.
+ const int VERSE_INDEX = 1;
+ string verse_string = chapter_and_verse_numbers[VERSE_INDEX];
+ int verse = int.Parse(verse_string);
+
+ // ADD THE PARSED THE BIBLE VERSE REFERENCE.
+ BibleVerseReference verse_reference = new BibleVerseReference
+ {
+ Book = book,
+ Chapter = chapter,
+ Verse = verse
+ };
+ verse_references.Add(verse_reference);
+ }
+
+ return verse_references;
+ }
+ }
+}
diff --git a/DynamicBibleUtility/DynamicBibleUtility/frmMain.Designer.cs b/DynamicBibleUtility/DynamicBibleUtility/frmMain.Designer.cs
index 65a8d415..52d37069 100644
--- a/DynamicBibleUtility/DynamicBibleUtility/frmMain.Designer.cs
+++ b/DynamicBibleUtility/DynamicBibleUtility/frmMain.Designer.cs
@@ -28,6 +28,7 @@
///
private void InitializeComponent()
{
+ this.components = new System.ComponentModel.Container();
this.btnCreateIndex = new System.Windows.Forms.Button();
this.txtStatus = new System.Windows.Forms.TextBox();
this.btnCreateText = new System.Windows.Forms.Button();
@@ -35,13 +36,16 @@
this.btnCreateStrongsDict = new System.Windows.Forms.Button();
this.btnCreateRMAC = new System.Windows.Forms.Button();
this.btnRmacCrossRefs = new System.Windows.Forms.Button();
+ this.btnCreateGeolocationJson = new System.Windows.Forms.Button();
+ this.createGeolocationJsonTooltip = new System.Windows.Forms.ToolTip(this.components);
this.SuspendLayout();
//
// btnCreateIndex
//
- this.btnCreateIndex.Location = new System.Drawing.Point(12, 12);
+ this.btnCreateIndex.Location = new System.Drawing.Point(16, 15);
+ this.btnCreateIndex.Margin = new System.Windows.Forms.Padding(4);
this.btnCreateIndex.Name = "btnCreateIndex";
- this.btnCreateIndex.Size = new System.Drawing.Size(75, 23);
+ this.btnCreateIndex.Size = new System.Drawing.Size(100, 28);
this.btnCreateIndex.TabIndex = 0;
this.btnCreateIndex.Text = "Create Index";
this.btnCreateIndex.UseVisualStyleBackColor = true;
@@ -52,17 +56,19 @@
this.txtStatus.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
- this.txtStatus.Location = new System.Drawing.Point(13, 42);
+ this.txtStatus.Location = new System.Drawing.Point(17, 52);
+ this.txtStatus.Margin = new System.Windows.Forms.Padding(4);
this.txtStatus.Multiline = true;
this.txtStatus.Name = "txtStatus";
- this.txtStatus.Size = new System.Drawing.Size(734, 507);
+ this.txtStatus.Size = new System.Drawing.Size(1147, 623);
this.txtStatus.TabIndex = 1;
//
// btnCreateText
//
- this.btnCreateText.Location = new System.Drawing.Point(93, 12);
+ this.btnCreateText.Location = new System.Drawing.Point(124, 15);
+ this.btnCreateText.Margin = new System.Windows.Forms.Padding(4);
this.btnCreateText.Name = "btnCreateText";
- this.btnCreateText.Size = new System.Drawing.Size(75, 23);
+ this.btnCreateText.Size = new System.Drawing.Size(100, 28);
this.btnCreateText.TabIndex = 2;
this.btnCreateText.Text = "CreateText";
this.btnCreateText.UseVisualStyleBackColor = true;
@@ -70,9 +76,10 @@
//
// btnCreateStrongs
//
- this.btnCreateStrongs.Location = new System.Drawing.Point(174, 12);
+ this.btnCreateStrongs.Location = new System.Drawing.Point(232, 15);
+ this.btnCreateStrongs.Margin = new System.Windows.Forms.Padding(4);
this.btnCreateStrongs.Name = "btnCreateStrongs";
- this.btnCreateStrongs.Size = new System.Drawing.Size(144, 23);
+ this.btnCreateStrongs.Size = new System.Drawing.Size(192, 28);
this.btnCreateStrongs.TabIndex = 3;
this.btnCreateStrongs.Text = "Create Strongs Cross Refs";
this.btnCreateStrongs.UseVisualStyleBackColor = true;
@@ -80,9 +87,10 @@
//
// btnCreateStrongsDict
//
- this.btnCreateStrongsDict.Location = new System.Drawing.Point(324, 12);
+ this.btnCreateStrongsDict.Location = new System.Drawing.Point(432, 15);
+ this.btnCreateStrongsDict.Margin = new System.Windows.Forms.Padding(4);
this.btnCreateStrongsDict.Name = "btnCreateStrongsDict";
- this.btnCreateStrongsDict.Size = new System.Drawing.Size(126, 23);
+ this.btnCreateStrongsDict.Size = new System.Drawing.Size(168, 28);
this.btnCreateStrongsDict.TabIndex = 4;
this.btnCreateStrongsDict.Text = "Create Strongs Dict";
this.btnCreateStrongsDict.UseVisualStyleBackColor = true;
@@ -90,9 +98,10 @@
//
// btnCreateRMAC
//
- this.btnCreateRMAC.Location = new System.Drawing.Point(456, 12);
+ this.btnCreateRMAC.Location = new System.Drawing.Point(608, 15);
+ this.btnCreateRMAC.Margin = new System.Windows.Forms.Padding(4);
this.btnCreateRMAC.Name = "btnCreateRMAC";
- this.btnCreateRMAC.Size = new System.Drawing.Size(101, 23);
+ this.btnCreateRMAC.Size = new System.Drawing.Size(135, 28);
this.btnCreateRMAC.TabIndex = 5;
this.btnCreateRMAC.Text = "Create RMAC";
this.btnCreateRMAC.UseVisualStyleBackColor = true;
@@ -100,19 +109,33 @@
//
// btnRmacCrossRefs
//
- this.btnRmacCrossRefs.Location = new System.Drawing.Point(563, 12);
+ this.btnRmacCrossRefs.Location = new System.Drawing.Point(751, 15);
+ this.btnRmacCrossRefs.Margin = new System.Windows.Forms.Padding(4);
this.btnRmacCrossRefs.Name = "btnRmacCrossRefs";
- this.btnRmacCrossRefs.Size = new System.Drawing.Size(149, 23);
+ this.btnRmacCrossRefs.Size = new System.Drawing.Size(199, 28);
this.btnRmacCrossRefs.TabIndex = 6;
this.btnRmacCrossRefs.Text = "Create RMAC Cross Refs";
this.btnRmacCrossRefs.UseVisualStyleBackColor = true;
this.btnRmacCrossRefs.Click += new System.EventHandler(this.btnRmacCrossRefs_Click);
//
+ // btnCreateGeolocationJson
+ //
+ this.btnCreateGeolocationJson.Location = new System.Drawing.Point(957, 15);
+ this.btnCreateGeolocationJson.Name = "btnCreateGeolocationJson";
+ this.btnCreateGeolocationJson.Size = new System.Drawing.Size(207, 28);
+ this.btnCreateGeolocationJson.TabIndex = 7;
+ this.btnCreateGeolocationJson.Text = "Create Geolocation JSON";
+ this.createGeolocationJsonTooltip.SetToolTip(this.btnCreateGeolocationJson, "Creates JSON files for geolocation data from https://www.openbible.info/geo/data/" +
+ "merged.txt");
+ this.btnCreateGeolocationJson.UseVisualStyleBackColor = true;
+ this.btnCreateGeolocationJson.Click += new System.EventHandler(this.btnCreateGeolocationJson_Click);
+ //
// frmMain
//
- this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
- this.ClientSize = new System.Drawing.Size(759, 561);
+ this.ClientSize = new System.Drawing.Size(1182, 690);
+ this.Controls.Add(this.btnCreateGeolocationJson);
this.Controls.Add(this.btnRmacCrossRefs);
this.Controls.Add(this.btnCreateRMAC);
this.Controls.Add(this.btnCreateStrongsDict);
@@ -120,6 +143,7 @@
this.Controls.Add(this.btnCreateText);
this.Controls.Add(this.txtStatus);
this.Controls.Add(this.btnCreateIndex);
+ this.Margin = new System.Windows.Forms.Padding(4);
this.Name = "frmMain";
this.Text = "Dynamic Bible Utility";
this.ResumeLayout(false);
@@ -136,6 +160,8 @@
private System.Windows.Forms.Button btnCreateStrongsDict;
private System.Windows.Forms.Button btnCreateRMAC;
private System.Windows.Forms.Button btnRmacCrossRefs;
+ private System.Windows.Forms.Button btnCreateGeolocationJson;
+ private System.Windows.Forms.ToolTip createGeolocationJsonTooltip;
}
}
diff --git a/DynamicBibleUtility/DynamicBibleUtility/frmMain.cs b/DynamicBibleUtility/DynamicBibleUtility/frmMain.cs
index e9c6e19a..13fddc07 100644
--- a/DynamicBibleUtility/DynamicBibleUtility/frmMain.cs
+++ b/DynamicBibleUtility/DynamicBibleUtility/frmMain.cs
@@ -1,4 +1,5 @@
using DynamicBible.Schemas;
+using DynamicBibleUtility.Geolocation;
using JMW.Extensions.String;
using System;
using System.Collections.Generic;
@@ -647,6 +648,78 @@ namespace DynamicBibleUtility
}
}
+
#endregion RMAC
+
+ #region Geolocation JSON
+
+ ///
+ /// Handles creating geolocation JSON files when the appropriate button is clicked.
+ ///
+ /// Sender of the event; ignored.
+ /// Event arguments; ignored.
+ private void btnCreateGeolocationJson_Click(object sender, EventArgs eventArguments)
+ {
+ var _thread = new Thread(CreateGeolocationJson);
+ _thread.SetApartmentState(ApartmentState.STA);
+ _thread.IsBackground = true;
+ _thread.Start();
+ }
+
+ ///
+ /// Prompts the user for a geolocation data file ()
+ /// and converts a chosen file into the appropriate output JSON files for the Dynamic Bible app.
+ ///
+ private void CreateGeolocationJson()
+ {
+ // LET THE USER CHOOSE THE FILE WITH GEOLOCATION DATA.
+ OpenFileDialog open_file_dialog = new OpenFileDialog();
+ DialogResult file_dialog_result = open_file_dialog.ShowDialog();
+ bool file_chosen = (file_dialog_result == DialogResult.OK);
+ if (!file_chosen)
+ {
+ // The user chose not to create a file.
+ return;
+ }
+
+ try
+ {
+ // READ THE LOCATION INFORMATION FROM THE FILE.
+ IEnumerable locations = OpenBibleDotInfoLocationParser.Parse(open_file_dialog.FileName);
+ UpdateStatus($"Parsed {locations.Count()} locations.\n");
+
+ // CREATE MORE USEFUL INDICES FOR THE LOCATIONS.
+ // Indexing by name and verse references is useful for quick lookups
+ // in the Dynamic Bible app.
+ BibleLocationIndexByName locations_by_name = new BibleLocationIndexByName(locations);
+ UpdateStatus($"Finished indexing locations by name.\n");
+ BibleLocationIndexByVerse locations_by_verse = new BibleLocationIndexByVerse(locations);
+ UpdateStatus($"Finished indexing locations by verse.\n");
+
+ // WRITE OUT THE GEOLOCATION DATA TO JSON FORMAT.
+ const string LOCATIONS_BY_NAME_JSON_FILENAME = "locations_by_name.json";
+ string locations_by_name_in_json = JSON.ToJSON(locations_by_name.NameToLocationLookup);
+ File.WriteAllText(LOCATIONS_BY_NAME_JSON_FILENAME, locations_by_name_in_json);
+ UpdateStatus($"Wrote locations by name to {LOCATIONS_BY_NAME_JSON_FILENAME} in current working directory.\n");
+
+ const string LOCATIONS_BY_VERSE_JSON_FILENAME = "locations_by_verse.json";
+ string locations_by_verse_in_json = JSON.ToJSON(locations_by_verse.VerseToLocationNameLookup);
+ File.WriteAllText(LOCATIONS_BY_VERSE_JSON_FILENAME, locations_by_verse_in_json);
+ UpdateStatus($"Wrote locations by verse to {LOCATIONS_BY_VERSE_JSON_FILENAME} in current working directory.\n");
+
+ /// TODO(Jacob): Add Strong's numbers to the location data (with JavaScript property name of 'sn')
+ /// and create a lookup based on Strong's numbers. This would be more useful in the context of
+ /// the Dynamic Bible app.
+
+ // INFORM THE USER THAT CREATING THE GEOLOCATION JSON FILES IS COMPLETE.
+ UpdateStatus("Done.\n");
+ }
+ catch (Exception exception)
+ {
+ UpdateStatus($"Exception while processing geolocations: {exception}\n");
+ }
+ }
+
+ #endregion
}
}
\ No newline at end of file
diff --git a/DynamicBibleUtility/DynamicBibleUtility/frmMain.resx b/DynamicBibleUtility/DynamicBibleUtility/frmMain.resx
index 29dcb1b3..2d953a41 100644
--- a/DynamicBibleUtility/DynamicBibleUtility/frmMain.resx
+++ b/DynamicBibleUtility/DynamicBibleUtility/frmMain.resx
@@ -117,4 +117,7 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ 17, 17
+
\ No newline at end of file