package be.iminds.ilabt.jfed.highlevel.jobs;

import be.iminds.ilabt.jfed.experiment.tasks.ExperimentTaskStatus;
import be.iminds.ilabt.jfed.lowlevel.JFedException;

import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * A state which has been sliced into multiple sub-states (called {@link StateSlice}).
 * This type of states is typically used when the same action needs to be performed on several parts of an experiment.
 * <p>
 * In many cases, you want to slice a state over the ExperimentParts of the Experiment,
 * for which you can use {@link ExperimentPartsSlicedState}.
 * <p>
 * User: twalcari
 * Date: 1/13/2016
 * Time: 11:51
 */
public abstract class SlicedState<S extends StateSlice> extends State {

    protected SlicedState(String name) {
        super(name);
    }

    @Nonnull
    @Override
    protected ExperimentTaskStatus executeState(Job<?> job) throws InterruptedException, JFedException {
        Collection<S> jobSlices = getSlices();

        List<StateSliceThread> threads =
                jobSlices.stream().map(ss -> new StateSliceThread<>(ss, getName())).collect(Collectors.toList());

        threads.forEach(Thread::start);

        for (StateSliceThread thread : threads) {
            thread.join();
        }

        boolean allSuccess = true;
        boolean allFailed = true;

        for (StateSliceThread thread : threads) {
            if (thread.getResult() != ExperimentTaskStatus.SUCCESS)
                allSuccess = false;
            if (thread.getResult() != ExperimentTaskStatus.FAILED)
                allFailed = false;
        }

        if (allSuccess)
            return ExperimentTaskStatus.SUCCESS;
        else if (allFailed)
            return ExperimentTaskStatus.FAILED;
        else
            return ExperimentTaskStatus.WARNING;
    }

    /**
     * @return This method will return the StateSlices of this sliced state.
     */
    public abstract Collection<S> getSlices();


}
