package be.iminds.ilabt.jfed.experiment.util;

import be.iminds.ilabt.jfed.experiment.Experiment;
import be.iminds.ilabt.jfed.experiment.ExperimentPart;
import be.iminds.ilabt.jfed.experiment.SfaExperimentPart;
import be.iminds.ilabt.jfed.highlevel.model.InternalState;
import be.iminds.ilabt.jfed.highlevel.model.Sliver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.time.Instant;

/**
 * User: twalcari
 * Date: 8/14/2015
 * Time: 10:38
 */
public class NextExperimentExpiration {
    private static final Logger LOG = LoggerFactory.getLogger(NextExperimentExpiration.class);

    private final ExperimentPart firstExpiringPart;
    private final Instant firstExpirationTime;


    public NextExperimentExpiration(@Nonnull Experiment experiment) {
        assert experiment.getSlice() != null;

        ExperimentPart firstExpiringPart = null;
        Instant firstExpirationTime = experiment.getSlice().getExpirationDate();

        for (ExperimentPart part : experiment.getParts()) {
            if (part.getState() == InternalState.UNALLOCATED || part.getState() == InternalState.DELETED) {
                LOG.trace("Skipping part {}, as status is {}", part.getName(), part.getState());
                continue; //old slivers that don't exist anymore, should not be taken into account
            }

            if(part instanceof SfaExperimentPart){
                boolean hasNodes = false, hasLinks = false;

                for (Sliver sliver : ((SfaExperimentPart) part).getSlivers()) {
                    hasNodes |= sliver.getNodes() != null && !sliver.getNodes().isEmpty();
                    hasLinks |= sliver.getLinks() != null && !sliver.getLinks().isEmpty();
                }

                if (!hasNodes && hasLinks) {
                    LOG.trace("Skipping part {}, as it has only links", part.getName());
                    continue;
                }
            }


            if (part.getExpirationTime() == null) {
                LOG.trace("Skipping part {}, as it has no expiration date", part.getName());
                continue;
            }

            if (firstExpirationTime == null || part.getExpirationTime().isBefore(firstExpirationTime)) {
                firstExpiringPart = part;
                firstExpirationTime = part.getExpirationTime();
            }
        }

        this.firstExpirationTime = firstExpirationTime;
        this.firstExpiringPart = firstExpiringPart;

        LOG.debug("Next expiration time was determined to be {} (source: {})", firstExpirationTime,
                firstExpiringPart != null ? firstExpiringPart.getName() : "experiment");
    }

    @Nullable
    public Instant getFirstExpirationTime() {
        return firstExpirationTime;
    }

    @Nullable
    public ExperimentPart getFirstExpiringPart() {
        return firstExpiringPart;
    }

    public boolean hasPartExpired() {
        return firstExpirationTime.isBefore(Instant.now());
    }
}
