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 java.nio.file.Path;
022import java.util.ArrayList;
023import java.util.Arrays;
024import java.util.List;
025import java.util.Locale;
026import java.util.Optional;
027import java.util.logging.Level;
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 final List<String> options = new ArrayList<>();
040
041    /// Instantiates a new java tool.
042    ///
043    /// @param project the project
044    ///
045    public JavaTool(Project project) {
046        super(project);
047    }
048
049    /// Adds the given options.
050    ///
051    /// @param options the options
052    /// @return the javadoc
053    ///
054    public JavaTool options(Stream<String> options) {
055        this.options.addAll(options.toList());
056        return this;
057    }
058
059    /// Adds the given options.
060    ///
061    /// @param options the options
062    /// @return the javadoc
063    ///
064    public JavaTool options(String... options) {
065        this.options.addAll(Arrays.asList(options));
066        return this;
067    }
068
069    /// Return the options.
070    ///
071    /// @return the stream
072    ///
073    public List<String> options() {
074        return options;
075    }
076
077    /// Find the argument for the given option. As some options are
078    /// allows in different styles, several names can be specified. 
079    ///
080    /// @param names the names
081    /// @return the optional
082    ///
083    public Optional<String> optionArgument(String... names) {
084        var itr = options.iterator();
085        if (itr.hasNext()) {
086            String opt = itr.next();
087            if (Arrays.stream(names).anyMatch(opt::equals) && itr.hasNext()) {
088                return Optional.of(itr.next());
089            }
090        }
091        return Optional.empty();
092    }
093
094    /// Log diagnostic.
095    ///
096    /// @param diagnostic the diagnostic
097    ///
098    protected void logDiagnostic(
099            Diagnostic<? extends JavaFileObject> diagnostic) {
100        String msg;
101        if (diagnostic.getSource() == null) {
102            msg = diagnostic.getMessage(Locale.ENGLISH);
103        } else {
104            msg = String.format("%s:%d: %s",
105                project().rootProject().directory().relativize(
106                    Path.of(diagnostic.getSource().toUri().getPath())),
107                diagnostic.getLineNumber(),
108                diagnostic.getMessage(null));
109        }
110        Level level = switch (diagnostic.getKind()) {
111        case ERROR -> Level.SEVERE;
112        case WARNING -> Level.WARNING;
113        case MANDATORY_WARNING -> Level.WARNING;
114        default -> Level.INFO;
115        };
116        log.log(level, () -> msg);
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}