package org.implab.gradle.common;

import javax.inject.Inject;

import org.gradle.api.Action;
import org.gradle.api.NamedDomainObjectProvider;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.file.Directory;
import org.gradle.api.tasks.TaskContainer;
import org.gradle.api.tasks.TaskProvider;
import org.implab.gradle.common.dsl.TaskGroup;
import org.implab.gradle.common.dsl.TasksMixin;
import org.implab.gradle.common.utils.ExtraProps;

/** Project configuration traits */
public interface ProjectMixin extends TasksMixin {
    @Inject
    Project getProject();

    @Override
    default <T extends Task> TaskProvider<T> task(String name, Class<T> clazz) {
        return getProject().getTasks().register(name, clazz);
    }

    /** Creates a new task group */
    default TaskGroup taskGroup(String name) {
        return new TaskGroup(name) {
            @Override
            protected TaskContainer tasks() {
                return getProject().getTasks();
            }
        };
    }

    /** Registers the new configuration */
    default NamedDomainObjectProvider<Configuration> configuration(String name, Action<? super Configuration> configure) {
        return getProject().getConfigurations().register(name, configure);
    }

    /** Returns the project directory */
    default Directory projectDirectory() {
        return getProject().getLayout().getProjectDirectory();
    }

    /** Applies and returns the specified plugin, the plugin is applied only once. */
    default <T extends Plugin<Project>> T plugin(Class<T> clazz) {
        getProject().getPluginManager().apply(clazz);
        return getProject().getPlugins().findPlugin(clazz);
    }

    /**
     * @param classes The list of classes to register as extensions
     */
    default void exportClasses(Class<?>... classes) {
        var props = ExtraProps.of(getProject());
        for (var clazz : classes)
            props.put(clazz.getSimpleName(), clazz);
    }

    /** Creates and register a new project extension.
     * 
     * @param <T> The type of the extension
     * @param extensionName The name of the extension in the project
     * @param clazz The class of the extension
     * @return the newly created extension
     */
    default <T> T extension(String extensionName, Class<T> clazz) {
        T extension = getProject().getObjects().newInstance(clazz);
        getProject().getExtensions().add(extensionName, extension);
        return extension;
    }

}

