001/*
002 * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.  Oracle designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Oracle in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022 * or visit www.oracle.com if you need additional information or have any
023 * questions.
024 */
025
026package org.jdrupes.mdoclet.internal.doclets.formats.html;
027
028import java.util.Collection;
029import java.util.EnumMap;
030import java.util.Objects;
031import java.util.regex.Matcher;
032import java.util.regex.Pattern;
033
034import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.ContentBuilder;
035import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.Entity;
036import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.Text;
037import org.jdrupes.mdoclet.internal.doclets.toolkit.Content;
038import org.jdrupes.mdoclet.internal.doclets.toolkit.Resources;
039import org.jdrupes.mdoclet.internal.doclets.toolkit.util.VisibleMemberTable;
040
041/**
042 * Constants and factory methods for common fragments of content
043 * used by HtmlDoclet. The string content of these fragments is
044 * generally obtained from the {@link Resources resources} found
045 * in the doclet's configuration.
046 *
047 * @implNote
048 * Many constants are made available in this class, so that they are
049 * only created once per doclet-instance, instead of once per generated page.
050 */
051public class Contents {
052
053    public final Content allClassesAndInterfacesLabel;
054    public final Content allImplementedInterfacesLabel;
055    public final Content allModulesLabel;
056    public final Content allPackagesLabel;
057    public final Content allSuperinterfacesLabel;
058    public final Content also;
059    public final Content annotationTypeOptionalMemberLabel;
060    public final Content annotationTypeRequiredMemberLabel;
061    public final Content annotateTypeOptionalMemberSummaryLabel;
062    public final Content annotateTypeRequiredMemberSummaryLabel;
063    public final Content annotationType;
064    public final Content annotationTypeDetailsLabel;
065    public final Content annotationTypeMemberDetail;
066    public final Content annotationtypes;
067    public final Content annotationTypes;
068    public final Content classLabel;
069    public final Content classes;
070    public final Content constantFieldLabel;
071    public final Content constantsSummaryTitle;
072    public final Content constructorLabel;
073    public final Content constructorDetailsLabel;
074    public final Content constructorSummaryLabel;
075    public final Content constructors;
076    public final Content contentsHeading;
077    public final Content defaultPackageLabel;
078    public final Content default_;
079    public final Content deprecatedAPI;
080    public final Content deprecatedLabel;
081    public final Content deprecatedPhrase;
082    public final Content deprecatedForRemovalPhrase;
083    public final Content descriptionFromClassLabel;
084    public final Content descriptionFromInterfaceLabel;
085    public final Content descriptionLabel;
086    public final Content detailLabel;
087    public final Content enclosingClassLabel;
088    public final Content enclosingInterfaceLabel;
089    public final Content enumConstantLabel;
090    public final Content enumConstantDetailLabel;
091    public final Content enumConstantSummary;
092    public final Content enum_;
093    public final Content enums;
094    public final Content exceptionClass;
095    public final Content exceptionClasses;
096    public final Content exportedTo;
097    public final Content externalSpecifications;
098    public final Content fieldLabel;
099    public final Content fieldDetailsLabel;
100    public final Content fieldSummaryLabel;
101    public final Content fields;
102    public final Content fromLabel;
103    public final Content functionalInterface;
104    public final Content functionalInterfaceMessage;
105    public final Content helpLabel;
106    public final Content helpSubNavLabel;
107    public final Content hierarchyForAllPackages;
108    public final Content implementation;
109    public final Content implementingClassesLabel;
110    public final Content inClass;
111    public final Content inInterface;
112    public final Content indexLabel;
113    public final Content interfaceLabel;
114    public final Content interfaces;
115    public final Content methodDetailLabel;
116    public final Content methodLabel;
117    public final Content methodSummary;
118    public final Content methods;
119    public final Content modifierAndTypeLabel;
120    public final Content modifierLabel;
121    public final Content moduleLabel;
122    public final Content module_;
123    public final Content moduleSubNavLabel;
124    public final Content modulesLabel;
125    public final Content navAnnotationTypeMember;
126    public final Content navAnnotationTypeOptionalMember;
127    public final Content navAnnotationTypeRequiredMember;
128    public final Content navClassesAndInterfaces;
129    public final Content navConstructor;
130    public final Content navDescription;
131    public final Content navEnum;
132    public final Content navField;
133    public final Content navHelpNavigation;
134    public final Content navHelpPages;
135    public final Content navMethod;
136    public final Content navModules;
137    public final Content navNested;
138    public final Content navPackages;
139    public final Content navProperty;
140    public final Content navServices;
141    public final Content nestedClassSummary;
142    public final Content newAPI;
143    public final Content newLabel;
144    public final Content noScriptMessage;
145    public final Content openModuleLabel;
146    public final Content openedTo;
147    public final Content overridesLabel;
148    public final Content overviewLabel;
149    public final Content packageHierarchies;
150    public final Content packageLabel;
151    public final Content package_;
152    public final Content packagesLabel;
153    public final Content packageSubNavLabel;
154    public final Content packageSummaryLabel;
155    public final Content parameters;
156    public final Content previewAPI;
157    public final Content previewLabel;
158    public final Content previewMark;
159    public final Content previewPhrase;
160    public final Content properties;
161    public final Content propertyLabel;
162    public final Content propertyDetailsLabel;
163    public final Content propertySummaryLabel;
164    public final Content records;
165    public final Content recordComponents;
166    public final Content referencedIn;
167    public final Content relatedPackages;
168    public final Content returns;
169    public final Content seeAlso;
170    public final Content serializedForm;
171    public final Content servicesLabel;
172    public final Content specificationLabel;
173    public final Content specifiedByLabel;
174    public final Content subclassesLabel;
175    public final Content subinterfacesLabel;
176    public final Content summaryLabel;
177    public final Content systemPropertiesLabel;
178    public final Content systemPropertiesSummaryLabel;
179    public final Content throws_;
180    public final Content treeLabel;
181    public final Content typeLabel;
182    public final Content typeParameters;
183    public final Content useLabel;
184    public final Content valueLabel;
185
186    private final EnumMap<VisibleMemberTable.Kind, Content> navLinkLabels;
187
188    private final Resources resources;
189
190    /**
191     * Creates a {@code Contents} object.
192     *
193     * @param configuration the configuration in which to find the
194     * resources used to look up resource keys, and other details.
195     */
196    Contents(HtmlConfiguration configuration) {
197        this.resources = configuration.getDocResources();
198
199        this.allClassesAndInterfacesLabel
200            = getContent("doclet.All_Classes_And_Interfaces");
201        allImplementedInterfacesLabel
202            = getContent("doclet.All_Implemented_Interfaces");
203        allModulesLabel = getNonBreakResource("doclet.All_Modules");
204        allPackagesLabel = getNonBreakResource("doclet.All_Packages");
205        allSuperinterfacesLabel = getContent("doclet.All_Superinterfaces");
206        also = getContent("doclet.also");
207        annotationTypeOptionalMemberLabel
208            = getContent("doclet.Annotation_Type_Optional_Member");
209        annotationTypeRequiredMemberLabel
210            = getContent("doclet.Annotation_Type_Required_Member");
211        annotateTypeOptionalMemberSummaryLabel
212            = getContent("doclet.Annotation_Type_Optional_Member_Summary");
213        annotateTypeRequiredMemberSummaryLabel
214            = getContent("doclet.Annotation_Type_Required_Member_Summary");
215        annotationType = getContent("doclet.AnnotationType");
216        annotationTypeDetailsLabel
217            = getContent("doclet.Annotation_Type_Member_Detail");
218        annotationTypeMemberDetail
219            = getContent("doclet.Annotation_Type_Member_Detail");
220        annotationTypes = getContent("doclet.AnnotationTypes");
221        annotationtypes = getContent("doclet.annotationtypes");
222        classLabel = getContent("doclet.Class");
223        classes = getContent("doclet.Classes");
224        constantFieldLabel = getContent("doclet.ConstantField");
225        constantsSummaryTitle = getContent("doclet.Constants_Summary");
226        constructorLabel = getContent("doclet.Constructor");
227        constructorDetailsLabel = getContent("doclet.Constructor_Detail");
228        constructorSummaryLabel = getContent("doclet.Constructor_Summary");
229        constructors = getContent("doclet.Constructors");
230        contentsHeading = getContent("doclet.Contents");
231        defaultPackageLabel = getContent("doclet.Unnamed_Package");
232        default_ = getContent("doclet.Default");
233        deprecatedAPI = getContent("doclet.Deprecated_API");
234        deprecatedLabel = getContent("doclet.navDeprecated");
235        deprecatedPhrase = getContent("doclet.Deprecated");
236        deprecatedForRemovalPhrase = getContent("doclet.DeprecatedForRemoval");
237        descriptionFromClassLabel = getContent("doclet.Description_From_Class");
238        descriptionFromInterfaceLabel
239            = getContent("doclet.Description_From_Interface");
240        descriptionLabel = getContent("doclet.Description");
241        detailLabel = getContent("doclet.Detail");
242        enclosingClassLabel = getContent("doclet.Enclosing_Class");
243        enclosingInterfaceLabel = getContent("doclet.Enclosing_Interface");
244        enumConstantLabel = getContent("doclet.Enum_Constant");
245        enumConstantDetailLabel = getContent("doclet.Enum_Constant_Detail");
246        enumConstantSummary = getContent("doclet.Enum_Constant_Summary");
247        enum_ = getContent("doclet.Enum");
248        enums = getContent("doclet.Enums");
249        exceptionClass = getContent("doclet.ExceptionClass");
250        exceptionClasses = getContent("doclet.ExceptionClasses");
251        exportedTo = getContent("doclet.ExportedTo");
252        externalSpecifications = getContent("doclet.External_Specifications");
253        fieldDetailsLabel = getContent("doclet.Field_Detail");
254        fieldSummaryLabel = getContent("doclet.Field_Summary");
255        fieldLabel = getContent("doclet.Field");
256        fields = getContent("doclet.Fields");
257        fromLabel = getContent("doclet.From");
258        functionalInterface = getContent("doclet.Functional_Interface");
259        functionalInterfaceMessage
260            = getContent("doclet.Functional_Interface_Message");
261        helpLabel = getContent("doclet.Help");
262        helpSubNavLabel = getContent("doclet.Help_Sub_Nav");
263        hierarchyForAllPackages
264            = getContent("doclet.Hierarchy_For_All_Packages");
265        implementation = getContent("doclet.Implementation");
266        implementingClassesLabel = getContent("doclet.Implementing_Classes");
267        inClass = getContent("doclet.in_class");
268        inInterface = getContent("doclet.in_interface");
269        indexLabel = getContent("doclet.Index");
270        interfaceLabel = getContent("doclet.Interface");
271        interfaces = getContent("doclet.Interfaces");
272        methodDetailLabel = getContent("doclet.Method_Detail");
273        methodSummary = getContent("doclet.Method_Summary");
274        methodLabel = getContent("doclet.Method");
275        methods = getContent("doclet.Methods");
276        modifierLabel = getContent("doclet.Modifier");
277        modifierAndTypeLabel = getContent("doclet.Modifier_and_Type");
278        moduleLabel = getContent("doclet.Module");
279        module_ = getContent("doclet.module");
280        moduleSubNavLabel = getContent("doclet.Module_Sub_Nav");
281        modulesLabel = getContent("doclet.Modules");
282        navAnnotationTypeMember = getContent("doclet.navAnnotationTypeMember");
283        navAnnotationTypeOptionalMember
284            = getContent("doclet.navAnnotationTypeOptionalMember");
285        navAnnotationTypeRequiredMember
286            = getContent("doclet.navAnnotationTypeRequiredMember");
287        navClassesAndInterfaces = getContent("doclet.navClassesAndInterfaces");
288        navConstructor = getContent("doclet.navConstructor");
289        navEnum = getContent("doclet.navEnum");
290        navField = getContent("doclet.navField");
291        navHelpNavigation = getContent("doclet.navNavigation");
292        navHelpPages = getContent("doclet.navPages");
293        navMethod = getContent("doclet.navMethod");
294        navDescription = getContent("doclet.navDescription");
295        navModules = getContent("doclet.navModules");
296        navNested = getContent("doclet.navNested");
297        navPackages = getContent("doclet.navPackages");
298        navProperty = getContent("doclet.navProperty");
299        navServices = getContent("doclet.navServices");
300        nestedClassSummary = getContent("doclet.Nested_Class_Summary");
301        newAPI = getContent("doclet.New_API");
302        newLabel = getContent("doclet.New_Label");
303        noScriptMessage = getContent("doclet.No_Script_Message");
304        openedTo = getContent("doclet.OpenedTo");
305        openModuleLabel = getContent("doclet.Open_Module");
306        overridesLabel = getContent("doclet.Overrides");
307        overviewLabel = getContent("doclet.Overview");
308        packageHierarchies = getContent("doclet.Package_Hierarchies");
309        packageLabel = getContent("doclet.Package");
310        package_ = getContent("doclet.package");
311        packagesLabel = getContent("doclet.Packages");
312        packageSubNavLabel = getContent("doclet.Package_Sub_Nav");
313        this.packageSummaryLabel = getContent("doclet.Package_Summary");
314        parameters = getContent("doclet.Parameters");
315        previewAPI = getContent("doclet.Preview_API");
316        previewLabel = getContent("doclet.Preview_Label");
317        previewMark = getContent("doclet.Preview_Mark");
318        previewPhrase = getContent("doclet.Preview");
319        properties = getContent("doclet.Properties");
320        propertyLabel = getContent("doclet.Property");
321        propertyDetailsLabel = getContent("doclet.Property_Detail");
322        propertySummaryLabel = getContent("doclet.Property_Summary");
323        records = getContent("doclet.RecordClasses");
324        recordComponents = getContent("doclet.RecordComponents");
325        referencedIn = getContent("doclet.ReferencedIn");
326        relatedPackages = getContent("doclet.Related_Packages");
327        returns = getContent("doclet.Returns");
328        seeAlso = getContent("doclet.See_Also");
329        serializedForm = getContent("doclet.Serialized_Form");
330        servicesLabel = getContent("doclet.Services");
331        specificationLabel = getContent("doclet.Specification");
332        specifiedByLabel = getContent("doclet.Specified_By");
333        subclassesLabel = getContent("doclet.Subclasses");
334        subinterfacesLabel = getContent("doclet.Subinterfaces");
335        summaryLabel = getContent("doclet.Summary");
336        systemPropertiesLabel = getContent("doclet.systemProperties");
337        systemPropertiesSummaryLabel
338            = getContent("doclet.systemPropertiesSummary");
339        throws_ = getContent("doclet.Throws");
340        treeLabel = getContent("doclet.Tree");
341        typeLabel = getContent("doclet.Type");
342        typeParameters = getContent("doclet.TypeParameters");
343        useLabel = getContent("doclet.navClassUse");
344        valueLabel = getContent("doclet.Value");
345
346        navLinkLabels = new EnumMap<>(VisibleMemberTable.Kind.class);
347        navLinkLabels.put(VisibleMemberTable.Kind.NESTED_CLASSES,
348            getContent("doclet.navNested"));
349        navLinkLabels.put(VisibleMemberTable.Kind.ENUM_CONSTANTS,
350            getContent("doclet.navEnum"));
351        navLinkLabels.put(VisibleMemberTable.Kind.FIELDS,
352            getContent("doclet.navField"));
353        navLinkLabels.put(VisibleMemberTable.Kind.CONSTRUCTORS,
354            getContent("doclet.navConstructor"));
355        navLinkLabels.put(VisibleMemberTable.Kind.METHODS,
356            getContent("doclet.navMethod"));
357        navLinkLabels.put(
358            VisibleMemberTable.Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL,
359            getContent("doclet.navAnnotationTypeOptionalMember"));
360        navLinkLabels.put(
361            VisibleMemberTable.Kind.ANNOTATION_TYPE_MEMBER_REQUIRED,
362            getContent("doclet.navAnnotationTypeRequiredMember"));
363    }
364
365    /**
366     * Gets a {@code Content} object, containing the string for
367     * a given key in the doclet's resources.
368     *
369     * @param key the key for the desired string
370     * @return the string
371     */
372    public Content getContent(String key) {
373        return Text.of(resources.getText(key));
374    }
375
376    /**
377     * Gets a {@code Content} object, containing the string for
378     * a given key in the doclet's resources, formatted with
379     * given arguments.
380     *
381     * @param key the key for the desired string
382     * @param o0  string or content argument to be formatted into the result
383     * @return the string
384     */
385    public Content getContent(String key, Object o0) {
386        return getContent(key, o0, null, null);
387    }
388
389    /**
390     * Gets a {@code Content} object, containing the string for
391     * a given key in the doclet's resources, formatted with
392     * given arguments.
393    
394     * @param key the key for the desired string
395     * @param o0  string or content argument to be formatted into the result
396     * @param o1  string or content argument to be formatted into the result
397     * @return the string
398     */
399    public Content getContent(String key, Object o0, Object o1) {
400        return getContent(key, o0, o1, null);
401    }
402
403    /**
404     * Gets a {@code Content} object, containing the string for
405     * a given key in the doclet's resources, formatted with
406     * given arguments.
407     *
408     * @param key the key for the desired string
409     * @param o0  string or content argument to be formatted into the result
410     * @param o1  string or content argument to be formatted into the result
411     * @param o2  string or content argument to be formatted into the result
412     * @return the string
413     */
414    public Content getContent(String key, Object o0, Object o1, Object o2) {
415        Content c = new ContentBuilder();
416        Pattern p = Pattern.compile("\\{([012])\\}");
417        String text = resources.getText(key); // TODO: cache
418        Matcher m = p.matcher(text);
419        int start = 0;
420        while (m.find(start)) {
421            c.add(text.substring(start, m.start()));
422
423            Object o = null;
424            switch (m.group(1).charAt(0)) {
425            case '0':
426                o = o0;
427                break;
428            case '1':
429                o = o1;
430                break;
431            case '2':
432                o = o2;
433                break;
434            }
435
436            if (o == null) {
437                c.add("{" + m.group(1) + "}");
438            } else if (o instanceof String str) {
439                c.add(str);
440            } else if (o instanceof Content con) {
441                c.add(con);
442            }
443
444            start = m.end();
445        }
446
447        c.add(text.substring(start));
448        return c;
449    }
450
451    /**
452     * Returns content composed of items joined together with the specified separator.
453     *
454     * @param separator the separator
455     * @param items     the items
456     * @return the composition
457     */
458    public Content join(Content separator, Collection<Content> items) {
459        Content result = new ContentBuilder();
460        boolean first = true;
461        for (Content c : items) {
462            if (first) {
463                first = false;
464            } else {
465                result.add(separator);
466            }
467            result.add(c);
468        }
469        return result;
470    }
471
472    /**
473     * Gets a {@code Content} object, containing the string for
474     * a given key in the doclet's resources, substituting
475     * <code>&nbsp;</code> for any space characters found in
476     * the named resource string.
477     *
478     * @param key the key for the desired string
479     * @return the string
480     */
481    private Content getNonBreakResource(String key) {
482        return getNonBreakString(resources.getText(key));
483    }
484
485    /**
486     * Gets a {@code Content} object for a string, substituting
487     * <code>&nbsp;</code> for any space characters found in
488     * the named resource string.
489     *
490     * @param text the string
491     * @return the string content
492     */
493    public Content getNonBreakString(String text) {
494        Content c = new ContentBuilder();
495        int start = 0;
496        int p;
497        while ((p = text.indexOf(" ", start)) != -1) {
498            c.add(text.substring(start, p));
499            c.add(Entity.NO_BREAK_SPACE);
500            start = p + 1;
501        }
502        c.add(text.substring(start));
503        return c; // TODO: should be made immutable
504    }
505
506    /**
507     * {@return a label that describes the VisibleMemberTable kind}
508     *
509     * @param kind the visible member table kind.
510     */
511    public Content getNavLinkLabelContent(VisibleMemberTable.Kind kind) {
512        return Objects.requireNonNull(navLinkLabels.get(kind));
513    }
514}