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

import be.iminds.ilabt.jfed.experiment.Experiment;
import be.iminds.ilabt.jfed.experiment.ExperimentPart;
import be.iminds.ilabt.jfed.highlevel.jobs.parts.ExperimentPartController;
import be.iminds.ilabt.jfed.highlevel.jobs.parts.ExperimentPartControllerManager;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * Abstract class for states which are sliced over the ExperimentParts of an Experiment
 *
 * User: twalcari
 * Date: 1/12/2016
 * Time: 17:06
 */
public abstract class ExperimentPartsSlicedState<JS extends ExperimentPartStateSlice> extends SlicedState<JS> {

    private final Experiment experiment;
    Map<ExperimentPart, JS> experimentPartJobSlices = null;

    private final ExperimentPartControllerManager manager;
    private final Collection<ExperimentPart> parts;

    protected ExperimentPartsSlicedState(String name, Experiment experiment, ExperimentPartControllerManager manager) {
        this(name, experiment, null, manager);
    }


    /**
     * Use this constructor if you only want to execute the action for certain experiment parts.
     */
    protected ExperimentPartsSlicedState(String name, Experiment experiment, Collection<ExperimentPart> experimentParts, ExperimentPartControllerManager manager) {
        super(name);
        this.experiment = experiment;
        this.manager = manager;

        parts = experimentParts != null ? experimentParts : experiment.getParts();
    }

    private void initializeStateSlices() {
        experimentPartJobSlices = new HashMap<>();
        for (ExperimentPart experimentPart : parts) {
            ExperimentPartController controller = this.manager.getController(experimentPart);
            //noinspection unchecked
            JS jobSlice = (JS) createJobSlice(controller, experimentPart);

            experimentPartJobSlices.put(experimentPart, jobSlice);
        }
    }


    @Override
    public synchronized final Collection<JS> getSlices() {
        if (experimentPartJobSlices == null) {
            initializeStateSlices();
        }

        return experimentPartJobSlices.values();
    }

    public abstract <EP extends ExperimentPart> ExperimentPartStateSlice createJobSlice(ExperimentPartController<EP> controller, EP experimentPart);
}
