using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Linq; using Runtime.ADAggregator; public sealed class ToponControllerOptions { public const string ChannelKey = "topon.channel"; public const string SubChannelKey = "topon.sub_channel"; public const string DebugKey = "topon.debug"; public const string DebuggerKeyKey = "topon.debugger_key"; public const string SDKAreaKey = "topon.sdk_area"; public const string LongitudeKey = "topon.longitude"; public const string LatitudeKey = "topon.latitude"; public const string ExcludeBundleIdsKey = "topon.exclude_bundle_ids"; public const string RewardedExcludeAdSourceIdsKey = "topon.rewarded_exclude_ad_source_ids"; public const string QueryAreaOnInitKey = "topon.query_area_on_init"; public string Channel { get; set; } public string SubChannel { get; set; } public bool? Debug { get; set; } public string DebuggerKey { get; set; } public int? SDKArea { get; set; } public double? Longitude { get; set; } public double? Latitude { get; set; } public string[] ExcludeBundleIds { get; set; } public string[] RewardedExcludeAdSourceIds { get; set; } public bool QueryAreaOnInit { get; set; } public Action OnAreaReceived { get; set; } public Action OnAreaError { get; set; } public static ToponControllerOptions Resolve(ADConfig adConfig, object[] args) { var options = new ToponControllerOptions(); options.ApplyCommonKeyValues(adConfig?.CommonKeyValues); options.ApplyLegacyArgs(args); if (args == null) { return options; } foreach (var arg in args) { switch (arg) { case ToponControllerOptions explicitOptions: options.ApplyExplicitOptions(explicitOptions); break; case IDictionary dictionary: options.ApplyDictionary(dictionary); break; } } return options; } private void ApplyCommonKeyValues(List keyValues) { if (keyValues == null || keyValues.Count == 0) { return; } var map = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (var keyValue in keyValues) { if (keyValue == null || string.IsNullOrWhiteSpace(keyValue.key)) { continue; } map[keyValue.key] = keyValue.value; } Channel = GetString(map, ChannelKey, "channel") ?? Channel; SubChannel = GetString(map, SubChannelKey, "sub_channel") ?? SubChannel; Debug = GetBool(map, DebugKey, "debug") ?? Debug; DebuggerKey = GetString(map, DebuggerKeyKey) ?? DebuggerKey; SDKArea = GetInt(map, SDKAreaKey) ?? SDKArea; Longitude = GetDouble(map, LongitudeKey) ?? Longitude; Latitude = GetDouble(map, LatitudeKey) ?? Latitude; ExcludeBundleIds = GetStringArray(map, ExcludeBundleIdsKey) ?? ExcludeBundleIds; RewardedExcludeAdSourceIds = GetStringArray(map, RewardedExcludeAdSourceIdsKey) ?? RewardedExcludeAdSourceIds; QueryAreaOnInit = GetBool(map, QueryAreaOnInitKey) ?? QueryAreaOnInit; } private void ApplyLegacyArgs(object[] args) { if (args == null || args.Length == 0) { return; } if (args.Length > 0 && args[0] is string channel) { Channel = channel; } if (args.Length > 1 && TryConvertBool(args[1], out var debug)) { Debug = debug; } } private void ApplyExplicitOptions(ToponControllerOptions explicitOptions) { if (explicitOptions == null) { return; } Channel = explicitOptions.Channel ?? Channel; SubChannel = explicitOptions.SubChannel ?? SubChannel; Debug = explicitOptions.Debug ?? Debug; DebuggerKey = explicitOptions.DebuggerKey ?? DebuggerKey; SDKArea = explicitOptions.SDKArea ?? SDKArea; Longitude = explicitOptions.Longitude ?? Longitude; Latitude = explicitOptions.Latitude ?? Latitude; ExcludeBundleIds = explicitOptions.ExcludeBundleIds ?? ExcludeBundleIds; RewardedExcludeAdSourceIds = explicitOptions.RewardedExcludeAdSourceIds ?? RewardedExcludeAdSourceIds; QueryAreaOnInit = explicitOptions.QueryAreaOnInit || QueryAreaOnInit; OnAreaReceived = explicitOptions.OnAreaReceived ?? OnAreaReceived; OnAreaError = explicitOptions.OnAreaError ?? OnAreaError; } private void ApplyDictionary(IDictionary dictionary) { if (dictionary == null || dictionary.Count == 0) { return; } var map = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (DictionaryEntry entry in dictionary) { if (entry.Key == null) { continue; } map[entry.Key.ToString()] = ConvertDictionaryValue(entry.Value); } Channel = GetString(map, ChannelKey, "channel") ?? Channel; SubChannel = GetString(map, SubChannelKey, "sub_channel") ?? SubChannel; Debug = GetBool(map, DebugKey, "debug") ?? Debug; DebuggerKey = GetString(map, DebuggerKeyKey) ?? DebuggerKey; SDKArea = GetInt(map, SDKAreaKey) ?? SDKArea; Longitude = GetDouble(map, LongitudeKey) ?? Longitude; Latitude = GetDouble(map, LatitudeKey) ?? Latitude; ExcludeBundleIds = GetStringArray(map, ExcludeBundleIdsKey) ?? ExcludeBundleIds; RewardedExcludeAdSourceIds = GetStringArray(map, RewardedExcludeAdSourceIdsKey) ?? RewardedExcludeAdSourceIds; QueryAreaOnInit = GetBool(map, QueryAreaOnInitKey) ?? QueryAreaOnInit; } private static string GetString(IDictionary map, params string[] keys) { foreach (var key in keys) { if (!string.IsNullOrWhiteSpace(key) && map.TryGetValue(key, out var value) && !string.IsNullOrWhiteSpace(value)) { return value.Trim(); } } return null; } private static bool? GetBool(IDictionary map, params string[] keys) { var value = GetString(map, keys); return TryConvertBool(value, out var result) ? result : null; } private static int? GetInt(IDictionary map, params string[] keys) { var value = GetString(map, keys); if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { return result; } return null; } private static double? GetDouble(IDictionary map, params string[] keys) { var value = GetString(map, keys); if (double.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var result)) { return result; } return null; } private static string[] GetStringArray(IDictionary map, params string[] keys) { var value = GetString(map, keys); if (string.IsNullOrWhiteSpace(value)) { return null; } var normalized = value.Replace("[", string.Empty) .Replace("]", string.Empty) .Replace("\"", string.Empty) .Replace("'", string.Empty); var items = normalized .Split(new[] { ',', ';', '|', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) .Select(item => item.Trim()) .Where(item => !string.IsNullOrWhiteSpace(item)) .Distinct(StringComparer.OrdinalIgnoreCase) .ToArray(); return items.Length > 0 ? items : null; } private static bool TryConvertBool(object value, out bool result) { switch (value) { case bool boolValue: result = boolValue; return true; case string stringValue: if (bool.TryParse(stringValue, out result)) { return true; } if (string.Equals(stringValue, "1", StringComparison.OrdinalIgnoreCase)) { result = true; return true; } if (string.Equals(stringValue, "0", StringComparison.OrdinalIgnoreCase)) { result = false; return true; } break; } result = false; return false; } private static string ConvertDictionaryValue(object value) { if (value == null) { return null; } if (value is string stringValue) { return stringValue; } if (value is IEnumerable enumerable) { var items = new List(); foreach (var item in enumerable) { if (item == null) { continue; } items.Add(item.ToString()); } return string.Join(",", items); } return value.ToString(); } }