using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Serilog.Events; using System; using System.Collections.Generic; using System.Linq; using TINK.Model.Connector; using TINK.Services.BluetoothLock; using TINK.Model.Services.CopriApi.ServerUris; using TINK.Model.Services.Geolocation; using TINK.Settings; using TINK.ViewModel.Map; using TINK.ViewModel.Settings; namespace TINK.Model.Settings { public static class JsonSettingsDictionary { /// Title of the settings file. public const string SETTINGSFILETITLE = "Setting.Json"; /// Key of the app version entry. public const string APPVERIONKEY = "AppVersion"; /// Key of the app version entry. public const string SHOWWHATSNEWKEY = "ShowWhatsNew"; /// Key of the app version entry. public const string EXPIRESAFTER = "ExpiresAfter"; /// Key of the connect timeout. public const string CONNECTTIMEOUT = "ConnectTimeout"; /// Key of the logging level entry. public const string MINLOGGINGLEVELKEY = "MinimumLoggingLevel"; /// Key of the logging level entry. public const string ISREPORTLEVELVERBOSEKEY = "IsReportLevelVerbose"; /// Key of the center to ... entry. public const string CENTERMAPTOCURRENTLOCATION = "CenterMapToCurrentLocation"; public const string LOGTOEXTERNALFOLDER = "LogToExternalFolder"; public const string THEMEKEY = "Theme"; public const string ISSITECACHINGON = "IsSiteCachingOn"; /// Gets a nullable value. /// Dictionary to get value from. public static T? GetNullableEntry( string keyName, Dictionary settingsJSON) where T : struct { if (!settingsJSON.TryGetValue(keyName, out string boolText) || string.IsNullOrEmpty(boolText)) { // File holds no entry. return null; } return JsonConvert.DeserializeObject(boolText); } /// Gets a value to type class. /// Dictionary to get value from. public static T GetEntry( string keyName, Dictionary settingsJSON) where T : class { if (!settingsJSON.TryGetValue(keyName, out string boolText) || string.IsNullOrEmpty(boolText)) { // File holds no entry. return null; } return JsonConvert.DeserializeObject(boolText); } /// Sets a nullable. /// Entry to add to dictionary. /// Key to use for value. /// Dictionary to set value to. public static Dictionary SetEntry(T entry, string keyName, IDictionary targetDictionary) { // Set value. if (targetDictionary == null) throw new Exception($"Writing entry value {keyName} to dictionary failed. Dictionary must not be null."); return targetDictionary.Union(new Dictionary { { keyName, JsonConvert.SerializeObject(entry) } }).ToDictionary(key => key.Key, value => value.Value); } /// Sets the timeout to apply when connecting to bluetooth lock. /// Dictionary to write information to. /// Connect timeout value. public static Dictionary SetConnectTimeout( this IDictionary targetDictionary, TimeSpan connectTimeout) { if (targetDictionary == null) throw new Exception("Writing conntect timeout info failed. Dictionary must not be null."); return targetDictionary.Union(new Dictionary { { CONNECTTIMEOUT, JsonConvert.SerializeObject(connectTimeout, new JavaScriptDateTimeConverter()) } }).ToDictionary(key => key.Key, value => value.Value); } /// Sets the uri of the active copri host. /// Dictionary holding parameters from JSON. public static Dictionary SetCopriHostUri(this IDictionary p_oTargetDictionary, string p_strNextActiveUriText) { if (p_oTargetDictionary == null) throw new Exception("Writing copri host uri to dictionary failed. Dictionary must not be null."); return p_oTargetDictionary.Union(new Dictionary { { typeof(CopriServerUriList).ToString(), JsonConvert.SerializeObject(p_strNextActiveUriText) }, }).ToDictionary(key => key.Key, value => value.Value); } /// Gets the timeout to apply when connecting to bluetooth lock. /// Dictionary to get information from. /// Connect timeout value. public static TimeSpan? GetConnectTimeout(Dictionary settingsJSON) { if (!settingsJSON.TryGetValue(CONNECTTIMEOUT, out string connectTimeout) || string.IsNullOrEmpty(connectTimeout)) { // File holds no entry. return null; } return JsonConvert.DeserializeObject(connectTimeout, new JavaScriptDateTimeConverter()); } /// Gets the logging level. /// Dictionary to get logging level from. /// Logging level public static Uri GetCopriHostUri(this IDictionary settingsJSON) { // Get uri of corpi server. if (!settingsJSON.TryGetValue(typeof(CopriServerUriList).ToString(), out string uriText) || string.IsNullOrEmpty(uriText)) { // File holds no entry. return null; } return JsonConvert.DeserializeObject(uriText); } /// Sets the version of the app. /// Dictionary holding parameters from JSON. public static Dictionary SetAppVersion(this IDictionary p_oTargetDictionary, Version p_strAppVersion) { if (p_oTargetDictionary == null) throw new Exception("Writing copri host uri to dictionary failed. Dictionary must not be null."); return p_oTargetDictionary.Union(new Dictionary { {APPVERIONKEY , JsonConvert.SerializeObject(p_strAppVersion, new VersionConverter()) }, }).ToDictionary(key => key.Key, value => value.Value); } /// Gets the app versions. /// Dictionary to get logging level from. /// Logging level public static Version GetAppVersion(this IDictionary settingsJSON) { // Get the version of the app which wrote the settings file. if (!settingsJSON.TryGetValue(APPVERIONKEY, out string l_oAppVersion) || string.IsNullOrEmpty(l_oAppVersion)) { // File holds no entry. return null; } return l_oAppVersion.TrimStart().StartsWith("\"") ? JsonConvert.DeserializeObject(l_oAppVersion, new VersionConverter()) : Version.Parse(l_oAppVersion); // Format used up to version 3.0.0.115 } /// Sets whether polling is on or off and the periode if polling is on. /// Dictionary to write entries to. public static Dictionary SetPollingParameters(this IDictionary p_oTargetDictionary, PollingParameters p_oPollingParameter) { if (p_oTargetDictionary == null) throw new Exception("Writing polling parameters to dictionary failed. Dictionary must not be null."); return p_oTargetDictionary.Union(new Dictionary { { $"{typeof(PollingParameters).Name}_{typeof(TimeSpan).Name}", JsonConvert.SerializeObject(p_oPollingParameter.Periode) }, { $"{typeof(PollingParameters).Name}_{typeof(bool).Name}", JsonConvert.SerializeObject(p_oPollingParameter.IsActivated) }, }).ToDictionary(key => key.Key, value => value.Value); } /// Get whether polling is on or off and the periode if polling is on. /// Dictionary holding parameters from JSON. /// Polling parameters. public static PollingParameters GetPollingParameters(this IDictionary settingsJSON) { // Check if dictionary contains entry for periode. if (settingsJSON.TryGetValue($"{typeof(PollingParameters).Name}_{typeof(TimeSpan).Name}", out string l_strPeriode) && settingsJSON.TryGetValue($"{typeof(PollingParameters).Name}_{typeof(bool).Name}", out string l_strIsActive) && !string.IsNullOrEmpty(l_strPeriode) && !string.IsNullOrEmpty(l_strIsActive)) { return new PollingParameters( JsonConvert.DeserializeObject(l_strPeriode), JsonConvert.DeserializeObject(l_strIsActive)); } return null; } /// Saves object to file. /// Settings to save. public static void Serialize(string p_strSettingsFileFolder, IDictionary p_SettingsList) { // Save settings to file. var l_oText = JsonConvert.SerializeObject(p_SettingsList, Formatting.Indented); var l_oFolder = p_strSettingsFileFolder; System.IO.File.WriteAllText($"{l_oFolder}{System.IO.Path.DirectorySeparatorChar}{SETTINGSFILETITLE}", l_oText); } /// Gets TINK app settings form xml- file. /// Directory to read settings from. /// Dictionary of settings. public static Dictionary Deserialize(string p_strSettingsDirectory) { var l_oFileName = $"{p_strSettingsDirectory}{System.IO.Path.DirectorySeparatorChar}{SETTINGSFILETITLE}"; if (!System.IO.File.Exists(l_oFileName)) { // File is empty. Nothing to read. return new Dictionary(); ; } var l_oJSONFile = System.IO.File.ReadAllText(l_oFileName); if (string.IsNullOrEmpty(l_oJSONFile)) { // File is empty. Nothing to read. return new Dictionary(); } // Load setting file. return JsonConvert.DeserializeObject>(l_oJSONFile); } /// Gets the logging level. /// Dictionary to get logging level from. /// Logging level. public static LogEventLevel? GetMinimumLoggingLevel( Dictionary settingsJSON) { // Get logging level. if (!settingsJSON.TryGetValue(MINLOGGINGLEVELKEY, out string l_strLevel) || string.IsNullOrEmpty(l_strLevel)) { // File holds no entry. return null; } return (LogEventLevel)int.Parse(JsonConvert.DeserializeObject(l_strLevel)); } /// Gets a value indicating whether report level is verbose or not. /// Dictionary to get value from. public static bool? GetIsReportLevelVerbose(Dictionary settingsJSON) => GetNullableEntry(ISREPORTLEVELVERBOSEKEY, settingsJSON); /// Sets a value indicating whether report level is verbose or not. /// Dictionary to get value from. public static Dictionary SetIsReportLevelVerbose(this IDictionary targetDictionary, bool isReportLevelVerbose) => SetEntry(isReportLevelVerbose, ISREPORTLEVELVERBOSEKEY, targetDictionary); /// Sets the logging level. /// Dictionary to get logging level from. public static Dictionary SetMinimumLoggingLevel(this IDictionary p_oTargetDictionary, LogEventLevel p_oLevel) { // Set logging level. if (p_oTargetDictionary == null) throw new Exception("Writing logging level to dictionary failed. Dictionary must not be null."); return p_oTargetDictionary.Union(new Dictionary { { MINLOGGINGLEVELKEY, JsonConvert.SerializeObject((int)p_oLevel) } }).ToDictionary(key => key.Key, value => value.Value); } /// Gets the version of app when whats new was shown. /// Dictionary to get logging level from. /// Version of the app. public static Version GetWhatsNew(Dictionary settingsJSON) { // Get logging level. if (!settingsJSON.TryGetValue(SHOWWHATSNEWKEY, out string l_strWhatsNewVersion) || string.IsNullOrEmpty(l_strWhatsNewVersion)) { // File holds no entry. return null; } return JsonConvert.DeserializeObject(l_strWhatsNewVersion, new VersionConverter()); } /// Sets the version of app when whats new was shown. /// Dictionary to get information from. public static Dictionary SetWhatsNew(this IDictionary p_oTargetDictionary, Version p_oAppVersion) { // Set logging level. if (p_oTargetDictionary == null) throw new Exception("Writing WhatsNew info failed. Dictionary must not be null."); return p_oTargetDictionary.Union(new Dictionary { { SHOWWHATSNEWKEY, JsonConvert.SerializeObject(p_oAppVersion, new VersionConverter()) } }).ToDictionary(key => key.Key, value => value.Value); } /// Gets the expires after value. /// Dictionary to get expries after value from. /// Expires after value. public static TimeSpan? GetExpiresAfter(Dictionary settingsJSON) { if (!settingsJSON.TryGetValue(EXPIRESAFTER, out string expiresAfter) || string.IsNullOrEmpty(expiresAfter)) { // File holds no entry. return null; } return JsonConvert.DeserializeObject(expiresAfter, new JavaScriptDateTimeConverter()); } /// Sets the the expiration time. /// Dictionary to write information to. public static Dictionary SetExpiresAfter(this IDictionary p_oTargetDictionary, TimeSpan expiresAfter) { if (p_oTargetDictionary == null) throw new Exception("Writing ExpiresAfter info failed. Dictionary must not be null."); return p_oTargetDictionary.Union(new Dictionary { { EXPIRESAFTER, JsonConvert.SerializeObject(expiresAfter, new JavaScriptDateTimeConverter()) } }).ToDictionary(key => key.Key, value => value.Value); } /// Sets the active lock service name. /// Dictionary holding parameters from JSON. public static Dictionary SetActiveLockService(this IDictionary targetDictionary, string activeLockService) { if (targetDictionary == null) throw new Exception("Writing active lock service name to dictionary failed. Dictionary must not be null."); return targetDictionary.Union(new Dictionary { { typeof(ILocksService).Name, activeLockService }, }).ToDictionary(key => key.Key, value => value.Value); } /// Gets the active lock service name. /// Dictionary to get logging level from. /// Active lock service name. public static string GetActiveLockService(this IDictionary settingsJSON) { // Get uri of corpi server. if (!settingsJSON.TryGetValue(typeof(ILocksService).Name, out string activeLockService) || string.IsNullOrEmpty(activeLockService)) { // File holds no entry. return null; } if (activeLockService == "TINK.Services.BluetoothLock.BLE.LockItByScanService") { // Name of this service was switched. return typeof(TINK.Services.BluetoothLock.BLE.LockItByScanServicePolling).FullName; } return activeLockService; } /// Sets the active Geolocation service name. /// Dictionary holding parameters from JSON. public static Dictionary SetActiveGeolocationService( this IDictionary targetDictionary, string activeGeolocationService) { if (targetDictionary == null) throw new Exception("Writing active geolocation service name to dictionary failed. Dictionary must not be null."); return targetDictionary.Union(new Dictionary { { typeof(IGeolocation).Name, activeGeolocationService }, }).ToDictionary(key => key.Key, value => value.Value); } /// Gets the active Geolocation service name. /// Dictionary to get name of geolocation service from. /// Active lock service name. public static string GetActiveGeolocationService(this IDictionary settingsJSON) { // Get uri of corpi server. if (!settingsJSON.TryGetValue(typeof(IGeolocation).Name, out string activeGeolocationService) || string.IsNullOrEmpty(activeGeolocationService)) { // File holds no entry. return null; } return activeGeolocationService; } /// Gets a value indicating whether to center the map to location or not. /// Dictionary to get value from. public static bool? GetCenterMapToCurrentLocation(Dictionary settingsJSON) => GetNullableEntry(CENTERMAPTOCURRENTLOCATION, settingsJSON); /// Sets a value indicating whether to center the map to location or not. /// Dictionary to get value from. public static Dictionary SetCenterMapToCurrentLocation(this IDictionary targetDictionary, bool centerMapToCurrentLocation) => SetEntry(centerMapToCurrentLocation, CENTERMAPTOCURRENTLOCATION, targetDictionary); /// Gets whether to store logging data on SD card or not. /// Dictionary to get value from. public static bool? GetLogToExternalFolder(Dictionary settingsJSON) => GetNullableEntry(LOGTOEXTERNALFOLDER, settingsJSON); /// Gets full class name of active theme. /// Dictionary to get value from. public static string GetActiveTheme(Dictionary settingsJSON) => GetEntry(THEMEKEY, settingsJSON); /// Gets a value indicating whether site caching is on or off. /// Dictionary to get value from. public static bool? GetIsSiteCachingOn(Dictionary settingsJSON) => GetNullableEntry(ISSITECACHINGON, settingsJSON); /// Sets whether to store logging data on SD card or not. /// Dictionary to get value from. public static Dictionary SetLogToExternalFolder(this IDictionary targetDictionary, bool useSdCard) => SetEntry(useSdCard, LOGTOEXTERNALFOLDER, targetDictionary); /// Sets active theme. /// Dictionary to set value to. public static Dictionary SetActiveTheme(this IDictionary targetDictionary, string theme) => SetEntry(theme, THEMEKEY, targetDictionary); /// Sets whether site caching is on or off. /// Dictionary to get value from. public static Dictionary SetIsSiteCachingOn(this IDictionary targetDictionary, bool useSdCard) => SetEntry(useSdCard, ISSITECACHINGON, targetDictionary); /// Gets the map page filter. /// Settings objet to load from. public static IGroupFilterMapPage GetGroupFilterMapPage(this IDictionary settings) { var l_oKeyName = "FilterCollection_MapPageFilter"; if (settings == null || !settings.ContainsKey(l_oKeyName)) { return null; } return new GroupFilterMapPage(JsonConvert.DeserializeObject>(settings[l_oKeyName])); } public static IDictionary SetGroupFilterMapPage( this IDictionary settings, IDictionary p_oFilterCollection) { if (settings == null || p_oFilterCollection == null || p_oFilterCollection.Count < 1) { return settings; } settings["FilterCollection_MapPageFilter"] = JsonConvert.SerializeObject(p_oFilterCollection); return settings; } /// Gets the settings filter. /// Settings objet to load from. public static IGroupFilterSettings GetGoupFilterSettings(this IDictionary settings) { var l_oKeyName = "FilterCollection"; if (settings == null || !settings.ContainsKey(l_oKeyName)) { return null; } var legacyFilterCollection = new GroupFilterSettings(JsonConvert.DeserializeObject>(settings[l_oKeyName])); // Process legacy entries. var updatedFilterCollection = legacyFilterCollection.Where(x => x.Key.ToUpper() != "TINK.SMS" && x.Key.ToUpper() != "TINK.COPRI").ToDictionary(x => x.Key, x => x.Value); if (legacyFilterCollection.Count() <= updatedFilterCollection.Count()) { // No legacy entries "INK.SMS" or "TINK.COPRI" found. return legacyFilterCollection; } var list = updatedFilterCollection.ToList(); updatedFilterCollection.Add( "TINK", legacyFilterCollection.Any(x => x.Key.ToUpper() == "TINK.COPRI") ? legacyFilterCollection.FirstOrDefault(x => x.Key.ToUpper() == "TINK.COPRI").Value : FilterState.Off); return new GroupFilterSettings(updatedFilterCollection); } public static IDictionary SetGroupFilterSettings( this IDictionary settings, IDictionary p_oFilterCollection) { if (settings == null || p_oFilterCollection == null || p_oFilterCollection.Count < 1) { return settings; } settings["FilterCollection"] = JsonConvert.SerializeObject(p_oFilterCollection); return settings; } } }