001/*
002 * JDrupes Builder
003 * Copyright (C) 2025, 2026 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.api;
020
021import java.util.HashSet;
022import java.util.Set;
023import java.util.function.Consumer;
024import java.util.stream.Stream;
025
026/// Helper class for implementing [Project#from].
027///
028public class FromHelper {
029    private final BuildContext context;
030    private final Stream<ResourceProvider> providers;
031    private final Set<ResourceProvider> excluded = new HashSet<>();
032    private final Set<Class<? extends ResourceProvider>> excludedTypes
033        = new HashSet<>();
034    private Consumer<ResourceProvider> providerLog = _ -> {
035    };
036
037    /// Initializes a new from helper.
038    ///
039    /// @param context the context
040    /// @param providers the providers
041    ///
042    public FromHelper(BuildContext context,
043            Stream<ResourceProvider> providers) {
044        this.context = context;
045        this.providers = providers;
046    }
047
048    /// Exclude the given provider when requesting resources.
049    ///
050    /// @param provider the provider
051    /// @return the from helper
052    ///
053    public FromHelper without(ResourceProvider provider) {
054        excluded.add(provider);
055        return this;
056    }
057
058    /// Exclude providers of the given type when requesting resources.
059    ///
060    /// @param providerType the provider type
061    /// @return the from helper
062    ///
063    public FromHelper
064            without(Class<? extends ResourceProvider> providerType) {
065        excludedTypes.add(providerType);
066        return this;
067    }
068
069    /// Register a callback for logging the providers used.
070    ///
071    /// @param providerLog the provider log
072    /// @return the from helper
073    ///
074    public FromHelper log(Consumer<ResourceProvider> providerLog) {
075        this.providerLog = providerLog;
076        return this;
077    }
078
079    /// Returns the requested resources using the context and providers 
080    /// passed to the record's constructor.
081    ///
082    /// @param <T> the generic type
083    /// @param request the request
084    /// @return the stream
085    ///
086    public <T extends Resource> Stream<T> get(ResourceRequest<T> request) {
087        return providers.filter(p -> !excluded.contains(p))
088            .filter(p -> excludedTypes.stream()
089                .filter(t -> t.isAssignableFrom(p.getClass())).findAny()
090                .isEmpty())
091            .peek(providerLog::accept)
092            .flatMap(provider -> context.fetch(provider, request));
093    }
094}