/*
 * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */
package jdk.javadoc.internal.doclets.formats.html;

import jdk.javadoc.internal.doclets.formats.html.markup.Entity;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
import jdk.javadoc.internal.doclets.formats.html.markup.ListBuilder;
import jdk.javadoc.internal.doclets.formats.html.markup.TagName;
import jdk.javadoc.internal.doclets.formats.html.markup.Text;

/**
 * A class used by various {@link HtmlDocletWriter} subclasses to build tables of contents.
 */
public class TableOfContents {
    private final ListBuilder listBuilder;
    private final HtmlDocletWriter writer;

    /**
     * Constructor
     * @param writer the writer
     */
    public TableOfContents(HtmlDocletWriter writer) {
        this.writer = writer;
        listBuilder = new ListBuilder(HtmlTree.OL(HtmlStyle.tocList));
    }

    /**
     * Adds a link to the table of contents.
     * @param id the link fragment
     * @param label the link label
     * @return this object
     */
    public TableOfContents addLink(HtmlId id, Content label) {
        listBuilder.add(writer.links.createLink(id, label).put(HtmlAttr.TABINDEX, "0"));
        return this;
    }

    /**
     * Adds a new nested list to add new items to.
     */
    public void pushNestedList() {
        listBuilder.pushNestedList(HtmlTree.OL(HtmlStyle.tocList));
    }

    /**
     * Closes the current nested list and go back to the parent list.
     */
    public void popNestedList() {
        listBuilder.popNestedList();
    }

    /**
     * Returns a content object containing the table of contents, consisting
     * of a header and the contents list itself. If the contents list is empty,
     * an empty content object is returned.
     *
     * @param hasFilterInput whether to add a filter text input
     * @return a content object
     */
    protected Content toContent(boolean hasFilterInput) {
        if (listBuilder.isEmpty()) {
            return Text.EMPTY;
        }
        var content = HtmlTree.NAV()
                .setStyle(HtmlStyle.toc)
                .put(HtmlAttr.ARIA_LABEL, writer.resources.getText("doclet.table_of_contents"));
        var header = HtmlTree.DIV(HtmlStyle.tocHeader, writer.contents.contentsHeading);
        if (hasFilterInput) {
            header.add(Entity.NO_BREAK_SPACE)
                    .add(HtmlTree.INPUT(HtmlAttr.InputType.TEXT, HtmlStyle.filterInput)
                            .put(HtmlAttr.PLACEHOLDER, writer.resources.getText("doclet.filter_label"))
                            .put(HtmlAttr.ARIA_LABEL, writer.resources.getText("doclet.filter_table_of_contents"))
                            .put(HtmlAttr.AUTOCOMPLETE, "off"))
                    .add(HtmlTree.INPUT(HtmlAttr.InputType.RESET, HtmlStyle.resetFilter)
                            .put(HtmlAttr.VALUE, writer.resources.getText("doclet.filter_reset")));
        }
        content.add(header);
        content.add(new HtmlTree(TagName.BUTTON).addStyle(HtmlStyle.hideSidebar)
                .add(HtmlTree.SPAN(writer.contents.hideSidebar).add(Entity.NO_BREAK_SPACE))
                .add(Entity.LEFT_POINTING_ANGLE));
        content.add(new HtmlTree(TagName.BUTTON).addStyle(HtmlStyle.showSidebar)
                .add(Entity.RIGHT_POINTING_ANGLE)
                .add(HtmlTree.SPAN(Entity.NO_BREAK_SPACE).add(writer.contents.showSidebar)));
        return content.add(listBuilder);
    }

}
