package be.iminds.jfed.gts_highlevel.tasks;

import be.iminds.ilabt.jfed.highlevel.controller.TaskExecution;
import be.iminds.ilabt.jfed.util.JavaFXLogger;
import be.iminds.jfed.gts_highlevel.controller.GtsException;
import be.iminds.jfed.gts_highlevel.controller.GtsModel;
import be.iminds.jfed.gts_highlevel.controller.GtsReservationManager;
import be.iminds.jfed.gts_highlevel.controller.GtsReservationManagerFactory;
import be.iminds.jfed.gts_highlevel.model.GtsXmlProject;
import be.iminds.jfed.gts_highlevel.model.GtsXmlReservation;
import be.iminds.jfed.gts_highlevel.model.GtsXmlType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Provider;
import java.util.List;
import java.util.Objects;

/**
 * User: twalcari
 * Date: 9/24/2015
 * Time: 15:42
 */
public class StartGtsResourcesTask extends LoggedInGtsTask {
    private static final Logger LOG = LoggerFactory.getLogger(StartGtsResourcesTask.class);

    private final String scriptName;
    private final String script;
    private final GtsXmlProject project;

    private GtsXmlType type;
    private GtsXmlReservation reservation;

    StartGtsResourcesTask(String scriptName, String script, GtsXmlProject project,
                                  GtsReservationManagerFactory gtsReservationManagerFactory,
                                Provider<GtsLoginTask> loginGtsTaskProvider,
                                 GtsModel gtsModel, JavaFXLogger logger) {
        super("Start GTS Resources " + scriptName, logger, gtsReservationManagerFactory, loginGtsTaskProvider, gtsModel);
        this.scriptName = scriptName;
        this.script = script;
        this.project = project;
    }

    @Override
    protected void doGtsRMTask(TaskExecution taskExecution, GtsReservationManager reservationManager) throws GtsException {
        String typeName = reservationManager.addType(script, project);

        Integer reservationId = null;
        try {

            List<GtsXmlType> types = reservationManager.listTypes(project);

            this.type = types.stream().filter(type -> Objects.equals(typeName, type.getName())).findFirst()
                    .orElseThrow(() -> new GtsException("Could not find newly created type in list of types"));


            reservationId = reservationManager.reserveType(project, type);

            List<GtsXmlReservation> reservations = reservationManager.listReservations(project);

            final Integer finalReservationId = reservationId;
            reservation = reservations.stream().filter(res -> Objects.equals(res.getId(), finalReservationId)).findFirst()
                    .orElseThrow(() -> new GtsException("Could not find newly created reservation in list of reservations"));

            reservationManager.activateReservation(reservationId);

        } catch (GtsException ex) {
            LOG.warn("Error while starting GTS resources of type {}. Performing rollback.", typeName, ex);

            if (reservationId != null) {
                try {
                    reservationManager.releaseReservation(reservationId);
                    LOG.info("Successfully released reservation {} during rollback.", reservationId);
                } catch (GtsException ex2) {
                    LOG.info("Could not release reservation {} during rollback. Creating it had probably failed too.",
                            reservationId, ex2);
                }
            } else LOG.info("No reservation to rollback");

            if (typeName != null) {
                try {
                    reservationManager.removeType(project, typeName);
                    LOG.info("Successfully removed type {} from {} during rollback.", typeName, project.getId());
                } catch (GtsException ex2) {
                    LOG.info("Could not remove type {} from {} during rollback. Creating it had probably failed too.",
                            typeName, project.getId(), ex2);
                }
            } else LOG.info("No type to rollback");
            throw ex;
        }
    }

    public String getScriptName() {
        return scriptName;
    }

    public GtsXmlProject getProject() {
        return project;
    }

    public String getScript() {
        return script;
    }

    public GtsXmlReservation getReservation() {
        return reservation;
    }

    public GtsXmlType getType() {
        return type;
    }
}
