using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading; namespace RefererParser { /// /// Referer definition catalog /// public class Referers { public static readonly Referers Catalog = new Referers(); Lazy> _catalog; /// /// Look up a referer definition in the catalog /// /// Domain name of referer to look up. /// Referer definitions for the given domain or an empty array when no matching definitions are found. public RefererDefinition[] this[string domain] { get { var result = _catalog.Value[domain]; return result.Any() ? result.ToArray() : null; } } /// /// Private constructor, so that only one catalog can exist. /// private Referers() { _catalog = new Lazy>(() => Initialize(), LazyThreadSafetyMode.PublicationOnly); } /// /// Initialize referer catalog. /// Load referer definitions from embedded referer resource file. /// ILookup Initialize() { // Parse referer json definition file var q = from category in JObject.Parse(Encoding.UTF8.GetString(Resources.referers)).Properties() from definition in ((JObject)category.Value).Properties() let domains = definition.Value["domains"] as JArray let parameters = definition.Value["parameters"] as JArray select new RefererDefinition { Medium = ParseMedium(category.Name), Name = definition.Name, Domains = domains != null ? domains.Values().ToArray() : new string[0], Parameters = parameters != null ? parameters.Values().ToArray() : new string[0], }; // Flatten referer definition, list a definition per domain var allDomainsPerDefinition = from definition in q from domain in definition.Domains select new { Key = domain, Definition = definition }; // Generate a dictionary mapping of domains (case-insensitive) => referer definitions return allDomainsPerDefinition.ToLookup(pair => pair.Key, pair => pair.Definition, StringComparer.OrdinalIgnoreCase); } /// /// Parse a referer medium/category type /// /// Name to parse /// A referer medium value RefererMedium ParseMedium(string name) { RefererMedium value; if (!Enum.TryParse(name, true, out value)) { throw new ArgumentOutOfRangeException("name", "Unknown referer medium type: " + name); } return value; } } }