package be.iminds.jfed.gts_highlevel.jobs.gts_parts;

import be.iminds.ilabt.jfed.experiment.tasks.ExperimentTaskStatus;
import be.iminds.ilabt.jfed.highlevel.jobs.Job;
import be.iminds.ilabt.jfed.highlevel.jobs.SingleCallState;
import be.iminds.ilabt.jfed.highlevel.jobs.StateSlice;
import be.iminds.ilabt.jfed.highlevel.model.InternalState;
import be.iminds.ilabt.jfed.lowlevel.JFedException;
import be.iminds.jfed.gts_highlevel.GtsHighLevelException;
import be.iminds.jfed.gts_highlevel.controller.GtsModel;
import be.iminds.jfed.gts_highlevel.model.GtsXmlProject;
import be.iminds.jfed.gts_highlevel.tasks.CreateGtsProjectTask;
import be.iminds.jfed.gts_highlevel.tasks.GtsLoginTask;
import be.iminds.jfed.gts_highlevel.tasks.GtsTaskFactory;
import be.iminds.jfed.gts_highlevel.util.PasswordUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;

/**
 * User: twalcari
 * Date: 1/15/2016
 * Time: 11:43
 */
public class InitializeGtsProjectStateSlice extends StateSlice {
    private static final Logger LOG = LoggerFactory.getLogger(InitializeGtsProjectStateSlice.class);

    private static final int PASSWORD_LENGTH = 12;
    private static final int VPN_USERNAME_SUFFIX_LENGTH = 5;

    private final GtsModel model;
    private final GtsTaskFactory gtsTaskFactory;

    protected InitializeGtsProjectStateSlice(Job<?> job, GtsModel model, GtsTaskFactory gtsTaskFactory) {
        super(job);
        this.model = model;
        this.gtsTaskFactory = gtsTaskFactory;
    }

    @Override
    public String getName() {
        return "Creating GTS Project";
    }

    @Override
    public ExperimentTaskStatus statefulRun() throws JFedException, InterruptedException {
        //make sure we are logged in
        LOG.trace("Logging into GTS");
        if (model.getCredentials() == null) {
            final GtsLoginState loginState = new GtsLoginState();
            setAndRunState(loginState);

            if (loginState.getStatus() != ExperimentTaskStatus.SUCCESS) {
                throw new GtsHighLevelException("Could not login", loginState.getTaskExecution().getException());
            }
        }


        LOG.trace("Creating GTS project {}", experiment.getName());

        String vpnUsername = experiment.getName() + "_" + PasswordUtil.generatePassword(VPN_USERNAME_SUFFIX_LENGTH);
        String vpnPassword = PasswordUtil.generatePassword(PASSWORD_LENGTH);
        final CreateGtsProjectState createGtsProjectState =
                new CreateGtsProjectState(experiment.getName(), vpnUsername, vpnPassword);
        setAndRunState(createGtsProjectState);

        if (createGtsProjectState.getStatus() != ExperimentTaskStatus.SUCCESS) {
            throw new GtsHighLevelException(
                    String.format("Could not create a GTS project for experiment '%s'", experiment.getName()),
                    createGtsProjectState.getTaskExecution().getException());
        }

        GtsExperimentPartsContainer experimentPartsContainer = new GtsExperimentPartsContainer(createGtsProjectState.getGtsProject(), true, model);

        experiment.getParts().stream().filter(experimentPart -> experimentPart instanceof GtsExperimentPart).forEach(experimentPart -> {
            experimentPart.setContainer(experimentPartsContainer);
            experimentPart.setState(InternalState.UNALLOCATED);

        });


        return null;
    }

    private final class GtsLoginState extends SingleCallState<GtsLoginTask> {
        protected GtsLoginState() {
            super("Logging into GTS", gtsTaskFactory.createLoginGtsTask());
        }
    }


    private final class CreateGtsProjectState extends SingleCallState<CreateGtsProjectTask> {
        protected CreateGtsProjectState(String projectName, String vpnUsername, String vpnPassword) {
            super("Creating GTS Project '" + projectName + "'",
                    gtsTaskFactory.createCreateGtsProjectTask(projectName, vpnUsername, vpnPassword,
                            Collections.singletonList(model.getUsername())));
        }

        public GtsXmlProject getGtsProject() {
            return task.getProject();
        }
    }
}
