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