001/*
002 * Copyright © 2025 CUI-OpenSource-Software (info@cuioss.de)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package de.cuioss.benchmarking.common.report;
017
018import de.cuioss.benchmarking.common.config.BenchmarkType;
019import de.cuioss.benchmarking.common.model.BenchmarkData;
020import de.cuioss.tools.logging.CuiLogger;
021
022import java.io.IOException;
023import java.io.InputStream;
024import java.nio.file.Files;
025import java.nio.file.Path;
026import java.nio.file.StandardCopyOption;
027
028import static de.cuioss.benchmarking.common.constants.BenchmarkConstants.Files.Html.*;
029import static de.cuioss.benchmarking.common.constants.BenchmarkConstants.Files.Support.*;
030import static de.cuioss.benchmarking.common.constants.BenchmarkConstants.Report.Templates.NOT_FOUND_FORMAT;
031import static de.cuioss.benchmarking.common.constants.BenchmarkConstants.Report.Templates.PATH_PREFIX;
032import static de.cuioss.benchmarking.common.util.BenchmarkingLogMessages.INFO;
033
034/**
035 * Generates HTML reports by creating a data JSON file and copying templates.
036 * <p>
037 * This generator now works in conjunction with ReportDataGenerator to:
038 * <ol>
039 *   <li>Generate a standardized benchmark-data.json file with all report data</li>
040 *   <li>Copy HTML templates that load and render the JSON data</li>
041 * </ol>
042 * <p>
043 * Templates use JavaScript to dynamically load and display the JSON data,
044 * making the system more maintainable and flexible.
045 */
046public class ReportGenerator {
047
048    private static final CuiLogger LOGGER = new CuiLogger(ReportGenerator.class);
049    private final ReportDataGenerator dataGenerator;
050
051    /**
052     * Creates a ReportGenerator.
053     */
054    public ReportGenerator() {
055        this.dataGenerator = new ReportDataGenerator();
056    }
057
058    /**
059     * Generates the main index page and benchmark data.
060     *
061     * @param benchmarkData the benchmark data to generate reports from
062     * @param benchmarkType the type of benchmark being processed
063     * @param outputDir the output directory for HTML files
064     * @throws IOException if writing files fails
065     */
066    public void generateIndexPage(BenchmarkData benchmarkData, BenchmarkType benchmarkType, String outputDir) throws IOException {
067        // First generate the data file
068        dataGenerator.generateDataFile(benchmarkData, benchmarkType, outputDir);
069
070        // Then copy the index template
071        LOGGER.info(INFO.GENERATING_INDEX_PAGE, 0);
072        copyTemplate(INDEX, outputDir);
073
074        Path indexFile = Path.of(outputDir).resolve(INDEX);
075        LOGGER.info(INFO.INDEX_PAGE_GENERATED, indexFile);
076    }
077
078    /**
079     * Generates the trends page.
080     *
081     * @param outputDir the output directory for HTML files
082     * @throws IOException if writing HTML files fails
083     */
084    public void generateTrendsPage(String outputDir) throws IOException {
085        LOGGER.info(INFO.GENERATING_TRENDS_PAGE);
086
087        // Copy the trends template
088        copyTemplate(TRENDS, outputDir);
089
090        Path trendsFile = Path.of(outputDir).resolve(TRENDS);
091        LOGGER.info(INFO.TRENDS_PAGE_GENERATED, trendsFile);
092    }
093
094    /**
095     * Generates the detailed visualizer page.
096     *
097     * @param outputDir the output directory for HTML files
098     * @throws IOException if writing HTML files fails
099     */
100    public void generateDetailedPage(String outputDir) throws IOException {
101        LOGGER.info(INFO.GENERATING_REPORTS);
102
103        // Copy the detailed template
104        copyTemplate(DETAILED, outputDir);
105
106        Path detailedFile = Path.of(outputDir).resolve(DETAILED);
107        LOGGER.info(INFO.DETAILED_PAGE_GENERATED, detailedFile);
108    }
109
110    /**
111     * Copies all necessary support files (CSS, JS, etc.) to the output directory.
112     *
113     * @param outputDir the output directory
114     * @throws IOException if copying files fails
115     */
116    public void copySupportFiles(String outputDir) throws IOException {
117        Path outputPath = Path.of(outputDir);
118        Files.createDirectories(outputPath);
119
120        // Copy CSS file
121        copyTemplate(REPORT_STYLES_CSS, outputDir);
122
123        // Copy the data loader JavaScript
124        copyTemplate(DATA_LOADER_JS, outputDir);
125
126        // Copy robots.txt and sitemap if needed
127        copyTemplate(ROBOTS_TXT, outputDir);
128        copyTemplate(SITEMAP_XML, outputDir);
129    }
130
131    /**
132     * Copies a template file from resources to the output directory.
133     *
134     * @param templateName the name of the template file
135     * @param outputDir the output directory
136     * @throws IOException if copying fails
137     */
138    private void copyTemplate(String templateName, String outputDir) throws IOException {
139        Path outputPath = Path.of(outputDir);
140        Files.createDirectories(outputPath);
141
142        String resourcePath = PATH_PREFIX + templateName;
143        try (InputStream is = getClass().getResourceAsStream(resourcePath)) {
144            if (is == null) {
145                throw new IOException(NOT_FOUND_FORMAT.formatted(resourcePath));
146            }
147            Path targetFile = outputPath.resolve(templateName);
148            Files.copy(is, targetFile, StandardCopyOption.REPLACE_EXISTING);
149        }
150    }
151
152}