001/*
002 * SPDX-License-Identifier: Apache-2.0
003 *
004 * Copyright 2025-2026 The Enola <https://enola.dev> Authors
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 *     https://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package dev.enola.common.template.tool;
019
020import static dev.enola.common.io.resource.FileDescriptorResource.STDOUT_URI;
021
022import dev.enola.common.context.TLC;
023import dev.enola.common.function.MoreStreams;
024import dev.enola.common.io.iri.URIs;
025import dev.enola.common.io.mediatype.MediaTypeProviders;
026import dev.enola.common.io.mediatype.StandardMediaTypes;
027import dev.enola.common.io.mediatype.YamlMediaType;
028import dev.enola.common.io.object.ObjectReaderChain;
029import dev.enola.common.io.object.csv.CsvReader;
030import dev.enola.common.io.object.jackson.JacksonObjectReaderWriterChain;
031import dev.enola.common.io.object.template.TemplatedObjectReader;
032import dev.enola.common.io.resource.FileDescriptorResource;
033import dev.enola.common.io.resource.FileResource;
034import dev.enola.common.io.resource.ResourceProvider;
035import dev.enola.common.io.resource.ResourceProviders;
036import dev.enola.common.template.TemplateProvider;
037import dev.enola.common.template.handlebars.HandlebarsMediaType;
038import dev.enola.common.template.handlebars.HandlebarsTemplateProvider;
039
040import java.io.IOException;
041import java.net.URI;
042import java.nio.file.Paths;
043import java.util.Arrays;
044import java.util.List;
045
046// This is used by //MODULE.update.bash
047public class TemplyMain {
048
049    // TODO Expose this as an ./enola template CLI sub-command too
050
051    private final Temply temply;
052    private final ResourceProvider rp;
053
054    public TemplyMain(ResourceProvider rp, TemplateProvider templateProvider) {
055        this.rp = rp;
056        ObjectReaderChain delegateObjectReader =
057                new ObjectReaderChain(new JacksonObjectReaderWriterChain(), new CsvReader());
058        this.temply = new Temply(new TemplatedObjectReader(delegateObjectReader), templateProvider);
059    }
060
061    private static ResourceProvider rp() {
062        var fileRP = new FileResource.Provider();
063        var fdRP = new FileDescriptorResource.Provider();
064        return new ResourceProviders(fileRP, fdRP);
065    }
066
067    private static final TemplyMain INSTANCE =
068            new TemplyMain(rp(), new HandlebarsTemplateProvider());
069
070    public static void main(String[] args) throws IOException {
071        if (args.length < 1) {
072            var use = "USAGE: temply [data1.yaml data2.json data3.csv...] <template.handlebars>";
073            System.err.println(use);
074            System.exit(1);
075        }
076        var dataURIs = Arrays.stream(args, 0, args.length - 1).map(URI::create).toList();
077        var templateURI = URI.create(args[args.length - 1]);
078
079        MediaTypeProviders.set(
080                new HandlebarsMediaType(), new YamlMediaType(), new StandardMediaTypes());
081        try (var ctx = TLC.open().push(URIs.ContextKeys.BASE, Paths.get("").toUri())) {
082            INSTANCE.run(dataURIs, templateURI, STDOUT_URI);
083        }
084    }
085
086    public void run(List<URI> dataURIs, URI templateURI, URI outURI) throws IOException {
087        var dataResources = MoreStreams.map(dataURIs.stream(), rp::getNonNull).toList();
088        var templateResource = rp.getNonNull(templateURI);
089        var outResource = rp.getNonNull(outURI);
090
091        temply.convert(dataResources, templateResource, outResource);
092    }
093}