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.controller.TaskExecution;
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.jobs.states.JobStateFactory;
import be.iminds.ilabt.jfed.highlevel.jobs.states.UpdateUntilReadyOrFailTaskState;
import be.iminds.ilabt.jfed.highlevel.tasks.HighLevelTaskFactory;
import be.iminds.ilabt.jfed.highlevel.tasks.SliceManifestForAuthorityTask;
import be.iminds.ilabt.jfed.lowlevel.JFedException;
import be.iminds.ilabt.jfed.lowlevel.api_wrapper.StatusDetails;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.Instant;

/**
 * User: twalcari
 * Date: 1/18/2016
 * Time: 18:10
 */
public class RestoreSfaExperimentPartStateSlice extends ExperimentPartStateSlice<SfaExperimentPart> {
    private static final Logger LOG = LoggerFactory.getLogger(RestoreSfaExperimentPartStateSlice.class);


    private final HighLevelTaskFactory hltf;
    private final JobStateFactory jobStateFactory;


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

    @Override
    public ExperimentTaskStatus statefulRun() throws JFedException, InterruptedException {

        if (experimentPart.getConnectSfaAuthority().isEdgeVlan()) {
            LOG.debug("Skipping restore of fake authority {}", experimentPart.getConnectSfaAuthority().getName());
            return ExperimentTaskStatus.SUCCESS;
        }

        FetchSliceManifestForAuthorityState fetchManifestState =
                new FetchSliceManifestForAuthorityState(experimentPart);
        setAndRunState(fetchManifestState);

        if (fetchManifestState.getTaskExecution().getState() != TaskExecution.TaskState.SUCCESS ||
                experiment.getRequestedStartTime() != null && experiment.getRequestedStartTime().isAfter(Instant.now())) {
            // do nothing: it makes no sense to request status as the resources in the experiment part don't exist (yet).
            return ExperimentTaskStatus.WARNING;
        }
        if (experimentPart.getStatusDetails().getGlobalStatus() == StatusDetails.SliverStatus.READY)
            return ExperimentTaskStatus.SUCCESS;

        UpdateUntilReadyOrFailTaskState updateUntilReadyOrFailTaskState =
                jobStateFactory.createGetStatusUntilReadyOrFailTaskState(job, experimentPart);
        updateUntilReadyOrFailTaskState.setWaitForFirstCheck(false);
        setAndRunState(updateUntilReadyOrFailTaskState);

        return updateUntilReadyOrFailTaskState.getStatus();
    }


    private class FetchSliceManifestForAuthorityState extends SingleCallState<SliceManifestForAuthorityTask> {
        public FetchSliceManifestForAuthorityState(SfaExperimentPart experimentPart) {
            super(String.format("Requesting experiment information at %s", experimentPart.getName()),
                    hltf.getSliceManifest(experiment.getSlice(), experimentPart.getConnectSfaAuthority()));
        }
    }
}
