////////////////////////////////////////////////////////////////////////////////
// checkstyle: Checks Java source code for adherence to a set of rules.
// Copyright (C) 2001-2020 the original author or authors.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
////////////////////////////////////////////////////////////////////////////////

package com.puppycrawl.tools.checkstyle.api;

import java.util.Map;

/**
 * Serves as an abstract base class for all modules that report inspection
 * findings. Such modules have a Severity level which is used for the
 * {@link LocalizedMessage localized messages} that are created by the module.
 *
 * @noinspection NoopMethodInAbstractClass
 */
public abstract class AbstractViolationReporter
    extends AutomaticBean {

    /** The severity level of any violations found. */
    private SeverityLevel severityLevel = SeverityLevel.ERROR;

    /** The identifier of the reporter. */
    private String id;

    /**
     * Returns the severity level of the messages generated by this module.
     *
     * @return the severity level
     * @see SeverityLevel
     * @see LocalizedMessage#getSeverityLevel
     * @noinspection WeakerAccess
     */
    public final SeverityLevel getSeverityLevel() {
        return severityLevel;
    }

    /**
     * Sets the severity level.  The string should be one of the names
     * defined in the {@code SeverityLevel} class.
     *
     * @param severity  The new severity level
     * @see SeverityLevel
     */
    public final void setSeverity(String severity) {
        severityLevel = SeverityLevel.getInstance(severity);
    }

    /**
     *  Get the severity level's name.
     *
     *  @return  the check's severity level name.
     *  @noinspection WeakerAccess
     */
    public final String getSeverity() {
        return severityLevel.getName();
    }

    /**
     * Returns the identifier of the reporter. Can be null.
     *
     * @return the id
     */
    public final String getId() {
        return id;
    }

    /**
     * Sets the identifier of the reporter. Can be null.
     *
     * @param id the id
     */
    public final void setId(final String id) {
        this.id = id;
    }

    /**
     * Returns an unmodifiable map instance containing the custom messages
     * for this configuration.
     *
     * @return unmodifiable map containing custom messages
     */
    protected Map<String, String> getCustomMessages() {
        return getConfiguration().getMessages();
    }

    /**
     * Returns the message bundle name resource bundle that contains the messages
     * used by this module.
     * <p>
     * The default implementation expects the resource files to be named
     * messages.properties, messages_de.properties, etc. The file must
     * be placed in the same package as the module implementation.
     * </p>
     * <p>
     * Example: If you write com/foo/MyCoolCheck, create resource files
     * com/foo/messages.properties, com/foo/messages_de.properties, etc.
     * </p>
     *
     * @return name of a resource bundle that contains the messages
     *     used by this module.
     */
    protected String getMessageBundle() {
        final String className = getClass().getName();
        return getMessageBundle(className);
    }

    /**
     * For unit tests, especially with a class with no package name.
     *
     * @param className class name of the module.
     * @return name of a resource bundle that contains the messages
     *     used by the module.
     */
    private static String getMessageBundle(final String className) {
        final String messageBundle;
        final int endIndex = className.lastIndexOf('.');
        final String messages = "messages";
        if (endIndex == -1) {
            messageBundle = messages;
        }
        else {
            final String packageName = className.substring(0, endIndex);
            messageBundle = packageName + "." + messages;
        }
        return messageBundle;
    }

    @Override
    protected void finishLocalSetup() throws CheckstyleException {
        // No code by default
    }

    /**
     * Log a message that has no column information.
     *
     * @param line the line number where the audit event was found
     * @param key the message that describes the audit event
     * @param args the details of the message
     *
     * @see java.text.MessageFormat
     */
    // -@cs[CustomDeclarationOrder] CustomDeclarationOrder does not treat groups of
    // overloaded methods. See https://github.com/sevntu-checkstyle/sevntu.checkstyle/issues/414
    public abstract void log(int line, String key, Object... args);

    /**
     * Log a message that has column information.
     *
     * @param line the line number where the audit event was found
     * @param col the column number where the audit event was found
     * @param key the message that describes the audit event
     * @param args the details of the message
     *
     * @see java.text.MessageFormat
     */
    // -@cs[CustomDeclarationOrder] CustomDeclarationOrder does not treat groups of
    // overloaded methods. See https://github.com/sevntu-checkstyle/sevntu.checkstyle/issues/414
    public abstract void log(int line, int col, String key,
            Object... args);

}
