Messages.java

/*
 * Copyright (C) 2017-2025 Gerd Neugebauer
 *
 * This file is distributed under the 3-clause BSD license.
 * See file LICENSE for details.
 */
package org.ctan.site.services.upload.util;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.ws.rs.core.Response.Status;
import lombok.Getter;

/**
 * This class is a container for messages. The messages may have the type
 * <code>ERROR</code>, <code>WARNING</code>, or <code>INFO</code>.
 *
 * @author <a href="mailto:gene@ctan.org">Gerd Neugebauer</a>
 */
public class Messages implements Iterable<List<String>> {

    /**
     * The field <code>serialVersionUID</code> contains the version number.
     */
    public static final long serialVersionUID = 1L;

    /**
     * The method <code>errorMessage</code> provides means to create a new
     * Messages instance populated with an error.
     *
     * @param msg the error attributes
     * @return a new Messages
     */
    public static Messages errorMessage(String... msg) {

        return new Messages().error(msg);
    }

    /**
     * The field <code>values</code> contains the values.
     */
    @Getter
    @SuppressFBWarnings(value = "EI_EXPOSE_REP")
    private List<List<String>> values = new ArrayList<>();

    /**
     * The field <code>status</code> contains the status.
     */
    @Getter
    private Status status = Status.OK;

    /**
     * The field <code>errors</code> contains the indicator that an error has
     * been encountered.
     */
    private boolean errors = false;

    /**
     * The field <code>errorMode</code> contains the indication whether errors
     * should be degraded to warnings.
     */
    private boolean errorMode = true;

    /**
     * This method adds an error message with the given parameters.
     *
     * @param msg the parameters
     *
     * @return this
     */
    public Messages error(String... msg) {

        var a = new ArrayList<String>();
        a.add("ERROR");
        for (var it : msg) {
            a.add(it);
        }
        values.add(a);
        errors = true;
        status = Status.CONFLICT;
        return this;
    }

    /**
     * This method adds an error message with the given parameters.
     *
     * @param msg the parameters
     *
     * @return this
     */
    public Messages errorOrWarning(String... msg) {

        return errorMode ? error(msg) : warning(msg);
    }

    /**
     * The method <code>hasErrors</code> returns the indicator whether the
     * messages contain at least one error message.
     *
     * @return the indicator whether errors are contained
     */
    public boolean hasErrors() {

        return errors;
    }

    /**
     * This method adds an info message with the given parameters.
     *
     * @param msg the parameters
     *
     * @return this
     */
    public Messages info(String... msg) {

        var a = new ArrayList<String>();
        a.add("INFO");
        for (var it : msg) {
            a.add(it);
        }
        values.add(a);
        return this;
    }

    /**
     * The method <code>infoMode</code> provides means to switch to info mode.
     */
    public void infoMode() {

        errorMode = false;
    }

    /**
     * {@inheritDoc}
     *
     * @see java.lang.Iterable#iterator()
     */
    @Override
    public Iterator<List<String>> iterator() {

        return values.iterator();
    }

    /**
     * The method <code>size</code> provides means to get the number of
     * messages.
     *
     * @return the number of messages
     */
    public int size() {

        return values.size();
    }

    /**
     * The method <code>toHtml</code> provides means to format the messages as
     * HTML.
     *
     * @return the formatted messages
     */
    public String toHtml() {

        StringBuilder buffer = new StringBuilder();
        buffer.append("<ul>");
        for (var it : values) {
            buffer.append("<li>");
            buffer.append(String.join(" ", it));
            buffer.append("</li>\n");
        }
        buffer.append("</ul>");
        return buffer.toString();
    }

    /**
     * {@inheritDoc}
     *
     * @see java.util.AbstractCollection#toString()
     */
    @Override
    public String toString() {

        StringBuilder buffer = new StringBuilder();
        buffer.append("[");
        var next = false;
        for (var it : values) {
            if (next) {
                buffer.append(",\n");
            } else {
                next = true;
            }
            buffer.append("[");
            buffer.append(String.join(", ", it));
            buffer.append("]");
        }
        buffer.append("]");
        return buffer.toString();
    }

    /**
     * The method <code>toText</code> provides means to format the messages as
     * text.
     *
     * @return the formatted messages
     */
    public String toText() {

        StringBuilder buffer = new StringBuilder();
        for (var it : values) {
            buffer.append(String.join(" ", it).replaceFirst(" ", ":\t"));
            buffer.append("\n");
        }
        return buffer.toString();
    }

    /**
     * This method adds a warning message with the given parameters.
     *
     * @param msg the parameters
     *
     * @return this
     */
    public Messages warning(String... msg) {

        var a = new ArrayList<String>();
        a.add("WARNING");
        for (var it : msg) {
            a.add(it);
        }
        values.add(a);
        return this;
    }
}