1+ /*==============================================================================================================================
2+ | Author Ignia, LLC
3+ | Client Ignia, LLC
4+ | Project Topics Library
5+ \=============================================================================================================================*/
6+ using System ;
7+ using System . Collections ;
8+ using System . Collections . Generic ;
9+ using System . Collections . ObjectModel ;
10+ using System . Diagnostics . CodeAnalysis ;
11+ using System . Linq ;
12+ using OnTopic . Internal . Diagnostics ;
13+
14+ #pragma warning disable CA1710 // Identifiers should have correct suffix
15+
16+ namespace OnTopic . Collections {
17+
18+ /*============================================================================================================================
19+ | CLASS: READ-ONLY TOPIC MULTIMAP
20+ \---------------------------------------------------------------------------------------------------------------------------*/
21+ /// <summary>
22+ /// The <see cref="ReadOnlyTopicMultiMap"/> provides a read-only façade to a <see cref="TopicMultiMap"/>.
23+ /// </summary>
24+ public class ReadOnlyTopicMultiMap : IEnumerable < KeyValuesPair < string , ReadOnlyCollection < Topic > > > {
25+
26+ /*==========================================================================================================================
27+ | CONSTRUCTOR
28+ \-------------------------------------------------------------------------------------------------------------------------*/
29+ /// <summary>
30+ /// Constructs a new instance of a <see cref="ReadOnlyTopicMultiMap"/> class with a reference to an underlying <see cref=
31+ /// "TopicMultiMap"/> instance.
32+ /// </summary>
33+ public ReadOnlyTopicMultiMap ( TopicMultiMap source ) {
34+ Contract . Requires ( source , nameof ( source ) ) ;
35+ Source = source ;
36+ }
37+
38+ /// <summary>
39+ /// Constructs a new instance of a <see cref="ReadOnlyTopicMultiMap"/> class.
40+ /// </summary>
41+ /// <remarks>
42+ /// The <see cref="ReadOnlyTopicMultiMap"/> requires an underlying <see cref="Source"/> <see cref="TopicMultiMap"/> to
43+ /// derive values from. It's normally expected that callers will pass that via the public <see cref="
44+ /// ReadOnlyTopicMultiMap(TopicMultiMap)"/> constructor. Derived classes, however, cannot pass instance parameters to a
45+ /// base class. As such, the protected <see cref="ReadOnlyTopicMultiMap()"/> constructor allows the derived class to
46+ /// intialize the <see cref="ReadOnlyTopicMultiMap"/> without a <see cref="Source"/>—but expects that it will immediately
47+ /// set one via its constructor.
48+ /// </remarks>
49+ protected ReadOnlyTopicMultiMap ( ) { }
50+
51+ /*==========================================================================================================================
52+ | PROPERTY: SOURCE
53+ \-------------------------------------------------------------------------------------------------------------------------*/
54+ /// <summary>
55+ /// Provides access to the underlying <see cref="TopicMultiMap"/> from which the <see cref="ReadOnlyTopicMultiMap"/> will
56+ /// derive values.
57+ /// </summary>
58+ /// <returns>
59+ /// The <see cref="Source"/> must be passed in via either the public <see cref="ReadOnlyTopicMultiMap(TopicMultiMap)"/>
60+ /// constructor, or must be set manually from the constructor of a derived class when using the protected <see cref="
61+ /// ReadOnlyTopicMultiMap()"/> constructor.
62+ /// </returns>
63+ [ NotNull , DisallowNull ]
64+ protected TopicMultiMap ? Source { get ; init ; }
65+
66+ /*==========================================================================================================================
67+ | PROPERTY: KEYS
68+ \-------------------------------------------------------------------------------------------------------------------------*/
69+ /// <summary>
70+ /// Retrieves a list of keys available for the available collections.
71+ /// </summary>
72+ /// <returns>
73+ /// Returns an enumerable list of keys.
74+ /// </returns>
75+ public IEnumerable < string > Keys => Source . Select ( m => m . Key ) . ToList ( ) ;
76+
77+ /*==========================================================================================================================
78+ | PROPERTY: VALUES
79+ \-------------------------------------------------------------------------------------------------------------------------*/
80+ /// <summary>
81+ /// Retrieves a list of values available for the available collections.
82+ /// </summary>
83+ /// <returns>
84+ /// Returns an enumerable list of <see cref="ReadOnlyCollection{Topic}"/> instances.
85+ /// </returns>
86+ public IEnumerable < ReadOnlyCollection < Topic > > Values => Source . Select ( m => new ReadOnlyCollection < Topic > ( m . Values ) ) ;
87+
88+ /*==========================================================================================================================
89+ | PROPERTY: COUNT
90+ \-------------------------------------------------------------------------------------------------------------------------*/
91+ /// <summary>
92+ /// Retrieves a count of items in the source collection.
93+ /// </summary>
94+ /// <returns>
95+ /// The number of collections in the underlying source collection.
96+ /// </returns>
97+ public int Count => Source . Count ;
98+
99+ /*==========================================================================================================================
100+ | INDEXER
101+ \-------------------------------------------------------------------------------------------------------------------------*/
102+ /// <summary>
103+ /// Retrieves a <see cref="ReadOnlyCollection{Topic}"/> collection from the source collection based on the <paramref
104+ /// name="key"/>.
105+ /// </summary>
106+ /// <returns>
107+ /// A <see cref="ReadOnlyCollection{Topic}"/> collection.
108+ /// </returns>
109+ public ReadOnlyCollection < Topic > this [ string key ] => new ( Source [ key ] . Values ) ;
110+
111+ /*==========================================================================================================================
112+ | METHOD: CONTAINS?
113+ \-------------------------------------------------------------------------------------------------------------------------*/
114+ /// <inheritdoc cref="KeyedCollection{TKey, TItem}.Contains(TKey)" />
115+ public bool Contains ( string key ) => Source . Contains ( key ) ;
116+
117+ /// <inheritdoc cref="TopicMultiMap.Contains(String, Topic)" />
118+ public bool Contains ( string key , Topic topic ) => Source . Contains ( key , topic ) ;
119+
120+ /*==========================================================================================================================
121+ | METHOD: GET TOPICS
122+ \-------------------------------------------------------------------------------------------------------------------------*/
123+ /// <summary>
124+ /// Retrieves a list of <see cref="Topic"/> objects grouped by a specific <paramref name="key"/>.
125+ /// </summary>
126+ /// <remarks>
127+ /// Returns a reference to the underlying <see cref="Collection{Topic}"/> collection.
128+ /// </remarks>
129+ /// <param name="key">The key of the collection to be returned.</param>
130+ public ReadOnlyCollection < Topic > GetTopics ( string key ) {
131+ Contract . Requires < ArgumentNullException > ( ! String . IsNullOrWhiteSpace ( key ) , nameof ( key ) ) ;
132+ if ( Contains ( key ) ) {
133+ return new ( Source [ key ] . Values ) ;
134+ }
135+ return new ( new List < Topic > ( ) ) ;
136+ }
137+
138+ /*==========================================================================================================================
139+ | METHOD: GET ALL TOPICS
140+ \-------------------------------------------------------------------------------------------------------------------------*/
141+ /// <summary>
142+ /// Retrieves a list of all related <see cref="Topic"/> objects, independent of collection key.
143+ /// </summary>
144+ /// <returns>
145+ /// Returns an enumerable list of <see cref="Topic"/> objects.
146+ /// </returns>
147+ public ReadOnlyCollection < Topic > GetAllTopics ( ) =>
148+ Source . SelectMany ( list => list . Values ) . Distinct ( ) . ToList ( ) . AsReadOnly ( ) ;
149+
150+ /// <summary>
151+ /// Retrieves a list of all related <see cref="Topic"/> objects, independent of relationship key, filtered by content
152+ /// type.
153+ /// </summary>
154+ /// <returns>
155+ /// Returns an enumerable list of <see cref="Topic"/> objects.
156+ /// </returns>
157+ public ReadOnlyCollection < Topic > GetAllTopics ( string contentType ) =>
158+ GetAllTopics ( ) . Where ( t => t . ContentType == contentType ) . ToList ( ) . AsReadOnly ( ) ;
159+
160+ /*==========================================================================================================================
161+ | GET ENUMERATOR
162+ \-------------------------------------------------------------------------------------------------------------------------*/
163+ /// <inheritdoc/>
164+ public IEnumerator < KeyValuesPair < string , ReadOnlyCollection < Topic > > > GetEnumerator ( ) {
165+ foreach ( var collection in Source ) {
166+ yield return new ( collection . Key , new ( collection . Values ) ) ;
167+ }
168+ }
169+
170+ /// <inheritdoc/>
171+ IEnumerator IEnumerable . GetEnumerator ( ) => Source . GetEnumerator ( ) ;
172+
173+ } //Class
174+ } //Namespace
175+
176+ #pragma warning restore CA1710 // Identifiers should have correct suffix
0 commit comments