001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
002 *
003 * Copyright © 2025 microBean™.
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
006 * the License. You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
011 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
012 * specific language governing permissions and limitations under the License.
013 */
014package org.microbean.bean;
015
016import java.util.ArrayList;
017import java.util.Collection;
018import java.util.Collections;
019import java.util.List;
020
021import org.microbean.attributes.Attributes;
022
023/**
024 * A {@link org.microbean.assign.Qualifiers} extended to work with commonly-used {@linkplain #anyQualifier() any},
025 * {@linkplain #defaultQualifier() default}, and {@linkplain #primordialQualifier() primordial} qualifiers.
026 *
027 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
028 *
029 * @see org.microbean.assign.Qualifiers
030 * 
031 * @see Attributes
032 */
033public class Qualifiers extends org.microbean.assign.Qualifiers {
034
035  private final Attributes ANY_QUALIFIER;
036
037  private final List<Attributes> ANY_QUALIFIERS;
038
039  private final Attributes DEFAULT_QUALIFIER;
040
041  private final List<Attributes> DEFAULT_QUALIFIERS;
042
043  private final List<Attributes> ANY_AND_DEFAULT_QUALIFIERS;
044
045  private final Attributes PRIMORDIAL_QUALIFIER;
046
047  private final List<Attributes> PRIMORDIAL_QUALIFIERS;
048
049  /**
050   * Creates a new {@link Qualifiers}.
051   */
052  public Qualifiers() {
053    super();
054    this.ANY_QUALIFIER = Attributes.of("Any", this.qualifiers());
055    this.ANY_QUALIFIERS = List.of(this.ANY_QUALIFIER);
056
057    this.DEFAULT_QUALIFIER = Attributes.of("Default", this.qualifiers());
058    this.DEFAULT_QUALIFIERS = List.of(this.DEFAULT_QUALIFIER);
059
060    this.ANY_AND_DEFAULT_QUALIFIERS = List.of(ANY_QUALIFIER, DEFAULT_QUALIFIER);
061
062    this.PRIMORDIAL_QUALIFIER = Attributes.of("Primordial", this.qualifiers());
063    this.PRIMORDIAL_QUALIFIERS = List.of(PRIMORDIAL_QUALIFIER);
064  }
065
066  /**
067   * Returns an unmodifiable {@link List} consisting solely of the unattributed <dfn>any qualifier</dfn> and the
068   * <dfn>default qualifier</dfn>.
069   *
070   * @return an unmodifiable {@link List} consisting solely of the unattributed any qualifier and the default qualifier;
071   * never {@code null}
072   *
073   * @see #anyQualifier()
074   *
075   * @see #defaultQualifier()
076   */
077  public List<Attributes> anyAndDefaultQualifiers() {
078    return ANY_AND_DEFAULT_QUALIFIERS;
079  }
080
081  /**
082   * Returns the unattributed <dfn>any qualifier</dfn>.
083   *
084   * @return the <dfn>any qualifier</dfn>; never {@code null}
085   *
086   * @see #anyQualifiers()
087   */
088  public Attributes anyQualifier() {
089    return ANY_QUALIFIER;
090  }
091
092  /**
093   * Returns {@code true} if and only if the supplied {@link Attributes} {@linkplain Attributes#equals(Object) is equal
094   * to} the unattributed {@linkplain #anyQualifier() any qualifier}.
095   *
096   * @param a an {@link Attributes}; must not be {@code null}
097   *
098   * @return {@code true} if and only if the supplied {@link Attributes} {@linkplain Attributes#equals(Object) is equal
099   * to} the unattributed {@linkplain #anyQualifier() any qualifier}
100   *
101   * @exception NullPointerException if {@code a} is {@code null}
102   */
103  public boolean anyQualifier(final Attributes a) {
104    return this.anyQualifier() == a || this.anyQualifier().equals(a) && this.qualifier(a);
105  }
106
107  /**
108   * Returns an immutable {@link List} consisting solely of the unattributed <dfn>any qualifier</dfn>.
109   *
110   * @return an immutable {@link List}; never {@code null}
111   *
112   * @see #anyQualifier()
113   */
114  public List<Attributes> anyQualifiers() {
115    return ANY_QUALIFIERS;
116  }
117
118  /**
119   * Returns the <dfn>default qualifier</dfn>.
120   *
121   * @return the <dfn>default qualifier</dfn>; never {@code null}
122   *
123   * @see #defaultQualifiers()
124   */
125  public Attributes defaultQualifier() {
126    return DEFAULT_QUALIFIER;
127  }
128
129  /**
130   * Returns {@code true} if and only if the supplied {@link Attributes} {@linkplain
131   * Attributes#equals(Object) is equal to} the {@linkplain #defaultQualifier() default qualifier}.
132   *
133   * @param a an {@link Attributes}; must not be {@code null}
134   *
135   * @return {@code true} if and only if the supplied {@link Attributes} {@linkplain
136   * Attributes#equals(Object) is equal to} the {@linkplain #defaultQualifier() default qualifier}
137   *
138   * @exception NullPointerException if {@code a} is {@code null}
139   */
140  public boolean defaultQualifier(final Attributes a) {
141    return this.defaultQualifier() == a || this.defaultQualifier().equals(a) && qualifier(a);
142  }
143
144  /**
145   * Returns an immutable {@link List} consisting solely of the <dfn>default qualifier</dfn>.
146   *
147   * @return an immutable {@link List}; never {@code null}
148   *
149   * @see #defaultQualifier()
150   */
151  public List<Attributes> defaultQualifiers() {
152    return DEFAULT_QUALIFIERS;
153  }
154
155  /**
156   * Returns an {@link Attributes} that is {@linkplain Attributes#equals(Object) equal to} the supplied {@link
157   * Attributes}.
158   *
159   * <p>The returned {@link Attributes} may be the supplied {@link Attributes} or a different instance.</p>
160   *
161   * @param a an {@link Attributes}; must not be {@code null}
162   *
163   * @return an {@link Attributes} that is {@linkplain Attributes#equals(Object) equal to} the supplied {@link
164   * Attributes}; never {@code null}
165   *
166   * @exception NullPointerException if {@code a} is {@code null}
167   */
168  public Attributes normalize(final Attributes a) {
169    return switch (a) {
170    case null -> throw new NullPointerException("a");
171    case Attributes q when this.defaultQualifier(q) -> this.defaultQualifier();
172    default -> super.normalize(a);
173    };
174  }
175
176  /**
177   * Returns an immutable {@link List} of {@link Attributes}s that is {@linkplain List#equals(Object) equal to} the
178   * supplied {@link List}.
179   *
180   * <p>The returned {@link List} may be the supplied {@link List} or a different instance.</p>
181   *
182   * @param list a {@link List} of {@link Attributes}s; must not be {@code null}
183   *
184   * @return an immutable {@link List} of {@link Attributes}s that is {@linkplain List#equals(Object) equal to} the
185   * supplied {@link List}; never {@code null}
186   *
187   * @exception NullPointerException if {@code list} is {@code null}
188   */
189  public List<Attributes> normalize(final List<Attributes> list) {
190    return switch (list.size()) {
191    case 0 -> List.of();
192    case 1 -> list.equals(this.defaultQualifiers()) ? this.defaultQualifiers() : List.copyOf(list);
193    default -> super.normalize(list);
194    };
195  }
196
197  /**
198   * Returns the <dfn>primordial qualifier</dfn>.
199   *
200   * @return the <dfn>primordial qualifier</dfn>; never {@code null}
201   *
202   * @see #primordialQualifiers()
203   */
204  public Attributes primordialQualifier() {
205    return PRIMORDIAL_QUALIFIER;
206  }
207
208  /**
209   * Returns {@code true} if and only if the supplied {@link Attributes} {@linkplain
210   * Attributes#equals(Object) is equal to} the {@linkplain #primordialQualifier() primordial qualifier}.
211   *
212   * @param a an {@link Attributes}; must not be {@code null}
213   *
214   * @return {@code true} if and only if the supplied {@link Attributes} {@linkplain
215   * Attributes#equals(Object) is equal to} the {@linkplain #primordialQualifier() primordial qualifier}
216   *
217   * @exception NullPointerException if {@code a} is {@code null}
218   */
219  public boolean primordialQualifier(final Attributes a) {
220    return this.primordialQualifier() == a || this.primordialQualifier().equals(a) && this.qualifier(a);
221  }
222
223  /**
224   * Returns an immutable {@link List} consisting solely of the <dfn>primordial qualifier</dfn>.
225   *
226   * @return an immutable {@link List}; never {@code null}
227   *
228   * @see #primordialQualifier()
229   */
230  public List<Attributes> primordialQualifiers() {
231    return PRIMORDIAL_QUALIFIERS;
232  }
233
234  /**
235   * Returns an unmodifiable {@link List} consisting only of those {@link Attributes} in the supplied {@link
236   * Collection} that {@linkplain #qualifier(Attributes) are qualifiers}.
237   *
238   * @param c a {@link Collection} of {@link Attributes}s; must not be {@code null}
239   *
240   * @return an unmodifiable {@link List} consisting only of those {@link Attributes}s in the supplied {@link
241   * Collection} that {@linkplain #qualifier(Attributes) are qualifiers}; never {@code null}
242   *
243   * @exception NullPointerException if {@code c} is {@code null}
244   */
245  public List<Attributes> qualifiers(final Collection<? extends Attributes> c) {
246    return switch (c) {
247    case Collection<?> c0 when c0.isEmpty() -> List.of();
248    case Collection<?> c0 when c0.equals(defaultQualifiers()) -> defaultQualifiers();
249    case Collection<?> c0 when c0.equals(anyAndDefaultQualifiers()) -> anyAndDefaultQualifiers();
250    default -> super.qualifiers(c);
251    };
252  }
253
254}