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

import be.iminds.ilabt.jfed.experiment.Experiment;
import be.iminds.ilabt.jfed.experiment.tasks.ExperimentTaskStatus;
import be.iminds.ilabt.jfed.lowlevel.JFedException;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import java.util.Objects;
import java.util.concurrent.Callable;

/**
 * A StateSlice is slice of a {@link SlicedState}. It has the same properties as a {@link State}.
 *
 * User: twalcari
 * Date: 1/13/2016
 * Time: 11:46
 */
public abstract class StateSlice implements Callable<ExperimentTaskStatus> {
    private static final Logger LOG = LoggerFactory.getLogger(StateSlice.class);

    //input parameters
    protected final Job<?> job;
    protected final Experiment experiment;

    //execution parameters
    private final ReadOnlyObjectWrapper<State> state = new ReadOnlyObjectWrapper<>();

    //output parameters
    private ExperimentTaskStatus result = null;

    protected StateSlice(@Nonnull Job<?> job) {
        Objects.nonNull(job);
        this.job = job;
        this.experiment = job.getExperiment();
    }

    public abstract String getName();

    @Override
    public ExperimentTaskStatus call() {
        try {
            this.result = statefulRun();
        } catch (JFedException | InterruptedException e) {
            this.result = ExperimentTaskStatus.FAILED;
            LOG.error("UNCAUGHT exception in {}: {}", this.getClass().getName(), e.getMessage(), e);
        }

        return result;
    }

    public abstract ExperimentTaskStatus statefulRun() throws JFedException, InterruptedException;

    protected void setAndRunState(State newState) throws JFedException {
        this.state.set(newState);
        newState.run(job);
    }

    public State getState() {
        return state.get();
    }

    public ReadOnlyObjectProperty<State> stateProperty() {
        return state.getReadOnlyProperty();
    }

    public ExperimentTaskStatus getResult() {
        return result;
    }

}
