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

import be.iminds.ilabt.jfed.highlevel.controller.JFedHighLevelException;
import be.iminds.ilabt.jfed.highlevel.controller.Task;
import be.iminds.ilabt.jfed.highlevel.controller.TaskExecution;
import be.iminds.ilabt.jfed.highlevel.model.Slice;
import be.iminds.ilabt.jfed.highlevel.util.AggregateManagerWrapperFactory;
import be.iminds.ilabt.jfed.lowlevel.ApiInfo;
import be.iminds.ilabt.jfed.lowlevel.JFedException;
import be.iminds.ilabt.jfed.lowlevel.api_wrapper.AggregateManagerWrapper;
import be.iminds.ilabt.jfed.lowlevel.api_wrapper.StatusDetails;
import be.iminds.ilabt.jfed.fedmon.webapi.service.json.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nullable;
import java.util.Collections;
import java.util.List;

/**
 * User: twalcari
 * Date: 6/17/2015
 * Time: 12:22
 */
public final class StatusTask extends Task {
    private static final Logger LOG = LoggerFactory.getLogger(StatusTask.class);

    //input parameters
    private final Server auth;
    private final Slice slice;

    //results
    private boolean busy = false;
    private boolean softFailure = false;
    private boolean hardFailure = false;
    private StatusDetails statusDetails;

    //enviroment parameters
    private final AggregateManagerWrapperFactory aggregateManagerWrapperFactory;
    private final HighLevelTaskFactory highLevelTaskFactory;


    public StatusTask(Server auth, Slice slice,
                      AggregateManagerWrapperFactory aggregateManagerWrapperFactory,
                      HighLevelTaskFactory highLevelTaskFactory) {
        super("Status @ " + auth.getDefaultComponentManagerUrn());
        this.auth = auth;
        this.slice = slice;
        this.aggregateManagerWrapperFactory = aggregateManagerWrapperFactory;
        this.highLevelTaskFactory = highLevelTaskFactory;
    }

    @Override
    public void doTask(TaskExecution taskExecution) throws JFedException, InterruptedException {
        AggregateManagerWrapper amWrapper =
                aggregateManagerWrapperFactory.getAggregateManagerWrapper(taskExecution, auth);

        if (!ApiInfo.hasService(auth, ApiInfo.ApiName.GENI_AM)) {
            throw new JFedHighLevelException("Tried to get Status for slice \"" + slice.getUrnString() + "\", " +
                    "at authority \"" + auth.getDefaultComponentManagerUrn() + "\", but that authority has no AM URL: cannot continue.");
        }

        busy = false;
        statusDetails = null;
        try {
            statusDetails = amWrapper.status(slice.getUrn(), slice.getCredentials());

            /*TODO: check whether there are any slivers whose expiration time is past the currently known slice expiration time

            (Probably to be placed somewhere else?)
                    //check if we now have an inconsistent slice expiration time
        assert slice.getExpirationDate() != null;
        if (slice.getSlivers().stream()
                .anyMatch(sliver -> sliver.getExpirationDate() != null &&
                        sliver.getExpirationDate().isAfter(slice.getExpirationDate()))) {
            userAndSliceApiWrapper.getSliceExpiration(
                    JavaFXLogger.wrap(logger, taskExecution), slice.getCredentials(), slice.getUrn());
        }
             */

        } catch (JFedException ex) {
            if (ex.getGeniResponseCode() != null && ex.getGeniResponseCode().isBusy()) {
                LOG.warn("Got an busy-error while fetching status of sliver. Skipping...");
                busy = true;
            } else {
                hardFailure = true;
                throw ex;
            }
        }

        softFailure = !busy && statusDetails == null;
    }

    @Override
    public List<Task> initDependsOn() {
        return Collections.singletonList(highLevelTaskFactory.getSliceCredential(slice));
    }

    @Nullable
    public StatusDetails getStatusDetails() {
        return statusDetails;
    }

    public Server getAuthority() {
        return auth;
    }

    public boolean isHardFailure() {
        return hardFailure;
    }

    public boolean isBusy() {
        return busy;
    }

    public boolean isSoftFailure() {
        return softFailure;
    }
}
