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.core;
020
021import java.util.Arrays;
022import java.util.EnumSet;
023import java.util.Objects;
024import java.util.Optional;
025import java.util.Set;
026import java.util.stream.Collectors;
027import org.jdrupes.builder.api.Intent;
028import org.jdrupes.builder.api.Project;
029import org.jdrupes.builder.api.Resource;
030import org.jdrupes.builder.api.ResourceRequest;
031import org.jdrupes.builder.api.ResourceType;
032
033/// An implementation of [ResourceRequest]. 
034///
035/// @param <T> the resource type
036///
037public class DefaultResourceRequest<T extends Resource>
038        implements ResourceRequest<T> {
039
040    private final ResourceType<? extends T> type;
041    private Project[] queried;
042    private Set<Intent> uses;
043    private String name;
044
045    /// Instantiates a new resource request without any intents.
046    ///
047    /// @param type the requested type
048    ///
049    /* default */ DefaultResourceRequest(ResourceType<? extends T> type) {
050        this.type = Objects.requireNonNull(type);
051        uses = EnumSet.noneOf(Intent.class);
052        queried = new Project[0];
053    }
054
055    @Override
056    @SuppressWarnings("unchecked")
057    public DefaultResourceRequest<T> clone() {
058        try {
059            // This class is immutable
060            return (DefaultResourceRequest<T>) super.clone();
061        } catch (CloneNotSupportedException e) {
062            throw new IllegalStateException(e);
063        }
064    }
065
066    @Override
067    public ResourceType<? extends T> type() {
068        return type;
069    }
070
071    @Override
072    public ResourceRequest<T> withName(String name) {
073        var result = clone();
074        result.name = name;
075        return result;
076    }
077
078    @Override
079    public Optional<String> name() {
080        return Optional.ofNullable(name);
081    }
082
083    @Override
084    public ResourceRequest<T> using(Set<Intent> intents) {
085        var result = clone();
086        result.uses = Objects.requireNonNull(intents);
087        return result;
088    }
089
090    @Override
091    public Set<Intent> uses() {
092        return EnumSet.copyOf(uses);
093    }
094
095    @Override
096    public boolean accepts(ResourceType<?> type) {
097        return this.type.isAssignableFrom(type);
098    }
099
100    @Override
101    public boolean requires(ResourceType<?> type) {
102        return type.isAssignableFrom(this.type);
103    }
104
105    @SuppressWarnings("PMD.MethodReturnsInternalArray")
106    /* default */ Project[] queried() {
107        return queried;
108    }
109
110    /* default */ DefaultResourceRequest<T> queried(Project project) {
111        var newQueried = Arrays.copyOf(queried, queried.length + 1);
112        newQueried[newQueried.length - 1] = Objects.requireNonNull(project);
113        var result = clone();
114        result.queried = newQueried;
115        return result;
116    }
117
118    @Override
119    public int hashCode() {
120        return Objects.hash(type, name, uses);
121    }
122
123    @Override
124    public boolean equals(Object obj) {
125        if (this == obj) {
126            return true;
127        }
128        if (obj == null) {
129            return false;
130        }
131        if (getClass() != obj.getClass()) {
132            return false;
133        }
134        DefaultResourceRequest<?> other = (DefaultResourceRequest<?>) obj;
135        return Objects.equals(type, other.type)
136            && Objects.equals(name, other.name)
137            && Objects.equals(uses, other.uses);
138    }
139
140    @Override
141    public String toString() {
142        return "ResourceRequest<" + type + ">"
143            + name().map(n -> ":" + n).orElse("") + " [" + uses.stream()
144                .map(Intent::toString).collect(Collectors.joining(", "))
145            + "]";
146    }
147
148}