2024-03-25 16:14:17 +00:00

83 lines
3.9 KiB
C#

namespace DynamicBibleUtility.Geolocation;
/// <summary>
/// An index of Bible location data by Strong's numbers.
/// Strong's numbers tend to be more useful for lookups in the Dynamic Bible app
/// due to how they're integrated into the rest of the app and can help more clearly
/// define a particular location.
/// This class maintains a simple lookup of Strong's numbers to location names
/// in addition to a lookup that includes the full location data.
/// </summary>
public class BibleLocationIndexByStrongsNumbers
{
/// <summary>
/// A mapping of Strong's numbers to normalized location names.
/// A Strong's number may refer to multiple locations.
/// </summary>
public readonly IDictionary<string, List<string>> StrongsNumberToLocationNameLookup = new Dictionary<string, List<string>>();
/// <summary>
/// A mapping of Strong's numbers to full location data (in JSON format).
/// A Strong's number may refer to multiple locations.
/// </summary>
public readonly IDictionary<string, List<dynamic>> StrongsNumberToLocationLookup = new Dictionary<string, List<dynamic>>();
/// <summary>
/// Creates the index from the provided locations.
/// </summary>
/// <param name="locations">The locations to put in the index.</param>
/// <exception cref="System.NullReferenceException">Thrown if the locations are null.</exception>
public BibleLocationIndexByStrongsNumbers(IEnumerable<BibleLocationReference> locations)
{
// INDEX THE LOCATIONS BY STRONG'S NUMBERS.
foreach (var location in locations)
{
// DON'T INDEX THE LOCATION IF IT HAS GEOGRAPHIC COORDINATES.
// The information currently isn't useful without these coordinates.
if (!location.HasGeographicCoordinates)
{
continue;
}
// DON'T INDEX THE LOCATION IF IT DOESN'T HAVE ANY STRONG'S NUMBERS.
var location_has_strongs_numbers = location.StrongsNumbers.Any();
if (!location_has_strongs_numbers)
{
continue;
}
// INDEX THE LOCATION BY STRONG'S NUMBERS.
foreach (var strongs_number in location.StrongsNumbers)
{
// MAKE SURE EXISTING COLLECTIONS EXIST FOR THE STRONG'S NUMBER.
var strongs_number_exists_in_index = StrongsNumberToLocationLookup.ContainsKey(strongs_number);
if (!strongs_number_exists_in_index)
{
StrongsNumberToLocationNameLookup[strongs_number] = [];
StrongsNumberToLocationLookup[strongs_number] = [];
}
// CONVERT THE LOCATION TO JSON FORMAT.
// Since the location data needs to be converted to JSON in different
// scenarios with different properties serialized, there's not an easy
// way to simply mark which fields should/shouldn't be serialized in
// all situations. While a custom JSON converter could be used,
// creating a dynamic object here seemed simpler. In this scenario,
// the Strong's number doesn't need to be included in the member data
// since it already serves as the key in the lookup.
dynamic converted_location = new
{
name = location.Name,
lat = location.Latitude,
lon = location.Longitude,
vss = location.VerseReferenceStrings,
};
// INDEX THE LOCATION BY STRONG'S NUMBER.
// Indices with just the location name and full location data are maintained.
StrongsNumberToLocationNameLookup[strongs_number].Add(location.Name);
StrongsNumberToLocationLookup[strongs_number].Add(converted_location);
}
}
}
}