QueryContainer.java

/*
 * Copyright © 2012-2025 The CTAN Team and individual authors
 *
 * This file is distributed under the 3-clause BSD license.
 * See file LICENSE for details.
 */
package org.ctan.site.services.search;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import org.ctan.site.services.DateUtils;
import org.ctan.site.services.search.base.IndexType;

import com.fasterxml.jackson.annotation.JsonIgnore;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Builder.Default;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;

/**
 * This class is a command object for passing search relevant parameters to the
 * SearchService and keeping the associated search results.
 *
 * @author <a href="mailto:gene@ctan.org">Gerd Neugebauer</a>
 */
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@SuppressFBWarnings(value = "EI_EXPOSE_REP")
public class QueryContainer {

    /**
     * This class represents a hit of the search.
     */
    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    public static class HitInfo {

        @JsonIgnore
        private long lastModified;

        private String path;

        private String title;

        private String display;

        private String type;

        /**
         * The method <code>getLink</code> provides means to retrieve a link.
         *
         * @return the path
         */
        public String getLink() {

            return path;
        }

        /**
         * The method <code>getModified</code> provides means to retrieve the
         * modification date.
         *
         * @return the modification date and time
         */
        public String getModified() {

            return DateUtils.formatDateTime(lastModified);
        }
    }

    /**
     * The field <code>phrase</code> contains the search phrase.
     */
    private String phrase;

    /**
     * The field <code>sections</code> contains the sections to search in.
     */
    @Default
    private Set<IndexType> sections = new HashSet();

    /**
     * The field <code>offset</code> contains the contains the hit offset.
     */
    @Default
    private int offset = 0;

    /**
     * The field <code>max</code> contains the page size.
     */
    @Default
    private int max = 16;

    /**
     * The field <code>wildcard</code> contains the indicator for adding
     * wildcards.
     */
    @Default
    private boolean wildcard = true;

    /**
     * The field <code>extended</code> contains the indicator for extended
     * search.
     */
    @Default
    private boolean extended = false;

    /**
     * The field <code>types</code> contains the mapping of names to types.
     */
    @Default
    private Map<String, Boolean> types = new HashMap();

    /**
     * The field <code>runtime</code> contains the runtime in a printable form.
     */
    private String runtime;

    /**
     * The field <code>locale</code> contains the locale.
     */
    private Locale locale;

    /**
     * The field <code>hits</code> contains the list of hits.
     */
    @Default
    private List<HitInfo> hits = List.of();

    /**
     * The field <code>hitNumber</code> contains the total number of hits.
     */
    private long hitNumber;

    /**
     * The method <code>getLocale</code> provides means to get the language of
     * the fallback if the locale is null.
     *
     * @param fallback the fallback value
     * @return null-safe locale
     */
    public Locale getLocale(@NonNull Locale fallback) {

        return locale != null ? locale : fallback;
    }

    /**
     * The method <code>hasType</code> provides means to retrieve a type for a
     * given key.
     *
     * @param key the key
     * @return the matching type
     */
    public boolean hasType(String key) {

        var b = types.get(key);
        return b == null ? false : b;
    }

    /**
     * The method <code>resetHits</code> provides means to reinitialise the
     * hits.
     *
     * @return this
     */
    public QueryContainer resetHits() {

        phrase = null;
        hitNumber = 0;
        offset = 0;
        hits = new ArrayList<>();
        runtime = "0ms";
        return this;
    }

    /**
     * The method <code>setType</code> provides means to set the value of a
     * given type.
     *
     * @param key the key of the type
     * @param value the value of the type
     * @return the old value
     */
    public Boolean setType(String key, Boolean value) {

        return types.put(key, value);
    }
}