001/*
002 * JDrupes Builder
003 * Copyright (C) 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.core;
020
021import java.util.Arrays;
022import java.util.EnumSet;
023import java.util.Objects;
024import java.util.Set;
025import org.jdrupes.builder.api.Cleanliness;
026import org.jdrupes.builder.api.Generator;
027import org.jdrupes.builder.api.Intent;
028import static org.jdrupes.builder.api.Intent.*;
029import org.jdrupes.builder.api.Project;
030import org.jdrupes.builder.api.Resource;
031import org.jdrupes.builder.api.ResourceProvider;
032import org.jdrupes.builder.api.ResourceQuery;
033import org.jdrupes.builder.api.ResourceType;
034
035/// Represents a request for [Resource]s of a specified type.
036/// The specified type provides two kinds of type information:
037///
038/// 1. The type of the [Resource]s that are actually provided.
039/// 2. The type of the "context" in which the [Resource]s are to be provided.
040///
041/// As an example, consider requests for a compile time and a runtime
042/// classpath. In both cases, the actually provided [Resource]s are
043/// of type "classpath element". However, depending on the kind of
044/// classpath, a [ResourceProvider] may deliver different collections of
045/// instances of "classpath elements". So instead of requesting
046/// "classpath element", 
047///
048/// Not all requested resource types require context information. For
049/// example, a request for [Cleanliness] usually refers to all resources
050/// that a [Generator] has created and does not depend on a context.
051/// However, in order to keep the API simple, the context is always
052/// required. 
053///
054/// @param <T> the generic type
055///
056public class DefaultResourceQuery<T extends Resource>
057        implements ResourceQuery<T> {
058
059    private final ResourceType<? extends T> type;
060    private final Project[] queried;
061    private Set<Intent> uses;
062
063    /// Instantiates a new resource request without any restriction.
064    ///
065    /// @param type the requested type
066    ///
067    /* default */ DefaultResourceQuery(ResourceType<? extends T> type) {
068        this(type, EnumSet.of(Supply, Expose), new Project[0]);
069    }
070
071    @SuppressWarnings("PMD.UseVarargs")
072    private DefaultResourceQuery(ResourceType<? extends T> type,
073            Set<Intent> using, Project[] queried) {
074        this.type = type;
075        uses = using;
076        this.queried = queried;
077    }
078
079    @Override
080    public ResourceQuery<T> using(Set<Intent> intends) {
081        uses = intends;
082        return this;
083    }
084
085    @Override
086    public Set<Intent> uses() {
087        return EnumSet.copyOf(uses);
088    }
089
090    @Override
091    public ResourceType<? extends T> type() {
092        return type;
093    }
094
095    @Override
096    public boolean wants(ResourceType<?> type) {
097        return this.type.isAssignableFrom(type);
098    }
099
100    @SuppressWarnings("PMD.MethodReturnsInternalArray")
101    /* default */ Project[] queried() {
102        return queried;
103    }
104
105    /* default */ DefaultResourceQuery<T> queried(Project project) {
106        var newQueried = Arrays.copyOf(queried, queried.length + 1);
107        newQueried[newQueried.length - 1] = project;
108        return new DefaultResourceQuery<>(type(), uses, newQueried);
109    }
110
111    @Override
112    public int hashCode() {
113        return Objects.hash(type, uses);
114    }
115
116    @Override
117    public boolean equals(Object obj) {
118        if (this == obj) {
119            return true;
120        }
121        if (obj == null) {
122            return false;
123        }
124        if (getClass() != obj.getClass()) {
125            return false;
126        }
127        DefaultResourceQuery<?> other = (DefaultResourceQuery<?>) obj;
128        return Objects.equals(type, other.type)
129            && Objects.equals(uses, other.uses);
130    }
131
132    @Override
133    public String toString() {
134        return "ResourceRequest<" + type + ">";
135    }
136
137}