package org.implab.gradle.common.dsl;

import java.util.stream.Stream;

import org.gradle.api.Action;
import org.gradle.api.Task;
import org.gradle.api.tasks.TaskProvider;

/**
 * Wrapper around TaskProvider for simplified lazy task configuration
 */
public class TaskSpec<T extends Task> implements TaskDependency {
    private final TaskProvider<T> taskProvider;

    public TaskSpec(TaskProvider<T> taskProvider) {
        this.taskProvider = taskProvider;
    }

    public TaskSpec<T> configure(Action<T> configure) {
        taskProvider.configure(configure);
        return this;
    }

    public TaskSpec<T> dependsOn(TaskDependency... other) {
        taskProvider.configure(t -> t.dependsOn(references(other)));
        return this;
    }

    public TaskSpec<T> finalizedBy(TaskDependency... other) {
        taskProvider.configure(t -> t.finalizedBy(references(other)));
        return this;
    }

    public TaskSpec<T> mustRunAfter(TaskDependency... other) {
        taskProvider.configure(t -> t.mustRunAfter(references(other)));
        return this;
    }

    public TaskSpec<T> doLast(Action<T> action) {
        taskProvider.configure(t -> t.doLast(self -> action.execute(t)));
        return this;
    }

    public TaskSpec<T> doFirst(Action<T> action) {
        taskProvider.configure(t -> t.doFirst(self -> action.execute(t)));
        return this;
    }

    /** Returns a task provider for this task, can be used as dependency object */
    @Override
    public Object reference() {
        return taskProvider;
    }

    private static Object[] references(TaskDependency[] other) {
        return Stream.of(other).map(TaskDependency::reference).toArray(Object[]::new);
    }
}
