namespace UglyToad.PdfPig.Tokens { using System; using System.Collections.Generic; using System.Linq; /// /// A dictionary object is an associative table containing pairs of objects, known as the dictionary's entries. /// The key must be a and the value may be an kind of . /// public class DictionaryToken : IDataToken>, IEquatable { /// /// The key value pairs in this dictionary. /// public IReadOnlyDictionary Data { get; } /// /// Create a new . /// /// The data this dictionary will contain. public DictionaryToken(IReadOnlyDictionary data) { if (data == null) { throw new ArgumentNullException(nameof(data)); } var result = new Dictionary(data.Count); foreach (var keyValuePair in data) { result[keyValuePair.Key.Data] = keyValuePair.Value; } Data = result; } private DictionaryToken(IReadOnlyDictionary data) { Data = data; } /// /// Try and get the entry with a given name. /// /// The name of the entry to retrieve. /// The token, if it is found. /// if the token is found, otherwise. public bool TryGet(NameToken name, out IToken token) { if (name == null) { throw new ArgumentNullException(nameof(name)); } return Data.TryGetValue(name.Data, out token); } /// /// Try and get the entry with a given name and a specific data type. /// /// The expected data type of the dictionary value. /// The name of the entry to retrieve. /// The token, if it is found. /// if the token is found with this type, otherwise. public bool TryGet(NameToken name, out T token) where T : IToken { token = default(T); if (!TryGet(name, out var t) || !(t is T typedToken)) { return false; } token = typedToken; return true; } /// /// Whether the dictionary contains an entry with this name. /// /// The name to check. /// if the token is found, otherwise. public bool ContainsKey(NameToken name) { return Data.ContainsKey(name.Data); } /// /// Create a copy of this dictionary with the additional entry (or override the value of the existing entry). /// /// The key of the entry to create or override. /// The value of the entry to create or override. /// A new with the entry created or modified. public DictionaryToken With(NameToken key, IToken value) => With(key.Data, value); /// /// Create a copy of this dictionary with the additional entry (or override the value of the existing entry). /// /// The key of the entry to create or override. /// The value of the entry to create or override. /// A new with the entry created or modified. public DictionaryToken With(string key, IToken value) { if (key == null) { throw new ArgumentNullException(nameof(key)); } if (value == null) { throw new ArgumentNullException(nameof(value)); } var result = new Dictionary(Data.Count + 1); foreach (var keyValuePair in Data) { result[keyValuePair.Key] = keyValuePair.Value; } result[key] = value; return new DictionaryToken(result); } /// /// Creates a copy of this dictionary with the entry with the specified key removed (if it exists). /// /// The key of the entry to remove. /// A new with the entry removed. public DictionaryToken Without(NameToken key) => Without(key.Data); /// /// Creates a copy of this dictionary with the entry with the specified key removed (if it exists). /// /// The key of the entry to remove. /// A new with the entry removed. public DictionaryToken Without(string key) { if (key == null) { throw new ArgumentNullException(nameof(key)); } var result = new Dictionary(Data.ContainsKey(key) ? Data.Count - 1 : Data.Count); foreach (var keyValuePair in Data.Where(x => !x.Key.Equals(key))) { result[keyValuePair.Key] = keyValuePair.Value; } return new DictionaryToken(result); } /// /// Create a new . /// /// The data this dictionary will contain. public static DictionaryToken With(IReadOnlyDictionary data) { return new DictionaryToken(data ?? throw new ArgumentNullException(nameof(data))); } /// public bool Equals(IToken obj) { return Equals(obj as DictionaryToken); } /// public bool Equals(DictionaryToken other) { if (other == null) { return false; } if (ReferenceEquals(this, other)) { return true; } if (Data.Count != other.Data.Count) { return false; } foreach (var kvp in other.Data) { if (!Data.TryGetValue(kvp.Key, out var val) || !val.Equals(kvp.Value)) { return false; } } return true; } /// public override string ToString() { return string.Join(", ", Data.Select(x => $"<{x.Key}, {x.Value}>")); } } }