001/*
002 * SPDX-License-Identifier: Apache-2.0
003 *
004 * Copyright 2024-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.thing.namespace;
019
020import dev.enola.data.iri.namespace.repo.CachingNamespaceRepository;
021import dev.enola.data.iri.namespace.repo.ImmutableNamespace;
022import dev.enola.data.iri.namespace.repo.Namespace;
023import dev.enola.data.iri.namespace.repo.NamespaceRepository;
024import dev.enola.thing.PredicatesObjects;
025import dev.enola.thing.repo.ThingProvider;
026
027import org.jspecify.annotations.Nullable;
028
029import java.util.Collections;
030import java.util.Optional;
031
032/**
033 * {@link NamespaceRepository} based on reading {@link #ACTIVE_NAMESPACES_IRI} from a {@link
034 * ThingProvider}.
035 *
036 * <p>This is (much!) slower than the {@link
037 * dev.enola.data.iri.namespace.repo.NamespaceRepositoryEnolaDefaults#INSTANCE}, and should only
038 * ever be used indirectly through {@link CachingNamespaceRepository}.
039 *
040 * @param thingProvider the provider of things used to retrieve namespace information
041 */
042public record ThingNamespaceRepository(ThingProvider thingProvider) implements NamespaceRepository {
043
044    public static final String ACTIVE_NAMESPACES_IRI = "https://enola.dev/namespaces";
045
046    public ThingNamespaceRepository() {
047        this(ThingProvider.CTX);
048    }
049
050    @Override
051    public @Nullable Namespace get(String iri) {
052        return thingProvider
053                .getOptional(ACTIVE_NAMESPACES_IRI)
054                .flatMap(
055                        ns ->
056                                ns.getOptional(iri, String.class)
057                                        .map(prefix -> new ImmutableNamespace(prefix, iri)))
058                .orElse(null);
059    }
060
061    @Override
062    public Optional<String> getIRI(String prefix) {
063        var optNamespaces = thingProvider.getOptional(ACTIVE_NAMESPACES_IRI);
064        if (optNamespaces.isEmpty()) return Optional.empty();
065        var namespaces = optNamespaces.get();
066        // TODO Replace with ThingVisitor, when available.
067        for (var iri : namespaces.predicateIRIs()) {
068            var object = namespaces.get(iri);
069            if (prefix.equals(object)) return Optional.of(iri);
070        }
071        return Optional.empty();
072    }
073
074    @Override
075    public Iterable<String> listIRI() {
076        return thingProvider
077                .getOptional(ACTIVE_NAMESPACES_IRI)
078                .map(PredicatesObjects::predicateIRIs)
079                .orElse(Collections.emptySet());
080    }
081}