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

import be.iminds.ilabt.jfed.experiment.SfaExperimentPart;
import be.iminds.ilabt.jfed.experiment.tasks.ExperimentTaskStatus;
import be.iminds.ilabt.jfed.highlevel.jobs.ExperimentPartStateSlice;
import be.iminds.ilabt.jfed.highlevel.jobs.Job;
import be.iminds.ilabt.jfed.highlevel.jobs.SingleCallState;
import be.iminds.ilabt.jfed.highlevel.model.InternalState;
import be.iminds.ilabt.jfed.highlevel.tasks.HighLevelTaskFactory;
import be.iminds.ilabt.jfed.highlevel.tasks.StatusTask;
import be.iminds.ilabt.jfed.lowlevel.JFedException;
import be.iminds.ilabt.jfed.lowlevel.api_wrapper.StatusDetails;

/**
 * User: twalcari
 * Date: 1/12/2016
 * Time: 15:48
 */

public class UpdateSfaExperimentPartStateSlice extends ExperimentPartStateSlice<SfaExperimentPart> {

    private final HighLevelTaskFactory hltf;

    public UpdateSfaExperimentPartStateSlice(Job<?> job, SfaExperimentPart experimentPart, HighLevelTaskFactory hltf) {
        super(job, experimentPart);
        this.hltf = hltf;
    }

    @Override
    public ExperimentTaskStatus statefulRun() throws JFedException, InterruptedException {
        assert experiment.getSlice() != null;

        setAndRunState(new UpdateExperimentPartState());

        //check if status of resources in ExperimentPart has changed

        StatusDetails.SliverStatus combinedStatus =
                experimentPart.getSlivers().stream()
                        .map(sliver -> sliver.getStatus().getGlobalStatus())
                        .reduce(StatusDetails.SliverStatus.READY, StatusDetails.SliverStatus::merge);

        experimentPart.setState(sliverStatusToInternalState(combinedStatus));

        return combinedStatus != StatusDetails.SliverStatus.FAIL ? ExperimentTaskStatus.SUCCESS
                : ExperimentTaskStatus.FAILED;
    }


    private class UpdateExperimentPartState extends SingleCallState<StatusTask> {
        @SuppressWarnings("ConstantConditions")
        public UpdateExperimentPartState() {
            super(String.format("Updating experiment status on %s", experimentPart.getName()),
                    hltf.status(experiment.getSlice(), experimentPart.getConnectSfaAuthority()));

        }
    }

    private static InternalState sliverStatusToInternalState(StatusDetails.SliverStatus sliverStatus) {
        switch (sliverStatus) {
            case READY:
                return InternalState.READY;
            case FAIL:
                return InternalState.FAILED;
            case CHANGING:
                return InternalState.CHANGING;
            case UNALLOCATED:
                return InternalState.UNALLOCATED;
            case UNINITIALISED:
            case UNKNOWN:
                return InternalState.UNKNOWN;
            default:
                throw new IllegalArgumentException("Unexpected SliverStatus: " + sliverStatus);
        }
    }
}
