001/*
002 * JDrupes Builder
003 * Copyright (C) 2025 Michael N. Lipp
004 * 
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Affero General Public License as
007 * published by the Free Software Foundation, either version 3 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013 * GNU Affero General Public License for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
017 */
018
019package org.jdrupes.builder.java;
020
021import com.google.common.flogger.FluentLogger;
022import java.nio.file.Path;
023import java.util.ArrayList;
024import java.util.Arrays;
025import java.util.List;
026import java.util.Locale;
027import java.util.Optional;
028import java.util.stream.Stream;
029import javax.tools.Diagnostic;
030import javax.tools.DiagnosticCollector;
031import javax.tools.JavaFileObject;
032import org.jdrupes.builder.api.Project;
033import org.jdrupes.builder.core.AbstractGenerator;
034
035/// A base class for generators that invoke java tools.
036///
037public abstract class JavaTool extends AbstractGenerator {
038
039    private static final FluentLogger logger = FluentLogger.forEnclosingClass();
040    private final List<String> options = new ArrayList<>();
041
042    /// Instantiates a new java tool.
043    ///
044    /// @param project the project
045    ///
046    public JavaTool(Project project) {
047        super(project);
048    }
049
050    /// Adds the given options.
051    ///
052    /// @param options the options
053    /// @return the javadoc
054    ///
055    public JavaTool options(Stream<String> options) {
056        this.options.addAll(options.toList());
057        return this;
058    }
059
060    /// Adds the given options.
061    ///
062    /// @param options the options
063    /// @return the javadoc
064    ///
065    public JavaTool options(String... options) {
066        this.options.addAll(Arrays.asList(options));
067        return this;
068    }
069
070    /// Return the options.
071    ///
072    /// @return the stream
073    ///
074    public List<String> options() {
075        return options;
076    }
077
078    /// Find the argument for the given option. As some options are
079    /// allows in different styles, several names can be specified. 
080    ///
081    /// @param names the names
082    /// @return the optional
083    ///
084    public Optional<String> optionArgument(String... names) {
085        var itr = options.iterator();
086        if (itr.hasNext()) {
087            String opt = itr.next();
088            if (Arrays.stream(names).anyMatch(opt::equals) && itr.hasNext()) {
089                return Optional.of(itr.next());
090            }
091        }
092        return Optional.empty();
093    }
094
095    /// Log diagnostic.
096    ///
097    /// @param diagnostic the diagnostic
098    ///
099    protected void logDiagnostic(
100            Diagnostic<? extends JavaFileObject> diagnostic) {
101        String msg;
102        if (diagnostic.getSource() == null) {
103            msg = diagnostic.getMessage(Locale.ENGLISH);
104        } else {
105            msg = String.format("%s:%d: %s",
106                project().rootProject().directory().relativize(
107                    Path.of(diagnostic.getSource().toUri().getPath())),
108                diagnostic.getLineNumber(),
109                diagnostic.getMessage(null));
110        }
111        switch (diagnostic.getKind()) {
112        case ERROR -> logger.atSevere().log(msg);
113        case WARNING -> logger.atWarning().log(msg);
114        case MANDATORY_WARNING -> logger.atWarning().log(msg);
115        default -> logger.atInfo().log(msg);
116        }
117    }
118
119    /// Log diagnostics.
120    ///
121    /// @param diagnostics the diagnostics
122    ///
123    protected void
124            logDiagnostics(DiagnosticCollector<JavaFileObject> diagnostics) {
125        for (var diagnostic : diagnostics.getDiagnostics()) {
126            logDiagnostic(diagnostic);
127        }
128    }
129}