package org.implab.gradle.common.sources;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

import org.gradle.api.InvalidUserDataException;
import org.gradle.api.attributes.Attribute;
import org.gradle.api.provider.ProviderFactory;
import org.gradle.api.provider.Provider;

/**
 * Typed attribute storage used by build variants.
 */
public final class VariantAttributes {
    private final ProviderFactory providers;
    private final LinkedHashMap<Attribute<?>, Provider<?>> values = new LinkedHashMap<>();
    private boolean finalized;

    VariantAttributes(ProviderFactory providers) {
        this.providers = providers;
    }

    public <T> void attribute(Attribute<T> key, T value) {
        ensureMutable("set attribute '" + key.getName() + "'");
        attributeProvider(key, providers.provider(() -> value));
    }

    public <T> void attributeProvider(Attribute<T> key, Provider<? extends T> value) {
        ensureMutable("set attribute provider '" + key.getName() + "'");
        values.put(key, value);
    }

    @SuppressWarnings("unchecked")
    public <T> Provider<T> get(Attribute<T> key) {
        return (Provider<T>) values.get(key);
    }

    public boolean contains(Attribute<?> key) {
        return values.containsKey(key);
    }

    public int size() {
        return values.size();
    }

    public Map<Attribute<?>, Provider<?>> asMap() {
        return Collections.unmodifiableMap(values);
    }

    void finalizeModel() {
        finalized = true;
    }

    private void ensureMutable(String operation) {
        if (finalized)
            throw new InvalidUserDataException("Variant attributes are finalized and cannot " + operation);
    }
}
