package org.implab.gradle.common.sources;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import org.gradle.api.Action;
import org.gradle.api.NamedDomainObjectProvider;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.provider.Property;

final class LayerBinding implements LayerBindingSpec {
    static final String DEFAULT_SOURCE_SET_NAME_PATTERN = "{variant}{layerCap}";

    private final String name;
    private final Property<String> sourceSetNamePattern;

    private final List<Action<? super GenericSourceSet>> sourceSetConfigureActions = new ArrayList<>();
    private final List<Action<? super SourceSetRegistration>> registeredActions = new ArrayList<>();
    private final List<Action<? super SourceSetUsageBinding>> boundActions = new ArrayList<>();
    private final List<NamedDomainObjectProvider<GenericSourceSet>> registeredSourceSets = new ArrayList<>();
    private final List<SourceSetRegistration> registeredContexts = new ArrayList<>();
    private final List<SourceSetUsageBinding> boundContexts = new ArrayList<>();
    private final Set<String> registeredSourceSetNames = new LinkedHashSet<>();

    LayerBinding(String name, ObjectFactory objects) {
        this.name = name;
        sourceSetNamePattern = objects.property(String.class);
        sourceSetNamePattern.convention(DEFAULT_SOURCE_SET_NAME_PATTERN);
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public Property<String> getSourceSetNamePattern() {
        return sourceSetNamePattern;
    }

    @Override
    public void configureSourceSet(Action<? super GenericSourceSet> configure) {
        sourceSetConfigureActions.add(configure);
        for (var sourceSet : registeredSourceSets)
            sourceSet.configure(configure);
    }

    @Override
    public void whenRegistered(Action<? super SourceSetRegistration> action) {
        registeredActions.add(action);
        for (var context : registeredContexts)
            action.execute(context);
    }

    @Override
    public void whenBound(Action<? super SourceSetUsageBinding> action) {
        boundActions.add(action);
        for (var context : boundContexts)
            action.execute(context);
    }

    void notifyRegistered(SourceSetRegistration registration) {
        if (registeredSourceSetNames.add(registration.sourceSetName())) {
            var sourceSet = registration.sourceSet();
            registeredSourceSets.add(sourceSet);

            for (var action : sourceSetConfigureActions)
                sourceSet.configure(action);
        }

        registeredContexts.add(registration);
        for (var action : registeredActions)
            action.execute(registration);
    }

    void notifyBound(SourceSetUsageBinding binding) {
        boundContexts.add(binding);
        for (var action : boundActions)
            action.execute(binding);
    }
}
